Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

Ruby初心者が必ずつまづくオブジェクトモデルの話(include, extendを理解する)

メタプログラミングRuby 第2版, Effective Rubyのオブジェクト階層・クラス定義などを2、3周読んで、わかったかも!なポイントを書きます。
とりあえずその辺のトピックスを1周して「と・・・特異・・クラス・・?」と恐れおののいた人の理解の助けになれば・・なメモ。

オブジェクト

  • Rubyではすべてのものがオブジェクトである
  • クラスもオブジェクトである
  • Rubyでたくさん存在しているクラスは、 Classクラスのオブジェクト である

クラス

  • クラスとはモジュールである
  • モジュールとクラスの違い、モジュールは new できない
  • つまりモジュールはインスタンス化できない

モジュール

  • モジュールのインスタンスメソッドは、クラスに include されると、インスタンスメソッドとして呼びだせる
  • モジュールのインスタンスメソッドは、クラスに extend されると、クラスメソッドとして呼びだせる
  • モジュールのクラスメソッドは、クラスに include しても extend しても呼び出せない
  • モジュールのクラスメソッドはモジュールの特異クラスに存在するから

include

  • モジュールを クラス に取り込むための機構

extend

  • モジュールを オブジェクト に取り込むための機構
  • Rubyの全てのクラスは Classクラスのオブジェクト なので、extend でクラスを拡張できる
  • Classクラスのオブジェクト を拡張するための仕組みが 特異クラス

includeとextendの例

module MyModule
  def my_instance_method
    'my_instance_method'
  end
  def self.my_class_method  # 呼び出せない
    'my_class_method'
  end
end

class MyIncludeClass
  include MyModule
end

my_include_class = MyIncludeClass.new
my_include_class.my_instance_method
# => "my_instance_method"


class MyExtendClass
  extend MyModule
end

MyExtendClass.my_instance_method
# => "my_instance_method"

メソッド

  • メソッドは1種類である
  • いろいろ種類があるじゃないかと思うが、どこに存在しているかの違い

インスタンスメソッド

  • オブジェクトから呼びだせるメソッド
  • オブジェクトのクラスに存在する

クラスにインスタンスメソッドを定義する例

class MyIncludeClass
  def my_method1
    'my_method1'
  end
end

class はすでに定義済みのクラス名(例ではMyIncludeClass)が渡されると、再オープンする。オープンしたクラスにメソッドを def で追加している。

インスタンスメソッドを呼び出してみる例

m1 = MyIncludeClass.new
m1.my_method1
=> "my_method1"

上の例で MyIncludeClassinclude MyModule しているので、モジュールのメソッドと、今追加したメソッドがインスタンスメソッドとして定義されている。

定義済みのインスタンスメソッドを確認する例

MyIncludeClass.instance_methods  # インスタンスメソッド一覧を表示
# => [:my_method1, :my_instance_method, ...]

クラスメソッド

  • クラスから呼びだせるメソッド
  • Classクラスのオブジェクト = クラス の特異クラスに存在する

クラスにクラスメソッドを定義する例

class MyExtendClass
  def self.my_extend1
    'my_extend1'
  end
end

def self とするとクラス定義の中の self つまりそのクラス自身をレシーバとしたメソッドが定義できる = クラスメソッド

クラスメソッドを呼び出してみる例

MyExtendClass.my_extend1
=> "my_extend1"

上の例で MyExtendClassextend MyModule しているので、モジュールのメソッドと、今追加したメソッドがクラスメソッドとして定義されている。

定義済みのクラスメソッドを確認する例

irb> MyExtendClass.singleton_methods
# => [:my_extend1, :my_instance_method]

特異クラス

  • すべての オブジェクト が裏に持つことができる特別なクラス
  • 特異クラスはオブジェクトを 1つしか持てない
  • ので singleton_class ともいう
  • オブジェクトの特異クラスに存在するメソッドは、オブジェクトの 特異メソッド である
  • オブジェクト特異メソッドは、オブジェクトのクラスのメソッド(クラスメソッド)である
  • つまりクラスは Classクラスのオブジェクト なので、 Classクラスのオブジェクトの特異クラス に定義されたメソッドはそのクラスだけで使える クラスメソッド である

特異クラスの確認方法 : singleton_class

irb> my_extend_class = MyExtendClass.new
=> #<MyExtendClass:0x007f8c2384cb08> 
irb> my_extend_class.singleton_class
=> #<Class:#<MyExtendClass:0x007f8c2384cb08>>

特異メソッドの確認方法 : singleton_methods

irb> my_extend_class.singleton_class.singleton_methods
=> [:my_extend1, :my_instance_method]

特異クラス側からメソッドを確認

irb> MyExtendClass.singleton_class.instance_methods
# => [:my_extend1, :my_instance_method, ...]

特異クラスはオブジェクト階層のどこに入る?

  • 特異メソッドの住処が特異クラス
  • オブジェクトが特異メソッドを持っていれば、まず特異クラスからメソッド探索される
  • 特異クラスもオブジェクト階層に組み込まれる
  • 特異クラスの superclass はオブジェクトの通常のクラス
  • 継承したサブクラスからもクラスメソッドが使えるようになる

特異クラスのsuperclassの確認方法

irb> my_extend_class.singleton_class.superclass
# => MyExtendClass

これらのポイントを頭の片隅に置きつつ、もう一度 「メタプログラミングRuby」 を読むとRubyわからん・・の闇がパッと晴れる・・!かも。。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
5
Help us understand the problem. What are the problem?