Question

Je souhaite écrire un simple Ruby DSL pour traduire certaines déclarations et expressions dans une autre langue.Un exemple de base serait :

some_function {
    t + 2
}

Ici, t n'est pas une variable Ruby et donc le bloc ne peut pas (et ne doit pas !) être évalué par Ruby.Mon meilleur pari serait donc d'utiliser la sortie d'analyse (ou AST) pour faire la traduction moi-même.Pour ce faire, je peux utiliser ParseTree et ruby2ruby.Cependant, j'ai d'autres constructions que j'aimerais utiliser, par exemple :

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

Ici, j'ai une variable locale et j'ai besoin d'obtenir sa valeur pour faire ma traduction.Cependant, dans la fonction qui effectue l'évaluation du bloc, je n'ai pas accès aux variables locales du bloc appelant.S'il s'agissait d'une variable globale ($x), je pourrais vérifier si son nom existe dans le tableau global_variables et, dans le pire des cas, utiliser eval, mais comment pourrais-je le faire pour une variable locale, si possible ?

Mise à jour:

Juste pour mettre les choses au clair.Comme je l'ai dit à l'origine, j'utilise ruby2ruby (et donc ParseTree) pour obtenir l'AST (en utilisant to_sexp) correspondant au bloc.Mais lorsque j'utilise une variable locale dans mon bloc, je rencontre ce qui suit :

[:dvar, :x]

Et ainsi, j'aurais besoin d'obtenir la valeur d'une variable à partir de son nom sous forme de chaîne/symbole.Et je ne peux pas utiliser method_missing ou instance_eval, car je souhaite traduire l'expression entière dans un autre langage ou syntaxe (comme un RPN).

Une autre solution non basée sur ParseTree serait néanmoins la bienvenue, puisqu'elle n'est apparemment pas entièrement supportée avec Ruby 1.9.

Était-ce utile?

La solution

Pour obtenir les valeurs des variables, utilisez la liaison du 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
  }
}

Autres conseils

Ici, T n'est pas une variable Ruby et donc le bloc ne peut pas (et ne doit pas!) Évalué par Ruby.

Une raison pour la restriction « non évalué » ?Il semble que méthode_missing gérerait avec élégance l'évaluation des "manquants" t variable, mais Ruby déréférencerait automatiquement la x variable.

Vous pouvez utiliser instance_eval sur un objet avec 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
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top