[Ruby] モジュール(module) 入門

概要

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!!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です