⚙️

【Ruby】モジュールについて

2024/12/29に公開

はじめに

Railsアプリを開発しているときや、Rubyの勉強をするときにモジュールという言葉がよく出てくるかと思います。自分自身何度も見たことや聞いたことはあったものの、説明してと言われると難しいなと思いまして、今回モジュールについて調べてまとめてみました。

モジュールとは?

モジュールを一言で言うと、メソッドやクラスなどをまとめるための箱みたいなものです。
複数のクラスで使用されるメソッドをまとめたり、名前空間を分けたりする場合に使われます。

モジュールの使用例

よくある使われ方(モジュールを用いた開発)

  • 複数箇所で共通する処理をまとめる

    例)ファイルのアップロード処理、

  • 名前空間を分ける

    例)adminとfrontで処理を分ける

モジュールを使ってみる

名前空間を分ける

module Modern
    class Child		
        def self.play
            puts "Nintendo Switch"
        end
    end
end

class Child
    def self.play
        puts "鬼ごっこ"
    end
end

Modern::Child.play
#=> Nintendo Switch

Child.play
#=>鬼ごっこ

モジュールブロックの中に、クラスを定義することでそのモジュールに属したクラスという意味になります。

このようにすることで、クラス名の衝突を防ぐことができたり、関連クラスやメソッドをフォルダにまとめ、プロジェクトの構造を整理するといったこともできます。

メソッドを取り込む(ミックスイン)

モジュールにメソッドを定義し、各クラスにミックスインすることで、モジュール内で定義したメソッドをクラスやそのインスタンスから呼び出すことができるようになります。
そのため、複数のクラスで共通するメソッドをまとめるといったことや多重継承と同じようなことができます。

ミックスインにはincludeextendprependの3種類があります。

  • include モジュール名
module Greeting 
    def greeting
        puts "hello"
    end
end

class Person
    include Greeting
end

person = Person.new
person.greeting
#=> hello

includeを使ってミックスインした場合、モジュール内で定義したメソッドをインスタンスメソッドとして使用することができるようになります。

  • extend モジュール名
module Greeting 
    def greeting
        puts "hello"
    end
end

class Person
    extend Greeting
end

Person.greeting
#=> hello

person = Person.new
person.greeting
#=> undefined method `greeting' for #<Person:0x0062c748>

extendでミックスインした場合は、モジュール内で定義したメソッドを取り込んだクラスのクラスメソッドとして使用することができるようになります。

prepend

module Greeting 
    def greeting
        puts "hello"
    end
end

class Person
    prepend Greeting
    
    def greeting
      puts "こんにちは"
    end
end

person = Person.new
person.greeting
#=>hello

Person.greeting
#=>undefined method `greeting' for Person:Class

pependを使用した場合、クラスのインスタンスメソッドとして使用できるようになります。ただ、includeと異なり、モジュールのメソッドが優先して実行されます。

モジュールとクラスとの違い

  • クラス
    • インスタンスを作成できる
    • 継承できる(単一継承)
  • モジュール
    • インスタンスを作成できない
    • 継承不可(Mixinで代用可)
      • Rubyは基本単一継承だが、Mixinにより多重継承に似たようなことが可能

モジュールの面白いと思った点

putsメソッド、ppメソッドなどは、Kernelモジュールで定義されています。 Kernelモジュールは、**Objectクラス(Rubyの実質トップレベルのクラス)**でincludeされています。 Rubyのクラスはすべて、Objectクラスを継承しているので、すべてのクラスでputsメソッドが使用できるという仕組みになっています。

イメージ

module Kernel
    def puts
        hogehoge
    end
end

class Object
    extend Kernel
end

メソッドの優先順位

module Hoge1
    def hoge
        puts "hoge1"
    end
end

module Hoge2
    def hoge
        puts "hoge2"
    end
end

class Parent
    def hoge
        puts "hoge_parent"
    end
end

class Child < Parent
    def hoge
        puts "hoge_child"
    end

    include Hoge1
    include Hoge2
end

c = Child.new
c.hoge

p Child.ancestors
#=>[Child, Hoge2, Hoge1, Parent, Object, Kernel, BasicObject]

同じ名前のメソッドが定義されている場合、上記コード内のp Child.ancestorsで出力されている順番で実行されるメソッドが決まります。

おわりに

今回モジュールはモジュールについて学習してみました。
内容としては基本的な部分になるかと思いますが、普段の業務での既存コードを読んでいるときにより理解しやすくなったと思います。

Discussion