简体   繁体   English

更改Ruby proc / block的结构

[英]Changing structure of Ruby proc/block

I am not sure if this is possible in Ruby, but in case someone knows a good solution. 我不确定在Ruby中是否可行,但是如果有人知道一个好的解决方案。

I'd like to change the structure of a block, replacing particular nodes in it with other code structures. 我想更改一个块的结构,用其他代码结构替换其中的特定节点。 Much like macros. 很像宏。

For example, say I have an unevaluated code block 例如,假设我有一个未评估的代码块

some_method do
  foo
  bar
end

Then I define some_method like 然后我定义some_method像

def some_method(&block)
   ...
end

In some_method, I really would like to replace "bar" in block with something else, eg with baz. 在some_method中,我真的很想用其他东西(例如baz)替换block中的“ bar”。

I want to do the replacement w/o evaluating the block, because ultimately I am passing the block around to other places. 我想进行替换而不评估块,因为最终我将块传递到其他地方。

Doable? 可行吗 or no? 或者没有?

I can think of fairly complicated answers: eg I can pass the block around with an additional closure that defines replacement for bar, and uses method_missing and continuation to replace bar with baz when bar is evaluated. 我可以想到相当复杂的答案:例如,我可以通过一个附加的闭包来传递块,该闭包定义bar的替换,并在评估bar时使用method_missing和continuation来用baz替换bar。 But is there a simpler way? 但是有没有更简单的方法?

Thanks. 谢谢。

Ruby doesn't have dynamic scoping and doesn't have macros, so unless you wrap the block in a function taking bar as a parameter, and pass that function around, I don't think you can substitute code like that. Ruby没有动态作用域,也没有宏,因此,除非您将块包装在以bar为参数的函数中,然后再传递该函数,否则我认为您不能像这样替换代码。 You can use eval of course, but I wouldn't recommend it=) 您当然可以使用eval ,但我不建议这样做=)

This is the simplest way i can think of: 这是我想到的最简单的方法:

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

output: 输出:

foo
bar
baz
bar

Do aliases and Procs help? 别名和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)

This prints "foo bar foo baz bar", ie: bar does something different in the block, but retains its original behavior outside. 这将打印“ foo bar foo baz bar”,即: bar在块中做一些不同的操作,但在外部保留其原始行为。

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"}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM