Использование instance_exec и преобразование метода в Proc

Я могу взять блок кода, instance_exec его и получить нужный результат. Я хотел бы взять метод с другого объекта и вызвать один из его методов в моей области. Когда я беру метод из другого объекта, превращаю его в процедуру, а затем instance_exec, я не получаю ожидаемого результата. Далее следует код.

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

person BeepDog    schedule 22.04.2013    source источник


Ответы (2)


Кажется, что в Ruby методы, определенные с помощью def some_method, постоянно привязаны к классу, в котором они определены.

Таким образом, когда вы вызываете для них .to_proc, они сохраняют привязку своей исходной реализации, и вы не можете их повторно привязать. Ну, можно, но только объекту того же типа, что и первый. Возможно, я мог бы пофантазировать с наследованием, но я так не думаю.

Решение становится вместо использования методов, я просто помещаю фактические Proc в переменные и затем использую их, поскольку они не связаны до времени выполнения.

person BeepDog    schedule 26.04.2013

не уверен, насколько хороша эта идея, но она проходит ваши тесты:

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
person dr.strangecode    schedule 25.04.2013
comment
Да, я бы предпочел избегать использования eval. Вместо этого я могу использовать блоки кода, и это работает лучше. - person BeepDog; 26.04.2013