Ruby Language
Dynamische evaluatie
Zoeken…
Syntaxis
- eval "bron"
- eval "bron", bindend
- eval "source", proc
- binding.eval "source" # gelijk aan
eval "source", binding
parameters
| Parameter | Details |
|---|---|
"source" | Elke Ruby-broncode |
binding | Een exemplaar van Binding class |
proc | Een exemplaar van Proc klasse |
Exemplaarevaluatie
De methode instance_eval is beschikbaar op alle objecten. Het evalueert code in de context van de ontvanger:
object = Object.new
object.instance_eval do
@variable = :value
end
object.instance_variable_get :@variable # => :value
instance_eval stelt self om object te object voor de duur van het codeblok:
object.instance_eval { self == object } # => true
De ontvanger wordt ook doorgegeven aan het blok als het enige argument:
object.instance_eval { |argument| argument == object } # => true
De methode instance_exec verschilt in dit opzicht: in plaats daarvan worden de argumenten doorgegeven aan het blok.
object.instance_exec :@variable do |name|
instance_variable_get name # => :value
end
Een string evalueren
Elke String kan tijdens runtime worden geëvalueerd.
class Example
def self.foo
:foo
end
end
eval "Example.foo" #=> :foo
Evalueren in een binding
Robijn houdt lokale variabelen en self variabel via een object genoemd binding. We kunnen binding van een scope krijgen door Kernel#binding aan te roepen en string binnen een binding te evalueren 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
Dynamisch methoden maken van tekenreeksen
Ruby biedt define_method als een define_method voor modules en klassen voor het definiëren van nieuwe instantiemethoden. De 'body' van de methode moet echter een Proc of een andere bestaande methode zijn.
Een manier om een methode te maken op basis van onbewerkte tekenreeksgegevens is door eval te gebruiken om een Proc van de code te maken:
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