Ruby Language
Evaluación dinámica
Buscar..
Sintaxis
- eval "fuente"
- eval "fuente", vinculante
- eval "fuente", proc
- binding.eval "source" # igual a
eval "source", binding
Parámetros
Parámetro | Detalles |
---|---|
"source" | Cualquier código fuente de Ruby |
binding | Una instancia de clase Binding |
proc | Una instancia de la clase Proc |
Evaluación de instancias
El método instance_eval
está disponible en todos los objetos. Evalúa el código en el contexto del receptor:
object = Object.new
object.instance_eval do
@variable = :value
end
object.instance_variable_get :@variable # => :value
instance_eval
establece self
para object
durante la duración del bloque de código:
object.instance_eval { self == object } # => true
El receptor también se pasa al bloque como su único argumento:
object.instance_eval { |argument| argument == object } # => true
El método instance_exec
difiere a este respecto: en su lugar, pasa sus argumentos al bloque.
object.instance_exec :@variable do |name|
instance_variable_get name # => :value
end
Evaluando una cadena
Cualquier String
puede ser evaluada en tiempo de ejecución.
class Example
def self.foo
:foo
end
end
eval "Example.foo" #=> :foo
Evaluando dentro de un enlace
Ruby realiza un seguimiento de las variables locales y de la self
variable a través de un objeto llamado enlace. Podemos obtener un enlace de un ámbito con Kernel#binding
y evaluar una cadena dentro de un enlace a través de 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
Creación dinámica de métodos a partir de cadenas
Ruby ofrece define_method
como un método privado en módulos y clases para definir nuevos métodos de instancia. Sin embargo, el 'cuerpo' del método debe ser un Proc
u otro método existente.
Una forma de crear un método a partir de datos de cadena sin procesar es utilizar eval
para crear un Proc a partir del código:
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