Class: GunDog::TraceMaker
- Inherits:
-
Object
- Object
- GunDog::TraceMaker
- Defined in:
- lib/gun_dog/trace_maker.rb
Instance Attribute Summary collapse
-
#call_trace ⇒ Object
readonly
Returns the value of attribute call_trace.
-
#complete_call_list ⇒ Object
readonly
Returns the value of attribute complete_call_list.
-
#klass ⇒ Object
readonly
Returns the value of attribute klass.
-
#return_trace ⇒ Object
readonly
Returns the value of attribute return_trace.
-
#trace_report ⇒ Object
readonly
Returns the value of attribute trace_report.
Instance Method Summary collapse
- #after_super?(defined_class) ⇒ Boolean
- #build_suppression_set(suppression_list) ⇒ Object
- #exec ⇒ Object
-
#initialize(klass, suppress: [], &exec_block) ⇒ TraceMaker
constructor
A new instance of TraceMaker.
- #set_call_trace ⇒ Object
- #set_method_return_trace(call_record) ⇒ Object
- #set_return_trace ⇒ Object
- #set_trace ⇒ Object
- #trace_method(binding_class, defined_class) ⇒ Object
Constructor Details
#initialize(klass, suppress: [], &exec_block) ⇒ TraceMaker
Returns a new instance of TraceMaker.
7 8 9 10 11 12 13 |
# File 'lib/gun_dog/trace_maker.rb', line 7 def initialize(klass, suppress: [], &exec_block) @klass = klass @trace_report = TraceReport.new(klass, suppression_set: build_suppression_set(suppress)) @trace_report.stack << MethodOwnerStackFrame.new(GunDog, :trace) @ancestor_cache = {} @exec_block = exec_block end |
Instance Attribute Details
#call_trace ⇒ Object (readonly)
Returns the value of attribute call_trace.
5 6 7 |
# File 'lib/gun_dog/trace_maker.rb', line 5 def call_trace @call_trace end |
#complete_call_list ⇒ Object (readonly)
Returns the value of attribute complete_call_list.
5 6 7 |
# File 'lib/gun_dog/trace_maker.rb', line 5 def complete_call_list @complete_call_list end |
#klass ⇒ Object (readonly)
Returns the value of attribute klass.
5 6 7 |
# File 'lib/gun_dog/trace_maker.rb', line 5 def klass @klass end |
#return_trace ⇒ Object (readonly)
Returns the value of attribute return_trace.
5 6 7 |
# File 'lib/gun_dog/trace_maker.rb', line 5 def return_trace @return_trace end |
#trace_report ⇒ Object (readonly)
Returns the value of attribute trace_report.
5 6 7 |
# File 'lib/gun_dog/trace_maker.rb', line 5 def trace_report @trace_report end |
Instance Method Details
#after_super?(defined_class) ⇒ Boolean
93 94 95 96 97 98 99 100 101 102 |
# File 'lib/gun_dog/trace_maker.rb', line 93 def after_super?(defined_class) return true unless klass.superclass != Object if @ancestor_cache.has_key?(defined_class) @ancestor_cache[defined_class] else ancestors = klass.ancestors @ancestor_cache[defined_class] = ancestors.index(klass.superclass) > ancestors.index(defined_class) end end |
#build_suppression_set(suppression_list) ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/gun_dog/trace_maker.rb', line 129 def build_suppression_set(suppression_list) suppression_list.map { |method_id| begin if class_method = method_id[/self\.(.*)/,1] klass.method(class_method).unbind else klass.instance_method(method_id) end rescue NameError nil end }.uniq.to_set end |
#exec ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/gun_dog/trace_maker.rb', line 15 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_trace ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/gun_dog/trace_maker.rb', line 42 def set_call_trace @call_trace ||= TracePoint.new(:call) do |tp| trace_report.stack << MethodOwnerStackFrame.new(tp.defined_class, tp.method_id) tp.disable binding_class = tp.binding.eval('self').class trace_type = trace_method(binding_class, tp.defined_class) unless trace_type tp.enable next end method_id = tp.binding.eval('__callee__') || tp.method_id called_method = if trace_type == :meta tp.binding.eval('self').method(method_id) else tp.self.method(tp.method_id) end # next if trace_report.suppression_set.include?(called_method.unbind) call_record = CallRecord.new( klass, called_method.name, class_method: trace_type == :eigen, generated: trace_type == :meta ) call_record.args = called_method.parameters.each.with_object({}) do |p, memo| memo[p.last] = tp.binding.local_variable_get(p.last) 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
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/gun_dog/trace_maker.rb', line 104 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| method_id = mrt.binding.eval('__callee__') || mrt.method_id next if method_id != call_record.method_name mrt.disable call_record.return_value = mrt.return_value if trace_report.stack.internal_stack? call_record.internal = true call_record.stack = trace_report.stack.since_first_klass_entry elsif trace_report.stack.cyclical_stack? call_record.cyclical = true call_record.stack = trace_report.stack.since_first_klass_entry end if trace_report.stack.dynamic_stack? call_record.dynamic = true call_record.stack = trace_report.stack.since_first_klass_entry end end end |
#set_return_trace ⇒ Object
36 37 38 39 40 |
# File 'lib/gun_dog/trace_maker.rb', line 36 def set_return_trace @return_trace ||= TracePoint.new(:return) do |tp| trace_report.stack.pop end end |
#set_trace ⇒ Object
31 32 33 34 |
# File 'lib/gun_dog/trace_maker.rb', line 31 def set_trace set_return_trace set_call_trace end |
#trace_method(binding_class, defined_class) ⇒ Object
85 86 87 88 89 90 91 |
# File 'lib/gun_dog/trace_maker.rb', line 85 def trace_method(binding_class, defined_class) return :eigen if defined_class == klass.singleton_class return false if binding_class != klass return :meta if klass < defined_class && (defined_class.anonymous? || after_super?(defined_class)) return :instance if defined_class == klass false end |