以此示例Proc:
proc = Proc.new {|x,y,&block| block.call(x,self.instance_method)}
它有两个参数x和y,也是一个块.
我想使用不同的值来执行该块.这样的东西几乎可以工作:
some_object.instance_exec("x arg","y arg",&proc)
但是,这不允许你传递一个块.这也不行
some_object.instance_exec("x arg",another_proc,&proc)
也没有
some_object.instance_exec("x arg",&another_proc,&proc)
我不知道还有什么可以在这里工作.这是可能的,如果是这样做的话呢?
编辑:基本上如果您可以通过更改change_scope_of_proc方法来获取此rspec文件,您已经解决了我的问题.
require 'rspec' class SomeClass def instance_method(x) "Hello #{x}" end end class AnotherClass def instance_method(x) "Goodbye #{x}" end def make_proc Proc.new do |x,&block| instance_method(block.call(x)) end end end def change_scope_of_proc(new_self,proc) # TODO fix me!!! proc end describe "change_scope_of_proc" do it "should change the instance method that is called" do some_class = SomeClass.new another_class = AnotherClass.new proc = another_class.make_proc fixed_proc = change_scope_of_proc(some_class,proc) result = fixed_proc.call("Wor") do |x| "#{x}ld" end result.should == "Hello World" end end
解决方法
要解决这个问题,您需要将Proc重新绑定到新类.
这是您的解决方案,利用Rails core_ext中的一些好的代码:
require 'rspec' # Same as original post class SomeClass def instance_method(x) "Hello #{x}" end end # Same as original post class AnotherClass def instance_method(x) "Goodbye #{x}" end def make_proc Proc.new do |x,&block| instance_method(block.call(x)) end end end ### SOLUTION ### # From activesupport lib/active_support/core_ext/kernel/singleton_class.rb module Kernel # Returns the object's singleton class. def singleton_class class << self self end end unless respond_to?(:singleton_class) # exists in 1.9.2 # class_eval on an object acts like singleton_class.class_eval. def class_eval(*args,&block) singleton_class.class_eval(*args,&block) end end # From activesupport lib/active_support/core_ext/proc.rb class Proc #:nodoc: def bind(object) block,time = self,Time.now object.class_eval do method_name = "__bind_#{time.to_i}_#{time.usec}" define_method(method_name,&block) method = instance_method(method_name) remove_method(method_name) method end.bind(object) end end # Here's the method you requested def change_scope_of_proc(new_self,proc) return proc.bind(new_self) end # Same as original post describe "change_scope_of_proc" do it "should change the instance method that is called" do some_class = SomeClass.new another_class = AnotherClass.new proc = another_class.make_proc fixed_proc = change_scope_of_proc(some_class,proc) result = fixed_proc.call("Wor") do |x| "#{x}ld" end result.should == "Hello World" end end