Pergunta

Eu quero escrever um simples rubi DSL para traduzir algumas afirmações e expressões em outro idioma. Um exemplo básico seria:

some_function {
    t + 2
}

Aqui, t não é uma variável rubi e, portanto, o bloco não pode (e não deve!) Ser avaliada por Ruby. Assim, a minha melhor aposta seria a de usar a saída de análise (ou AST) para fazer a tradução me. Para fazê-lo, eu posso usar ParseTree e ruby2ruby. No entanto, tenho outras construções que eu gostaria de usar, por exemplo:

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

Aqui, eu tenho uma variável local e eu preciso para obter o seu valor, a fim de fazer a minha tradução. No entanto, na função que faz a avaliação do bloqueio, eu não tenho acesso às variáveis ??locais do bloco de chamada. Se fosse uma variável global ($ x), eu poderia verificar se o seu nome existe na matriz global_variables e, no pior uso eval caso, mas como eu poderia fazê-lo para uma variável local, se possível em tudo?

Update:

Apenas para esclarecer as coisas. Como eu disse inicialmente, estou usando ruby2ruby (e, portanto, ParseTree) para obter a AST (usando to_sexp) correspondente ao bloco. Mas ao usar uma variável local dentro do meu bloco, me deparo com o seguinte:

[:dvar, :x]

E assim, eu precisaria para obter o valor de uma variável de seu nome como uma string / símbolo. E eu não posso usar method_missing ou instance_eval, porque eu quero traduzir a expressão inteira para outro idioma ou sintaxe (como um RPN).

Outra solução não baseada em ParseTree seria bem-vinda, no entanto, uma vez que, aparentemente, não é totalmente compatível com o Ruby 1.9.

Foi útil?

Solução

Para obter os valores das variáveis, utilize o proc de ligação:

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

Outras dicas

Aqui, t não é uma variável rubi e portanto, o bloco não pode (e não deve!) ser avaliado por Ruby.

Você tem algum motivo para a restrição "não avaliada"? Parece que method_missing seria elegantemente lidar com a avaliação da "falta" variável t, mas o ruby ??seria desreferenciava automaticamente a variável x.

Você pode usar instance_eval contra um objeto com 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
  }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top