Class: GunDog::TraceMaker

Inherits:
Object
  • Object
show all
Defined in:
lib/gun_dog/trace_maker.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, &exec_block) ⇒ TraceMaker

Returns a new instance of TraceMaker.



5
6
7
8
9
10
# File 'lib/gun_dog/trace_maker.rb', line 5

def initialize(klass, &exec_block)
  @klass = klass
  @trace_report = TraceReport.new(klass)
  @trace_report.stack << MethodOwnerStackFrame.new(GunDog, :trace)
  @exec_block = exec_block
end

Instance Attribute Details

#call_traceObject (readonly)

Returns the value of attribute call_trace.



3
4
5
# File 'lib/gun_dog/trace_maker.rb', line 3

def call_trace
  @call_trace
end

#klassObject (readonly)

Returns the value of attribute klass.



3
4
5
# File 'lib/gun_dog/trace_maker.rb', line 3

def klass
  @klass
end

#return_traceObject (readonly)

Returns the value of attribute return_trace.



3
4
5
# File 'lib/gun_dog/trace_maker.rb', line 3

def return_trace
  @return_trace
end

#trace_reportObject (readonly)

Returns the value of attribute trace_report.



3
4
5
# File 'lib/gun_dog/trace_maker.rb', line 3

def trace_report
  @trace_report
end

Instance Method Details

#execObject



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/gun_dog/trace_maker.rb', line 12

def exec
  set_trace

  call_trace.enable do
    return_trace.enable do
      @exec_block.call
    end
  end

  trace_report.finalize_report
  trace_report
ensure
  call_trace.disable
  return_trace.disable
end

#set_call_traceObject



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/gun_dog/trace_maker.rb', line 39

def set_call_trace
  @call_trace ||= TracePoint.new(:call) do |tp|
    trace_report.stack << MethodOwnerStackFrame.new(tp.defined_class, tp.method_id)
    next unless tp.defined_class == klass || tp.defined_class == klass.singleton_class

    tp.disable

    call_record = CallRecord.new(klass, tp.method_id, class_method: tp.defined_class == klass.singleton_class)
    called_method = tp.self.method(tp.method_id)
    call_record.args = called_method.parameters.each.with_object({}) do |p, memo|
      memo[p.last] = tp.binding.local_variable_get(p.last).class
    end

    trace_report.call_records << call_record

    set_method_return_trace(call_record).enable

    tp.enable
  end
end

#set_method_return_trace(call_record) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/gun_dog/trace_maker.rb', line 60

def set_method_return_trace(call_record)
  # instantiate a new return tracepoint to watch for the return of this
  # method only
  #
  TracePoint.new(:return) do |mrt|
    next if mrt.method_id != call_record.method_name
    mrt.disable
    call_record.return_value = mrt.return_value.class

    if trace_report.stack.internal_stack?
      call_record.internal = true
      call_record.stack = trace_report.stack.dup
    elsif trace_report.stack.cyclical_stack?
      call_record.cyclical = true
      call_record.stack = trace_report.stack.dup
    end
  end
end

#set_return_traceObject



33
34
35
36
37
# File 'lib/gun_dog/trace_maker.rb', line 33

def set_return_trace
  @return_trace ||= TracePoint.new(:return) do |tp|
    trace_report.stack.pop
  end
end

#set_traceObject



28
29
30
31
# File 'lib/gun_dog/trace_maker.rb', line 28

def set_trace
  set_return_trace
  set_call_trace
end