ruby – 如何调用在不同上下文中块的Proc?

前端之家收集整理的这篇文章主要介绍了ruby – 如何调用在不同上下文中块的Proc?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
以此示例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

猜你在找的Ruby相关文章