tapping_device 0.4.7 → 0.4.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72cee52830dca423c383eb154be4d7352b187cd2bcd848af5ed8d38af0f5ad40
4
- data.tar.gz: 96d64f49adfd1de6b3174c9ecdb38d0f8d7e6f03bc0b1b85a79bf3b86613e349
3
+ metadata.gz: 24fe45432978253d77089abca47f6b85e23b704936b6919a9e484a76bd423997
4
+ data.tar.gz: 2f57680abf620d45426c4d4208c4d812427f600b7913a3e305f5f44fdcf1fbb6
5
5
  SHA512:
6
- metadata.gz: a6675be23b1bbd4e0dfd6b1c4ea0ccbd39fba970af38a567928066935ab85a20003ecaf157f09f8e20223f2ec0717a72403261541d1b6836c393832c7240d35e
7
- data.tar.gz: b93a1bd72210aa7f528687da0edaca7e812cb0849d7d0da8578ba8f5551a2134f6014a1f8c3b7989d750a15bdb734db1826d748de42bf4b995e3f7850cec00de
6
+ metadata.gz: a449ed382aee9df385a3d64b50dced35aebb0f590243ec399c7e05c95cba9557d9e4b03ed7b158e83bc5dc7b3f9d032bb19608cff1d3344749eae8538efefef0
7
+ data.tar.gz: b6a75131cd536086df46aa9a624bc9ccebd61c0e83e26312dd3ad2c6e9257922f19dee6f2a98cfd8e9eef6b1b0581d8db1c96c4101ec2a90f00bef9ad3022e48
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tapping_device (0.4.7)
4
+ tapping_device (0.4.8)
5
5
  activerecord (>= 5.2)
6
6
 
7
7
  GEM
@@ -70,4 +70,4 @@ DEPENDENCIES
70
70
  tapping_device!
71
71
 
72
72
  BUNDLED WITH
73
- 2.0.2
73
+ 2.1.1
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # TappingDevice
2
2
 
