1. shiopon01

    Posted

    shiopon01
Changes in title
+RubyのModuleの使い方とはいったい
Changes in tags
Changes in body
Source | HTML | Preview

Module

Rubyにはオブジェクト指向で一般的なクラス以外にも、モジュールという概念が存在します。モジュールではクラスと同じように定数やメソッドをまとめたり、クラスに組み込んで多重継承を実現したり、クラスなどをまとめることで名前空間を提供するなど、いろいろな使い方ができます。
この記事では以下の内容について解説します。

  • 定数やメソッドをまとめる
  • クラスに組み込んで多重継承を実現する
  • 名前空間を提供する

リファレンスマニュアル(2.3.0)
http://docs.ruby-lang.org/ja/2.3.0/class/Module.html:title

定数やメソッドをまとめる

モジュールではクラスと同様に、定数やメソッドをまとめる機能があります。

定数

モジュール内で定義した定数は、モジュール名を経由して呼び出すことが可能です。

module Mod
  Version = "2.3.0"
end

Mod::Version #=> "2.3.0"

インスタンスメソッド

インスタンスメソッドは定義するだけでは呼び出すことができません。module_functionメソッドを使い、メソッドをモジュール関数にすることで呼び出すことができるようになります。

module Mod
  def hello
    puts 'Hello'
  end

  module_function :hello
end

Mod.hello #=> "Hello"

クラスメソッド

モジュール内で宣言されたクラスメソッド(self. から宣言されるメソッド)はincludeやextendで拡張したクラスから呼び出すことができませんが、クラスと同様にモジュールから直接呼び出すことができます。

module Mod
  def self.hello
    puts 'Hello'
  end
end

Mod.hello #=> "Hello"

モジュール関数とクラスメソッドの優先度

同名のモジュール関数とクラスメソッドがあった場合、後に定義されたメソッドのほうが実行されます。

module Mod
  def hello
    puts 'module'
  end

  def self.hello
    puts 'class'
  end

  module_function :hello
end

Mod.hello #=> "module"
module Mod
  def hello
    puts 'module'
  end

  module_function :hello

  def self.hello
    puts 'class'
  end
end

Mod.hello #=> "class"

クラスに組み込んで多重継承を実現する(Mix-in)

Rubyのクラスは単一継承のみですが、モジュールをクラスに組み込むことで多重継承を可能にしています(ここだけ聞くとJavaで言うinterfaceのようですが、moduleではメソッドの機能を実装することができます)。クラスにモジュールをincludeしたりextendすることをMix-inと言い、Mix-inによってクラスの肥大化を防いだり、クラスをまたがった同じ処理を切り出して繰り返しを防ぐことができます。
モジュール関数、クラスメソッドは組み込むことができません。

include

includeでは、対象のクラスにincludeしたモジュールのメソッドがインスタンスメソッドとして組み込まれます。クラスからnewで作成したインスタンスで呼び出すことができます。これをクラスメソッドとして呼びだそうとすると、undefinde methodのエラーが出ます。

module Mod
  def hello
    puts 'Hello'
  end
end

class Obj
  include Mod
end

ins = Obj.new
ins.hello #=> "Hello"

extend

extendでは、対象のクラスにextendしたモジュールのメソッドがクラスメソッドとして組み込まれます。クラスメソッドなのでインスタンスでは呼び出すことができず、いつも通りクラスから直接呼び出します。こちらもインスタンスから呼びだそうとすればundefined methodです。

module Mod
  def hello
    puts 'Hello'
  end
end

class Obj
  extend Mod
end

Obj.hello #=> "Hello"

名前空間を提供する

名前空間

ruby gemなどでは、クラス名やメソッド名の重複による使用者からのモンキーパッチを防ぐためにgemの中身を全て1つのモジュールで梱包することが多いです。

module Name
  class Hoge
    def self.hello
      puts 'hello'
    end
  end
end

Name::Hoge.hello #=> "hello"

名前空間とMix-in

モジュールを重ねることで、MIx-inに使うモジュールを名前空間内で提供することができます。

module Name # 名前空間としてのモジュール
  module Mod  # Mix-inとしてのモジュール
    def hello
      puts 'Hello'
    end
  end
end

class Obj # Mix-in
  extend Name::Mod
end

Obj.hello #=> "Hello"