Class: AppMap::Handler::Eval

Inherits:
Function show all
Defined in:
lib/appmap/handler/eval.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::Eval the lexical scope for constant lookup and definition; as a consequence eg. eval "class Foo; end" would define AppMap::Handler::Eval::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

FRAME_DEPTH =

The depth of the frame we need to pluck out:

  1. Hook::Method#do_call
  2. Hook::Method#trace_call
  3. Hook::Method#call
  4. proc generated by Hook::Method#hook_method_def
  5. the (intended) frame of the original eval that we hooked Note it needs to be adjusted if this call sequence changes.
5

Instance Attribute Summary

Attributes inherited from AppMap::Hook::Method

#arity, #hook_class, #hook_method, #hook_package, #parameters

Instance Method Summary collapse

Methods inherited from Function

#handle_call, #handle_return

Methods inherited from AppMap::Hook::Method

#activate, #call, #initialize

Constructor Details

This class inherits a constructor from AppMap::Hook::Method

Instance Method Details

#do_call(receiver, src = nil, context = nil, *rest) ⇒ Object



35
36
37
38
# File 'lib/appmap/handler/eval.rb', line 35

def do_call(receiver, src = nil, context = nil, *rest)
  context ||= AppMap.caller_binding FRAME_DEPTH
  hook_method.bind(receiver).call(src, context, *rest)
end