Dynamic Evaluation
Instance evaluation
Section titled “Instance evaluation”The instance_eval method is available on all objects. It evaluates code in the context of the receiver:
object = Object.new
object.instance_eval do @variable = :valueend
object.instance_variable_get :@variable # => :valueinstance_eval sets self to object for the duration of the code block:
object.instance_eval { self == object } # => trueThe receiver is also passed to the block as its only argument:
object.instance_eval { |argument| argument == object } # => trueThe instance_exec method differs in this regard: it passes its arguments to the block instead.
object.instance_exec :@variable do |name| instance_variable_get name # => :valueendEvaluating a String
Section titled “Evaluating a String”Any String can be evaluated at runtime.
class Example def self.foo :foo endend
eval "Example.foo" #=> :fooEvaluating Inside a Binding
Section titled “Evaluating Inside a Binding”Ruby keeps track of local variables and self variable via an object called binding. We can get binding of a scope with calling Kernel#binding and evaluate string inside a binding via Binding#eval.
b = proc do local_variable = :local bindingend.call
b.eval "local_variable" #=> :localdef 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 endend
class Exampleend
fake_class_eval Example, <<-BLOCK def self.foo :foo endBLOCK
fake_class_eval Example do def bar :bar endend
Example.foo #=> :fooExample.new.bar #=> :barDynamically Creating Methods from Strings
Section titled “Dynamically Creating Methods from Strings”Ruby offers define_method as a private method on modules and classes for defining new instance methods. However, the ‘body’ of the method must be a Proc or another existing method.
One way to create a method from raw string data is to use eval to create a Proc from the 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) endend
require 'nokogiri' # gem install nokogiridoc = Nokogiri.XML(xml)doc.xpath('//method').each do |meth| Foo.add_method( meth['name'], meth.text )end
f = Foo.newp Foo.instance_methods(false) #=> [:go, :stop]p f.public_methods(false) #=> [:go, :stop]f.go #=> "I'm going!"p f.stop #=> 42Syntax
Section titled “Syntax”- eval “source”
- eval “source”, binding
- eval “source”, proc
- binding.eval “source” # equal to
eval "source", binding
Parameters
Section titled “Parameters”|Parameter|Details
|---|---|---|---|---|---|---|---|---|---
|"source"|Any Ruby source code
|binding|An instance of Binding class
|proc|An instance of Proc class