tapping_device 0.5.0 → 0.5.1

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: 9806974025c4e1ba9042bf2df5a4b4211a7e4a9630b291e05892d472e54263cc
4
- data.tar.gz: fc609ed5be23cac4943e90c34d7126aaffd53816910320f7300d2a33a9d40585
3
+ metadata.gz: 1b44a9cf6d9eb0e17b965c87b38f5c431058c283c2a6b79dcce1d2b88aafcc5e
4
+ data.tar.gz: 6afad055a9606958c47534cfa68394bc859c465300ac2c3f9959335edc0b7f4d
5
5
  SHA512:
6
- metadata.gz: 15ee39e171f665492e47c378bcffedd3d7bc1c8204269607e54c1ac174f44fe5ee4cc33a0ffcd82d4b732abc63def63eefb8b1fda386d4e40503a4bd959e71e2
7
- data.tar.gz: 3b4bb1b05949fd4735fde568995e8c92c64634ad39f196f76649e2f401834d8fdc605080546655f90920e8c2cfc1cebb4bf686b7da34494217c677e058f6c73b
6
+ metadata.gz: e36715dc9d885af5b143ace2b5c3af6ff782e49d371e4b24787ac475f58d140abbad1a9730769722a59c2e06240a3a72930d9588f488595eaa6dc75973a17a31
7
+ data.tar.gz: e3bd4a46af607281dc82e6bb4e3f57ad54f600d99a25892d7914c4e5577dcf8a3dc212d60449e9ced5b1789680eead0f79f3758ef6b06c25b1b7647f52e2282e
@@ -33,10 +33,17 @@ jobs:
33
33
  gem install bundler
34
34
  bundle install --jobs 4 --retry 3
35
35
 
36
- - name: Run test with Rails ${{ matrix.rails_version }} and publish result
37
- uses: paambaati/codeclimate-action@v2.3.0
36
+ - name: Run test with Rails ${{ matrix.rails_version }}
37
+ run: bundle exec rake
38
+
39
+ - name: Publish Test Coverage
40
+ uses: paambaati/codeclimate-action@v2.6.0
38
41
  env:
39
- CC_TEST_REPORTER_ID: ${{secrets.CC_TEST_REPORTER_ID}}
42
+ CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
43
+ if: ${{ env.CC_TEST_REPORTER_ID != '' }}
40
44
  with:
41
- coverageCommand: bundle exec rake
45
+ # the coverage result should already be generated by the previous step
46
+ # so we don't need to provide and command in the step
47
+ # this is just a placeholder to avoid it run the default `yarn coverage` command
48
+ coverageCommand: ruby -v
42
49
  debug: true
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tapping_device (0.5.0)
4
+ tapping_device (0.5.1)
5
5
  activerecord (>= 5.2)
6
6
 
7
7
  GEM
@@ -23,7 +23,7 @@ GEM
23
23
  database_cleaner (1.7.0)
24
24
  diff-lcs (1.3)
25
25
  docile (1.3.2)
26
- i18n (1.8.2)
26
+ i18n (1.8.3)
27
27
  concurrent-ruby (~> 1.0)
28
28
  json (2.3.0)
29
29
  method_source (0.9.2)
data/README.md CHANGED
@@ -21,7 +21,7 @@ Still sounds vague? Let's see some examples:
21
21
 
22
22
  ### `print_calls` To Track Method Calls
23
23
 
