言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

Ruby辞典

  1. トップページ
  2. Ruby辞典
  3. module / include / extend / mixin

module / include / extend / mixin

対応: Ruby 1.8(2003)

Rubyのモジュール(module)とミックスイン(mixin)の仕組みです。複数のクラスに共通の機能を持たせる多重継承の代替手段として使われます。

構文

# モジュールの定義
module モジュール名
  def インスタンスメソッド
    処理
  end

  def self.モジュール関数
    処理
  end
end

# include: モジュールのメソッドをインスタンスメソッドとして追加する
class クラス名
  include モジュール名
end

# extend: モジュールのメソッドをクラスメソッドとして追加する
class クラス名
  extend モジュール名
end

# prepend: include より前にメソッド探索チェーンに挿入する(メソッドの前処理に使う)
class クラス名
  prepend モジュール名
end

# 特定のオブジェクトにだけモジュールを extend する(シングルトンメソッド)
オブジェクト.extend(モジュール名)

メソッド一覧

構文 / メソッド概要
module モジュール名モジュールを定義します。インスタンス化できず、クラスと異なり継承もできません。
include モジュール名モジュールのメソッドをクラスのインスタンスメソッドとして追加します。
extend モジュール名モジュールのメソッドをクラスのクラスメソッドとして追加します。
prepend モジュール名モジュールをメソッド探索チェーンの先頭に挿入します(オーバーライドの前処理に便利です)。
include? / ancestorsクラスがどのモジュールをインクルードしているか確認できます。

サンプルコード

『Greetable』は挨拶機能を提供するモジュール、『Loggable』はログ機能を提供するモジュールです。

module_include_extend.rb
module Greetable
  def greet
    "こんにちは!私は#{name}です。"
  end

  def farewell
    "さようなら!#{name}でした。"
  end
end

module Loggable
  def log(message)
    puts "[LOG] #{self.class}: #{message}"
  end
end

# include でインスタンスメソッドとして追加する
class Person
  include Greetable
  include Loggable

  attr_reader :name

  def initialize(name)
    @name = name
  end
end

class Robot
  include Greetable

  attr_reader :name

  def initialize(name)
    @name = name
  end
end

# モジュールのメソッドが使える
p = Person.new("綾波レイ")
puts p.greet    # こんにちは!私は綾波レイです。
puts p.farewell  # さようなら!綾波レイでした。
p.log("起動しました")  # [LOG] Person: 起動しました

r = Robot.new("初号機")
puts r.greet    # こんにちは!私は初号機です。

# モジュールの確認
puts Person.ancestors.inspect
# [Person, Loggable, Greetable, Object, Kernel, BasicObject]
ruby module_include_extend.rb
こんにちは!私は綾波レイです。
さようなら!綾波レイでした。
[LOG] Person: 起動しました
こんにちは!私は初号機です。
[Person, Loggable, Greetable, Object, Kernel, BasicObject]

extend と prepend の実践例

extend_prepend.rb
# extend: クラスメソッドとして追加する
module ClassMethods
  def find_by_name(name)
    puts "DB検索: #{name}"
    { name: name, series: "エヴァンゲリオン" }
  end
end

class Pilot
  extend ClassMethods  # クラスメソッドになる
end

Pilot.find_by_name("碇シンジ")  # DB検索: 碇シンジ(クラスメソッドとして呼び出します)

# prepend: メソッドの前処理に使う(オーバーライド前に挿入)
module Timestamp
  def save
    puts "[#{Time.now}] 保存前の処理"
    super  # 元の save メソッドを呼び出す
  end
end

class Record
  prepend Timestamp  # Record#save より先に Timestamp#save が呼ばれる

  def save
    puts "保存しました"
  end
end

Record.new.save
# [2026-...] 保存前の処理
# 保存しました
ruby extend_prepend.rb
DB検索: 碇シンジ
[2026-03-29 ...] 保存前の処理
保存しました

よくあるミス1: includeとextendの混同

include と extend を混同すると、インスタンスから呼んだときに NoMethodError になります。

module_extend_ng.rb
# NG: include と extend を混同する
module Greetable
  def greet
    "こんにちは!"
  end
end

class Person
  extend Greetable  # extend なのでクラスメソッドになる
end

p = Person.new
p.greet  # NoMethodError: undefined method 'greet' for an instance of Person
ruby module_extend_ng.rb
module_extend_ng.rb:12:in '<main>': undefined method 'greet' for an instance of Person (NoMethodError)
module_include_ok.rb
# OK: インスタンスメソッドにしたい場合は include を使う
class Person
  include Greetable  # include でインスタンスメソッドになる
end

Person.new.greet  # "こんにちは!"
ruby module_include_ok.rb
こんにちは!

『include』はインスタンスメソッドの追加、『extend』はクラスメソッドの追加です。混同すると NoMethodError になるため、使い分けに注意してください。

よくあるミス2: モジュールのインスタンス変数

モジュールにインスタンス変数を持たせると、複数のクラスが include した場合に @count が混在する予期しない動作になります。モジュールにはステートレスなメソッドのみを定義してください。

# NG: モジュールにインスタンス変数を持たせると予期しない動作になる
module Counter
  def increment
    @count ||= 0
    @count += 1  # インクルード先のインスタンス変数に影響する
  end
end

# 複数のクラスが Counter を include した場合、@count が混在する

概要

Rubyは多重継承を持ちませんが、モジュールのミックスインによって複数のクラスに共通機能を持たせることができます。モジュールは「機能の集まり」としてクラスとは別に定義し、必要なクラスに『include』または『extend』で取り込みます。

『include』はモジュールのメソッドをインスタンスメソッドとして追加し、『extend』はクラスメソッドとして追加します。メソッド探索の順序はMRO(Method Resolution Order)と呼ばれ、『ancestors』で確認できます。MROとは、メソッドを呼び出した際にRubyがどの順序でモジュールやクラスを探すかの優先順位です。後からインクルードしたモジュールが探索順で前になります(スタック構造)。

モジュールはインスタンス化できません。モジュールに状態(インスタンス変数)を持たせると、インクルード先のクラスのインスタンス変数と混在するため混乱を招きます。モジュールにはなるべくステートレスなメソッドのみを定義するとよいでしょう。

標準ライブラリの『Comparable』モジュールを使ったカスタム比較については『Comparable / <=>』を、継承の仕組みは『継承 / super』を参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。