instance_eval
との主な違いclass_eval
はinstance_eval
、インスタンスのコンテキストclass_eval
内で機能するのに対し、クラスのコンテキスト内で機能することです。Railsにどれだけ慣れているかはわかりませんが、例としてこれを見てみましょう。
class Test3 < ActiveRecord::Base
end
t = Test3.first
t.class_eval { belongs_to :test_25 } #=> Defines a relationship to test_25 for this instance
t.test_25 #=> Method is defined (but fails because of how belongs_to works)
t2 = Test3.find(2)
t2.test_25 #=> NoMethodError
t.class.class_eval { belongs_to :another_test }
t.another_test #=> returns an instance of another_test (assuming relationship exists)
t2.another_test #=> same as t.another_test
t.class_eval { id } #=> NameError
t.instance_eval { id } #=> returns the id of the instance
t.instance_eval { belongs_to :your_mom } #=> NoMethodError
これbelongs_to
は、実際にはクラス本体のコンテキスト内で発生するメソッド呼び出しであり、インスタンスから呼び出すことはできないために発生します。で呼び出そうとするとid
、はクラスではなくインスタンスで定義されたメソッドであるclass_eval
ため、失敗します。id
class_eval
両方でメソッドを定義instance_eval
し、インスタンスに対して呼び出された場合、基本的に同じように機能します。それらは、呼び出されるオブジェクトのインスタンスでのみメソッドを定義します。
t.class_eval do
def some_method
puts "Hi!"
end
end
t.instance_eval do
def another_method
puts "Hello!"
end
end
t.some_method #=> "Hi!"
t.another_method #=> "Hello!"
t2.some_method #=> NoMethodError
t2.another_method #=> NoMethodError
ただし、クラスを扱う場合は異なります。
t.class.class_eval do
def meow
puts "meow!"
end
end
t.class.instance_eval do
def bark
puts "woof!"
end
end
t.meow #=> meow!
t2.meow #=> meow!
t.bark #=> NoMethodError
t2.bark #=> NoMethodError
それで、樹皮はどこに行きましたか?クラスのシングルトンクラスのインスタンスで定義されました。以下で詳しく説明します。しかし、今のところ:
t.class.bark #=> woof!
Test3.bark #=> woof!
self
したがって、クラス本体内で何を参照しているかについての質問に答えるために、簡単なテストを作成できます。
a = class Test4
def bar
puts "Now, I'm a #{self.inspect}"
end
def self.baz
puts "I'm a #{self.inspect}"
end
class << self
def foo
puts "I'm a #{self.inspect}"
end
def self.huh?
puts "Hmmm? indeed"
end
instance_eval do
define_method :razors do
puts "Sounds painful"
end
end
"But check this out, I'm a #{self.inspect}"
end
end
puts Test4.foo #=> "I'm a Test4"
puts Test4.baz #=> "I'm a Test4"
puts Test4.new.bar #=> Now I'm a #<Test4:0x007fa473358cd8>
puts a #=> But check this out, I'm a #<Class:Test4>
したがって、ここで起こっていることは、上記の最初のputsステートメントで、inspectがself
、クラスメソッド本体のコンテキスト内でクラスTest4を参照していることを示していることがわかります。2番目puts
の例では、同じことがわかります。定義が異なるだけです(self.method_name
クラスメソッドを定義するための表記法を使用)。self
3番目では、これがTest4のインスタンスを参照していることがわかります。最後の1つは少し興味深いものです。これは、呼び出さself
れたのインスタンスを参照していることがわかるためです。これは、クラスを定義するときに、オブジェクトを作成しているためです。Rubyのすべてがオブジェクトです。このオブジェクトのインスタンスは、メタクラスまたは固有クラスまたはシングルトンクラスと呼ばれます。Class
Test4
イディオムを使用して固有クラスにアクセスできますclass << self
。そこにいる間、実際には固有クラスの内部にアクセスできます。を呼び出すことと一致する固有クラス内でインスタンスメソッドを定義できますself.method_name
。ただし、eigenclassのコンテキスト内にいるため、eigenclassのeigenclassにメソッドをアタッチできます。
Test4.huh? #=> NoMethodError
Test4.singleton_class.huh? #=> Hmmm? indeed
instance_eval
メソッドのコンテキストで呼び出す場合、実際instance_eval
にはクラス自体を呼び出しています。つまり、Test4でインスタンスメソッドを作成していることになります。固有クラス内でinstance_evalを呼び出した場所はどうですか?Test4の固有クラスのインスタンスにメソッドを作成します。
Test4.razors #=> Sounds painful
うまくいけば、これはあなたの質問のいくつかをクリアします。私はこの答えをタイプすることをいくつか学んだことを知っています!