3
- ![](https://github.com/st0012/tapping_device/workflows/Ruby/badge.svg)
3
+ ![GitHub Action](https://github.com/st0012/tapping_device/workflows/Ruby/badge.svg)
4
+ [![Gem Version](https://badge.fury.io/rb/tapping_device.svg)](https://badge.fury.io/rb/tapping_device)
4
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/3e3732a6983785bccdbd/maintainability)](https://codeclimate.com/github/st0012/tapping_device/maintainability)
5
6
  [![Test Coverage](https://api.codeclimate.com/v1/badges/3e3732a6983785bccdbd/test_coverage)](https://codeclimate.com/github/st0012/tapping_device/test_coverage)
6
7
  [![Open Source Helpers](https://www.codetriage.com/st0012/tapping_device/badges/users.svg)](https://www.codetriage.com/st0012/tapping_device)
@@ -11,64 +12,56 @@
11
12
 
12
13
  ## Table of Content
13
14
  - [Introduction](#introduction)
14
- - [Track Method Calls](#track-method-calls)
15
- - [Track Association Calls](#track-association-calls)
16
- - [Track Calls that Generates SQL Queries](#track-calls-that-generates-sql-queries)
15
+ - [Print Object’s Traces](print-objects-traces)
16
+ - [Track Calls that Generates SQL Queries](#track-calls-that-generates-sql-queries)
17
17
  - [Installation](#installation)
18
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)
25
- - [Options](#options)
26
- - [Payload](#payload-of-the-call)
27
- - [Advance Usages](#advance-usages)
19
+ - Tracing Helpers
20
+ - [print_traces](#print_traces)
21
+ - [print_calls_in_detail](#print_calls_in_detail)
22
+ - Tapping Methods
23
+ - [tap_init!](#tap_init)
24
+ - [tap_on!](#tap_on)
25
+ - [tap_passed!](#tap_passed)
26
+ - [tap_assoc!](#tap_assoc)
27
+ - [tap_sql!](#tap_sql)
28
+ - [Options](#options)
29
+ - [Payload](#payload-of-the-call)
30
+ - [Advance Usages](#advance-usages)
28
31
 
29
32
  ## Introduction
30
- `tapping_device` is a gem built on top of Rubys `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:
33
+ `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 of this gem is to make debugging Rails applications easier. Here are some sample usages:
31
34
 
32
- ### Track Method Calls
35
+ ### Print Object’s Traces
36
+
37
+ Let your objects report to you, so you don’t need to guess how they work!
33
38
 
34
39
  ```ruby
35
- class PostsController < ApplicationController
40
+ class OrdersController < ApplicationController
36
41
  include TappingDevice::Trackable
37
42
 
38
- def show
39
- @post = Post.find(params[:id])
40
- tap_on!(@post).and_print(:method_name_and_location)
43
+ def create
44
+ @cart = Cart.find(order_params[:cart_id])
45
+ print_traces(@cart, exclude_by_paths: [/gems/])
46
+ @order = OrderCreationService.new.perform(@cart)
41
47
  end
42
- end
43
48
  ```
44
49
 
45
- And you can see these in log:
46
-
47
50
  ```
48
- name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
49
- user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
50
- to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
51
+ Passed as 'cart' in 'OrderCreationService#perform' at /Users/st0012/projects/tapping_device-demo/app/controllers/orders_controller.rb:10
52
+ Passed as 'cart' in 'OrderCreationService#validate_cart' at /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:8
53
+ Called :reserved_until FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:18
54
+ Called :errors FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:9
55
+ Passed as 'cart' in 'OrderCreationService#apply_discount' at /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:10
56
+ Called :apply_discount FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:24
57
+ ……
51
58
  ```
52
59
 
53
- ### Track Association Calls
54
-
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
56
-
57
- ```ruby
58
- tap_assoc!(order).and_print(:method_name_and_location)
59
- ```
60
-
61
- ```
62
- payments FROM /RUBY_PATH/gems/2.6.0/gems/jsonapi-resources-0.9.10/lib/jsonapi/resource.rb:124
63
- line_items FROM /MY_PROJECT/app/models/line_item_container_helpers.rb:44
64
- effective_line_items FROM /MY_PROJECT/app/models/line_item_container_helpers.rb:110
65
- amending_orders FROM /MY_PROJECT/app/models/order.rb:385
66
- amends_order FROM /MY_PROJECT/app/models/order.rb:432
67
- ```
60
+ (Also see [print_calls_in_detail](#print_calls_in_detail))
68
61
 
69
62
  ### Track Calls that Generates SQL Queries
70
63
 
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.
64
+ `tap_sql!` method helps you track which method calls to generate SQL queries. This is particularly helpful when tracking calls created from a reused `ActiveRecord::Relation` object.
72
65
 
73
66
  ```ruby
74
67
  class PostsController < ApplicationController
@@ -103,10 +96,10 @@ Method: each generated sql: SELECT "posts".* FROM "posts" from /PROJECT_PATH/rai
103
96
  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
104
97
  ```
105
98
 
106
- However, depending on the size of your application, tapping any object could **harm the performance significantly**. **Dont use this on production**
99
+ However, depending on the size of your application, tapping any object could **harm the performance significantly**. **Don't use this on production**
107
100
 
108
101
  ## Installation
109
- Add this line to your applications Gemfile:
102
+ Add this line to your application's Gemfile:
110
103
 
111
104
  ```ruby
112
105
  gem 'tapping_device', group: :development
@@ -127,6 +120,68 @@ $ gem install tapping_device
127
120
  ## Usages
128
121
  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.
129
122
 
123
+ ### print_traces
124
+
125
+ It prints the object's trace. It's like mounting a GPS tracker + a spy camera on your object, so you can inspect your program through the object's eyes.
126
+
127
+ ```ruby
128
+ class OrdersController < ApplicationController
129
+ include TappingDevice::Trackable
130
+
131
+ def create
132
+ @cart = Cart.find(order_params[:cart_id])
133
+ print_traces(@cart, exclude_by_paths: [/gems/])
134
+ @order = OrderCreationService.new.perform(@cart)
135
+ end
136
+ ```
137
+
138
+ ```
139
+ Passed as 'cart' in 'OrderCreationService#perform' at /Users/st0012/projects/tapping_device-demo/app/controllers/orders_controller.rb:10
140
+ Passed as 'cart' in 'OrderCreationService#validate_cart' at /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:8
141
+ Called :reserved_until FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:18
142
+ Called :errors FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:9
143
+ Passed as 'cart' in 'OrderCreationService#apply_discount' at /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:10
144
+ Called :apply_discount FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:24
145
+ ……
146
+ ```
147
+
148
+ ### print_calls_in_detail
149
+
150
+ It prints the object's calls in detail (including call location, arguments, and return value). It's useful for observing an object's behavior when debugging.
151
+
152
+ ```ruby
153
+ class OrdersController < ApplicationController
154
+ include TappingDevice::Trackable
155
+
156
+ def create
157
+ @cart = Cart.find(order_params[:cart_id])
158
+ service = OrderCreationService.new
159
+ print_calls_in_detail(service)
160
+ @order = service.perform(@cart)
161
+ end
162
+ ```
163
+
164
+ ```
165
+ :validate_cart # OrderCreationService
166
+ <= {:cart=>#<Cart id: 1, total: 10, customer_id: 1, promotion_id: nil, reserved_until: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">}
167
+ => nil
168
+ FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:8
169
+ :apply_discount # OrderCreationService
170
+ <= {:cart=>#<Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">, :promotion=>#<Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">}
171
+ => true
172
+ FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:10
173
+ :create_order # OrderCreationService
174
+ <= {:cart=>#<Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">}
175
+ => #<Order:0x00007f9ebcb17f08>
176
+ FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:11
177
+ :perform # OrderCreationService
178
+ <= {:cart=>#<Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">, :promotion=>#<Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">}
179
+ => #<Order:0x00007f9ebcb17f08>
180
+ FROM /Users/st0012/projects/tapping_device-demo/app/controllers/orders_controller.rb:11
181
+ ```
182
+
183
+ The output's order might look strange. This is because tapping_device needs to wait for the call to return in order to have its return value.
184
+
130
185
  ### tap_init!
131
186
 
132
187
  `tap_init!(class)` - tracks a class’ instance initialization
@@ -145,7 +200,7 @@ puts(calls.to_s) #=> [[:initialize, {:name=>"Stan", :age=>18}], [:initialize, {:
145
200
 
146
201
  ### tap_on!
147
202
 
148
- `tap_on!(object)` - tracks any calls received by the object
203
+ `tap_on!(object)` - tracks any calls received by the object.
149
204
 
150
205
  ```ruby
151
206
  class PostsController < ApplicationController
@@ -283,7 +338,7 @@ post.title #=> this call will be recorded as well
283
338
  ```
284
339
 
285
340
  #### 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.
341
+ It takes an array of call path patterns that we want to skip. This could be very helpful when working on a large project like Rails applications.
287
342
 
288
343
  ```ruby
289
344
  tap_on!(@post, exclude_by_paths: [/active_record/]).and_print(:method_name_and_location)
@@ -305,19 +360,19 @@ to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/r
305
360
 
306
361
  #### filter_by_paths
307
362
 
308
- Like `exclude_by_paths`, but work in an opposite way.
363
+ Like `exclude_by_paths`, but work in the opposite way.
309
364
 
310
365
 
311
366
  ### 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
367
+ All tapping methods (start with `tap_`) takes a block and yield a `Payload` object as a block argument. It responds to
313
368
 
314
369
  - `target` - the target for `tap_x` call
315
370
  - `receiver` - the receiver object
316
371
  - `method_name` - method’s name (symbol)
317
- - e.g. `:name`
318
- - `method_object` - the method object thats being called. It might be `nil` in some edge cases.
372
+ - e.g. `:name`
373
+ - `method_object` - the method object that's being called. It might be `nil` in some edge cases.
319
374
  - `arguments` - arguments of the method call
320
- - e.g. `{name: “Stan”, age: 25}`
375
+ - e.g. `{name: “Stan”, age: 25}`
321
376
  - `return_value` - return value of the method call
322
377
  - `filepath` - path to the file that performs the method call
323
378
  - `line_number`
@@ -344,7 +399,7 @@ Passed as 'object' in method ':initialize'
344
399
  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
400
  ```
346
401
 
347
- You can also set `passed_at(with_method_head: true)` to see the methods head
402
+ You can also set `passed_at(with_method_head: true)` to see the method's head.
348
403
 
349
404
  ```
350
405
  Passed as 'object' in method ':initialize'
@@ -363,14 +418,14 @@ initialize @ Student
363
418
 
364
419
  ### Advance Usages
365
420
 
366
- Tapping methods introduced above like `tap_on!` are designed for simple use cases. Theyre actually short for
421
+ Tapping methods introduced above like `tap_on!` are designed for simple use cases. They're actually short for
367
422
 
368
423
  ```ruby
369
424
  device = TappingDevice.new { # tapping action }
370
425
  device.tap_on!(object)
371
426
  ```
372
427
 
373
- And if you want to do some more configurations like stopping them manually or setting stop condition, you must have a `TappingDevie` instance. You can either get them like the above code, or save the return value of `tap_*!` method calls.
428
+ And if you want to do some more configurations like stopping them manually or setting stop condition, you must have a `TappingDevie` instance. You can either get them like the above code or save the return value of `tap_*!` method calls.
374
429
 
375
430
  #### Stop tapping
376
431
 
@@ -388,16 +443,16 @@ end
388
443
 
389
444
  Each `TappingDevice` instance can have 3 states:
390
445
 
391
- - `Initial` - means the instance is initialized but hasnt tapped on anything.
392
- - `Enabled` - means the instance are tapping on something (has called `tap_*` methods).
446
+ - `Initial` - means the instance is initialized but hasn't tapped on anything.
447
+ - `Enabled` - means the instance is tapping on something (has called `tap_*` methods).
393
448
  - `Disabled` - means the instance has been disabled. It will no longer receive any call info.
394
449
 
395
- When debugging, we may create many device instances and tap objects in several places. Then itll be quite annoying to manage their states. So `TappingDevice` has several class methods that allows you to manage all `TappingDevice` instances:
450
+ When debugging, we may create many device instances and tap objects in several places. Then it'll be quite annoying to manage their states. So `TappingDevice` has several class methods that allows you to manage all `TappingDevice` instances:
396
451
 
397
- - `TappingDevice.devices` - Lists all registered devices with `initial` or `enabled` state. Note that any instance thats been stopped will be removed from the list.
452
+ - `TappingDevice.devices` - Lists all registered devices with `initial` or `enabled` state. Note that any instance that's been stopped will be removed from the list.
398
453
  - `TappingDevice.stop_all!` - Stops all registered devices and remove them from the `devices` list.
399
- - `TappingDevice.suspend_new!` - Suspends any device instance from changing their state from `initatial` to `enabled`. Which means any `tap_*` calls after it will no longer work.
400
- - `TappingDevice.reset!` - Cancels `suspend_new` (if called) and stops/removes all created devices. Useful to reset environment between test cases.
454
+ - `TappingDevice.suspend_new!` - Suspends any device instance from changing their state from `initial` to `enabled`. Which means any `tap_*` calls after it will no longer work.
455
+ - `TappingDevice.reset!` - Cancels `suspend_new` (if called) and stops/removes all created devices. Useful to reset the environment between test cases.
401
456
 
402
457
  ## Development
403
458
 
@@ -411,8 +466,8 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/st0012
411
466
 
412
467
  ## License
413
468
 
414
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
469
+ The gem is available as open-source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
415
470
 
416
471
  ## Code of Conduct
417
472
 
418
- Everyone interacting in the TappingDevice projects codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/tapping_device/blob/master/CODE_OF_CONDUCT.md).
473
+ Everyone interacting in the TappingDevice project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/tapping_device/blob/master/CODE_OF_CONDUCT.md).
@@ -42,12 +42,12 @@ class TappingDevice
42
42
  sql: "QUERIES",
43
43
  return_value: "=>",
44
44
  arguments: "<=",
45
- defined_class: "@"
45
+ defined_class: "#"
46
46
  }
47
47
 
48
48
  SYMBOLS.each do |name, symbol|
49
49
  define_method "method_name_and_#{name}" do
50
- "#{method_name} #{symbol} #{send(name)}"
50
+ ":#{method_name} #{symbol} #{send(name)}"
51
51
  end
52
52
  end
53
53
 
@@ -6,6 +6,24 @@ class TappingDevice
6
6
  end
7
7
  end
8
8
 
9
+ def print_traces(target, options = {})
10
+ options[:event_type] = :call
11
+
12
+ device_1 = tap_on!(target, options) do |payload|
13
+ puts("Called #{payload.method_name_and_location}")
14
+ end
15
+ device_2 = tap_passed!(target, options) do |payload|
16
+ arg_name = payload.arguments.keys.detect { |k| payload.arguments[k] == target }
17
+ next unless arg_name
18
+ puts("Passed as '#{arg_name}' in '#{payload.defined_class}##{payload.method_name}' at #{payload.location}")
19
+ end
20
+ [device_1, device_2]
21
+ end
22
+
23
+ def print_calls_in_detail(target, options = {})
24
+ tap_on!(target, options).and_print(:detail_call_info)
25
+ end
26
+
9
27
  def new_device(options, &block)
10
28
  TappingDevice.new(options, &block)
11
29
  end
@@ -1,3 +1,3 @@
1
1
  class TappingDevice
2
- VERSION = "0.4.7"
2
+ VERSION = "0.4.8"
3
3
  end
@@ -83,7 +83,7 @@ class TappingDevice
83
83
 
84
84
  def track(object, condition:)
85
85
  @target = object
86
- @trace_point = TracePoint.new(:return) do |tp|
86
+ @trace_point = TracePoint.new(options[:event_type]) do |tp|
87
87
  if send(condition, object, tp)
88
88
  filepath, line_number = get_call_location(tp)
89
89
 
@@ -209,6 +209,7 @@ class TappingDevice
209
209
  options[:exclude_by_paths] ||= []
210
210
  options[:with_trace_to] ||= 50
211
211
  options[:root_device] ||= self
212
+ options[:event_type] ||= :return
212
213
  options[:descendants] ||= []
213
214
  options[:track_as_records] ||= false
214
215
  options
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.7
4
+ version: 0.4.8
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-29 00:00:00.000000000 Z
11
+ date: 2020-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord