tapping_device 0.5.0 → 0.5.1

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