24
- In [Discourse](https://github.com/discourse/discourse), it uses the `Guardian` class for authorization (like policy objects). It's barely visible in controller actions, but it does many checks under the hood. Now, let's say we want to know what the `Guadian` would do when a user creates a post; here's the controller action:
24
+ In [Discourse](https://github.com/discourse/discourse), it uses the `Guardian` class for authorization (like policy objects). It's barely visible in controller actions, but it does many checks under the hood. Now, let's say we want to know what the `Guardian` would do when a user creates a post; here's the controller action:
25
25
 
26
26
  ```ruby
27
27
  def create
@@ -5,7 +5,6 @@ require "tapping_device/payload"
5
5
  require "tapping_device/output_payload"
6
6
  require "tapping_device/trackable"
7
7
  require "tapping_device/exceptions"
8
- require "tapping_device/sql_tapping_methods"
9
8
 
10
9
  class TappingDevice
11
10
 
@@ -17,7 +16,6 @@ class TappingDevice
17
16
  @devices = []
18
17
  @suspend_new = false
19
18
 
20
- include SqlTappingMethods
21
19
  extend Manageable
22
20
 
23
21
  def initialize(options = {}, &block)
@@ -111,6 +109,13 @@ class TappingDevice
111
109
 
112
110
  next unless with_condition_satisfied?(payload)
113
111
 
112
+ # skip TappingDevice related calls
113
+ if Module.respond_to?(:module_parents)
114
+ next if payload.defined_class.module_parents.include?(TappingDevice)
115
+ else
116
+ next if payload.defined_class.parents.include?(TappingDevice)
117
+ end
118
+
114
119
  record_call!(payload)
115
120
 
116
121
  stop_if_condition_fulfilled(payload)
@@ -1,6 +1,6 @@
1
1
  class TappingDevice
2
2
  module Trackable
3
- [:tap_on!, :tap_init!, :tap_assoc!, :tap_sql!, :tap_passed!].each do |method|
3
+ [:tap_on!, :tap_init!, :tap_assoc!, :tap_passed!].each do |method|
4
4
  define_method method do |object, options = {}, &block|
5
5
  new_device(options, &block).send(method, object)
6
6
  end
@@ -17,7 +17,7 @@ class TappingDevice
17
17
  device_2 = tap_passed!(target, options).and_print do |output_payload|
18
18
  output_payload.passed_at(inspect: inspect, colorize: colorize)
19
19
  end
20
- [device_1, device_2]
20
+ CollectionProxy.new([device_1, device_2])
21
21
  end
22
22
 
23
23
  def print_calls(target, options = {})
@@ -32,6 +32,20 @@ class TappingDevice
32
32
  def new_device(options, &block)
33
33
  TappingDevice.new(options, &block)
34
34
  end
35
+
36
+ class CollectionProxy
37
+ def initialize(devices)
38
+ @devices = devices
39
+ end
40
+
41
+ [:stop!, :stop_when, :with].each do |method|
42
+ define_method method do |&block|
43
+ @devices.each do |device|
44
+ device.send(method, &block)
45
+ end
46
+ end
47
+ end
48
+ end
35
49
  end
36
50
  end
37
51
 
@@ -1,3 +1,3 @@
1
1
  class TappingDevice
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
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.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - st0012
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-25 00:00:00.000000000 Z
11
+ date: 2020-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -153,7 +153,6 @@ files:
153
153
  - lib/tapping_device/manageable.rb
154
154
  - lib/tapping_device/output_payload.rb
155
155
  - lib/tapping_device/payload.rb
156
- - lib/tapping_device/sql_tapping_methods.rb
157
156
  - lib/tapping_device/trackable.rb
158
157
  - lib/tapping_device/version.rb
159
158
  - tapping_device.gemspec
@@ -1,89 +0,0 @@
1
- class TappingDevice
2
- module SqlTappingMethods
3
- CALL_STACK_SKIPPABLE_METHODS = [:transaction, :tap]
4
-
5
- # SQLListener acts like an interface for us to intercept activerecord query instrumentations
6
- # this means we only need to register one subscriber no matter how many objects we want to tap on
7
- class SQLListener
8
- def call(name, start, finish, message_id, values);end
9
- end
10
- @@sql_listener = SQLListener.new
11
-
12
- ActiveSupport::Notifications.subscribe("sql.active_record", @@sql_listener)
13
-
14
- def tap_sql!(object)
15
- @call_stack = []
16
- @target ||= object
17
- @trace_point = with_trace_point_on_target(object, event: [:call, :c_call]) do |start_tp|
18
- ########## Check if the call is worth recording ##########
19
- filepath, line_number = get_call_location(start_tp, padding: 1) # we need extra padding because of `with_trace_point_on_target`
20
- method = start_tp.callee_id
21
- next if already_recording?(method)
22
-
23
- ########## Start the recording ##########
24
- # 1. Mark recording state by pushing method into @call_stack
25
- # 2. Subscribe sql instrumentations generated by activerecord
26
- # 3. Record those sqls and run device callbacks
27
- # 4. Start waiting for current call's return callback
28
- @call_stack.push(method)
29
- payload = build_payload(tp: start_tp, filepath: filepath, line_number: line_number)
30
- device = tap_on_sql_instrumentation!(payload)
31
-
32
- with_trace_point_on_target(object, event: :return) do |return_tp|
33
- next unless return_tp.callee_id == method
34
-
35
- ########## End recording ##########
36
- # 1. Close itself
37
- # 2. Stop our subscription on SQLListener
38
- # 3. Remove current method from @call_stack
39
- # 4. Stop the device if stop condition is fulfilled
40
- return_tp.disable
41
- device.stop!
42
- @call_stack.pop
43
- stop_if_condition_fulfilled(payload)
44
-
45
- ########## Track descendant objects ##########
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
- end.enable
51
- end
52
-
53
- @trace_point.enable unless self.class.suspend_new
54
-
55
- self
56
- end
57
- end
58
-
59
- private
60
-
61
- def tap_on_sql_instrumentation!(payload)
62
- device = TappingDevice.new do |sql_listener_payload|
63
- values = sql_listener_payload.arguments[:values]
64
-
65
- next if should_be_skipped_by_paths?(payload.filepath) ||
66
- ["SCHEMA", "TRANSACTION"].include?(values[:name]) ||
67
- values[:sql].match?(/SAVEPOINT/)
68
-
69
- payload[:sql] = values[:sql]
70
- record_call!(payload)
71
- end
72
- device.tap_on!(@@sql_listener)
73
- end
74
-
75
- # usually, AR's query methods (like `first`) will end up calling `find_by_sql`
76
- # then to TappingDevice, both `first` and `find_by_sql` generates the sql
77
- # but the results are duplicated, we should only consider the `first` call
78
- def already_recording?(method)
79
- !@call_stack.empty? || CALL_STACK_SKIPPABLE_METHODS.include?(method)
80
- end
81
-
82
- def with_trace_point_on_target(object, event:)
83
- TracePoint.new(*event) do |tp|
84
- if is_from_target?(object, tp)
85
- yield(tp)
86
- end
87
- end
88
- end
89
- end