将方法包括在块中

时间:2010-03-04 18:58:03

标签: ruby

如果有可能,任何人都知道如何让它发挥作用吗?

class Foo
  def self.go(&block)
    class << block
      include Bar
    end    
    puts "Within Foo#go: #{block.methods.include? 'baz'}"
    block.call
  end
end

module Bar
  def baz
    puts "I'm happily in my place!"
  end
end

Foo.go { 
  puts "Within actual block: #{methods.include? 'baz'}"
  baz
}

这得到输出:

Within Foo#go: true
Within actual block: false
NameError: undefined local variable or method ‘baz’ for main:Object
编辑:当我在Foo#中打印出该块的类时,它是Proc,但当我在Proc中打印它时,它就是Object。这可能是相关的吗?

3 个答案:

答案 0 :(得分:3)

你不能这样做。你所看到的原因是这里有两种不同的背景。一个是块的上下文,closes over它定义的上下文。另一个是Proc对象包装器的上下文,它与任何其他对象上下文完全相同,并且与块本身的上下文完全无关。

我认为你最接近的是使用具有你想要的方法的上下文对象来instance_eval块,但是该块将无法访问存在于哪里的self它被定义了。是否对你想要写的方法有意义,取决于你。

另一种选择是将块传递给baz方法的实际接收器。

答案 1 :(得分:3)

您可以将evalProc#binding

一起使用
module Bar
  def baz
    puts "hi from baz!"
  end
end
def go(&block)
  eval('include Bar', block.binding)
  block[]
end

baz #=> NameError
go { baz } #=> "hi from baz!"
baz #=> "hi from baz!"

但除非你使用mixin / mixout框架(如mixico或mixology),否则你将把包含模块中的方法放入词法范围,这样一旦块返回它们仍然可以访问。

require 'rubygems'
require 'mixico'

module Bar
  def baz
    puts "hi from baz!"
  end
end
def go(&block)
  Module.mix_eval(Bar, &block)
end

baz #=> NameError
go { baz } #=> "hi from baz!"
baz #=> NameError

Here是关于在一个区块内使用DSL的不同方法的好文章。

答案 2 :(得分:2)

另一个替代方案是继续加速之后,在混合之前复制块的上下文,这样你就不会在完成后弄乱上下文。

module Bar
  def baz
    puts "hi from baz!"
  end
end
def go(&block)
  dup_context = eval('self', block.binding).dup
  dup_context.send(:include, Bar)
  dup_context.instance_eval &block
end

注意,如果你没有在块

中运行任何mutator方法,这只对你有用