Sha256: d2c5bc354cfeb0f61586e8aaa7d7ae3f98500826db516c1a34e965309c15f015
Contents?: true
Size: 1.56 KB
Versions: 15
Compression:
Stored size: 1.56 KB
Contents
# frozen_string_literal: true require 'appmap/handler/function' module AppMap module Handler # 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. class Eval < Function # 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. FRAME_DEPTH = 5 def do_call(receiver, src = nil, context = nil, *rest) context ||= AppMap.caller_binding FRAME_DEPTH hook_method.bind(receiver).call(src, context, *rest) end end end end
Version data entries
15 entries across 15 versions & 1 rubygems