The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Ruby: instance_eval and class_eval method definitions

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Jay Fields

Posts: 765
Nickname: jayfields
Registered: Sep, 2006

Jay Fields is a software developer for ThoughtWorks
Ruby: instance_eval and class_eval method definitions Posted: Mar 16, 2007 3:53 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by Jay Fields.
Original Post: Ruby: instance_eval and class_eval method definitions
Feed Title: Jay Fields Thoughts
Feed URL: http://feeds.feedburner.com/jayfields/mjKQ
Feed Description: Blog about Ruby, Agile, Testing and other topics related to software development.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by Jay Fields
Latest Posts From Jay Fields Thoughts

Advertisement
In yesterday's entry on Cleaning up Controller Tests you can find the following code.
# example 1
...
test_class.class_eval do
define_method :setup do
...
end
end
test_class.class_eval &block
...
An earlier version of this code only used one call to the class_eval method.
# example 2
...
test_class.class_eval do
define_method :setup do
...
end
instance_eval &block
end
...
Example 2 works when your controller tests contain only test methods.
# example 3
controller_tests do
test "should add the params" do
assert_equal 4, Math.add(2,2)
end

test "should multiply the params" do
assert_equal 9, Math.multiply(3,3)
end
end
However, Example 2 stops working if your test class contains any helper methods.
# example 4
controller_tests do
test "should not save if first name is nil" do
person = valid_person
person.first_name = nil
assert_equal false, person.save
end

def valid_person
Person.new(...)
end
end
So, what's the difference between example 1 and example 2? The context in which the block is evaluated.

The above examples are from actual code, but the essence of the issue can be captured in a much simpler example.
# example 5
Foo = Class.new
Foo.class_eval do
def bar
"bar"
end
end
Foo.instance_eval do
def baz
"baz"
end
end
Foo.bar #=> undefined method ���bar��� for Foo:Class
Foo.new.bar #=> "bar"
Foo.baz #=> "baz"
Foo.new.baz #=> undefined method ���baz��� for #<Foo:0x7dce8>
As you can see in example 5, using def in an instance_eval is different from using def in a class_eval method call.

Example 5 shows that using def in a class_eval defines an instance method on the receiver (Foo in our example). However, using def in an instance_eval defines an instance method on the singleton class of the receiver (the singleton class of Foo in our example).

This explains why example 3 does not work: the valid_person method was being defined on the singleton class of the controller test class and not as an instance method of the controller test class.

As I previously stated, using def in an instance_eval defines an instance method on the singleton class of the receiver. This also explains how using def in an instance_eval when the receiver is an instance of a class defines a method on that instance.
# example 6
Foo = Class.new
foo = Foo.new
foo.instance_eval do
def instance_bar
"instance_bar"
end
end
foo.instance_bar #=> "instance_bar"
I've already explained where methods are stored in the various examples; however, the following example serves to prove my assertion.
# example 7
class Object
def singleton_class
class << self; self; end
end
end

Foo = Class.new
Foo.class_eval do
def instance_method_of_Foo; end
end
Foo.instance_eval do
def instance_method_of_Foos_singleton_class; end
end

Foo.instance_methods(false).inspect
#=> ["instance_method_of_Foo"]
Foo.singleton_class.instance_methods(false).inspect
#=> ["instance_method_of_Foos_singleton_class", "new", "superclass", "allocate"]

foo = Foo.new
foo.instance_eval do
def instance_method_of_foos_singleton_class; end
end

foo.singleton_class.instance_methods(false).inspect
#=> ["instance_method_of_Foo", "instance_method_of_foos_singleton_class"]
How does define_method fit into this picture?
# example 8
Foo = Class.new
Foo.class_eval do
define_method :instance_method_of_Foo do end
end
Foo.instance_eval do
define_method :another_instance_method_of_Foo do end
end

Foo.instance_methods(false).inspect
#=> ["another_instance_method_of_Foo", "instance_method_of_Foo"]
As you can see from example 8 define_method always defines an instance method on the target (Foo in our example). This makes sense because define_method is being call on the implicit self, which evaluates to the receiver (Foo) in our example.
# example 9
Foo.class_eval do
self #=> Foo
end

Foo.instance_eval do
self #=> Foo
end
By combining examples 5 and 8 I can create the following code that should no longer be surprising.
class Object
def singleton_class
class << self; self; end
end
end

Foo = Class.new
Foo.instance_eval do
def an_instance_method_of_the_singleton_class
end

define_method :an_instance_method do
end
end

Foo.instance_methods(false).inspect
#=> ["an_instance_method"]
Foo.singleton_class.instance_methods(false).inspect
#=> ["an_instance_method_of_the_singleton_class", "new", "superclass", "allocate"]
Thanks to Ali Aghareza, Pat Farley, and Zak Tamsen for collaborating with me on this.

Read: Ruby: instance_eval and class_eval method definitions

Topic: The Call Stack - Debugging Ruby 'Backwards' Previous Topic   Next Topic Topic: Off to MtWest RubyConf 2007

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use