gun_dog 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/gun_dog.gemspec +2 -0
- data/lib/gun_dog/call_record.rb +47 -13
- data/lib/gun_dog/class_encoding.rb +20 -0
- data/lib/gun_dog/method_owner_stack_frame.rb +9 -0
- data/lib/gun_dog/trace_explorer.rb +57 -0
- data/lib/gun_dog/trace_maker.rb +75 -11
- data/lib/gun_dog/trace_report.rb +17 -9
- data/lib/gun_dog/trace_stack.rb +48 -10
- data/lib/gun_dog/utilities.rb +36 -0
- data/lib/gun_dog/version.rb +1 -1
- data/lib/gun_dog.rb +23 -2
- metadata +33 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8553b5cae7081c781faffb51279789d50c10b352
|
4
|
+
data.tar.gz: f1dae43fce48c756e6bc004a7708879d3f1e7d94
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bab212ec57b6f8d3b10b8fbb4adda795a932aa6b539ecd53b35b3977d628040696fe9544d49508f24be2c4827195b86100269694a8a05cb1ffd8f421c955cc70
|
7
|
+
data.tar.gz: 53117f89da46453a9e567265ab8bb781c2c6431b859b713fdefa57c502b5f62355ef9e1456001fe5c88439505bfa0704bcd7f432cd7ca4610f0155e6d71107b8
|
data/gun_dog.gemspec
CHANGED
@@ -27,4 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
29
29
|
spec.add_development_dependency "pry-byebug"
|
30
|
+
spec.add_development_dependency "activerecord", ">= 4.2.9"
|
31
|
+
spec.add_development_dependency "sqlite3"
|
30
32
|
end
|
data/lib/gun_dog/call_record.rb
CHANGED
@@ -1,30 +1,36 @@
|
|
1
1
|
module GunDog
|
2
2
|
class CallRecord
|
3
|
+
using ClassEncoding
|
4
|
+
|
3
5
|
attr_accessor :args, :return_value, :method_name
|
4
6
|
attr_accessor :stack
|
5
7
|
|
6
|
-
attr_writer :internal, :cyclical
|
8
|
+
attr_writer :internal, :cyclical, :dynamic
|
7
9
|
|
8
10
|
def self.from_json(json)
|
9
|
-
cr = new(
|
10
|
-
|
11
|
-
|
11
|
+
cr = new(
|
12
|
+
Utilities.get_class(json['klass']),
|
13
|
+
json['method_name'],
|
14
|
+
class_method: json['class_method'],
|
15
|
+
generated: json['generated']
|
16
|
+
)
|
12
17
|
|
13
18
|
cr.instance_eval do
|
14
19
|
@internal = json['internal']
|
15
20
|
@cyclical = json['cyclical']
|
16
21
|
@args = json['args']
|
17
22
|
@return_value = json['return_value']
|
18
|
-
@stack = json['stack']
|
23
|
+
@stack = TraceStack.from_array(klass: @klass, stack: json['stack']) if json['stack']
|
19
24
|
end
|
20
25
|
|
21
26
|
cr
|
22
27
|
end
|
23
28
|
|
24
|
-
def initialize(klass, method_name, class_method: false)
|
29
|
+
def initialize(klass, method_name, class_method: false, generated: false)
|
25
30
|
@klass = klass
|
26
31
|
@method_name = method_name
|
27
32
|
@class_method = class_method
|
33
|
+
@generated = generated
|
28
34
|
end
|
29
35
|
|
30
36
|
def method_location
|
@@ -39,31 +45,59 @@ module GunDog
|
|
39
45
|
!!@cyclical
|
40
46
|
end
|
41
47
|
|
48
|
+
def dynamic?
|
49
|
+
!!@dynamic
|
50
|
+
end
|
51
|
+
|
42
52
|
def class_method?
|
43
53
|
!!@class_method
|
44
54
|
end
|
45
55
|
|
46
|
-
def
|
47
|
-
|
56
|
+
def generated?
|
57
|
+
!!@generated
|
58
|
+
end
|
59
|
+
|
60
|
+
def unbound_method
|
61
|
+
if class_method?
|
62
|
+
@klass.method(method_name).unbind
|
63
|
+
else
|
64
|
+
@klass.instance_method(method_name)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def call_record_signature
|
69
|
+
"#{generated? ? "[generated] " : nil } \
|
70
|
+
def #{class_method? ? "self." : nil}#{method_name}(#{type_signatures(args)}) : #{return_value.class} \
|
71
|
+
#{ internal? ? " (internal)" : nil } \
|
72
|
+
#{ cyclical? ? " (cyclical)" : nil } \
|
73
|
+
#{ dynamic? ? " (dynamic)" : nil }".squish
|
48
74
|
end
|
49
75
|
|
50
76
|
def as_json
|
51
77
|
{
|
52
|
-
"klass" => @klass,
|
53
|
-
"method_name" => method_name,
|
78
|
+
"klass" => @klass.json_encoded,
|
79
|
+
"method_name" => method_name.to_s,
|
54
80
|
"class_method" => class_method?,
|
81
|
+
"generated" => generated?,
|
55
82
|
"internal" => internal?,
|
56
83
|
"cyclical" => cyclical?,
|
57
|
-
"
|
84
|
+
"dynamic" => dynamic?,
|
85
|
+
"args" => args.each_pair.with_object({}) { |(k,v), memo| memo[k.to_s] = v},
|
58
86
|
"return_value" => return_value,
|
59
|
-
"stack" => stack
|
87
|
+
"stack" => stack&.as_json
|
60
88
|
}.reject { |_,v| v.nil? }
|
61
89
|
end
|
62
90
|
|
63
91
|
private
|
64
92
|
|
65
93
|
def type_signatures(args)
|
66
|
-
|
94
|
+
if method_name == :method_missing
|
95
|
+
#TODO pass v here back through this method to show the type signatures for each method rather than
|
96
|
+
# individual arguments
|
97
|
+
args.each_pair.map { |k,v| "#{k} : #{v ? v.to_s : v.class}" }.join(', ')
|
98
|
+
else
|
99
|
+
args.each_pair.map { |k,v| "#{k} : #{v.class}" }.join(', ')
|
100
|
+
end
|
67
101
|
end
|
68
102
|
|
69
103
|
def method_separator
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module GunDog
|
2
|
+
module ClassEncoding
|
3
|
+
refine Class do
|
4
|
+
def json_encoded
|
5
|
+
if singleton_class?
|
6
|
+
"#{ObjectSpace.each_object(self).first}.singleton_class"
|
7
|
+
else
|
8
|
+
name || "(anonymous subclass of #{superclass.name}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
refine Module do
|
14
|
+
def json_encoded
|
15
|
+
return name if name
|
16
|
+
"(anonymous module extended to an instance of #{ObjectSpace.each_object(self).first.class})"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,7 +1,16 @@
|
|
1
1
|
module GunDog
|
2
2
|
class MethodOwnerStackFrame < Struct.new(:klass, :method_name)
|
3
|
+
using ClassEncoding
|
4
|
+
|
3
5
|
def to_s
|
4
6
|
"#{klass}##{method_name}"
|
5
7
|
end
|
8
|
+
|
9
|
+
def as_json
|
10
|
+
{
|
11
|
+
"klass" => klass.json_encoded,
|
12
|
+
"method_name" => method_name.to_s
|
13
|
+
}
|
14
|
+
end
|
6
15
|
end
|
7
16
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
|
3
|
+
module GunDog
|
4
|
+
class TraceExplorer
|
5
|
+
attr_reader :trace_report
|
6
|
+
|
7
|
+
def initialize(trace_report)
|
8
|
+
@trace_report = trace_report
|
9
|
+
end
|
10
|
+
|
11
|
+
def unique_call_signatures
|
12
|
+
@trace_report.call_records.map(&:call_record_signature).uniq
|
13
|
+
end
|
14
|
+
|
15
|
+
def cyclical_methods
|
16
|
+
@trace_report.call_records.select(&:cyclical?)
|
17
|
+
end
|
18
|
+
|
19
|
+
def internal_methods
|
20
|
+
@trace_report.call_records.select(&:internal?)
|
21
|
+
end
|
22
|
+
|
23
|
+
def collaborating_local_classes
|
24
|
+
@trace_report.collaborating_classes.select { |k| Utilities.local_locations_for_class(k).any? }
|
25
|
+
end
|
26
|
+
|
27
|
+
def collaborating_classes
|
28
|
+
@trace_report.collaborating_classes
|
29
|
+
end
|
30
|
+
|
31
|
+
def trace
|
32
|
+
@trace_report
|
33
|
+
end
|
34
|
+
|
35
|
+
def [](method_location)
|
36
|
+
find_cache[method_location]
|
37
|
+
end
|
38
|
+
|
39
|
+
def methods
|
40
|
+
find_cache.keys
|
41
|
+
end
|
42
|
+
|
43
|
+
def unique_traces(doc_name)
|
44
|
+
find_cache[doc_name].map { |cr| cr.stack&.map(&:to_s) }.uniq.compact
|
45
|
+
end
|
46
|
+
|
47
|
+
def call_count
|
48
|
+
find_cache.each_pair.with_object({}) { |(k,v), memo| memo[k] = v.count }
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def find_cache
|
54
|
+
find_cache ||= @trace_report.call_records.group_by(&:method_location)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/gun_dog/trace_maker.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
require 'active_support/core_ext/module/anonymous'
|
2
|
+
|
1
3
|
module GunDog
|
2
4
|
class TraceMaker
|
3
|
-
attr_reader :trace_report, :return_trace, :call_trace, :klass
|
5
|
+
attr_reader :trace_report, :return_trace, :call_trace, :klass, :complete_call_list
|
4
6
|
|
5
|
-
def initialize(klass, &exec_block)
|
7
|
+
def initialize(klass, suppress: [], &exec_block)
|
6
8
|
@klass = klass
|
7
|
-
@trace_report = TraceReport.new(klass)
|
9
|
+
@trace_report = TraceReport.new(klass, suppression_set: build_suppression_set(suppress))
|
8
10
|
@trace_report.stack << MethodOwnerStackFrame.new(GunDog, :trace)
|
11
|
+
@ancestor_cache = {}
|
9
12
|
@exec_block = exec_block
|
10
13
|
end
|
11
14
|
|
@@ -39,14 +42,36 @@ module GunDog
|
|
39
42
|
def set_call_trace
|
40
43
|
@call_trace ||= TracePoint.new(:call) do |tp|
|
41
44
|
trace_report.stack << MethodOwnerStackFrame.new(tp.defined_class, tp.method_id)
|
42
|
-
next unless tp.defined_class == klass || tp.defined_class == klass.singleton_class
|
43
45
|
|
44
46
|
tp.disable
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
+
binding_class = tp.binding.eval('self').class
|
49
|
+
trace_type = trace_method(binding_class, tp.defined_class)
|
50
|
+
|
51
|
+
unless trace_type
|
52
|
+
tp.enable
|
53
|
+
next
|
54
|
+
end
|
55
|
+
|
56
|
+
method_id = tp.binding.eval('__callee__') || tp.method_id
|
57
|
+
|
58
|
+
called_method = if trace_type == :meta
|
59
|
+
tp.binding.eval('self').method(method_id)
|
60
|
+
else
|
61
|
+
tp.self.method(tp.method_id)
|
62
|
+
end
|
63
|
+
|
64
|
+
# next if trace_report.suppression_set.include?(called_method.unbind)
|
65
|
+
|
66
|
+
call_record = CallRecord.new(
|
67
|
+
klass,
|
68
|
+
called_method.name,
|
69
|
+
class_method: trace_type == :eigen,
|
70
|
+
generated: trace_type == :meta
|
71
|
+
)
|
72
|
+
|
48
73
|
call_record.args = called_method.parameters.each.with_object({}) do |p, memo|
|
49
|
-
memo[p.last] = tp.binding.local_variable_get(p.last)
|
74
|
+
memo[p.last] = tp.binding.local_variable_get(p.last)
|
50
75
|
end
|
51
76
|
|
52
77
|
trace_report.call_records << call_record
|
@@ -57,23 +82,62 @@ module GunDog
|
|
57
82
|
end
|
58
83
|
end
|
59
84
|
|
85
|
+
def trace_method(binding_class, defined_class)
|
86
|
+
return :eigen if defined_class == klass.singleton_class
|
87
|
+
return false if binding_class != klass
|
88
|
+
return :meta if klass < defined_class && (defined_class.anonymous? || after_super?(defined_class))
|
89
|
+
return :instance if defined_class == klass
|
90
|
+
false
|
91
|
+
end
|
92
|
+
|
93
|
+
def after_super?(defined_class)
|
94
|
+
return true unless klass.superclass != Object
|
95
|
+
|
96
|
+
if @ancestor_cache.has_key?(defined_class)
|
97
|
+
@ancestor_cache[defined_class]
|
98
|
+
else
|
99
|
+
ancestors = klass.ancestors
|
100
|
+
@ancestor_cache[defined_class] = ancestors.index(klass.superclass) > ancestors.index(defined_class)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
60
104
|
def set_method_return_trace(call_record)
|
61
105
|
# instantiate a new return tracepoint to watch for the return of this
|
62
106
|
# method only
|
63
107
|
#
|
64
108
|
TracePoint.new(:return) do |mrt|
|
65
|
-
|
109
|
+
method_id = mrt.binding.eval('__callee__') || mrt.method_id
|
110
|
+
next if method_id != call_record.method_name
|
66
111
|
mrt.disable
|
67
|
-
call_record.return_value = mrt.return_value
|
112
|
+
call_record.return_value = mrt.return_value
|
68
113
|
|
69
114
|
if trace_report.stack.internal_stack?
|
70
115
|
call_record.internal = true
|
71
|
-
call_record.stack = trace_report.stack.
|
116
|
+
call_record.stack = trace_report.stack.since_first_klass_entry
|
72
117
|
elsif trace_report.stack.cyclical_stack?
|
73
118
|
call_record.cyclical = true
|
74
|
-
call_record.stack = trace_report.stack.
|
119
|
+
call_record.stack = trace_report.stack.since_first_klass_entry
|
120
|
+
end
|
121
|
+
|
122
|
+
if trace_report.stack.dynamic_stack?
|
123
|
+
call_record.dynamic = true
|
124
|
+
call_record.stack = trace_report.stack.since_first_klass_entry
|
75
125
|
end
|
76
126
|
end
|
77
127
|
end
|
128
|
+
|
129
|
+
def build_suppression_set(suppression_list)
|
130
|
+
suppression_list.map { |method_id|
|
131
|
+
begin
|
132
|
+
if class_method = method_id[/self\.(.*)/,1]
|
133
|
+
klass.method(class_method).unbind
|
134
|
+
else
|
135
|
+
klass.instance_method(method_id)
|
136
|
+
end
|
137
|
+
rescue NameError
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
}.uniq.to_set
|
141
|
+
end
|
78
142
|
end
|
79
143
|
end
|
data/lib/gun_dog/trace_report.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module GunDog
|
2
2
|
class TraceReport
|
3
|
-
|
3
|
+
using ClassEncoding
|
4
|
+
|
5
|
+
attr_reader :klass, :suppression_set
|
4
6
|
|
5
7
|
def self.load(filename)
|
6
8
|
json = MultiJson.load(File.open(filename, 'r') { |f| f.read })
|
@@ -19,12 +21,21 @@ module GunDog
|
|
19
21
|
tr
|
20
22
|
end
|
21
23
|
|
24
|
+
def all_calls
|
25
|
+
@all_calls ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
def explore
|
29
|
+
GunDog::TraceExplorer.new(self)
|
30
|
+
end
|
31
|
+
|
22
32
|
def call_records
|
23
33
|
@call_records ||= []
|
24
34
|
end
|
25
35
|
|
26
|
-
def initialize(klass)
|
36
|
+
def initialize(klass, suppression_set: [])
|
27
37
|
@klass = klass
|
38
|
+
@suppression_set = suppression_set
|
28
39
|
end
|
29
40
|
|
30
41
|
def collaborating_classes
|
@@ -52,21 +63,18 @@ module GunDog
|
|
52
63
|
|
53
64
|
def as_json
|
54
65
|
{
|
55
|
-
"klass" => klass,
|
56
|
-
"collaborating_classes" => collaborating_classes.
|
66
|
+
"klass" => klass.to_s,
|
67
|
+
"collaborating_classes" => collaborating_classes.map { |k| k.json_encoded },
|
57
68
|
"call_records" => call_records.map(&:as_json)
|
58
69
|
}
|
70
|
+
|
59
71
|
end
|
60
72
|
|
73
|
+
|
61
74
|
def to_json
|
62
75
|
MultiJson.dump(as_json)
|
63
76
|
end
|
64
77
|
|
65
|
-
def find_call_record(doc_name)
|
66
|
-
@find_cache ||= @call_records.group_by(&:method_location)
|
67
|
-
@find_cache[doc_name]
|
68
|
-
end
|
69
|
-
|
70
78
|
def method_list
|
71
79
|
@call_records.map(&:method_location)
|
72
80
|
end
|
data/lib/gun_dog/trace_stack.rb
CHANGED
@@ -6,7 +6,16 @@ module GunDog
|
|
6
6
|
ts = new(json['klass'])
|
7
7
|
|
8
8
|
ts.instance_eval do
|
9
|
-
@collaborating_classes = Set.new(json['collaborating_classes'].map { |k|
|
9
|
+
@collaborating_classes = Set.new(json['collaborating_classes'].map { |k| Utilities.get_class(k) })
|
10
|
+
end
|
11
|
+
|
12
|
+
ts
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.from_array(klass:, stack: )
|
16
|
+
ts = new(klass)
|
17
|
+
stack.each do |f|
|
18
|
+
ts << GunDog::MethodOwnerStackFrame.new(Utilities.get_class(f['klass']), f['method_name'])
|
10
19
|
end
|
11
20
|
|
12
21
|
ts
|
@@ -18,21 +27,27 @@ module GunDog
|
|
18
27
|
|
19
28
|
def initialize(klass)
|
20
29
|
@klass = klass
|
30
|
+
@traced_klass_entry_points = Array.new
|
21
31
|
@collaborating_classes = Set.new
|
22
32
|
end
|
23
33
|
|
24
34
|
def internal_stack?
|
25
|
-
# if the set of
|
26
|
-
# set of our own class then it is an
|
27
|
-
#
|
28
|
-
|
35
|
+
# if the set of classes contained in the trace since we entered our own
|
36
|
+
# class is equivalent to the set of our own class then it is an internal
|
37
|
+
# trace
|
38
|
+
since_first_klass_entry.classes_in_stack == self_set
|
29
39
|
end
|
30
40
|
|
31
41
|
def cyclical_stack?
|
32
|
-
# if the set of classes contained in the trace
|
33
|
-
# of our class then it is a cyclical stack
|
34
|
-
# within and without of the class)
|
35
|
-
|
42
|
+
# if the set of classes contained in the trace since we entered our own
|
43
|
+
# class is a superset of the set of our class then it is a cyclical stack
|
44
|
+
# (ie, it contains calls both within and without of the class)
|
45
|
+
since_first_klass_entry.classes_in_stack > self_set
|
46
|
+
end
|
47
|
+
|
48
|
+
def dynamic_stack?
|
49
|
+
methods = since_first_klass_entry.map { |f| f.method_name.to_s }
|
50
|
+
methods.include?('method_missing') || methods.include?('send') || methods.include?('__send__')
|
36
51
|
end
|
37
52
|
|
38
53
|
def preceded_by_traced_klass?
|
@@ -44,14 +59,37 @@ module GunDog
|
|
44
59
|
[klass].to_set
|
45
60
|
end
|
46
61
|
|
62
|
+
def since_first_klass_entry
|
63
|
+
# the stack since the first call to a traced method excluding the current
|
64
|
+
# frame
|
65
|
+
self.slice((@traced_klass_entry_points.first || 1) .. -2) || GunDog::TraceStack.new(@klass)
|
66
|
+
end
|
67
|
+
|
47
68
|
def call_stack
|
48
|
-
# the stack excluding the sentinel (element zero) and
|
69
|
+
# the stack excluding the gundog sentinel (element zero) and ourselves (element -1)
|
49
70
|
self.slice(1 .. -2) || TraceStack.new(klass)
|
50
71
|
end
|
51
72
|
|
73
|
+
def pop
|
74
|
+
super.tap do |popped|
|
75
|
+
if length == @traced_klass_entry_points.last
|
76
|
+
@traced_klass_entry_points.pop
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
52
81
|
def <<(frame)
|
53
82
|
collaborating_classes.add(frame.klass) if preceded_by_traced_klass?
|
83
|
+
@traced_klass_entry_points << length if frame_owned_by_traced_klass?(frame)
|
54
84
|
super(frame)
|
55
85
|
end
|
86
|
+
|
87
|
+
def frame_owned_by_traced_klass?(frame)
|
88
|
+
frame.klass == klass || frame.klass.singleton_class == klass.singleton_class
|
89
|
+
end
|
90
|
+
|
91
|
+
def as_json
|
92
|
+
map(&:as_json)
|
93
|
+
end
|
56
94
|
end
|
57
95
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module GunDog
|
2
|
+
module Utilities
|
3
|
+
class UnencodableClass; end
|
4
|
+
|
5
|
+
def self.get_class(str)
|
6
|
+
if str =~ /anonymous/
|
7
|
+
Class.new(UnencodableClass) do |k|
|
8
|
+
def json_encoded
|
9
|
+
k
|
10
|
+
end
|
11
|
+
end
|
12
|
+
else
|
13
|
+
begin
|
14
|
+
eval(str)
|
15
|
+
rescue => e
|
16
|
+
require 'pry'; binding.pry
|
17
|
+
e.message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.local_locations_for_class(c)
|
23
|
+
all_locations_for_class(c)
|
24
|
+
.reject { |p| p =~ /(gem)|(rubies)|(eval)/ }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.all_locations_for_class(c)
|
28
|
+
c.instance_methods
|
29
|
+
.map { |m| c.instance_method(m) }
|
30
|
+
.select { |m| m.owner == c }
|
31
|
+
.map { |m| m.source_location&.first }
|
32
|
+
.compact
|
33
|
+
.uniq
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/gun_dog/version.rb
CHANGED
data/lib/gun_dog.rb
CHANGED
@@ -1,17 +1,38 @@
|
|
1
|
-
require
|
1
|
+
require 'gun_dog/version'
|
2
2
|
require 'json'
|
3
3
|
require 'multi_json'
|
4
4
|
require 'active_support/core_ext/hash/slice'
|
5
5
|
require 'active_support/core_ext/string/filters'
|
6
|
+
require 'active_support/configurable'
|
6
7
|
|
7
8
|
module GunDog
|
9
|
+
include ActiveSupport::Configurable
|
10
|
+
|
11
|
+
config_accessor :suppress_methods do
|
12
|
+
{}
|
13
|
+
end
|
14
|
+
|
8
15
|
autoload :MethodOwnerStackFrame, 'gun_dog/method_owner_stack_frame'
|
9
16
|
autoload :CallRecord, 'gun_dog/call_record'
|
10
17
|
autoload :TraceMaker, 'gun_dog/trace_maker'
|
11
18
|
autoload :TraceReport, 'gun_dog/trace_report'
|
12
19
|
autoload :TraceStack, 'gun_dog/trace_stack'
|
20
|
+
autoload :TraceExplorer, 'gun_dog/trace_explorer'
|
21
|
+
autoload :ClassEncoding, 'gun_dog/class_encoding'
|
22
|
+
autoload :Utilities, 'gun_dog/utilities'
|
23
|
+
|
24
|
+
class << self
|
25
|
+
private def suppressed_methods_for_klass(klass)
|
26
|
+
config.suppress_methods.values_at(*klass.ancestors).flatten.compact
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
13
30
|
|
14
31
|
def self.trace(klass, &block)
|
15
|
-
TraceMaker.new(klass, &block).exec
|
32
|
+
TraceMaker.new(klass, suppress: suppressed_methods_for_klass(klass), &block).exec
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.load_trace(path)
|
36
|
+
TraceReport.load(path)
|
16
37
|
end
|
17
38
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gun_dog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Prater
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|
@@ -94,6 +94,34 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: activerecord
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 4.2.9
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 4.2.9
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
description: Log callsite information for a given class.
|
98
126
|
email:
|
99
127
|
- me@stephenprater.com
|
@@ -112,11 +140,14 @@ files:
|
|
112
140
|
- gun_dog.gemspec
|
113
141
|
- lib/gun_dog.rb
|
114
142
|
- lib/gun_dog/call_record.rb
|
143
|
+
- lib/gun_dog/class_encoding.rb
|
115
144
|
- lib/gun_dog/indexed_array.rb
|
116
145
|
- lib/gun_dog/method_owner_stack_frame.rb
|
146
|
+
- lib/gun_dog/trace_explorer.rb
|
117
147
|
- lib/gun_dog/trace_maker.rb
|
118
148
|
- lib/gun_dog/trace_report.rb
|
119
149
|
- lib/gun_dog/trace_stack.rb
|
150
|
+
- lib/gun_dog/utilities.rb
|
120
151
|
- lib/gun_dog/version.rb
|
121
152
|
homepage: http://github.com/stephenprater/gun_dog
|
122
153
|
licenses: []
|