Ruby Language
Évaluation dynamique
Recherche…
Syntaxe
- eval "source"
- eval "source", liaison
- eval "source", proc
- binding.eval "source" # égal à
eval "source", binding
Paramètres
| Paramètre | Détails |
|---|---|
"source" | Tout code source Ruby |
binding | Une instance de classe Binding |
proc | Une instance de classe Proc |
Évaluation d'instance
La méthode instance_eval est disponible sur tous les objets. Il évalue le code dans le contexte du récepteur:
object = Object.new
object.instance_eval do
@variable = :value
end
object.instance_variable_get :@variable # => :value
instance_eval définit lui- self object pour la durée du bloc de code:
object.instance_eval { self == object } # => true
Le récepteur est également transmis au bloc comme seul argument:
object.instance_eval { |argument| argument == object } # => true
La méthode instance_exec diffère à cet égard: elle transmet ses arguments au bloc à la place.
object.instance_exec :@variable do |name|
instance_variable_get name # => :value
end
Evaluer une chaîne
Toute String peut être évaluée au moment de l'exécution.
class Example
def self.foo
:foo
end
end
eval "Example.foo" #=> :foo
Evaluer à l'intérieur d'une liaison
Ruby conserve la trace des variables locales et self variables self via un objet appelé binding. Nous pouvons obtenir une liaison avec une portée en appelant la Kernel#binding et évaluer la chaîne à l'intérieur d'une liaison via Binding#eval .
b = proc do
local_variable = :local
binding
end.call
b.eval "local_variable" #=> :local
def fake_class_eval klass, source = nil, &block
class_binding = klass.send :eval, "binding"
if block
class_binding.local_variable_set :_fake_class_eval_block, block
class_binding.eval "_fake_class_eval_block.call"
else
class_binding.eval source
end
end
class Example
end
fake_class_eval Example, <<-BLOCK
def self.foo
:foo
end
BLOCK
fake_class_eval Example do
def bar
:bar
end
end
Example.foo #=> :foo
Example.new.bar #=> :bar
Création dynamique de méthodes à partir de chaînes
Ruby propose define_method comme méthode privée sur les modules et les classes pour la définition de nouvelles méthodes d'instance. Cependant, le «corps» de la méthode doit être un Proc ou une autre méthode existante.
Une façon de créer une méthode à partir de données de chaîne brutes consiste à utiliser eval pour créer un Proc à partir du code:
xml = <<ENDXML
<methods>
<method name="go">puts "I'm going!"</method>
<method name="stop">7*6</method>
</methods>
ENDXML
class Foo
def self.add_method(name,code)
body = eval( "Proc.new{ #{code} }" )
define_method(name,body)
end
end
require 'nokogiri' # gem install nokogiri
doc = Nokogiri.XML(xml)
doc.xpath('//method').each do |meth|
Foo.add_method( meth['name'], meth.text )
end
f = Foo.new
p Foo.instance_methods(false) #=> [:go, :stop]
p f.public_methods(false) #=> [:go, :stop]
f.go #=> "I'm going!"
p f.stop #=> 42