11

I have the following class:

class User
  code1 = Proc.new { }
  code2 = lambda { }

  define_method :test do
    self.class.instance_eval &code1
    self.class.instance_eval &code2
  end
end

User.new.test

Why does the secondinstance_eval fail with a wrong number of arguments (1 for 0) error?

user2398029
  • 6,699
  • 8
  • 48
  • 80
Nick Vanderbilt
  • 2,475
  • 3
  • 27
  • 33

2 Answers2

17

instance_eval is yielding self (User) to the lambda. Lambdas are particular about their parameters - in the same way methods are - and will raise an ArgumentError if there are too few/many.

class User
  code1 = Proc.new { |x| x == User } # true
  code2 = lambda { |x| x == User }   # true

  define_method :test do
    self.class.instance_eval &code1
    self.class.instance_eval &code2
  end
end

Relevant: What's the difference between a proc and a lambda in Ruby?

pdoherty926
  • 9,895
  • 4
  • 37
  • 68
  • 1
    Also relevant: http://stackoverflow.com/questions/12648157/instance-evals-block-arguments-documented-purpose – rampion Mar 08 '13 at 23:03
  • In my version lambda is not taking any argument. And I'm not passing any at the time of instance_eval. So why this issue of arguments number mismatch . – Nick Vanderbilt Mar 08 '13 at 23:26
  • `instance_eval` is yielding self to the proc/lambda. – pdoherty926 Mar 08 '13 at 23:27
  • Yes got it. http://www.ruby-doc.org/core-1.9.3/BasicObject.html#method-i-instance_eval in order to set the context, the variable self is set to obj while the code is executing, giving the code access to obj’s instance variables. – Nick Vanderbilt Mar 08 '13 at 23:31
12

If you still want to use lambda, this code will work:

block = lambda { "Hello" } # or -> { "Hello" }
some_obj.instance_exec(&block)

instance_exec contrary to instance_eval will not supply self as an argument to the given block, so wrong number of arguments (1 for 0) won't be thrown.

Look here for more info.

Community
  • 1
  • 1
Yury Kaspiarovich
  • 2,027
  • 2
  • 19
  • 25