Capture calls to `eval`.


(Samuel Williams) #1

I would like to capture calls to eval.

I tried using trace points which does get pretty close:

@call_trace = TracePoint.new(:c_call) do |trace_point|
  if trace_point.method_id == :eval
    # How to get args?
  end
end

I also tried to override Kernel.eval but that didn't seem to work correctly
either. I might be doing something wrong.

Any ideas or suggestions would be greatly appreciated.

Kind regards,
Samuel


(Greg Navis) #2

I looked at the docs and it seems there's no easy way to get the argument.
I recommend you try to patch Kernel like this:

module Kernel
  alias_method :original_eval, :eval

  def eval(*args)
    p args
    original_eval(*args)
  end
end

# This prints:

···

#
# ["1 + 3"] (#p in Kernel.eval)
# 4 (the actual result)

puts eval('1 + 3')


(Ryan Davis) #3

via the binding:

TRACE_FMT = "%s:%d %s#%s %p"

@call_trace = TracePoint.new(:c_call) do |tp|
  next unless tp.method_id == :eval

  args = tp.binding.local_variables.map { |v|
    [v, tp.binding.local_variable_get(v)]
  }.to_h

  puts TRACE_FMT % [tp.path, tp.lineno, tp.defined_class, tp.method_id, args]
end

···

On Jun 30, 2018, at 17:32, Samuel Williams <space.ship.traveller@gmail.com> wrote:

@call_trace = TracePoint.new(:c_call) do |trace_point|
  if trace_point.method_id == :eval
    # How to get args?
  end
end


(Samuel Williams) #4

I tried both those methods and the only one that worked was monkey patching
Kernel.

···

On 10 July 2018 at 04:52, Ryan Davis <ryand-ruby@zenspider.com> wrote:

> On Jun 30, 2018, at 17:32, Samuel Williams <space.ship.traveller@gmail. > > wrote:
>
> @call_trace = TracePoint.new(:c_call) do |trace_point|
> if trace_point.method_id == :eval
> # How to get args?
> end
> end

via the binding:

TRACE_FMT = "%s:%d %s#%s %p"

@call_trace = TracePoint.new(:c_call) do |tp|
  next unless tp.method_id == :eval

  args = tp.binding.local_variables.map { |v|
    [v, tp.binding.local_variable_get(v)]
  }.to_h

  puts TRACE_FMT % [tp.path, tp.lineno, tp.defined_class, tp.method_id,
args]
end

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>