モジュール¶
モジュールは2つの目的を果たします。
- 他の型、メソッド、定数を定義するための名前空間として
- 他の型にミックスインできる部分型として
名前空間としてのモジュールの例
module Curses
class Window
end
end
Curses::Window.new
ライブラリの作成者は、名前の衝突を避けるために、定義をモジュール内に入れることをお勧めします。標準ライブラリは、型とメソッドが非常に一般的であるため、長い名前を書くことを避けるために、通常は名前空間を持ちません。
モジュールを部分型として使用するには、include
またはextend
を使用します。
include
を使用すると、そのモジュールで定義されたメソッドをインスタンスメソッドとして型に含めることができます。
module ItemsSize
def size
items.size
end
end
class Items
include ItemsSize
def items
[1, 2, 3]
end
end
items = Items.new
items.size # => 3
上記の例では、モジュールからsize
メソッドをItems
クラスに貼り付けたかのようです。これが実際に機能する方法は、各型に祖先または親のリストを持たせることです。デフォルトでは、このリストはスーパークラスで始まります。モジュールがインクルードされると、このリストの先頭に追加されます。メソッドが型で見つからない場合、このリストで検索されます。super
を呼び出すと、この祖先リストの最初の型が使用されます。
module
は他のモジュールを含めることができるため、メソッドがモジュールで見つからない場合は、含まれているモジュールで検索されます。
extend
を使用すると、そのモジュールで定義されたメソッドをクラスメソッドとして型に含めることができます。
module SomeSize
def size
3
end
end
class Items
extend SomeSize
end
Items.size # => 3
include
とextend
の両方で、モジュールで定義された定数を含める/拡張する型で使用できるようにします。
どちらも、名前空間を何度も記述することを避けるためにトップレベルで使用できます(ただし、名前の衝突の可能性は高まります)。
module SomeModule
class SomeType
end
def some_method
1
end
end
include SomeModule
SomeType.new # OK, same as SomeModule::SomeType
some_method # OK, 1
extend self¶
モジュールの一般的なパターンは、extend self
です。
module Base64
extend self
def encode64(string)
# ...
end
def decode64(string)
# ...
end
end
これにより、モジュールを名前空間として使用できます。
Base64.encode64 "hello" # => "aGVsbG8="
また、プログラムに含めることができ、そのメソッドは名前空間なしで呼び出すことができます。
include Base64
encode64 "hello" # => "aGVsbG8="
これが役立つには、メソッド名にモジュールへの参照が含まれている必要があります。そうでない場合は、名前の衝突の可能性が高くなります。
モジュールはインスタンス化できません。
module Moo
end
Moo.new # undefined method 'new' for Moo:Module
モジュールの型チェック¶
モジュールは型チェックにも使用できます。
A
とB
という名前の2つのモジュールを定義する場合
module A; end
module B; end
これらはクラスに含めることができます。
class One
include A
end
class Two
include B
end
class Three < One
include B
end
次に、これらのクラスのインスタンスに対して、クラスだけでなく、含まれているモジュールに対しても型チェックを実行できます。
one = One.new
typeof(one) # => One
one.is_a?(A) # => true
one.is_a?(B) # => false
three = Three.new
typeof(three) # => Three
three.is_a?(A) # => true
three.is_a?(B) # => true
これにより、クラスではなくモジュール型に基づいて配列やメソッドを定義できます。
one = One.new
two = Two.new
three = Three.new
new_array = Array(A).new
new_array << one # Ok, One includes module A
new_array << three # Ok, Three inherits module A
new_array << two # Error, because Two neither inherits nor includes module A