1 # depends on: array.rb proc.rb binding.rb
2 # (due to alias_method)
8 ctx = MethodContext.current.sender
10 while ctx.kind_of? BlockContext
11 if names = ctx.method.local_names
12 names.each { |n| ary << n.to_s }
17 if names = ctx.method.local_names
18 names.each { |n| ary << n.to_s }
23 module_function :local_variables
26 ctx = MethodContext.current.sender
27 # If we are here because of eval, fetch the context of
28 # the thing that invoked eval
30 Binding.setup ctx.sender.sender
35 module_function :binding
37 def eval(string, binding=nil, filename='(eval)', lineno=1)
39 binding = Binding.setup MethodContext.current.sender
40 elsif binding.__kind_of__ Proc
41 binding = binding.binding
42 elsif !binding.__kind_of__ Binding
43 raise ArgumentError, "unknown type of binding"
46 compiled_method = Compile.compile_string string, binding.context, filename, lineno
47 compiled_method.staticscope = binding.context.method.staticscope.dup
49 # This has to be setup so __FILE__ works in eval.
50 script = CompiledMethod::Script.new
51 script.path = filename
52 compiled_method.staticscope.script = script
54 be = BlockEnvironment.new
55 be.under_context binding.context, compiled_method
57 # Pass the BlockEnvironment this binding was created from
58 # down into the new BlockEnvironment we just created.
59 # This indicates the "declaration trace" to the stack trace
60 # mechanisms, which can be different from the "call trace"
61 # in the case of, say: eval("caller", a_proc_instance)
62 if binding.from_proc? then
63 be.proc_environment = binding.proc_environment
74 # obj.instance_eval(string [, filename [, lineno]] ) => obj
75 # obj.instance_eval {| | block } => obj
77 # Evaluates a string containing Ruby source code, or the given block, within
78 # the context of the receiver +obj+. In order to set the context, the
79 # variable +self+ is set to +obj+ while the code is executing, giving the
80 # code access to +obj+'s instance variables. In the version of
81 # #instance_eval that takes a +String+, the optional second and third
82 # parameters supply a filename and starting line number that are used when
83 # reporting compilation errors.
91 # k.instance_eval { @secret } #=> 99
93 def instance_eval(string = nil, filename = "(eval)", line = 1, modeval = false, binding = nil, &prc)
96 raise ArgumentError, 'cannot pass both a block and a string to evaluate'
98 # Return a copy of the BlockEnvironment with the receiver set to self
99 env = prc.block.redirect_to self
100 env.method.staticscope = StaticScope.new(__metaclass__, env.method.staticscope)
101 original_scope = prc.block.home.method.staticscope
102 env.constant_scope = original_scope
103 return env.call(*self)
105 string = StringValue(string)
108 context = binding.context
110 context = MethodContext.current.sender
113 compiled_method = Compile.compile_string string, context, filename, line
114 compiled_method.inherit_scope context.method
116 # If this is a module_eval style evaluation, add self to the top of the
117 # staticscope chain, so that methods and such are added directly to it.
119 compiled_method.staticscope = StaticScope.new(self, compiled_method.staticscope)
122 # Otherwise add our metaclass, so thats where new methods go.
123 compiled_method.staticscope = StaticScope.new(metaclass, compiled_method.staticscope)
126 # This has to be setup so __FILE__ works in eval.
127 script = CompiledMethod::Script.new
128 script.path = filename
129 compiled_method.staticscope.script = script
131 be = BlockEnvironment.new
133 be.under_context context, compiled_method
134 be.call_on_instance(self)
136 raise ArgumentError, 'block not supplied'
145 # These have to be aliases, not methods that call instance eval, because we
146 # need to pull in the binding of the person that calls them, not the
147 # intermediate binding.
150 def module_eval(string = Undefined, filename = "(eval)", line = 1, &prc)
151 # we have a custom version with the prc, rather than using instance_exec
152 # so that we can setup the StaticScope properly.
154 unless string.equal?(Undefined)
155 raise ArgumentError, "cannot pass both string and proc"
158 env = prc.block.redirect_to self
159 env.method.staticscope = StaticScope.new(self, env.method.staticscope)
161 elsif string.equal?(Undefined)
162 raise ArgumentError, 'block not supplied'
165 context = MethodContext.current.sender
167 string = StringValue(string)
169 compiled_method = Compile.compile_string string, context, filename, line
171 # The staticscope of a module_eval CM is the receiver of module_eval
172 ss = StaticScope.new(self, context.method.staticscope)
174 # This has to be setup so __FILE__ works in eval.
175 script = CompiledMethod::Script.new
176 script.path = filename
179 compiled_method.staticscope = ss
181 # The gist of this code is that we need the receiver's static scope
182 # but the caller's binding to implement the proper constant behavior
183 be = BlockEnvironment.new
185 be.under_context context, compiled_method
187 be.home.receiver = self
188 be.home.make_independent
189 # open_module and friends in the VM use this field to determine scope
190 be.home.method.staticscope = ss
193 alias_method :class_eval, :module_eval
195 def _eval_under(*args, &block)
196 raise "not yet" unless block
198 env = block.block.redirect_to self
199 env.method.staticscope = StaticScope.new(self, env.method.staticscope)
201 return env.call(*args)