tapping_device 0.4.9 → 0.4.10

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: ac2d7b19e16c5c1f3f09d8d1abb81f8efe1238366a056457a804adf8c3ed5746
4
- data.tar.gz: d683824d3c9ba64dc968d11891b2d1a5522768dbea68e604a6ed4dc04bef7488
3
+ metadata.gz: 23d3086bd40ed2665b040147abdbd7ca9cf2fd6e8d0e4300e0dfe8c6c14def70
4
+ data.tar.gz: b980e4cbf079204151b81645aa9c097254c0be1f514c2e09482ee3a4ede1ec68
5
5
  SHA512:
6
- metadata.gz: bae37829ceac31871f11da1b9f2be3000572e65291229eb1208794e4214dc28bc55e4cc2dd44ec4a2dc1fd6cf01798509d860f132a6503b47368eadb544f172a
7
- data.tar.gz: 73053c155178b21ddb93627f227f7a50130684b29c95cf0c310aedd06bcbf3ab94529a79fd73451725b7180e93ffa9e64b9d3fd7dd8e2c5125a15c8ea1500d21
6
+ metadata.gz: 4d731a0cc9436e48354a55afe094cd16ce93778876fd541702813645be21e2d77cdfa0580b93486c0a59ddf48c614df9106d752483842da5bec2bb19ee06e97a
7
+ data.tar.gz: 1de7093fd6b474260a7b819ddffa8839dc26ff5e5553d450084515e9ce6b1d69cb97066c69fa49f48777548e18768dd52dc8114efc5a469e63e870f3005086c2
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6.5
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tapping_device (0.4.9)
4
+ tapping_device (0.4.10)
5
5
  activerecord (>= 5.2)
6
6
  awesome_print
7
7
 
