目次
概要
Rubyのモジュール(module)を何となく使ってきたので、基礎を振り返りつつ、ざっくばらんにコード例を掲載する。詳しい説明は省略するので必要に応じて各自で調べるものとする。
前提
以下環境で動作確認済み
debian | 9.3 |
ruby | 2.4.1 |
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!!