【Ruby】モジュールについて
はじめに
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
#=>鬼ごっこ
モジュールブロックの中に、クラスを定義することでそのモジュールに属したクラスという意味になります。
このようにすることで、クラス名の衝突を防ぐことができたり、関連クラスやメソッドをフォルダにまとめ、プロジェクトの構造を整理するといったこともできます。
メソッドを取り込む(ミックスイン)
モジュールにメソッドを定義し、各クラスにミックスインすることで、モジュール内で定義したメソッドをクラスやそのインスタンスから呼び出すことができるようになります。
そのため、複数のクラスで共通するメソッドをまとめるといったことや多重継承と同じようなことができます。
ミックスインにはincludeとextendとprependの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