data/README.md CHANGED
@@ -7,9 +7,11 @@
7
7
  [![Open Source Helpers](https://www.codetriage.com/st0012/tapping_device/badges/users.svg)](https://www.codetriage.com/st0012/tapping_device)
8
8
 
9
9
  ## Related Posts
10
+ - [Optimize Your Debugging Process With Object-Oriented Tracing and tapping_device](http://bit.ly/object-oriented-tracing)
10
11
  - [Debug Rails issues effectively with tapping_device](https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c)
11
12
  - [Want to know more about your Rails app? Tap on your objects!](https://dev.to/st0012/want-to-know-more-about-your-rails-app-tap-on-your-objects-bd3)
12
13
 
14
+
13
15
  ## Table of Content
14
16
  - [Introduction](#introduction)
15
17
  - [Print Object’s Traces](print-objects-traces)
@@ -30,7 +32,9 @@
30
32
  - [Advance Usages](#advance-usages)
31
33
 
32
34
  ## Introduction
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:
35
+ `tapping_device` is a debugging tool built based on a concept called `object-oriented tracing` and on top of Ruby's `TracePoint` class. It allows you to inspect an object’s behavior, and thus build the program’s execution path for later debugging. Here’s a post to explain how to use `object-oriented tracing` and this gem to improve your debugging workflow: [Optimize Your Debugging Process With Object-Oriented Tracing and tapping_device](http://bit.ly/object-oriented-tracing).
36
+
37
+ Sample usage:
34
38
 
35
39
  ### Print Object’s Traces
36
40
 
@@ -38,8 +42,6 @@ Let your objects report to you, so you don’t need to guess how they work!
38
42
 
39
43
  ```ruby
40
44
  class OrdersController < ApplicationController
41
- include TappingDevice::Trackable
42
-
43
45
  def create
44
46
  @cart = Cart.find(order_params[:cart_id])
45
47
  print_traces(@cart, exclude_by_paths: [/gems/])
@@ -59,42 +61,6 @@ Called :apply_discount FROM /Users/st0012/projects/tapping_device-demo/app/servi
59
61
 
60
62
  (Also see [print_calls_in_detail](#print_calls_in_detail))
61
63
 
62
- ### Track Calls that Generates SQL Queries
63
-
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.
65
-
66
- ```ruby
67
- class PostsController < ApplicationController
68
- def index
69
- # simulate current_user
70
- @current_user = User.last
71
- # reusable ActiveRecord::Relation
72
- @posts = Post.all
73
-
74
- tap_sql!(@posts) do |payload|
75
- puts("Method: #{payload[:method_name]} generated sql: #{payload[:sql]} from #{payload[:filepath]}:#{payload[:line_number]}")
76
- end
77
- end
78
- end
79
- ```
80
-
81
- ```erb
82
- <h1>Posts (<%= @posts.count %>)</h1>
83
- ......
84
- <% @posts.each do |post| %>
85
- ......
86
- <% end %>
87
- ......
88
- <p>Posts created by you: <%= @posts.where(user: @current_user).count %></p>
89
- ```
90
-
91
- And the output would be
92
-
93
- ```
94
- Method: count generated sql: SELECT COUNT(*) FROM "posts" from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:3
95
- Method: each generated sql: SELECT "posts".* FROM "posts" from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:16
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
97
- ```
98
64
 
99
65
  However, depending on the size of your application, tapping any object could **harm the performance significantly**. **Don't use this on production**
100
66
 
@@ -118,7 +84,6 @@ $ gem install tapping_device
118
84
  ```
119
85
 
120
86
  ## Usages
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.
122
87
 
123
88
  ### print_traces
124
89
 
@@ -126,8 +91,6 @@ It prints the object's trace. It's like mounting a GPS tracker + a spy camera on
126
91
 
127
92
  ```ruby
128
93
  class OrdersController < ApplicationController
129
- include TappingDevice::Trackable
130
-
131
94
  def create
132
95
  @cart = Cart.find(order_params[:cart_id])
133
96
  print_traces(@cart, exclude_by_paths: [/gems/])
@@ -154,8 +117,6 @@ It prints the object's calls in detail (including call location, arguments, and
154
117
 
155
118
  ```ruby
156
119
  class OrdersController < ApplicationController
157
- include TappingDevice::Trackable
158
-
159
120
  def create
160
121
  @cart = Cart.find(order_params[:cart_id])
161
122
  service = OrderCreationService.new
@@ -207,8 +168,6 @@ puts(calls.to_s) #=> [[:initialize, {:name=>"Stan", :age=>18}], [:initialize, {:
207
168
 
208
169
  ```ruby
209
170
  class PostsController < ApplicationController
210
- include TappingDevice::Trackable
211
-
212
171
  before_action :set_post, only: [:show, :edit, :update, :destroy]
213
172
 
214
173
  def show
@@ -233,7 +192,6 @@ Also check the `track_as_records` option if you want to track `ActiveRecord` rec
233
192
 
234
193
  ```ruby
235
194
  class PostsController < ApplicationController
236
- include TappingDevice::Trackable
237
195
  # GET /posts/new
238
196
  def new
239
197
  @post = Post.new
@@ -30,7 +30,10 @@ class TappingDevice
30
30
 
31
31
  def tap_init!(klass)
32
32
  raise "argument should be a class, got #{klass}" unless klass.is_a?(Class)
33
- track(klass, condition: :tap_init?)
33
+ track(klass, condition: :tap_init?) do |payload|
34
+ payload[:return_value] = payload[:receiver]
35
+ payload[:receiver] = klass
36
+ end
34
37
  end
35
38
 
36
39
  def tap_on!(object)
@@ -81,7 +84,7 @@ class TappingDevice
81
84
 
82
85
  private
83
86
 
84
- def track(object, condition:)
87
+ def track(object, condition:, &payload_block)
85
88
  @target = object
86
89
  @trace_point = TracePoint.new(options[:event_type]) do |tp|
87
90
  if send(condition, object, tp)
@@ -89,7 +92,7 @@ class TappingDevice
89
92
 
90
93
  next if should_be_skipped_by_paths?(filepath)
91
94
 
92
- payload = build_payload(tp: tp, filepath: filepath, line_number: line_number)
95
+ payload = build_payload(tp: tp, filepath: filepath, line_number: line_number, &payload_block)
93
96
 
94
97
  record_call!(payload)
95
98
 
@@ -130,15 +133,12 @@ class TappingDevice
130
133
  end
131
134
 
132
135
  def build_payload(tp:, filepath:, line_number:)
133
- arguments = {}
134
- tp.binding.local_variables.each { |name| arguments[name] = tp.binding.local_variable_get(name) }
135
-
136
- Payload.init({
136
+ payload = Payload.init({
137
137
  target: @target,
138
138
  receiver: tp.self,
139
139
  method_name: tp.callee_id,
140
140
  method_object: get_method_object_from(tp.self, tp.callee_id),
141
- arguments: arguments,
141
+ arguments: collect_arguments(tp),
142
142
  return_value: (tp.return_value rescue nil),
143
143
  filepath: filepath,
144
144
  line_number: line_number,
@@ -146,6 +146,10 @@ class TappingDevice
146
146
  trace: get_traces(tp),
147
147
  tp: tp
148
148
  })
149
+
150
+ yield(payload) if block_given?
151
+
152
+ payload
149
153
  end
150
154
 
151
155
  def tap_init?(klass, tp)
@@ -176,15 +180,7 @@ class TappingDevice
176
180
  return false if is_from_target?(self, tp)
177
181
  return false if tp.defined_class == TappingDevice::Trackable || tp.defined_class == TappingDevice
178
182
 
179
- method_object = get_method_object_from(tp.self, tp.callee_id)
180
- return false unless method_object.is_a?(Method)
181
- # if a no-arugment method is called, tp.binding.local_variables will be those local variables in the same scope
182
- # so we need to make sure the method takes arguments, then we can be sure that the locals are arguments
183
- return false unless method_object && method_object.arity.to_i > 0
184
-
185
- argument_values = tp.binding.local_variables.map { |name| tp.binding.local_variable_get(name) }
186
-
187
- argument_values.any? do |value|
183
+ collect_arguments(tp).values.any? do |value|
188
184
  # during comparison, Ruby might perform data type conversion like calling `to_sym` on the value
189
185
  # but not every value supports every conversion methods
190
186
  object == value rescue false
@@ -204,6 +200,19 @@ class TappingDevice
204
200
  nil
205
201
  end
206
202
 
203
+ def collect_arguments(tp)
204
+ parameters =
205
+ if RUBY_VERSION.to_f >= 2.6
206
+ tp.parameters
207
+ else
208
+ get_method_object_from(tp.self, tp.callee_id)&.parameters || []
209
+ end.map { |parameter| parameter[1] }
210
+
211
+ tp.binding.local_variables.each_with_object({}) do |name, args|
212
+ args[name] = tp.binding.local_variable_get(name) if parameters.include?(name)
213
+ end
214
+ end
215
+
207
216
  def process_options(options)
208
217
  options[:filter_by_paths] ||= []
209
218
  options[:exclude_by_paths] ||= []
@@ -66,6 +66,7 @@ class TappingDevice
66
66
  from: #{location}
67
67
  <= #{arguments_output}
68
68
  => #{return_value_output}
69
+
69
70
  MSG
70
71
  end
71
72
  end
@@ -33,3 +33,5 @@ class TappingDevice
33
33
  end
34
34
  end
35
35
  end
36
+
37
+ include TappingDevice::Trackable
@@ -1,3 +1,3 @@
1
1
  class TappingDevice
2
- VERSION = "0.4.9"
2
+ VERSION = "0.4.10"
3
3
  end
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.9
4
+ version: 0.4.10
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-20 00:00:00.000000000 Z
11
+ date: 2020-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -147,6 +147,7 @@ files:
147
147
  - ".github/workflows/ruby.yml"
148
148
  - ".gitignore"
149
149
  - ".rspec"
150
+ - ".ruby-version"
150
151
  - ".travis.yml"
151
152
  - CODE_OF_CONDUCT.md
152
153
  - Gemfile