我想编写一个简单的Ruby DSL来将一些语句和表达式翻译成另一种语言。一个基本的例子是:
some_function {
t + 2
}
这里,t不是ruby变量,因此块不能(并且不能!)由Ruby评估。所以我最好的选择是使用解析输出(或AST)自己进行翻译。为此,我可以使用ParseTree和ruby2ruby。但是,我还有其他想要使用的构造,例如:
1.upto(10) {|x|
some_function {
t + x
}
}
在这里,我有一个局部变量,我需要得到它的值才能进行翻译。但是,在执行块评估的函数中,我无法访问调用块的局部变量。如果它是一个全局变量($ x),我可以检查它的名字是否存在于global_variables数组中,并且在最坏的情况下使用eval,但是如果可能的话,我怎么能这样做呢?
更新
只是为了清理事情。就像我原来说的那样,我正在使用ruby2ruby(以及ParseTree)来获取与块对应的AST(使用to_sexp)。但是当我在块中使用局部变量时,我会遇到以下情况:
[:dvar, :x]
因此,我需要从其名称中获取变量的值作为字符串/符号。我不能使用method_missing或instance_eval,因为我想将整个表达式翻译成另一种语言或语法(如RPN)。
另一种不基于ParseTree的解决方案将受到欢迎,因为它显然不完全支持Ruby 1.9。
答案 0 :(得分:1)
要获取变量值,请使用proc的绑定:
def some_function(&block)
b = block.binding
p [b.eval("t"), b.eval("x")]
end
t = 1
1.upto(10) {|x|
some_function {
t + x
}
}
答案 1 :(得分:0)
这里,t不是ruby变量 因此块不能(而且一定不能!) 由Ruby评估。
“未评估”限制的任何原因?似乎method_missing可以优雅地处理评估“缺失”t
变量,但Ruby会自动取消引用x
变量。
答案 2 :(得分:0)
您可以对具有t
的对象使用instance_eval。
class Context
attr_accessor :t
def initialize(_t)
@t = _t
end
end
def some_function(&block)
puts Context.new(1).instance_eval(&block)
end
1.upto(10) {|x|
some_function {
t + x
}
}