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