Ruby 1.9.3: I am trying to implement a method which takes as argument a class, a symbol and a proc and defines (eventually overwriting) a new instance method for that class, but not a class method so that this test should pass:
require 'test/unit'
include Test::Unit::Assertions
class String
def my_method
'my_method'
end
end
def define_instance_method(klass, method, &block)
# klass.send :define_method, method, &block
# ...
end
define_instance_method(Object, :my_method) { 'define_instance_method my_method' }
define_instance_method(String, :my_method) { 'define_instance_method my_method' }
assert Object.new.my_method == 'define_instance_method my_method'
assert_raise(NoMethodError) { Object.my_method }
assert String.new.my_method == 'define_instance_method my_method'
assert_raise(NoMethodError) { String.my_method }
I did many tryings (define_method, define_singleton_method, class_eval, instance_eval, instance_exec, module_eval...) but with no success; do you have any ideas?
#ProGNOMmers, recall that objects in Ruby are classes and classes are objects.
So everything in Ruby are objects, even classes :)
And when you define a method inside Object it will also be available to Class as well as to any class that inherits from Object.
That's mean to all classes.
Some proof:
define_instance_method(String, :my_method) { 'define_instance_method my_method' }
p String.new.my_method
p String.my_method
# => "define_instance_method my_method"
# => stackoverflow.rb:11:in `<main>': undefined method `my_method' for String:Class (NoMethodError)
See, your method not yet defined inside Object, thus not available inside String.
Now let's do it:
define_instance_method(Object, :my_method) { 'define_instance_method my_method' }
p String.my_method
# => "define_instance_method my_method"
p Array.my_method
# => "define_instance_method my_method"
p NilClass.my_method
# => "define_instance_method my_method"
So just comment define_instance_method(Object... in your tests
and String specs will pass just well.
Here are some crash tests
class_eval should work for you. Let me know why it isn't working for you
class A
end
A.class_eval do
define_method(:foo) {puts 'hello'}
end
A.new.foo #hello
A.foo #NoMethodError: undefined method `foo' for A:Class
Related
How can I create a class with no instance methods defined? Not even __send__ or __id__.
You can use Module#undef_method to undefine methods:
class Foo < BasicObject
instance_methods.each { |method| undef_method(method) }
end
Foo.instance_methods #=> []
foo = Foo.new
foo.__id__ #=> NoMethodError: undefined method `__id__' for #<Foo:0x007fb9da565dd8>
foo.__send__(:test) #=> NoMethodError: undefined method `__send__' for #<Foo:0x007fb9da565dd8>
In this example Foo inherits from BasicObject, because this class itself has very few instance methods defined and thus, undefining them is faster. This is not obligatory, meaning, that you can undefine instance methods from any class no matter what it inherits from, so it could be very well written as:
class Foo
instance_methods.each { |method| undef_method(method) }
end
Below is my snippet which i tried,
class Person
def test(arg)
self.class.instance_eval do
define_method(arg) {puts "this is a class method"}
end
end
end
irb(main):005:0> Person.new.test("foo")
=> #<Proc:0x9270b60#/home/kranthi/Desktop/method_check.rb:4 (lambda)>
irb(main):003:0> Person.foo
NoMethodError: undefined method `foo' for Person:Class
irb(main):007:0> Person.new.foo
this is a class method
=> nil
Here am adding a method to the Person class dynamically using instance_eval and define_method. But why is this behaving as instance method?.
Is that completely dependent on self?
Confused. Can anyone explain me or a reference link also appreciated.
It's because define_method defines instance method of the receiver. Your receiver (self) is Person class, so it defines instance method of Person class. You can achieve what you want accessing to Person's metaclass:
def test(arg)
class << self.class
define_method(arg) { puts 'this is a class method' }
end
end
I haven't tested it, but it should work.
I have this class:
class Game
attr_accessor :player_fleet, :opponent_fleet
#player_fleet = []
#opponent_fleet = []
...
end
and create an instance like this:
my_game = Game.new
then use it like this:
my_game.opponent_fleet << opponent
which gives me this error:
undefined method `<<' for nil:NilClass (NoMethodError)
Why can't I treat an array like this? Do I have to create a method to push objects into the array?
You initialize #opponent_fleet at class level, so it's an instance variable of the class, not of the generated objects. Remember that in Ruby, even classes are objects :)
irb(main):001:0> class Game
irb(main):002:1> #foo = 3
irb(main):003:1> end
irb(main):004:0> Game.instance_eval { #foo }
=> 3
irb(main):005:0> Game.new.instance_eval { #foo }
=> nil
You want to initialize it in a constructor instead:
class Game
attr_accessor :player_fleet, :opponent_fleet
def initialize
#player_fleet = []
#opponent_fleet = []
end
end
I am writing a class method to create another class method. There seems to be some strangeness around how class_eval and instance_eval operate within the context of a class method. To illustrate:
class Test1
def self.add_foo
self.class_eval do # does what it says on the tin
define_method :foo do
puts "bar"
end
end
end
end
Test1.add_foo # creates new instance method, like I'd expect
Test1.new.foo # => "bar"
class Test2
def self.add_foo
self.instance_eval do # seems to do the same as "class_eval"
define_method :foo do
puts "bar"
end
end
end
end
Test2.add_foo # what is happening here?!
Test2.foo # => NoMethodError
Test2.new.foo # => "bar"
class Test3
def self.add_foo
(class << self; self; end).instance_eval do # call explicitly on metaclass
define_method :foo do
puts "bar"
end
end
end
end
Test3.add_foo # => creates new class method, as I'd expect
Test3.foo # => "bar"
My understanding is that class methods are instance methods defined on the metaclass of the class in question (Test2 in this case). Based on that logic, I would expect the receiver for the class method call add_foo to be the metaclass.
What is self referring to inside the Test2.add_foo method?
Why does calling instance_eval on this receiver object create an instance method?
The main difference between instance_eval and class_eval is that instance_eval works within the context of an instance, while class_eval works within the context of a class. I am not sure how familiar you are with Rails, but let's look at this for an example:
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
This happens because belongs_to is actually a method call that happens within the context of the class body, which you cannot call from an instance. When you try to call id with class_eval, it fails because id is a method defined on an instance, not in a class.
Defining methods with both class_eval and instance_eval work essentially the same when called against an instance. They will define a method only on the instance of the object it is called against.
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
They differ, however, when dealing with the class.
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
So where did bark go? It got defined on the instance of the class' singleton class. I'll explain more below. But for now:
t.class.bark #=> woof!
Test3.bark #=> woof!
So to answer your question about what self is referring to within the class body, you can construct a little test:
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>
So what is happening here is that in the first puts statement above, we see that inspect is telling us that self within the context of a class method body is referring to the class Test4. In the second puts, we see the same thing, it's just defined differently (using the self.method_name notation for defining class methods). In the third, we see that self refers to an instance of Test4. The last one is a bit interesting because what we see is that self is referring to an instance of Class called Test4. That is because when you define a class, you're creating an object. Everything in Ruby is an object. This instance of object is called the metaclass or the eigenclass or singleton class.
You can access the eigenclass with the class << self idiom. While you're in there, you actually have access to the internals of the eigenclass. You can define instance methods inside of the eigenclass, which is congruent with calling self.method_name. But since you are within the context of the eigenclass, you can attach methods to the eigenclass' eigenclass.
Test4.huh? #=> NoMethodError
Test4.singleton_class.huh? #=> Hmmm? indeed
When you call instance_eval in the context of a method, you're really calling instance_eval on the class itself, which means that you are creating instance methods on Test4. What about where I called instance_eval inside of the eigenclass? It creates a method on the instance of Test4's eigenclass:
Test4.razors #=> Sounds painful
Hopefully, this clears up a few of your questions. I know that I have learned a few things typing out this answer!
I play with metaprogramming in ruby and I have a question. I have a class:
class Klass
class << self
#x = "yeah"
end
end
b = Klass.new
a = class << Klass; self; end
a.instance_eval "#x" #=> yeah
Klass.instance_eval "#x" #=> nil
Why? In variable a I have a singleton class, right? And Klass.instance_eval exec in context of a singleton class:
Klass.instance_eval "def yeah; puts 10; end"
Klass.yeah #=> 10
Also, Klass in interpreter points to context of class, yes? And a points to context of a singleton class?
And which indicates a.class_eval and a.instance_eval? I do:
a.instance_eval "def pops; puts 0; end"
a.class_eval "def popsx; puts 1; end"
a.pops #=> 0
a.popsx # FAIL
Klass.pops # FAIL
Klass.popsx #=> 1
b.pops; b.popsx # DOUBLE FAIL
and I do not understand this. Thanks!
First, while it seems like eigentclass is used by some people singleton class is more common term. Singleton class contains object-specific behavior for an object in Ruby. You can't create other instances of that class except the original object this singleton class belongs to.
Speaking about defining of methods inside different types of eval this article introduces nice rule for methods defined in instance_eval and class_eval:
Use ClassName.instance_eval to define class methods.
Use ClassName.class_eval to define instance methods.
That pretty much describes the situation.
There was a huge write-up about classes that are instances of Class class, their singleton classes that are subclasses of Class class and some other crazy stuff (not that much related to the problem). But as your question can be easily applied to regular objects and their classes (and it makes things much easier to explain), I decided to remove that all (though, you can still see that stuff in revisions history of the answer).
Let's look at regular class and instance of that class and see how that all works:
class A; end
a = A.new
Method definitions inside different types of eval:
# define instance method inside class context
A.class_eval { def bar; 'bar'; end }
puts a.bar # => bar
puts A.new.bar # => bar
# class_eval is equivalent to re-opening the class
class A
def bar2; 'bar2'; end
end
puts a.bar2 # => bar2
puts A.new.bar2 # => bar2
Defining object-specific methods:
# define object-specific method in the context of object itself
a.instance_eval { def foo; 'foo'; end }
puts a.foo # => foo
# method definition inside instance_eval is equivalent to this
def a.foo2; 'foo2'; end
puts a.foo2 # => foo2
# no foo method here
# puts A.new.foo # => undefined method `foo' for #<A:0x8b35b20>
Let's now look at singleton class of object a:
# singleton class of a is subclass of A
p (class << a; self; end).ancestors
# => [A, Object, Kernel, BasicObject]
# define instance method inside a's singleton class context
class << a
def foobar; 'foobar'; end;
end
puts a.foobar # => foobar
# as expected foobar is not available for other instances of class A
# because it's instance method of a's singleton class and a is the only
# instance of that class
# puts A.new.foobar # => undefined method `foobar' for #<A:0x8b35b20>
# same for equivalent class_eval version
(class << a; self; end).class_eval do
def foobar2; 'foobar2'; end;
end
puts a.foobar2 # => foobar2
# no foobar2 here as well
# puts A.new.foobar2 # => undefined method `foobar2' for #<A:0x8b35b20>
Now let's look at instance variables:
# define instance variable for object a
a.instance_eval { #x = 1 }
# we can access that #x using same instance_eval
puts a.instance_eval { #x } # => 1
# or via convenient instance_variable_get method
puts a.instance_variable_get(:#x) # => 1
And now to instance variables inside class_eval:
# class_eval is instance method of Module class
# so it's not available for object a
# a.class_eval { } # => undefined method `class_eval' for #<A:0x8fbaa74>
# instance variable definition works the same inside
# class_eval and instance_eval
A.instance_eval { #y = 1 }
A.class_eval { #z = 1 }
# both variables belong to A class itself
p A.instance_variables # => [:#y, :#z]
# instance variables can be accessed in both ways as well
puts A.instance_eval { #y } # => 1
puts A.class_eval { #z } # => 1
# no instance_variables here
p A.new.instance_variables # => []
Now if you replace class A with class Class and object a with object Klass (that in this particular situation is nothing more than instance of class Class) I hope you'll get explanation to your questions. If you still have some feel free to ask.
It's hard to completely answer your question (for a thorough explanation of Ruby's class model, look at Dave Thomas' excellent presentation), nevertheless:
With class_eval, you actually define instance methods - it's as if you were inside the body of the class. For example:
class Klass
end
Klass.class_eval do
def instance_method
puts 'instance method'
end
end
obj = Klass.new
obj.instance_method # instance method
With instance_eval, you actually define class methods - it's as if you were inside the body of the singleton (eigenclass) class of the given object (nota bene that classes are objects too in Ruby). For example:
Klass.instance_eval do
def class_method
puts 'class method'
end
end
Klass.class_method # class method
And in your case:
Klass.instance_eval "#x" does not work because #x is not part of Klass, it's part of Klass' singleton class:
class Klass
class << self
#x = "yeah"
end
puts #x
end
# prints nothing
a.instance_eval "#x" works fine because you evaluate "#x" in the context of the a singleton class that is connected with the singleton class of Klass class in which you defined the #x instance variable. How singleton classes can be interconnected can be illustrated by this example:
class Foo
end
f = class << Foo; self; end
g = class << Foo; self; end
f.instance_eval "def yeah; puts 'yeah'; end"
g.yeah # yeah
g.instance_eval "def ghee; puts 'ghee'; end"
f.ghee # ghee
Klass.instance_eval "def yeah; puts 10; end" defines a 'normal' class method. Therefore Klass.yeah works fine (see Klass.class_method in the previous example).
a.instance_eval "def pops; puts 0; end" defines a class method on the a singleton class. Therefore, a.pops actually means calling the pops class method (again, it's as if calling Klass.class_method).
a.popsx does not work because you would first have to create an instance of a to be able to call popsx on it (but is not possible to create a new instance of a singleton class).
Klass.pops does not work because there isn't any pops method defined in Klass' singleton class (pops is defined in a's singleton class).
Klass.popsx works because with a.class_eval "def popsx; puts 1; end" you have defined the popsx instance method which you then call on the Klass object. It is, in a way, similar to this example:
class Other
end
o = Other.new
Other.class_eval "def yeah; puts 'yeah'; end"
o.yeah # yeah
Hope it helps.