概要
Rubyのモジュール(module)を何となく使ってきたので、基礎を振り返りつつ、ざっくばらんにコード例を掲載する。詳しい説明は省略するので必要に応じて各自で調べるものとする。
前提
以下環境で動作確認済み
moduleとは
Rubyにおけるモジュールは、Moduleクラスのインスタンスでうんたらであるが、ここではクラスと同じように変数やメソッドを持ってる名前空間ぐらいの認識から始める。
module MyModule
end
みたいに定義できる。
モジュールはクラスと違い
などの特徴がある。インスタンス作れない、継承できないでどうやって使うのよという疑問は後々。
moduleを入れ子にする
module Constant
module User
module Status
INVALID = 0
VALID = 1
end
end
end
p Constant::User::Status::VALID # 1
のように、moduleを入れ子にすることで、名前空間の階層化ができる。これによって階層的な定数の管理とかがしやすくなる。
モジュールに特異メソッドを実装する
module MyModule
def self.say_hello
p 'Hello'
end
end
MyModule::say_hello # Hello
のように、クラスのクラスメソッドみたいな書き方でメソッドを定義すると、モジュールの特異メソッドとして利用できるようになる。クラスに属さない汎用的なロジックとか定義すると捗る。
特異メソッドはmodule_functionメソッドで定義することも出来る。こっちのほうが一般的かも。
module MyModule
def say_hello
p 'Hello'
end
module_function :say_hello
end
MyModule::say_hello # Hello
モジュールをクラスにmixinする
モジュールはインスタンスを生成できないけど、クラスにインクルードする(mixinする)ことはできる。
module MyModule
def say_hello
p "Hello"
end
end
class MyClass
include MyModule
end
MyClass.new.say_hello # Hello
クラスにモジュールをincludeすると、モジュールのメソッドがあたかもクラスのインスタンスメソッドであるかのように利用できる。
Rubyはクラスの多重継承を行うことができないが、includeは複数のモジュールに対して行えるので、一つのクラスに複数の機能を取り込むような使い方ができる。
module FooModule
def say_foo
p 'Foo!!'
end
end
module BarModule
def say_bar
p 'Bar!!'
end
end
class MyClass
include FooModule
include BarModule
end
obj = MyClass.new
obj.say_foo # Foo!!
obj.say_bar # Bar!!
逆に、一つのモジュールを複数のクラスでincludeすることもできるので、ある共通の機能を複数のクラスに持たせることができる。
module Printable
def print_info
p "this class is #{self.class}"
end
end
class User
include Printable
end
class Post
include Printable
end
User.new.print_info # this class is User
Post.new.print_info # this class is Post
クラスをモジュールでextendする
includeでは、モジュールのメソッドをクラスのインスタンスメソッドにすることができた。
今度はextendを使うことで、モジュールのメソッドをクラスのクラスメソッドにすることができる。
module MyModule
def say_hello
p "Hello!!"
end
end
class MyClass
extend MyModule
end
MyClass.say_hello # Hello!!
mixin(include,extend)の継承
クラスの継承時に、親クラスのmixin(include,extend)はそのまま引き継がれる
module IncludeMyModule
def print_class
p "this class is #{self.class}"
end
end
module ExtendMyModule
def say_hello
p "Hello!!"
end
end
class ParentClass
include IncludeMyModule
extend ExtendMyModule
end
class ChildClass < ParentClass
end
ParentClass.new.print_class # this class is ParentClass
ChildClass.new.print_class # this class is ChildClass
ParentClass.say_hello # Hello!!
ChildClass.say_hello # Hello!!