tapping_device 0.4.9 → 0.4.10

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: 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