简体   繁体   中英

Why am I getting an error calling instance_eval with to_proc and not with Proc.new?

I'm doing this and it works:

class B
  def value
    "X"
  end
end

class A
  def initialize(context)
    @context = context
  end

  def m
    Proc.new do
      value
    end
  end

  def execute
    @context.instance_eval(&m)
  end
end

A.new(B.new).execute #=> "X"

But calling m.to_proc is not working...

class B
  def value
    "X"
  end
end

class A
  def initialize(context)
    @context = context
  end

  def m
    value
  end

  def execute
    @context.instance_eval(&m.to_proc)
  end
end

A.new(B.new).execute #=> NameError: undefined local variable or method `value' for #<A:0x007fae2ab02040 @context=#<B:0x007fae2ab02108>>

I want to know why these two examples are different and how to make it work with to_proc

In the second snippet, you are calling m , which returns the result of calling value , which is undefined. (And even if if were somehow magically calling B#value , then B#value returns a String and String s don't respond to to_proc , so you would get a NoMethodError there.) In the first snippet, you call m , which returns a Proc .

It looks like you are trying to pass the method m itself instead of the result of calling it. In Ruby, methods aren't objects, so you can't just grab them and pass them around (and even if methods were objects, then m is still the syntax for calling m , not for referencing it). You have to ask Ruby's reflection API for a reflective proxy for the method first, using the Object#method method, which returns a Method object representing the method:

@context.instance_eval(&method(:m).to_proc)

Note that the call to to_proc is completely redundant here, since & will call to_proc anyway if the argument isn't a Proc already. (You may have seen something like foo.map(&:bar) before, which will invoke Symbol#to_proc .)

@context.instance_eval(&method(:m))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM