Reputation: 178
I'm learning ruby metaprogramming at the moment and while I was playing around and testing stuff, I stumbled upon something I can't seem to find the answer to. Let's say we have the following code:
class Foo
end
Foo.instance_eval do
define_method("bar") do
1
end
end
I would expect this to add a class method called bar
to Foo
but instead when I call the method it says it's undefined. What baffles me even more is that the same code works when I use def
instead of define_method
. Both ways seem to work when I try to define an instance method with class_eval
as well. So what's really going on here?
Thanks in advance.
Upvotes: 3
Views: 2080
Reputation: 1241
Differences between def and define_method.
1:- define_method can use variables from the scope where it was defined.
local_var = "Hello World"
def greet1
local_var #undefined local_var
end
define_method(:greet2) do
local_var # returns local_var
end
2:- If you want to define method whose name is stored inside a variable, then you will have to use define_method. You can't declare methods dynamically using def.
So based on the requirement you will have to use def or define_method.
Explanation for your code.
Here you will have to use #define_singleton_method instead of #define_method to define class methods for Foo class. define_method will define instance methods for class Foo
So the expected code should be
class Foo
end
Foo.instance_eval do
define_singleton_method("bar") do
1
end
define_method("baz") do
2
end
end
Foo.bar #=> 1
Foo.new.baz #=> 2
Upvotes: 2
Reputation: 2572
Let's make it simple.
define_method
is a method. Or I should say a private class method of Object class. You invoke it by giving it an argument as instance method name you are going to define, and a block which contains the code of the method. apidock has very clear definition. You may want to read documentation.
def
is a keyword. You use this to define methods just as you do all the time. Not really related to meta-programming.
If you are trying define class method, use class_eval, and give it a string. As its name indicates, instance_eval
defines stuffs on instance level. In your code, if you do Foo.instance_methods
, you will find the bar
method. So if you do Foo.new.bar
it returns 1
, as TK-421 answered you. But since define_method
defines instance_method, as indicated by documentation, regardless if you use class_eval or instance_eval, you will get instance method.
Here's the documentations you can read and they will answer all you question.
class_eval: http://apidock.com/ruby/v1_9_3_392/Module/class_eval
define_method: http://apidock.com/ruby/Module/define_method
instance_eval: http://apidock.com/ruby/Object/instance_eval
And don't forget this all mighty: http://www.google.com :D
Upvotes: 2