我想编写一个简单的Ruby DSL翻译一些语句和表达式成另一种语言。一个基本的例子将是:

some_function {
    t + 2
}

下面,t不是一个红宝石变量,因此该块不能(和不得!)由红宝石进行评估。所以,我最好的选择是使用解析输出(或AST)做翻译我自己。要做到这一点,我可以使用分析树和ruby2ruby。然而,我有其他构造,我想用,例如:

1.upto(10) {|x|
    some_function {
        t + x
    }
}

在这里,我有一个局部变量,我需要为了做我的翻译得到它的价值。然而,在做了块评价的功能,我没有访问调用块的局部变量。如果它是一个全局变量($ x)的,我可以检查它的名字global_variables数组中,并在最坏的情况下使用eval存在,但我怎么能对一个局部变量这样做,如果有可能的话?

<强>更新

刚刚清理的东西。就像我最初说,我使用ruby2ruby(因此分析树)来获得AST(使用to_sexp)对应的块。但使用我的块内的局部变量的情况下,我会遇到以下情况:

[:dvar, :x]

和因此,我需要从它的名字得到一个变量的值作为字符串/符号。和我不能使用的method_missing或instance_eval的,因为我想翻译整个表达式为另一种语言或语法(如RPN)。

不是基于分析树的另一解决方案将是受欢迎的尽管如此,因为它显然不充分使用Ruby 1.9支持。

有帮助吗?

解决方案

要获得的变量值,使用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
  }
}

其他提示

  

下面,t不是一个红宝石变量和   因此,块不能(绝对不能!)   由红宝石进行评价。

任何原因“未评估”限制?好像 method_missing的会很好地处理评估“失踪” t可变的,但会红宝石自动取消引用x变量。

可以使用instance_eval的针对与t的对象。

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
  }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top