tapping_device 0.3.0 → 0.4.0
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 +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/Gemfile.lock +13 -11
- data/README.md +83 -2
- data/lib/tapping_device/sql_listener.rb +10 -0
- data/lib/tapping_device/sql_tapping_methods.rb +67 -0
- data/lib/tapping_device/trackable.rb +11 -3
- data/lib/tapping_device/version.rb +1 -1
- data/lib/tapping_device.rb +97 -36
- data/tapping_device.gemspec +4 -4
- metadata +22 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86f08b96d9d7d45cc1f0292a69749e5e5d853167e54a1981a26ec2b3905e31bd
|
4
|
+
data.tar.gz: 50a7e86833462d2392150182abb75d37bde739b04f582a56dc9438f26f34cbc9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3620752c8c95e09ebd81891f73ed5d30f2ff0d6b09aba90f0c34267936d7cd01e517beef6ea61aa5648124ba6d84c221ed0a42ae21a035bf12a7eb4bbdb4cf7e
|
7
|
+
data.tar.gz: 2fc5bd412fbab8e6cb33c28b12b89c7a403b4f481844bcca096838119887e3321fef37d21ad3374ac88c26b0c93efc56b59691000f8d62b067c8acf690e69075
|
data/.github/workflows/ruby.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -2,25 +2,25 @@ PATH
|
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
4
|
tapping_device (0.3.0)
|
5
|
-
activerecord (
|
5
|
+
activerecord (>= 5.2)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (
|
11
|
-
activesupport (=
|
12
|
-
activerecord (
|
13
|
-
activemodel (=
|
14
|
-
activesupport (=
|
15
|
-
|
16
|
-
activesupport (5.2.3)
|
10
|
+
activemodel (6.0.1)
|
11
|
+
activesupport (= 6.0.1)
|
12
|
+
activerecord (6.0.1)
|
13
|
+
activemodel (= 6.0.1)
|
14
|
+
activesupport (= 6.0.1)
|
15
|
+
activesupport (6.0.1)
|
17
16
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
18
17
|
i18n (>= 0.7, < 2)
|
19
18
|
minitest (~> 5.1)
|
20
19
|
tzinfo (~> 1.1)
|
21
|
-
|
20
|
+
zeitwerk (~> 2.2)
|
22
21
|
coderay (1.1.2)
|
23
22
|
concurrent-ruby (1.1.5)
|
23
|
+
database_cleaner (1.7.0)
|
24
24
|
diff-lcs (1.3)
|
25
25
|
i18n (1.7.0)
|
26
26
|
concurrent-ruby (~> 1.0)
|
@@ -43,20 +43,22 @@ GEM
|
|
43
43
|
diff-lcs (>= 1.2.0, < 2.0)
|
44
44
|
rspec-support (~> 3.8.0)
|
45
45
|
rspec-support (3.8.2)
|
46
|
-
sqlite3 (1.
|
46
|
+
sqlite3 (1.4.1)
|
47
47
|
thread_safe (0.3.6)
|
48
48
|
tzinfo (1.2.5)
|
49
49
|
thread_safe (~> 0.1)
|
50
|
+
zeitwerk (2.2.1)
|
50
51
|
|
51
52
|
PLATFORMS
|
52
53
|
ruby
|
53
54
|
|
54
55
|
DEPENDENCIES
|
55
56
|
bundler (~> 2.0)
|
57
|
+
database_cleaner
|
56
58
|
pry
|
57
59
|
rake (~> 10.0)
|
58
60
|
rspec (~> 3.0)
|
59
|
-
sqlite3 (
|
61
|
+
sqlite3 (>= 1.3.6)
|
60
62
|
tapping_device!
|
61
63
|
|
62
64
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|

|
4
4
|
|
5
|
-
|
5
|
+
**Please use 0.3.0+ versions, older versions have serious performance issues**
|
6
|
+
|
7
|
+
`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:
|
8
|
+
|
9
|
+
### Track method calls
|
6
10
|
|
7
11
|
```ruby
|
8
12
|
class PostsController < ApplicationController
|
@@ -25,6 +29,9 @@ Method: user_id line: /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
|
25
29
|
Method: to_param line: /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
26
30
|
```
|
27
31
|
|
32
|
+
|
33
|
+
### Track ActiveRecord records’ association calls
|
34
|
+
|
28
35
|
Or you can use `tap_assoc!`. This is very useful for tracking potential n+1 query calls, here’s a sample from my work
|
29
36
|
|
30
37
|
```ruby
|
@@ -41,8 +48,46 @@ Assoc: amending_orders line: /MY_PROJECT/app/models/order.rb:385
|
|
41
48
|
Assoc: amends_order line: /MY_PROJECT/app/models/order.rb:432
|
42
49
|
```
|
43
50
|
|
44
|
-
However, depending on the size of your application, tapping any object could **harm the performance significantly**. **Don’t use this on production**
|
45
51
|
|
52
|
+
### Track calls that generates sql queries! (Beta)
|
53
|
+
|
54
|
+
`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.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
class PostsController < ApplicationController
|
58
|
+
def index
|
59
|
+
# simulate current_user
|
60
|
+
@current_user = User.last
|
61
|
+
# reusable ActiveRecord::Relation
|
62
|
+
@posts = Post.all
|
63
|
+
|
64
|
+
tap_sql!(@posts) do |payload|
|
65
|
+
puts("Method: #{payload[:method_name]} generated sql: #{payload[:sql]} from #{payload[:filepath]}:#{payload[:line_number]}")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
```erb
|
72
|
+
<h1>Posts (<%= @posts.count %>)</h1>
|
73
|
+
......
|
74
|
+
<% @posts.each do |post| %>
|
75
|
+
......
|
76
|
+
<% end %>
|
77
|
+
......
|
78
|
+
<p>Posts created by you: <%= @posts.where(user: @current_user).count %></p>
|
79
|
+
```
|
80
|
+
|
81
|
+
And the output would be
|
82
|
+
|
83
|
+
```
|
84
|
+
Method: count generated sql: SELECT COUNT(*) FROM "posts" from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:3
|
85
|
+
Method: each generated sql: SELECT "posts".* FROM "posts" from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:16
|
86
|
+
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
|
87
|
+
```
|
88
|
+
|
89
|
+
|
90
|
+
However, depending on the size of your application, tapping any object could **harm the performance significantly**. **Don’t use this on production**
|
46
91
|
|
47
92
|
## Installation
|
48
93
|
|
@@ -71,6 +116,7 @@ In order to use `tapping_device`, you need to include `TappingDevice::Trackable`
|
|
71
116
|
- `tap_init!(class)` - tracks a class’ instance initialization
|
72
117
|
- `tap_on!(object)` - tracks any calls received by the object
|
73
118
|
- `tap_assoc!(activerecord_object)` - tracks association calls on a record, like `post.comments`
|
119
|
+
- `tap_sql!(activerecord_relation_or_model)` - tracks sql queries generated from the target
|
74
120
|
|
75
121
|
### Info of the call
|
76
122
|
All tapping methods (start with `tap_`) takes a block and yield a hash as block argument.
|
@@ -184,6 +230,41 @@ Assoc: amending_orders line: /MY_PROJECT/app/models/order.rb:385
|
|
184
230
|
Assoc: amends_order line: /MY_PROJECT/app/models/order.rb:432
|
185
231
|
```
|
186
232
|
|
233
|
+
### `tap_sql!` (beta)
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
class PostsController < ApplicationController
|
237
|
+
def index
|
238
|
+
# simulate current_user
|
239
|
+
@current_user = User.last
|
240
|
+
# reusable ActiveRecord::Relation
|
241
|
+
@posts = Post.all
|
242
|
+
|
243
|
+
tap_sql!(@posts) do |payload|
|
244
|
+
puts("Method: #{payload[:method_name]} generated sql: #{payload[:sql]} from #{payload[:filepath]}:#{payload[:line_number]}")
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
```
|
249
|
+
|
250
|
+
```erb
|
251
|
+
<h1>Posts (<%= @posts.count %>)</h1>
|
252
|
+
......
|
253
|
+
<% @posts.each do |post| %>
|
254
|
+
......
|
255
|
+
<% end %>
|
256
|
+
......
|
257
|
+
<p>Posts created by you: <%= @posts.where(user: @current_user).count %></p>
|
258
|
+
```
|
259
|
+
|
260
|
+
```
|
261
|
+
Method: count generated sql: SELECT COUNT(*) FROM "posts" from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:3
|
262
|
+
Method: each generated sql: SELECT "posts".* FROM "posts" from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:16
|
263
|
+
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
|
264
|
+
```
|
265
|
+
|
266
|
+
|
267
|
+
|
187
268
|
### Advance Usages
|
188
269
|
|
189
270
|
Tapping methods introduced above like `tap_on!` are designed for simple use cases. They’re actually short for
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "tapping_device/sql_listener"
|
2
|
+
|
3
|
+
class TappingDevice
|
4
|
+
module SqlTappingMethods
|
5
|
+
@@sql_listeners = []
|
6
|
+
|
7
|
+
ActiveSupport::Notifications.subscribe('sql.active_record') do |_1, _2, _3, _4, payload|
|
8
|
+
if !["SCHEMA", "TRANSACTION"].include? payload[:name]
|
9
|
+
@@sql_listeners.each do |listener|
|
10
|
+
listener.payload[:sql] = payload[:sql]
|
11
|
+
listener.payload[:binds] = payload[:binds]
|
12
|
+
listener.device.record_call!(listener.payload)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def tap_sql!(object)
|
18
|
+
@trace_point = TracePoint.new(:call, :b_call, :c_call) do |start_tp|
|
19
|
+
method = start_tp.callee_id
|
20
|
+
|
21
|
+
if is_from_target?(object, start_tp)
|
22
|
+
filepath, line_number = get_call_location(start_tp)
|
23
|
+
|
24
|
+
next if should_be_skip_by_paths?(filepath)
|
25
|
+
|
26
|
+
yield_parameters = build_yield_parameters(tp: start_tp, filepath: filepath, line_number: line_number)
|
27
|
+
|
28
|
+
# usually, AR's query methods (like `first`) will end up calling `find_by_sql`
|
29
|
+
# then to TappingDevice, both `first` and `find_by_sql` generates the sql
|
30
|
+
# but the results are duplicated, we should only consider the `first` call
|
31
|
+
# so @in_call is used to determine if we're already in a middle of a call
|
32
|
+
# it's not an optimal solution and should be updated
|
33
|
+
next if @in_call
|
34
|
+
|
35
|
+
@in_call = true
|
36
|
+
|
37
|
+
sql_listener = SqlListenser.new(method, yield_parameters, self)
|
38
|
+
|
39
|
+
@@sql_listeners << sql_listener
|
40
|
+
|
41
|
+
# return of the method call
|
42
|
+
TracePoint.trace(:return) do |return_tp|
|
43
|
+
if is_from_target?(object, return_tp)
|
44
|
+
# if it's a query method, end the sql tapping
|
45
|
+
if return_tp.callee_id == method
|
46
|
+
# if the method creates another Relation object
|
47
|
+
if return_tp.defined_class == ActiveRecord::QueryMethods
|
48
|
+
create_child_device.tap_sql!(return_tp.return_value)
|
49
|
+
end
|
50
|
+
|
51
|
+
@@sql_listeners.delete(sql_listener)
|
52
|
+
return_tp.disable
|
53
|
+
@in_call = false
|
54
|
+
|
55
|
+
stop_if_condition_fulfilled(yield_parameters)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
@trace_point.enable unless self.class.suspend_new
|
63
|
+
|
64
|
+
self
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,15 +1,23 @@
|
|
1
1
|
class TappingDevice
|
2
2
|
module Trackable
|
3
3
|
def tap_init!(klass, options = {}, &block)
|
4
|
-
|
4
|
+
new_device(options, &block).tap_init!(klass)
|
5
5
|
end
|
6
6
|
|
7
7
|
def tap_assoc!(record, options = {}, &block)
|
8
|
-
|
8
|
+
new_device(options, &block).tap_assoc!(record)
|
9
9
|
end
|
10
10
|
|
11
11
|
def tap_on!(object, options = {}, &block)
|
12
|
-
|
12
|
+
new_device(options, &block).tap_on!(object)
|
13
|
+
end
|
14
|
+
|
15
|
+
def tap_sql!(object, options = {}, &block)
|
16
|
+
new_device(options, &block).tap_sql!(object)
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_device(options, &block)
|
20
|
+
TappingDevice.new(options, &block)
|
13
21
|
end
|
14
22
|
end
|
15
23
|
end
|
data/lib/tapping_device.rb
CHANGED
@@ -2,15 +2,24 @@ require "active_record"
|
|
2
2
|
require "tapping_device/version"
|
3
3
|
require "tapping_device/trackable"
|
4
4
|
require "tapping_device/exceptions"
|
5
|
+
require "tapping_device/sql_tapping_methods"
|
5
6
|
|
6
7
|
class TappingDevice
|
7
|
-
|
8
|
+
|
9
|
+
CALLER_START_POINT = 3
|
10
|
+
C_CALLER_START_POINT = 2
|
8
11
|
|
9
12
|
attr_reader :options, :calls, :trace_point
|
10
13
|
|
11
14
|
@@devices = []
|
12
15
|
@@suspend_new = false
|
13
16
|
|
17
|
+
include SqlTappingMethods
|
18
|
+
|
19
|
+
def self.suspend_new
|
20
|
+
@@suspend_new
|
21
|
+
end
|
22
|
+
|
14
23
|
# list all registered devices
|
15
24
|
def self.devices
|
16
25
|
@@devices
|
@@ -41,23 +50,24 @@ class TappingDevice
|
|
41
50
|
|
42
51
|
def initialize(options = {}, &block)
|
43
52
|
@block = block
|
44
|
-
@options = options
|
53
|
+
@options = process_options(options)
|
45
54
|
@calls = []
|
55
|
+
@disabled = false
|
46
56
|
self.class.devices << self
|
47
57
|
end
|
48
58
|
|
49
59
|
def tap_init!(klass)
|
50
60
|
raise "argument should be a class, got #{klass}" unless klass.is_a?(Class)
|
51
|
-
track(klass, condition: :tap_init
|
61
|
+
track(klass, condition: :tap_init?)
|
52
62
|
end
|
53
63
|
|
54
64
|
def tap_on!(object)
|
55
|
-
track(object, condition: :tap_on
|
65
|
+
track(object, condition: :tap_on?)
|
56
66
|
end
|
57
67
|
|
58
68
|
def tap_assoc!(record)
|
59
69
|
raise "argument should be an instance of ActiveRecord::Base" unless record.is_a?(ActiveRecord::Base)
|
60
|
-
track(record, condition: :tap_associations
|
70
|
+
track(record, condition: :tap_associations?)
|
61
71
|
end
|
62
72
|
|
63
73
|
def set_block(&block)
|
@@ -65,6 +75,7 @@ class TappingDevice
|
|
65
75
|
end
|
66
76
|
|
67
77
|
def stop!
|
78
|
+
@disabled = true
|
68
79
|
self.class.delete_device(self)
|
69
80
|
end
|
70
81
|
|
@@ -72,9 +83,34 @@ class TappingDevice
|
|
72
83
|
@stop_when = block
|
73
84
|
end
|
74
85
|
|
86
|
+
def create_child_device
|
87
|
+
new_device = self.class.new(@options.merge(root_device: root_device), &@block)
|
88
|
+
new_device.stop_when(&@stop_when)
|
89
|
+
self.descendants << new_device
|
90
|
+
new_device
|
91
|
+
end
|
92
|
+
|
93
|
+
def root_device
|
94
|
+
options[:root_device]
|
95
|
+
end
|
96
|
+
|
97
|
+
def descendants
|
98
|
+
options[:descendants]
|
99
|
+
end
|
100
|
+
|
101
|
+
def record_call!(yield_parameters)
|
102
|
+
return if @disabled
|
103
|
+
|
104
|
+
if @block
|
105
|
+
root_device.calls << @block.call(yield_parameters)
|
106
|
+
else
|
107
|
+
root_device.calls << yield_parameters
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
75
111
|
private
|
76
112
|
|
77
|
-
def track(object, condition
|
113
|
+
def track(object, condition:)
|
78
114
|
@trace_point = TracePoint.new(:return) do |tp|
|
79
115
|
validation_params = {
|
80
116
|
receiver: tp.self,
|
@@ -82,39 +118,16 @@ class TappingDevice
|
|
82
118
|
}
|
83
119
|
|
84
120
|
if send(condition, object, validation_params)
|
121
|
+
filepath, line_number = get_call_location(tp)
|
85
122
|
|
86
|
-
|
87
|
-
|
88
|
-
# this needs to be placed upfront so we can exclude noise before doing more work
|
89
|
-
next if exclude_by_paths.any? { |pattern| pattern.match?(filepath) }
|
90
|
-
|
91
|
-
if filter_by_paths
|
92
|
-
next unless filter_by_paths.any? { |pattern| pattern.match?(filepath) }
|
93
|
-
end
|
123
|
+
next if should_be_skip_by_paths?(filepath)
|
94
124
|
|
95
|
-
|
125
|
+
yield_parameters = build_yield_parameters(tp: tp, filepath: filepath, line_number: line_number)
|
96
126
|
|
97
|
-
|
98
|
-
receiver: tp.self,
|
99
|
-
method_name: tp.callee_id,
|
100
|
-
arguments: arguments,
|
101
|
-
return_value: (tp.return_value rescue nil),
|
102
|
-
filepath: filepath,
|
103
|
-
line_number: line_number,
|
104
|
-
defined_class: tp.defined_class,
|
105
|
-
trace: [],
|
106
|
-
tp: tp
|
107
|
-
}
|
127
|
+
record_call!(yield_parameters)
|
108
128
|
|
109
|
-
|
110
|
-
if @block
|
111
|
-
@calls << block.call(yield_parameters)
|
112
|
-
else
|
113
|
-
@calls << yield_parameters
|
114
|
-
end
|
129
|
+
stop_if_condition_fulfilled(yield_parameters)
|
115
130
|
end
|
116
|
-
|
117
|
-
stop! if @stop_when&.call(yield_parameters)
|
118
131
|
end
|
119
132
|
|
120
133
|
@trace_point.enable unless @@suspend_new
|
@@ -122,7 +135,35 @@ class TappingDevice
|
|
122
135
|
self
|
123
136
|
end
|
124
137
|
|
125
|
-
|
138
|
+
def get_call_location(tp)
|
139
|
+
if tp.event == :c_call
|
140
|
+
caller(C_CALLER_START_POINT)
|
141
|
+
else
|
142
|
+
caller(CALLER_START_POINT)
|
143
|
+
end.first.split(":")[0..1]
|
144
|
+
end
|
145
|
+
|
146
|
+
# this needs to be placed upfront so we can exclude noise before doing more work
|
147
|
+
def should_be_skip_by_paths?(filepath)
|
148
|
+
options[:exclude_by_paths].any? { |pattern| pattern.match?(filepath) } ||
|
149
|
+
(options[:filter_by_paths].present? && !options[:filter_by_paths].any? { |pattern| pattern.match?(filepath) })
|
150
|
+
end
|
151
|
+
|
152
|
+
def build_yield_parameters(tp:, filepath:, line_number:)
|
153
|
+
arguments = tp.binding.local_variables.map { |n| [n, tp.binding.local_variable_get(n)] }
|
154
|
+
|
155
|
+
{
|
156
|
+
receiver: tp.self,
|
157
|
+
method_name: tp.callee_id,
|
158
|
+
arguments: arguments,
|
159
|
+
return_value: (tp.return_value rescue nil),
|
160
|
+
filepath: filepath,
|
161
|
+
line_number: line_number,
|
162
|
+
defined_class: tp.defined_class,
|
163
|
+
trace: caller[CALLER_START_POINT..(CALLER_START_POINT + options[:with_trace_to])],
|
164
|
+
tp: tp
|
165
|
+
}
|
166
|
+
end
|
126
167
|
|
127
168
|
def tap_init?(klass, parameters)
|
128
169
|
receiver = parameters[:receiver]
|
@@ -136,7 +177,7 @@ class TappingDevice
|
|
136
177
|
end
|
137
178
|
|
138
179
|
def tap_on?(object, parameters)
|
139
|
-
parameters[:receiver].
|
180
|
+
parameters[:receiver].__id__ == object.__id__
|
140
181
|
end
|
141
182
|
|
142
183
|
def tap_associations?(object, parameters)
|
@@ -146,4 +187,24 @@ class TappingDevice
|
|
146
187
|
associations = model_class.reflections
|
147
188
|
associations.keys.include?(parameters[:method_name].to_s)
|
148
189
|
end
|
190
|
+
|
191
|
+
def process_options(options)
|
192
|
+
options[:filter_by_paths] ||= []
|
193
|
+
options[:exclude_by_paths] ||= []
|
194
|
+
options[:with_trace_to] ||= 50
|
195
|
+
options[:root_device] ||= self
|
196
|
+
options[:descendants] ||= []
|
197
|
+
options
|
198
|
+
end
|
199
|
+
|
200
|
+
def stop_if_condition_fulfilled(yield_parameters)
|
201
|
+
if @stop_when&.call(yield_parameters)
|
202
|
+
stop!
|
203
|
+
root_device.stop!
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def is_from_target?(object, tp)
|
208
|
+
object.__id__ == tp.self.__id__
|
209
|
+
end
|
149
210
|
end
|
data/tapping_device.gemspec
CHANGED
@@ -26,14 +26,14 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ["lib"]
|
28
28
|
|
29
|
-
if ENV["RAILS_VERSION"]
|
29
|
+
if ENV["RAILS_VERSION"]
|
30
30
|
spec.add_dependency "activerecord", "~> #{ENV["RAILS_VERSION"]}"
|
31
|
-
spec.add_development_dependency "sqlite3", "~> 1.4.1"
|
32
31
|
else
|
33
|
-
spec.add_dependency "activerecord", "
|
34
|
-
spec.add_development_dependency "sqlite3", "~> 1.3.6"
|
32
|
+
spec.add_dependency "activerecord", ">= 5.2"
|
35
33
|
end
|
36
34
|
|
35
|
+
spec.add_development_dependency "sqlite3", ">= 1.3.6"
|
36
|
+
spec.add_development_dependency "database_cleaner"
|
37
37
|
spec.add_development_dependency "bundler", "~> 2.0"
|
38
38
|
spec.add_development_dependency "pry"
|
39
39
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tapping_device
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- st0012
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-11-
|
11
|
+
date: 2019-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: sqlite3
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 1.3.6
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 1.3.6
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: database_cleaner
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,6 +130,8 @@ files:
|
|
116
130
|
- bin/setup
|
117
131
|
- lib/tapping_device.rb
|
118
132
|
- lib/tapping_device/exceptions.rb
|
133
|
+
- lib/tapping_device/sql_listener.rb
|
134
|
+
- lib/tapping_device/sql_tapping_methods.rb
|
119
135
|
- lib/tapping_device/trackable.rb
|
120
136
|
- lib/tapping_device/version.rb
|
121
137
|
- tapping_device.gemspec
|