tapping_device 0.4.7 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
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