Robert
Robert

Reputation: 178

Ruby: difference between def and define_method

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

Answers (3)

Nikhil Mohadikar
Nikhil Mohadikar

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

Edmund Lee
Edmund Lee

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

TK-421
TK-421

Reputation: 10763

It's an instance method. So:

f = Foo.new
f.bar # 1

Upvotes: 0

Related Questions