tapping_device 0.4.6 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +11 -2
- data/Gemfile.lock +9 -1
- data/README.md +134 -98
- data/lib/tapping_device.rb +30 -6
- data/lib/tapping_device/payload.rb +1 -0
- data/lib/tapping_device/sql_tapping_methods.rb +4 -3
- data/lib/tapping_device/version.rb +1 -1
- data/tapping_device.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72cee52830dca423c383eb154be4d7352b187cd2bcd848af5ed8d38af0f5ad40
|
4
|
+
data.tar.gz: 96d64f49adfd1de6b3174c9ecdb38d0f8d7e6f03bc0b1b85a79bf3b86613e349
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6675be23b1bbd4e0dfd6b1c4ea0ccbd39fba970af38a567928066935ab85a20003ecaf157f09f8e20223f2ec0717a72403261541d1b6836c393832c7240d35e
|
7
|
+
data.tar.gz: b93a1bd72210aa7f528687da0edaca7e812cb0849d7d0da8578ba8f5551a2134f6014a1f8c3b7989d750a15bdb734db1826d748de42bf4b995e3f7850cec00de
|
data/.github/workflows/ruby.yml
CHANGED
@@ -13,10 +13,12 @@ jobs:
|
|
13
13
|
os: [ubuntu-latest]
|
14
14
|
steps:
|
15
15
|
- uses: actions/checkout@v1
|
16
|
+
|
16
17
|
- name: Set up Ruby ${{ matrix.ruby_version }}
|
17
18
|
uses: actions/setup-ruby@v1
|
18
19
|
with:
|
19
20
|
ruby-version: ${{ matrix.ruby_version }}
|
21
|
+
|
20
22
|
- name: Install sqlite
|
21
23
|
run: |
|
22
24
|
# See https://github.community/t5/GitHub-Actions/ubuntu-latest-Apt-repository-list-issues/td-p/41122/page/2
|
@@ -24,10 +26,17 @@ jobs:
|
|
24
26
|
sudo apt-get update
|
25
27
|
sudo apt-get install libsqlite3-dev
|
26
28
|
|
27
|
-
- name: Build
|
29
|
+
- name: Build with Rails ${{ matrix.rails_version }}
|
28
30
|
env:
|
29
31
|
RAILS_VERSION: ${{ matrix.rails_version }}
|
30
32
|
run: |
|
31
33
|
gem install bundler
|
32
34
|
bundle install --jobs 4 --retry 3
|
33
|
-
|
35
|
+
|
36
|
+
- name: Run test with Rails ${{ matrix.rails_version }} and publish result
|
37
|
+
uses: paambaati/codeclimate-action@v2.3.0
|
38
|
+
env:
|
39
|
+
CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}}
|
40
|
+
with:
|
41
|
+
coverageCommand: bundle exec rake
|
42
|
+
debug: true
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
tapping_device (0.4.
|
4
|
+
tapping_device (0.4.7)
|
5
5
|
activerecord (>= 5.2)
|
6
6
|
|
7
7
|
GEM
|
@@ -22,8 +22,10 @@ GEM
|
|
22
22
|
concurrent-ruby (1.1.5)
|
23
23
|
database_cleaner (1.7.0)
|
24
24
|
diff-lcs (1.3)
|
25
|
+
docile (1.3.2)
|
25
26
|
i18n (1.7.0)
|
26
27
|
concurrent-ruby (~> 1.0)
|
28
|
+
json (2.3.0)
|
27
29
|
method_source (0.9.2)
|
28
30
|
minitest (5.13.0)
|
29
31
|
pry (0.12.2)
|
@@ -43,6 +45,11 @@ GEM
|
|
43
45
|
diff-lcs (>= 1.2.0, < 2.0)
|
44
46
|
rspec-support (~> 3.8.0)
|
45
47
|
rspec-support (3.8.2)
|
48
|
+
simplecov (0.17.1)
|
49
|
+
docile (~> 1.1)
|
50
|
+
json (>= 1.8, < 3)
|
51
|
+
simplecov-html (~> 0.10.0)
|
52
|
+
simplecov-html (0.10.2)
|
46
53
|
sqlite3 (1.4.1)
|
47
54
|
thread_safe (0.3.6)
|
48
55
|
tzinfo (1.2.6)
|
@@ -58,6 +65,7 @@ DEPENDENCIES
|
|
58
65
|
pry
|
59
66
|
rake (~> 10.0)
|
60
67
|
rspec (~> 3.0)
|
68
|
+
simplecov (= 0.17.1)
|
61
69
|
sqlite3 (>= 1.3.6)
|
62
70
|
tapping_device!
|
63
71
|
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# TappingDevice
|
2
2
|
|
3
3
|
![](https://github.com/st0012/tapping_device/workflows/Ruby/badge.svg)
|
4
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/3e3732a6983785bccdbd/maintainability)](https://codeclimate.com/github/st0012/tapping_device/maintainability)
|
5
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/3e3732a6983785bccdbd/test_coverage)](https://codeclimate.com/github/st0012/tapping_device/test_coverage)
|
6
|
+
[![Open Source Helpers](https://www.codetriage.com/st0012/tapping_device/badges/users.svg)](https://www.codetriage.com/st0012/tapping_device)
|
4
7
|
|
5
8
|
## Related Posts
|
6
9
|
- [Debug Rails issues effectively with tapping_device](https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c)
|
@@ -12,14 +15,18 @@
|
|
12
15
|
- [Track Association Calls](#track-association-calls)
|
13
16
|
- [Track Calls that Generates SQL Queries](#track-calls-that-generates-sql-queries)
|
14
17
|
- [Installation](#installation)
|
15
|
-
- [Usages](#
|
16
|
-
-
|
17
|
-
|
18
|
+
- [Usages](#usages)
|
19
|
+
- Tapping Methods
|
20
|
+
- [tap_init!](#tap_init)
|
21
|
+
- [tap_on!](#tap_on)
|
22
|
+
- [tap_passed!](#tap_passed)
|
23
|
+
- [tap_assoc!](#tap_assoc)
|
24
|
+
- [tap_sql!](#tap_sql)
|
18
25
|
- [Options](#options)
|
26
|
+
- [Payload](#payload-of-the-call)
|
19
27
|
- [Advance Usages](#advance-usages)
|
20
28
|
|
21
29
|
## Introduction
|
22
|
-
|
23
30
|
`tapping_device` is a gem built on top of Ruby’s `TracePoint` class that allows you to tap method calls of specified objects. The purpose for this gem is to make debugging Rails applications easier. Here are some sample usages:
|
24
31
|
|
25
32
|
### Track Method Calls
|
@@ -43,7 +50,6 @@ user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
|
43
50
|
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
44
51
|
```
|
45
52
|
|
46
|
-
|
47
53
|
### Track Association Calls
|
48
54
|
|
49
55
|
Or you can use `tap_assoc!`. This is very useful for tracking potential n+1 query calls, here’s a sample from my work
|
@@ -60,7 +66,6 @@ amending_orders FROM /MY_PROJECT/app/models/order.rb:385
|
|
60
66
|
amends_order FROM /MY_PROJECT/app/models/order.rb:432
|
61
67
|
```
|
62
68
|
|
63
|
-
|
64
69
|
### Track Calls that Generates SQL Queries
|
65
70
|
|
66
71
|
`tap_sql!` method helps you track which method calls generate sql queries. This is particularly helpful when tracking calls created from a reused `ActiveRecord::Relation` object.
|
@@ -98,11 +103,9 @@ Method: each generated sql: SELECT "posts".* FROM "posts" from /PROJECT_PATH/rai
|
|
98
103
|
Method: count generated sql: SELECT COUNT(*) FROM "posts" WHERE "posts"."user_id" = ? from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:31
|
99
104
|
```
|
100
105
|
|
101
|
-
|
102
106
|
However, depending on the size of your application, tapping any object could **harm the performance significantly**. **Don’t use this on production**
|
103
107
|
|
104
108
|
## Installation
|
105
|
-
|
106
109
|
Add this line to your application’s Gemfile:
|
107
110
|
|
108
111
|
```ruby
|
@@ -121,93 +124,12 @@ Or install it yourself as:
|
|
121
124
|
$ gem install tapping_device
|
122
125
|
```
|
123
126
|
|
124
|
-
##
|
125
|
-
In order to use `tapping_device`, you need to include `TappingDevice::Trackable` module in where you want to track your code.
|
126
|
-
|
127
|
-
### Methods
|
128
|
-
- `tap_init!(class)` - tracks a class’ instance initialization
|
129
|
-
- `tap_on!(object)` - tracks any calls received by the object
|
130
|
-
- `tap_assoc!(activerecord_object)` - tracks association calls on a record, like `post.comments`
|
131
|
-
- `tap_sql!(activerecord_relation_or_model)` - tracks sql queries generated from the target
|
132
|
-
|
133
|
-
### Payload of the call
|
134
|
-
All tapping methods (start with `tap_`) takes a block and yield a `Payload` object as block argument. It responds to
|
135
|
-
|
136
|
-
- `target` - the target for `tap_x` call
|
137
|
-
- `receiver` - the receiver object
|
138
|
-
- `method_name` - method’s name (symbol)
|
139
|
-
- e.g. `:name`
|
140
|
-
- `method_object` - the method object that’s being called. It might be `nil` in some edge cases.
|
141
|
-
- `arguments` - arguments of the method call
|
142
|
-
- e.g. `{name: “Stan”, age: 25}`
|
143
|
-
- `return_value` - return value of the method call
|
144
|
-
- `filepath` - path to the file that performs the method call
|
145
|
-
- `line_number`
|
146
|
-
- `defined_class` - in which class that defines the method being called
|
147
|
-
- `trace` - stack trace of the call. Default is an empty array unless `with_trace_to` option is set
|
148
|
-
- `tp` - trace point object of this call
|
149
|
-
|
150
|
-
|
151
|
-
#### Symbols for helpers
|
152
|
-
- `FROM` for method call’s location
|
153
|
-
- `<=` for arguments
|
154
|
-
- `=>` for return value
|
155
|
-
- `@` for defined class
|
156
|
-
|
157
|
-
#### Helpers
|
158
|
-
- `method_name_and_location` - `initialize FROM /PROJECT_PATH/tapping_device/spec/payload_spec.rb:7`
|
159
|
-
- `method_name_and_arguments` - `initialize <= {:name=>\"Stan\", :age=>25}`
|
160
|
-
- `method_name_and_return_value` - `ten => 10`
|
161
|
-
- `method_name_and_defined_class` - `initialize @ Student`
|
162
|
-
- `passed_at` -
|
163
|
-
```
|
164
|
-
Passed as 'object' in method ':initialize'
|
165
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
166
|
-
```
|
167
|
-
|
168
|
-
You can also set `passed_at(with_method_head: true)` to see the method’s head
|
127
|
+
## Usages
|
128
|
+
In order to use `tapping_device`, you need to include `TappingDevice::Trackable` module in where you want to track your code and call the following helpers.
|
169
129
|
|
170
|
-
|
171
|
-
Passed as 'object' in method ':initialize'
|
172
|
-
> def initialize(template_object, object_name, method_name, object, tag_value)
|
173
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
174
|
-
```
|
130
|
+
### tap_init!
|
175
131
|
|
176
|
-
|
177
|
-
|
178
|
-
```
|
179
|
-
initialize @ Student
|
180
|
-
<= {:name=>"Stan", :age=>25}
|
181
|
-
=> 25
|
182
|
-
FROM /Users/st0012/projects/tapping_device/spec/payload_spec.rb:7
|
183
|
-
```
|
184
|
-
|
185
|
-
|
186
|
-
### Options
|
187
|
-
- `with_trace_to: 10` - the number of traces we want to put into `trace`. Default is `nil`, so `trace` would be empty
|
188
|
-
- `exclude_by_paths: [/path/]` - an array of call path patterns that we want to skip. This could be very helpful when working on large project like Rails applications.
|
189
|
-
- `filter_by_paths: [/path/]` - only contain calls from the specified paths
|
190
|
-
|
191
|
-
```ruby
|
192
|
-
tap_on!(@post, exclude_by_paths: [/active_record/]).and_print(:method_name_and_location)
|
193
|
-
```
|
194
|
-
|
195
|
-
```
|
196
|
-
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
197
|
-
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
198
|
-
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
199
|
-
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
200
|
-
.......
|
201
|
-
|
202
|
-
# versus
|
203
|
-
|
204
|
-
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
205
|
-
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
206
|
-
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
207
|
-
```
|
208
|
-
|
209
|
-
|
210
|
-
### `#tap_init!`
|
132
|
+
`tap_init!(class)` - tracks a class’ instance initialization
|
211
133
|
|
212
134
|
```ruby
|
213
135
|
calls = []
|
@@ -221,7 +143,9 @@ Student.new("Jane", 23)
|
|
221
143
|
puts(calls.to_s) #=> [[:initialize, {:name=>"Stan", :age=>18}], [:initialize, {:name=>"Jane", :age=>23}]]
|
222
144
|
```
|
223
145
|
|
224
|
-
###
|
146
|
+
### tap_on!
|
147
|
+
|
148
|
+
`tap_on!(object)` - tracks any calls received by the object
|
225
149
|
|
226
150
|
```ruby
|
227
151
|
class PostsController < ApplicationController
|
@@ -243,9 +167,11 @@ user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
|
243
167
|
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
244
168
|
```
|
245
169
|
|
246
|
-
|
170
|
+
Also check the `track_as_records` option if you want to track `ActiveRecord` records.
|
171
|
+
|
172
|
+
### tap_passed!
|
247
173
|
|
248
|
-
This is particularly useful when debugging libraries. It saves your time from jumping between files and check which path the object will go.
|
174
|
+
`tap_passed!(target)` tracks method calls that **takes the target as its argument**. This is particularly useful when debugging libraries. It saves your time from jumping between files and check which path the object will go.
|
249
175
|
|
250
176
|
```ruby
|
251
177
|
class PostsController < ApplicationController
|
@@ -276,7 +202,9 @@ Passed as 'record_or_hash_or_array' in method ':polymorphic_method'
|
|
276
202
|
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionpack-6.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:139
|
277
203
|
```
|
278
204
|
|
279
|
-
###
|
205
|
+
### tap_assoc!
|
206
|
+
|
207
|
+
`tap_assoc!(activerecord_object)` tracks association calls on a record, like `post.comments`
|
280
208
|
|
281
209
|
```ruby
|
282
210
|
tap_assoc!(order).and_print(:method_name_and_location)
|
@@ -290,7 +218,9 @@ amending_orders FROM /MY_PROJECT/app/models/order.rb:385
|
|
290
218
|
amends_order FROM /MY_PROJECT/app/models/order.rb:432
|
291
219
|
```
|
292
220
|
|
293
|
-
###
|
221
|
+
### tap_sql!
|
222
|
+
|
223
|
+
`tap_sql!(anything_that_generates_sql_queries)` tracks sql queries generated from the target
|
294
224
|
|
295
225
|
```ruby
|
296
226
|
class PostsController < ApplicationController
|
@@ -324,6 +254,112 @@ Method: count generated sql: SELECT COUNT(*) FROM "posts" WHERE "posts"."user_id
|
|
324
254
|
```
|
325
255
|
|
326
256
|
|
257
|
+
### Options
|
258
|
+
#### with_trace_to
|
259
|
+
It takes an integer as the number of traces we want to put into `trace`. Default is `nil`, so `trace` would be empty.
|
260
|
+
|
261
|
+
```ruby
|
262
|
+
stan = Student.new("Stan", 18)
|
263
|
+
tap_on!(stan, with_trace_to: 5)
|
264
|
+
|
265
|
+
stan.name
|
266
|
+
|
267
|
+
puts(device.calls.first.trace) #=>
|
268
|
+
/Users/st0012/projects/tapping_device/spec/tapping_device_spec.rb:287:in `block (4 levels) in <top (required)>'
|
269
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `instance_exec'
|
270
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `block in run'
|
271
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:503:in `block in with_around_and_singleton_context_hooks'
|
272
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:460:in `block in with_around_example_hooks'
|
273
|
+
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/hooks.rb:464:in `block in run'
|
274
|
+
```
|
275
|
+
|
276
|
+
#### track_as_records
|
277
|
+
It makes the device to track objects as they are ActiveRecord instances. For example:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
tap_on!(@post, track_as_records: true)
|
281
|
+
post = Post.find(@post.id) # same record but a different object
|
282
|
+
post.title #=> this call will be recorded as well
|
283
|
+
```
|
284
|
+
|
285
|
+
#### exclude_by_paths
|
286
|
+
It takes an array of call path patterns that we want to skip. This could be very helpful when working on large project like Rails applications.
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
tap_on!(@post, exclude_by_paths: [/active_record/]).and_print(:method_name_and_location)
|
290
|
+
```
|
291
|
+
|
292
|
+
```
|
293
|
+
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
294
|
+
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
295
|
+
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
296
|
+
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
297
|
+
.......
|
298
|
+
|
299
|
+
# versus
|
300
|
+
|
301
|
+
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
302
|
+
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
303
|
+
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
304
|
+
```
|
305
|
+
|
306
|
+
#### filter_by_paths
|
307
|
+
|
308
|
+
Like `exclude_by_paths`, but work in an opposite way.
|
309
|
+
|
310
|
+
|
311
|
+
### Payload of The Call
|
312
|
+
All tapping methods (start with `tap_`) takes a block and yield a `Payload` object as block argument. It responds to
|
313
|
+
|
314
|
+
- `target` - the target for `tap_x` call
|
315
|
+
- `receiver` - the receiver object
|
316
|
+
- `method_name` - method’s name (symbol)
|
317
|
+
- e.g. `:name`
|
318
|
+
- `method_object` - the method object that’s being called. It might be `nil` in some edge cases.
|
319
|
+
- `arguments` - arguments of the method call
|
320
|
+
- e.g. `{name: “Stan”, age: 25}`
|
321
|
+
- `return_value` - return value of the method call
|
322
|
+
- `filepath` - path to the file that performs the method call
|
323
|
+
- `line_number`
|
324
|
+
- `defined_class` - in which class that defines the method being called
|
325
|
+
- `trace` - stack trace of the call. Default is an empty array unless `with_trace_to` option is set
|
326
|
+
- `sql` - sql that generated from the call (only present in `tap_sql!` payloads)
|
327
|
+
- `tp` - trace point object of this call
|
328
|
+
|
329
|
+
|
330
|
+
#### Symbols for Payload Helpers
|
331
|
+
- `FROM` for method call’s location
|
332
|
+
- `<=` for arguments
|
333
|
+
- `=>` for return value
|
334
|
+
- `@` for defined class
|
335
|
+
|
336
|
+
#### Payload Helpers
|
337
|
+
- `method_name_and_location` - `initialize FROM /PROJECT_PATH/tapping_device/spec/payload_spec.rb:7`
|
338
|
+
- `method_name_and_arguments` - `initialize <= {:name=>\"Stan\", :age=>25}`
|
339
|
+
- `method_name_and_return_value` - `ten => 10`
|
340
|
+
- `method_name_and_defined_class` - `initialize @ Student`
|
341
|
+
- `passed_at` -
|
342
|
+
```
|
343
|
+
Passed as 'object' in method ':initialize'
|
344
|
+
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
345
|
+
```
|
346
|
+
|
347
|
+
You can also set `passed_at(with_method_head: true)` to see the method’s head
|
348
|
+
|
349
|
+
```
|
350
|
+
Passed as 'object' in method ':initialize'
|
351
|
+
> def initialize(template_object, object_name, method_name, object, tag_value)
|
352
|
+
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
353
|
+
```
|
354
|
+
|
355
|
+
- `detail_call_info`
|
356
|
+
|
357
|
+
```
|
358
|
+
initialize @ Student
|
359
|
+
<= {:name=>"Stan", :age=>25}
|
360
|
+
=> 25
|
361
|
+
FROM /Users/st0012/projects/tapping_device/spec/payload_spec.rb:7
|
362
|
+
```
|
327
363
|
|
328
364
|
### Advance Usages
|
329
365
|
|
data/lib/tapping_device.rb
CHANGED
@@ -103,11 +103,24 @@ class TappingDevice
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def get_call_location(tp, padding: 0)
|
106
|
+
caller(get_trace_index(tp) + padding).first.split(":")[0..1]
|
107
|
+
end
|
108
|
+
|
109
|
+
def get_trace_index(tp)
|
106
110
|
if tp.event == :c_call
|
107
|
-
|
111
|
+
C_CALLER_START_POINT
|
112
|
+
else
|
113
|
+
CALLER_START_POINT
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def get_traces(tp)
|
118
|
+
if with_trace_to = options[:with_trace_to]
|
119
|
+
trace_index = get_trace_index(tp)
|
120
|
+
caller[trace_index..(trace_index + with_trace_to)]
|
108
121
|
else
|
109
|
-
|
110
|
-
end
|
122
|
+
[]
|
123
|
+
end
|
111
124
|
end
|
112
125
|
|
113
126
|
# this needs to be placed upfront so we can exclude noise before doing more work
|
@@ -130,7 +143,7 @@ class TappingDevice
|
|
130
143
|
filepath: filepath,
|
131
144
|
line_number: line_number,
|
132
145
|
defined_class: tp.defined_class,
|
133
|
-
trace:
|
146
|
+
trace: get_traces(tp),
|
134
147
|
tp: tp
|
135
148
|
})
|
136
149
|
end
|
@@ -159,8 +172,9 @@ class TappingDevice
|
|
159
172
|
end
|
160
173
|
|
161
174
|
def tap_passed?(object, tp)
|
162
|
-
# we don't care about calls from the device instance
|
175
|
+
# we don't care about calls from the device instance or helper methods
|
163
176
|
return false if is_from_target?(self, tp)
|
177
|
+
return false if tp.defined_class == TappingDevice::Trackable || tp.defined_class == TappingDevice
|
164
178
|
|
165
179
|
method_object = get_method_object_from(tp.self, tp.callee_id)
|
166
180
|
return false unless method_object.is_a?(Method)
|
@@ -196,6 +210,7 @@ class TappingDevice
|
|
196
210
|
options[:with_trace_to] ||= 50
|
197
211
|
options[:root_device] ||= self
|
198
212
|
options[:descendants] ||= []
|
213
|
+
options[:track_as_records] ||= false
|
199
214
|
options
|
200
215
|
end
|
201
216
|
|
@@ -207,7 +222,16 @@ class TappingDevice
|
|
207
222
|
end
|
208
223
|
|
209
224
|
def is_from_target?(object, tp)
|
210
|
-
|
225
|
+
comparsion = tp.self
|
226
|
+
is_the_same_record?(object, comparsion) || object.__id__ == comparsion.__id__
|
227
|
+
end
|
228
|
+
|
229
|
+
def is_the_same_record?(target, comparsion)
|
230
|
+
return false unless options[:track_as_records]
|
231
|
+
if target.is_a?(ActiveRecord::Base) && comparsion.is_a?(target.class)
|
232
|
+
primary_key = target.class.primary_key
|
233
|
+
target.send(primary_key) && target.send(primary_key) == comparsion.send(primary_key)
|
234
|
+
end
|
211
235
|
end
|
212
236
|
|
213
237
|
def record_call!(payload)
|
@@ -18,7 +18,7 @@ class TappingDevice
|
|
18
18
|
########## Check if the call is worth recording ##########
|
19
19
|
filepath, line_number = get_call_location(start_tp, padding: 1) # we need extra padding because of `with_trace_point_on_target`
|
20
20
|
method = start_tp.callee_id
|
21
|
-
next if
|
21
|
+
next if already_recording?(method)
|
22
22
|
|
23
23
|
########## Start the recording ##########
|
24
24
|
# 1. Mark recording state by pushing method into @call_stack
|
@@ -62,8 +62,9 @@ class TappingDevice
|
|
62
62
|
device = TappingDevice.new do |sql_listener_payload|
|
63
63
|
values = sql_listener_payload.arguments[:values]
|
64
64
|
|
65
|
-
next if
|
66
|
-
|
65
|
+
next if should_be_skipped_by_paths?(payload.filepath) ||
|
66
|
+
["SCHEMA", "TRANSACTION"].include?(values[:name]) ||
|
67
|
+
values[:sql].match?(/SAVEPOINT/)
|
67
68
|
|
68
69
|
payload[:sql] = values[:sql]
|
69
70
|
record_call!(payload)
|
data/tapping_device.gemspec
CHANGED
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.
|
4
|
+
version: 0.4.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- st0012
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.17.1
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.17.1
|
111
125
|
description: tapping_device provides useful helpers to intercept method calls
|
112
126
|
email:
|
113
127
|
- stan001212@gmail.com
|