改变Ruby proc / block的结构

时间:2012-03-21 15:06:42

标签: ruby macros metaprogramming

我不确定这是否可以在Ruby中使用,但是如果有人知道一个好的解决方案。

我想更改块的结构,用其他代码结构替换其中的特定节点。很像宏。

例如,假设我有一个未评估的代码块

some_method do
  foo
  bar
end

然后我将some_method定义为

def some_method(&block)
   ...
end

在some_method中,我真的想将块中的“bar”替换为其他内容,例如:与巴兹。

我想更换w / o评估块,因为最终我将块传递到其他地方。

可行?还是不?

我可以想到相当复杂的答案:例如我可以通过一个额外的闭包来传递块,它定义了bar的替换,并且在计算bar时使用method_missing和continuation来替换bar和baz。但有更简单的方法吗?

感谢。

4 个答案:

答案 0 :(得分:0)

Ruby没有动态作用域并且没有宏,所以除非你将块包装在以bar作为参数的函数中,并传递该函数,我认为你不能替代这样的代码。您当然可以使用eval,但我不推荐它=)

答案 1 :(得分:0)

这是我能想到的最简单的方法:

class Base
  def some_method(&block)
     self.instance_eval(&block)
  end
  def foo; puts 'foo'; end
  def bar; puts 'bar'; end
end

class Replacement < Base
  def foo; puts 'baz'; end
end

Base.new.some_method do
  foo
  bar
end

Replacement.new.some_method do
  foo
  bar
end

输出:

foo
bar
baz
bar

答案 2 :(得分:0)

别名和Procs帮助吗?

def foo; p 'foo'; end
def bar; p 'bar'; end
def sm(&block)
    @@Block = Proc.new {
        alias :oldbar :bar
        def bar; p 'baz'; end  #redefine
        block.call
        alias :bar :oldbar  #restore
    }
    yield    #prints foo,bar
end


sm do 
    foo 
    bar
end


def later(&block)
    yield
end
def delayedEx
    later { @@Block.call}
end

delayedEx  #prints foo,baz
bar  #prints bar (unchanged)

这会打印“foo bar foo baz bar”,即:bar在块中执行不同的操作,但保留其原始行为。

答案 3 :(得分:-1)

def some_method(a_proc=Proc.new{puts "Bar"}, &block)
  a_proc.call
  yield
end

p1 = Proc.new{puts "Baz"}

some_method{puts "a block"}
some_method(p1){puts "a block"}