moduleについて

モジュールの定義

モジュールの構文

module <モジュール名>
  # 定数やメソッドなど
end

# 例
module Greeter
  def hello
    'hello'
  end
end

クラスの構文と同じだが、以下の注意点がある。

  • モジュールからインスタンスを作成できない。
  • 他のモジュールやクラスを継承することはできない。

ミックスイン

include

モジュールで定義したメソッドをインスタンスメソッドとして使用することができる。

module Loggable
  def log(text)
    puts "[Log] #{text}"
  end
end

class Product
  # モジュールをincludeする。
  include Loggable 

  def initialize(title)
    @title = title
  end

  def title
    # logメソッドはモジュールで定義したもの。
    log('name is called') 
    @title
  end
end

product = Product.new('A great movie')
product.title 
# => [Log] name is called
# => A great movie

extend

モジュール内のメソッドをそのクラスの特異メソッド(クラスメソッド)にすることができる。

module Loggable
  def log(text)
    puts "[Log] #{text}"
  end
end

class Product
  # extendを使用することでクラスメソッドとしてmixinすることができる。
  extend Loggable

  # クラス構文の直下で使用可能。(selfがクラス自身のため)
  log('Defined Product class')

  def initialize(title)
    @title = title
  end

  def self.create_products(names)
    # クラスメソッド内で呼び出すことが可能になる。
    log('create_products is called')
  end
end

# クラスメソッド経由でlogメソッドが呼び出される。
Product.create_products([]) # => [Log] create_products is called

# Productクラスのクラスメソッドとして直接呼び出すことも可能。
puts Product.log('hello') # => [Log] hello

モジュールに特異メソッドを定義する

mixinせずにモジュール単体でメソッドを使用したい場合に使用する。 モジュールはインスタンスオブジェクトが作れないので、newする必要がない 「単なるメソッドの集まり」を作りたいケースに向いている。

module Loggable
  # 特異メソッドとして定義する。
  def self.log(text)
    puts "[LOG] #{text}"
  end
end

# クラスと同様にclass << self を使用して定義できる。
module Loggable
  class << self
    def log(text)
      puts "[LOG] #{text}"
    end
  end
end

Loggable.log('hello')

module_functionメソッド

ミックイン、モジュールの特異メソッドとして両方で使えるメソッドを定義する際に使用する。このように両方で使用できるメソッドをモジュール関数という。

module Loggable
  def log(text)
    puts "[LOG] #{text}"
  end

  # module_functionは対象のメソッドの定義よりも下で定義すること!
  module_function :log
end

Loggable.log('hello') # => [Log] hello

class Product
  include Loggable

  def title
    log('title is called')
  end
end

product = Product.new
product.title # => [Log] title is called

注意1

モジュール関数はミックスインされると自動的にprivateメソッドになる。

product = Product.new
product.log('hello') # => NoMethodError

注意2

module_functionメソッドを引数なしで呼び出した場合、そこから下に定義されたメソッドが全てモジュール関数になる。

module Loggable
  module_function
  
  def log(text)
    puts "[Log] #{text}"
  end
end

moduleに状態を保持する。

外部ライブラリでは、そのライブラリを実行するための設定値をモジュール自身に保存させることがあるらしい。

module AwesomeApi
  @base_url = ''
  @debug_mode = false

  # クラスインスタンス変数を読み書きするための特異メソッドを定義する。
  class << self
    attr_accessor :base_url, :debug_mode
  end
end


AwesomeApi.base_url = 'http://example.com'
AwesomeApi.debug_mode = true

AwesomeApi.base_url # => http://example.com
AwesomeApi.debug_mode # => true