Ruby singleton methods with (class_eval, define_method) vs (instance_eval, define_method)
No difference for define_method
. But there is a difference when you use def
.
o = Object.new
# class_eval example
class << o; self; end.class_eval { def test1; :test1; end }
o.test1 #=> test1
# instance_eval example
class << o; self; end.instance_eval { def test2; :test2; end }
o.test2 #=> NoMethodError
Why the difference in behaviour between def
and define_method
? define_method
is a method call and so operates on the self
in the eval context. The self
in both instance_eval
and class_eval
is the same - it is the receiver (the eigenclass of o).
However def
behaves differently, it does not operate on the self
but instead on the default define
. In the case of class_eval
the default definee
is the same as self
but for instance_eval
it is instead the metaclass of self
.
How do we access the test2
method defined above? test2 must be an instance method defined on the metaclass of the eigenclass of o.
It is a class method on the eigenclass of o:
class << o; test2; end #=> :test2
define_method inside instance_eval
This quirky behavior makes a little more sense if you look at instance_eval
in the context of instances (which is its main purpose).
class A
end
a = A.new
a.instance_eval do
def foo
end
end
Where is foo
defined? The only sensible place I can think of is a
's singleton class, and indeed that is true
a.method(:foo).owner == a.singleton_class
# true
So this demonstrates the rule
def
insideinstance_eval
defines a method inself
's singleton class.
which is completely consistent with what you saw.
A.instance_eval do
# defines method in A's singleton class!
def method; end
end
So why does define_method
behave differently? Because unlike def
it's a method! So this
A.instance_eval do
define_method(:foo) {}
end
is really just
A.define_method(:foo) {}
which is the metaprogramming way of creating normal instance methods. This inconsistency may seem annoying, but again look at the case for normal instances and you'll see why def
and define_method
can't be consistent. This
a.instance_eval do
define_method(:foo) {}
end
is really just
a.define_method(:foo) {}
which is nonsense
NoMethodError: undefined method `define_method' for #<A:0x00008>
a confusing case in Ruby MetaProgramming
In addition to all other comments :
[from the Pickaxe] The method Object#instance_eval lets you set self to be some arbitrary object, evaluates the code in a block with [self], and then resets self.
And Module#define_method : Defines an instance method in the receiver [self, which must be a (anonymous) Class or Module].
singleton_class_of_object_a = aa = class << a; self; end
aa.instance_eval { def foo3; puts "foo3 from singleton class of a, self=#{self}"; end }
aa.foo3 # => foo3 from singleton class of a, self=#<Class:#<A:0x007fc2e4049e68>>
aa.instance_eval do
puts "about to define_method :bar3 in self=#{self}"
define_method :bar3 do; puts "bar3 from singleton class of a, self=#{self}"; end
end # => about to define_method :bar3 in self=#<Class:#<A:0x007fc2e4049e68>>
a.bar3 # => bar3 from singleton class of a, self=#<A:0x007fc2e4049e68>
define_method :bar3
is executed in the context of singleton_class_of_object_a (an anonymous class, see below), thus defines an instance method of that class, hence bar3 becomes a singleton method of a. As already said in my previous answer, it is equivalent to defining directly on the object :
def a.bar4; puts 'bar4 from singleton class of a' end
a.bar4 # => bar4 from singleton class of a
p a.singleton_methods.sort # => [:bar3, :bar4, :foo2]
p a.methods(false).sort # => [:bar3, :bar4, :foo2]
After a = A.new
, the field class of instance a points to class A.
With class << a
or def a.bar4
, Ruby creates an anonymous class, the field class of instance a now points to this anonymous class, and from there to A.
Methods defined in this context with def
or define_method
go into the methods table of the anonymous class.
class_eval vs instance_eval
Long story short:
Object.instance_eval &block
sets:self
toObject
- The "current class" to
Object.singleton_class
Object.class_eval &block
sets:self
toObject
- The "current class" to
Object
The "current class" is used for def
, undef
and alias
, as well as constant and class variable lookups.
Now, let's have a look at the implementation details.
Here's how module_eval
and instance_eval
are implemented in C:
VALUE rb_mod_module_eval(int argc, VALUE *argv, VALUE mod) {
return specific_eval(argc, argv, mod, mod);
}
VALUE rb_obj_instance_eval(int argc, VALUE *argv, VALUE self) {
VALUE klass;
if (SPECIAL_CONST_P(self)) { klass = Qnil; }
else { klass = rb_singleton_class(self); }
return specific_eval(argc, argv, klass, self);
}
Both call specific_eval
, which takes the following arguments: int argc
, VALUE *argv
, VALUE klass
and VALUE self
.
Note that:
module_eval
passes theModule
orClass
instance as bothklass
andself
instance_eval
passes the object's singleton class asklass
If given a block, specific_eval
will call yield_under
, which takes the following arguments: VALUE under
, VALUE self
and VALUE values
.
if (rb_block_given_p()) {
rb_check_arity(argc, 0, 0);
return yield_under(klass, self, Qundef);
}
There are two important lines in yield_under
:
block.self = self;
This sets the
self
of the block to the receiver.cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
The
cref
is a linked list
which specifies the "current class", which is used fordef
,undef
andalias
, as well
as constant and class variable lookups.That line basically sets the
cref
tounder
.Finally:
When called from
module_eval
,under
will be theClass
orModule
instance.When called from
instance_eval
,under
will be the singleton class ofself
.
Using send method inside define_method in class_eval block
The reciever is the current value of self
So you can do:
class MethodLogger
def log_method((klass,method_name)
klass.class_eval do
alias_method "#{method_name}_original" method_name
define_method method_name do
puts "#{Time.now}: Called #{method_name} on #{self.class}"
send "#{method_name}_original"
end
end
end
end
After a while you'll learn to keep track of self
in your mind :)
Ruby's def and instance_eval vs. class_eval
I think your confusion comes from the fact that def does not depend on the current self, you might think about it as being a "current class" that has it's own rules.
Following your examples:
class A
# defs here go to A
puts self # => A
class << self
#defs here go to A's eigenclass
end
end
A.class_eval do
#defs here go to A
end
A.instance_eval do
#defs here go to A's eigenclass
end
s = "Hello World"
class << s
#defs here go to s's eigenclass
end
Here's the portion of the chapter that talks about the issue and it's pretty clear about the behaviour
class_eval and instance_eval both set
self for the duration of the block.
However, they differ in the way they
set up the environment for method
definition. class_eval sets things up
as if you were in the body of a class
definition, so method definitions will
define instance methods In contrast,
calling instance_eval on a class acts
as if you were working inside the
singleton class of self. Therefore,
any methods you define will become
class methods.
The only thing I think is worth adding is that you can call instance_eval in any object, not just classes, and the behaviour doesn't change but has different consequences.
Some relevant reading:
Ruby: instance_eval and class_eval method definitions
Chapter 4 of this most excelent series
How to understand the difference between class_eval() and instance_eval()?
As the documentation says, class_eval
evaluates the string or block in the context of the Module or Class. So the following pieces of code are equivalent:
class String
def lowercase
self.downcase
end
end
String.class_eval do
def lowercase
self.downcase
end
end
In each case, the String class has been reopened and a new method defined. That method is available across all instances of the class, so:
"This Is Confusing".lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
=> "the smiths on charlie's bus"
class_eval
has a number of advantages over simply reopening the class. Firstly, you can easily call it on a variable, and it's clear what your intent is. Another advantage is that it will fail if the class doesn't exist. So the example below will fail as Array
is spelt incorrectly. If the class was simply reopened, it would succeed (and a new incorrect Aray
class would be defined):
Aray.class_eval do
include MyAmazingArrayExtensions
end
Finally class_eval
can take a string, which can be useful if you're doing something a little more nefarious...
instance_eval
on the other hand evaluates code against a single object instance:
confusing = "This Is Confusing"
confusing.instance_eval do
def lowercase
self.downcase
end
end
confusing.lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
NoMethodError: undefined method ‘lowercase’ for "The Smiths on Charlie's Bus":String
So with instance_eval
, the method is only defined for that single instance of a string.
So why does instance_eval
on a Class
define class methods?
Just as "This Is Confusing"
and "The Smiths on Charlie's Bus"
are both String
instances, Array
, String
, Hash
and all other classes are themselves instances of Class
. You can check this by calling #class
on them:
"This Is Confusing".class
=> String
String.class
=> Class
So when we call instance_eval
it does the same on a class as it would on any other object. If we use instance_eval
to define a method on a class, it will define a method for just that instance of class, not all classes. We might call that method a class method, but it is just an instance method for that particular class.
use define_method to create a method with equal on console
Note that if you have an expression
x.y=z
the Method "y=" is invoked on the object x, with the argument z.
However, if you have an expression
y=z
y is interpreted as the name of a variable, and gets assigned the value z.
Since you want the a= method to be invoked, you need a receiver. While we often can leave out the receiver, if it is 'self', Ruby can't recognize here that you want to do a method invocation. Hence you have to explicitly use 'self'.
Ruby metaprogramming: define_method block not maintaining scope
When you reference the class Base::Test
like this, ruby does not take the Base::
as the module context to look up constants. That is the normal behaviour and would also not work, if you would define the moethod directly.
But you could do it in this way:
module Base
Test.instance_eval do
def asdf
puts "Test#asdf called"
Foo.new.info
end
end
end
Related Topics
How to Get the Width of Terminal Window in Ruby
Rails: How to Write Tests for a Ruby Module
How to Reflect in the Database a New Belongs_To and Has_Many Relationship in Ruby on Rails
No Implicit Conversion of String into Integer (Typeerror)
Ruby Array Each_Slice_With_Index
How to Make Sign Up Page Be Root Page in Devise
Does Scala Scale Better Than Other Jvm Languages
$ Bundle Exec Rake Db:Reset Command Raising Couldn't Drop Db/Development.Sqlite3
How to Check If a Folder Exists in Chef
How to Sort a Hash by Value in Descending Order and Output a Hash in Ruby
How to Recompile a Ruby with Rvm
Better Way to Turn a Ruby Class into a Module Than Using Refinements
Can't Convert Fixnum to String During Rake Db:Create
How Might I Pass Text Data from the Ruby Console into My Clipboard Without Saving to a File
Check Ruby Http Response for Success