tapping_device 0.4.8 → 0.5.1

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.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tapping_device
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - st0012
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-05 00:00:00.000000000 Z
11
+ date: 2020-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '10.0'
89
+ version: '13.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '10.0'
96
+ version: '13.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -122,17 +122,20 @@ dependencies:
122
122
  - - '='
123
123
  - !ruby/object:Gem::Version
124
124
  version: 0.17.1
125
- description: tapping_device provides useful helpers to intercept method calls
125
+ description: tapping_device lets you understand what your Ruby objects do without
126
+ digging into the code
126
127
  email:
127
128
  - stan001212@gmail.com
128
129
  executables: []
129
130
  extensions: []
130
131
  extra_rdoc_files: []
131
132
  files:
133
+ - ".DS_Store"
132
134
  - ".github/workflows/gempush.yml"
133
135
  - ".github/workflows/ruby.yml"
134
136
  - ".gitignore"
135
137
  - ".rspec"
138
+ - ".ruby-version"
136
139
  - ".travis.yml"
137
140
  - CODE_OF_CONDUCT.md
138
141
  - Gemfile
@@ -142,11 +145,14 @@ files:
142
145
  - Rakefile
143
146
  - bin/console
144
147
  - bin/setup
148
+ - images/print_calls - single entry.png
149
+ - images/print_calls.png
150
+ - images/print_traces.png
145
151
  - lib/tapping_device.rb
146
152
  - lib/tapping_device/exceptions.rb
147
153
  - lib/tapping_device/manageable.rb
154
+ - lib/tapping_device/output_payload.rb
148
155
  - lib/tapping_device/payload.rb
149
- - lib/tapping_device/sql_tapping_methods.rb
150
156
  - lib/tapping_device/trackable.rb
151
157
  - lib/tapping_device/version.rb
152
158
  - tapping_device.gemspec
@@ -175,5 +181,6 @@ requirements: []
175
181
  rubygems_version: 3.0.3
176
182
  signing_key:
177
183
  specification_version: 4
178
- summary: tapping_device provides useful helpers to intercept method calls
184
+ summary: tapping_device lets you understand what your Ruby objects do without digging
185
+ into the code
179
186
  test_files: []
@@ -1,89 +0,0 @@
1
- class TappingDevice
2
- module SqlTappingMethods
3
- CALL_STACK_SKIPPABLE_METHODS = [:transaction, :tap]
4
-
5
- # SQLListener acts like an interface for us to intercept activerecord query instrumentations
6
- # this means we only need to register one subscriber no matter how many objects we want to tap on
7
- class SQLListener
8
- def call(name, start, finish, message_id, values);end
9
- end
10
- @@sql_listener = SQLListener.new
11
-
12
- ActiveSupport::Notifications.subscribe("sql.active_record", @@sql_listener)
13
-
14
- def tap_sql!(object)
15
- @call_stack = []
16
- @target ||= object
17
- @trace_point = with_trace_point_on_target(object, event: [:call, :c_call]) do |start_tp|
18
- ########## Check if the call is worth recording ##########
19
- filepath, line_number = get_call_location(start_tp, padding: 1) # we need extra padding because of `with_trace_point_on_target`
20
- method = start_tp.callee_id
21
- next if already_recording?(method)
22
-
23
- ########## Start the recording ##########
24
- # 1. Mark recording state by pushing method into @call_stack
25
- # 2. Subscribe sql instrumentations generated by activerecord
26
- # 3. Record those sqls and run device callbacks
27
- # 4. Start waiting for current call's return callback
28
- @call_stack.push(method)
29
- payload = build_payload(tp: start_tp, filepath: filepath, line_number: line_number)
30
- device = tap_on_sql_instrumentation!(payload)
31
-
32
- with_trace_point_on_target(object, event: :return) do |return_tp|
33
- next unless return_tp.callee_id == method
34
-
35
- ########## End recording ##########
36
- # 1. Close itself
37
- # 2. Stop our subscription on SQLListener
38
- # 3. Remove current method from @call_stack
39
- # 4. Stop the device if stop condition is fulfilled
40
- return_tp.disable
41
- device.stop!
42
- @call_stack.pop
43
- stop_if_condition_fulfilled(payload)
44
-
45
- ########## Track descendant objects ##########
46
- # if the method creates another Relation object
47
- if return_tp.defined_class == ActiveRecord::QueryMethods
48
- create_child_device.tap_sql!(return_tp.return_value)
49
- end
50
- end.enable
51
- end
52
-
53
- @trace_point.enable unless self.class.suspend_new
54
-
55
- self
56
- end
57
- end
58
-
59
- private
60
-
61
- def tap_on_sql_instrumentation!(payload)
62
- device = TappingDevice.new do |sql_listener_payload|
63
- values = sql_listener_payload.arguments[:values]
64
-
65
- next if should_be_skipped_by_paths?(payload.filepath) ||
66
- ["SCHEMA", "TRANSACTION"].include?(values[:name]) ||
67
- values[:sql].match?(/SAVEPOINT/)
68
-
69
- payload[:sql] = values[:sql]
70
- record_call!(payload)
71
- end
72
- device.tap_on!(@@sql_listener)
73
- end
74
-
75
- # usually, AR's query methods (like `first`) will end up calling `find_by_sql`
76
- # then to TappingDevice, both `first` and `find_by_sql` generates the sql
77
- # but the results are duplicated, we should only consider the `first` call
78
- def already_recording?(method)
79
- !@call_stack.empty? || CALL_STACK_SKIPPABLE_METHODS.include?(method)
80
- end
81
-
82
- def with_trace_point_on_target(object, event:)
83
- TracePoint.new(*event) do |tp|
84
- if is_from_target?(object, tp)
85
- yield(tp)
86
- end
87
- end
88
- end
89
- end