13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rubyメタプロあれこれ1

Last updated at Posted at 2014-10-21

rubyのメタプロに関するまとめ

特異メソッド

特定のオブジェクトに特化したメソッドの事を特異メソッドという。以下例。

hoge_test.rb
hoge = "abc"

def hoge.moji?
  self.upcase == self
end

hoge.moji?  # => false

この場合のselfはhogeにあたる。

クラスメソッドの正体

上記、特異メソッドの形はクラスメソッドの形に似ていないだろうか?

def hoge.moji?; end
def MyClass.moji?; end

結論から言えば、クラスメソッドはクラスの特異メソッド。
クラスの中でのself(特定のオブジェクト)は、クラス自身になる。
なので、以下のように書ける。

class MyClass
    def self.moji?
    end
end

##特異クラス

オブジェクトのクラスを参照するにはObject#classで参照できる。しかし、見えているクラスとは別にRubyは裏に特別なクラスを持っている。それが、オブジェクトの特異クラスである。

Object#classでは特異クラスを隠されてしまうので、スコープに入れない。そこで、classキーワードを使った特別な構文があり、特異クラスのスコープに入る事ができる。

class << obj
   #メソッドなど定義
end

rubyの入門書などにクラスメソッドの書き方として目にすることがあるが、
これは、特異クラスに特異メソッドを書いている事になる。

tokui_test.rb
class MyClass
    class << self
        def method_1; end
    end
end

上記、コードはクラスMyClassの特異クラスに特異メソッドを定義という意味。

つまり、クラスの特異クラスにメソッドを定義する事は、クラスメソッドを定義したことと同じ意味ということ

また、特異クラスのある場所は、特異メソッドが存在するオブジェクトにある。継承チェーンとしては以下のようになる。

オブジェクト->オブジェクトの特異クラス->オブジェクトのsuperclass
->Object

##クラス拡張とオブジェクト拡張(include,extend)
オブジェクトやクラスの拡張として、include,extentdがよく用いられる。
その例を示す。

例としてクラスにモジュールからクラスメソッドを拡張する。
includeとextendを使用するがどちらも同じ意味になるが、
includeの例をより簡単にしたのがextend。

kakucyo_test.rb
module MyModule1
	def hoge1
		'hello'
	end
end

class Booo
	class << self
	    include MyModule1
	end
end

class Waaaa
	extend MyModule1
end

p Booo.hoge1   # => "hello"
p Waaaa.hoge1  # => "hello"

includeは特に説明はしない。extend(Object#extend)は、
レシーバーの特異クラスにモジュールをインクルードするための
ショートカットである。この場合のレシーバーはself(Waaa自身)。

##フックメソッド

特定のイベントをフックとしてRubyから呼び出されるメソッド

・Class#inherited #クラスが継承されたときに呼ばれる
・Object#initialize #オブジェクトを作成(new)するとき呼ばれる。
・Module#included #インクルードされたあとで呼ばれる。

例えば、Module#includedをオーバーライドすれば、モジュールの
ライフサイクルにプラグインできる

fook_test.rb

module MyModule
	def self.included(base)
		puts "MyModule は #{base} にミックスインされました"
      # baseには呼び出したオブジェクト(この場合はMyClassが返ってくる)
	end
end

class MyClass
	include MyModule
end

実行結果 # => MyModule は MyClassにミックスインされました

この技術はRailsのActiveRecordでも使用されている。
以下ソース抜粋

validation.rb
module ActiveRecord
	module Validation
		def self.included(base)
                   #クラスメソッドの定義
			base.extend ClassMethods
			base.class_eval do
				~~
				~~
			end
			base.send :include, ActiveSupport::CallBacks
		end

		module ClassMethods
			def validates_each(*args)
				....
			end
		

上記を簡単に説明するとActiveRecord::Validationがどこかでインクルードされたらフックメソッドincludedが呼ばれ、base.extendでクラスメソッドを定義。さらに、includeしたクラスに動的ディスパッチを使用して、ActiveSupport::CallBacksをインクルードさせている。

なお、base.include ActiveSupport::CallBacksとは書けない。
理由はModuleクラスのprivateメソッドのため。

13
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?