문제

I can take a block of code, instance_exec it, and get the proper result. I would like to take a method off a different object and call one of it's methods in my scope. When I take a method from a different object, turn it into a proc, and then instance_exec it, I don't get the expected result. Code follows.

class Test1
    def ohai(arg)
        "magic is #{@magic} and arg is #{arg}"
    end
end

class Test2
    def initialize
        @magic = "MAGICAL!"
    end

    def scope_checking
        @magic
    end

    def do_it
        ohai = Test1.new.method(:ohai)
        self.instance_exec("foobar", &ohai)
    end
end

describe "Test2 and scopes" do
    before do
        @t2 = Test2.new
    end

    it "has MAGICAL! in @magic" do
        @t2.scope_checking.should == "MAGICAL!"
    end

    # This one fails :(
    it "works like I expect converting a method to a proc" do
        val = @t2.do_it
        val.should == "magic is MAGICAL! and arg is foobar"
    end

    it "should work like I expect" do
        val = @t2.instance_exec do
            "#{@magic}"
        end

        val.should == "MAGICAL!"
    end
end
도움이 되었습니까?

해결책

It seems that, in Ruby, methods defined using def some_method are bound permanently to the class they're defined in.

So, when you call .to_proc on them they keep the binding of their original implementation, and you cannot rebind them. Well, you can, but only to an object of the same type as the first one. It's possible I could do some fancyness with inheritance, but I don't think so.

The solution becomes instead of using methods, I just put actual Procs into variables and use them then, as they're not bound until execution time.

다른 팁

not sure how good of an idea this is, but this passes your tests:

class Test1
  def ohai(arg, binding)
    eval('"magic is #{@magic} "', binding).to_s + "and arg is #{arg}"
  end
end

class Test2
  def initialize
    @magic = "MAGICAL!"
  end

  def scope_checking
    @magic
  end

  def get_binding
    return binding()
  end

  def do_it
    self.instance_exec(get_binding) {|binding| Test1.new.ohai("foobar", binding) }
  end
end
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top