Class: AppMap::Handler::EvalHandler
- Inherits:
-
FunctionHandler
- Object
- AppMap::Hook::Method
- FunctionHandler
- AppMap::Handler::EvalHandler
- Defined in:
- lib/appmap/handler/eval_handler.rb
Overview
Handler class for Kernel#eval.
Second argument to eval is a Binding, which despite the name (and the accessible methods) in addition to locals and receiver also encapsulates the entire execution context, in particular including the lexical scope. This is especially important for constant lookup and definition.
If the binding is not provided, by default eval will run in the current frame. Since we call it here, this will mean the #do_call frame, which would make AppMap::Handler::EvalHandler the lexical scope for constant lookup and definition; as a consequence eg. ‘eval “class Foo; end”` would define AppMap::Handler::EvalHandler::Foo instead of defining it in the module where the original call was made.
To avoid this, we explicitly substitute the correct execution context, up several stack frames.
Constant Summary collapse
- PARAMETERS =
Kernel#eval reports the method parameters as :rest, instead of what you might expect from the documented signature: eval(string [, binding [, filename [,lineno]]]) In the C code, it’s defined as rb_f_eval(int argc, const VALUE *argv, VALUE self), so maybe that’s why the parameters are reported as :rest.
In any case, reporting the parameters as :rest means that the code string, binding, etc are reported in the AppMap as members of an Array, without individual object ids or types.
To make eval easier to analyze, fake the hook_method parameters to better match the documentation.
[ [ :req, :string ], [ :rest ], ]
- FRAME_DEPTH =
The depth of the frame we need to pluck out:
-
Hook::Method#do_call
-
Hook::Method#trace_call
-
Hook::Method#call
-
proc generated by Hook::Method#hook_method_def
-
the (intended) frame of the original eval that we hooked
Note it needs to be adjusted if this call sequence changes.
-
5
Constants inherited from AppMap::Hook::Method
AppMap::Hook::Method::HOOK_DISABLE_KEY
Constants included from AppMap::Hook::RecordAround
AppMap::Hook::RecordAround::APPMAP_OUTPUT_DIR
Instance Attribute Summary
Attributes inherited from AppMap::Hook::Method
#arity, #hook_class, #hook_method, #hook_package, #parameters, #record_around
Instance Method Summary collapse
Methods inherited from FunctionHandler
Methods inherited from AppMap::Hook::Method
Methods included from AppMap::Hook::RecordAround
#record_around?, #record_around_after, #record_around_before
Constructor Details
This class inherits a constructor from AppMap::Hook::Method
Instance Method Details
#do_call(receiver, src = nil, context = nil, *rest) ⇒ Object
54 55 56 57 |
# File 'lib/appmap/handler/eval_handler.rb', line 54 def do_call(receiver, src = nil, context = nil, *rest) context ||= AppMap.caller_binding FRAME_DEPTH hook_method.bind(receiver).call(src, context, *rest) end |
#handle_call(receiver, args) ⇒ Object
50 51 52 |
# File 'lib/appmap/handler/eval_handler.rb', line 50 def handle_call(receiver, args) AppMap::Event::MethodCall.build_from_invocation(defined_class, hook_method, receiver, args, parameters: PARAMETERS) end |