core/binding.rb
class Binding
attr_accessor :variables
attr_accessor :compiled_code
attr_accessor :lexical_scope
attr_accessor :proc_environment
attr_accessor :location
attr_accessor :receiver
def from_proc?
@proc_environment
end
def self.self_context(recv, variables)
Rubinius::Type.object_equal(recv, Kernel) ? recv : variables.self
end
private :self_context
# Create a new Binding object. MRI does not allow .new to be called, so
# we used .setup(). Any code can use this as they wish, provided they have
# all the right arguments.
#
# +variables+ is a Rubinius::VariableScope object
# +code+ is a Rubinius::CompiledCode object
# +lexical_scope+ is a Rubinius::LexicalScope object
#
# See Kernel#binding in core/eval.rb for a simple example of creating a
# Binding object.
#
def self.setup(variables, code, lexical_scope, recv=nil, location=nil)
bind = allocate()
bind.receiver = self_context(recv, variables)
bind.variables = variables
bind.compiled_code = code
bind.lexical_scope = lexical_scope
bind.location = location
return bind
end
def line_number
if proc_environment
proc_environment.line
else
location ? location.line : 1
end
end
# Evaluates the Ruby expression(s) in string, in the binding‘s context.
# If the optional filename and lineno parameters are present,
# they will be used when reporting syntax errors.
def eval(expr, filename=nil, lineno=nil)
lineno ||= filename ? 1 : line_number
Kernel.eval(expr, self, filename, lineno)
end
def local_variables
variables.local_variables
end
def local_variable_set(name, value)
unless name.is_a?(Symbol)
name = Rubinius::Type.coerce_to(name, String, :to_str).to_sym
end
vars = variables
# If a local variable is defined in a parent scope we should update the
# variable in said scope and all child scopes, instead of _only_ setting it
# in the current scope.
while vars
meth = vars.method
if meth.local_names.include?(name)
return vars.set_local(meth.local_slot(name), value)
elsif vars.eval_local_defined?(name)
return vars.set_eval_local(name, value)
end
vars = vars.parent
end
variables.set_eval_local(name, value)
end
def local_variable_get(name)
unless name.is_a?(Symbol)
name = Rubinius::Type.coerce_to(name, String, :to_str).to_sym
end
vars = variables
while vars
meth = vars.method
if meth.local_names.include?(name)
return vars.locals[meth.local_slot(name)]
elsif vars.eval_local_defined?(name)
return vars.get_eval_local(name)
end
vars = vars.parent
end
raise NameErrror, "local variable #{name.inspect} not defined for #{inspect}"
end
def local_variable_defined?(name)
unless name.is_a?(Symbol)
name = Rubinius::Type.coerce_to(name, String, :to_str).to_sym
end
variables.local_defined?(name)
end
end