Question

I want to write a simple Ruby DSL to translate some statements and expressions into another language. A basic example would be:

some_function {
    t + 2
}

Here, t is not a ruby variable and thus the block can't (and must not!) be evaluated by Ruby. So my best bet would be to use the parsing output (or AST) to do the translation myself. To do so, I can use ParseTree and ruby2ruby. However, I have other constructs that I would like to use, for example:

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

Here, I have a local variable and I need to get its value in order to do my translation. However, in the function that does the block evaluation, I don't have access to the local variables of the calling block. If it were a global variable ($x), I could check if its name exists in the global_variables array and in the worst case use eval, but how could I do so for a local variable, if possible at all?

Update:

Just to clear up things. Like I said originally, I'm using ruby2ruby (and hence ParseTree) to get the AST (using to_sexp) corresponding to the block. But when using a local variable inside my block, I encounter the following:

[:dvar, :x]

And thus, I would need to get the value of a variable from its name as a string/symbol. And I can't use method_missing or instance_eval, because I want to translate the whole expression to another language or syntax (like a RPN).

Another solution not based on ParseTree would be welcome nonetheless, since it apparently is not fully supported with Ruby 1.9.

Was it helpful?

Solution

To get the variable values, use the proc's binding:

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

OTHER TIPS

Here, t is not a ruby variable and thus the block can't (and must not!) be evaluated by Ruby.

Any reason for the "not evaluated" restriction? It seems like method_missing would elegantly handle evaluating the "missing" t variable, but Ruby would automatically dereference the x variable.

You can use instance_eval against an object with 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
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top