tapping_device 0.4.11 → 0.5.4
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/.DS_Store +0 -0
- data/.github/workflows/ruby.yml +11 -4
- data/CHANGELOG.md +210 -0
- data/Gemfile.lock +18 -17
- data/README.md +182 -306
- data/images/print_calls - single entry.png +0 -0
- data/images/print_calls.png +0 -0
- data/images/print_mutations.png +0 -0
- data/images/print_traces.png +0 -0
- data/lib/tapping_device.rb +118 -115
- data/lib/tapping_device/configurable.rb +27 -0
- data/lib/tapping_device/exceptions.rb +12 -0
- data/lib/tapping_device/method_hijacker.rb +51 -0
- data/lib/tapping_device/output.rb +42 -0
- data/lib/tapping_device/output/file_writer.rb +21 -0
- data/lib/tapping_device/output/payload.rb +179 -0
- data/lib/tapping_device/output/stdout_writer.rb +9 -0
- data/lib/tapping_device/output/writer.rb +20 -0
- data/lib/tapping_device/payload.rb +4 -78
- data/lib/tapping_device/trackable.rb +114 -18
- data/lib/tapping_device/trackers/association_call_tracker.rb +17 -0
- data/lib/tapping_device/trackers/initialization_tracker.rb +35 -0
- data/lib/tapping_device/trackers/method_call_tracker.rb +9 -0
- data/lib/tapping_device/trackers/mutation_tracker.rb +112 -0
- data/lib/tapping_device/trackers/passed_tracker.rb +16 -0
- data/lib/tapping_device/version.rb +1 -1
- data/tapping_device.gemspec +5 -3
- metadata +50 -17
- data/lib/tapping_device/sql_tapping_methods.rb +0 -89
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 231efa59a44f630df303db52d0d3bb460698c02a116374838e4bad4d71d7f69e
|
|
4
|
+
data.tar.gz: ca80df8a0ea00350c1e074628425848b5cba4d7f53a7aa4176947d55a3164929
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 77131aab9e85a2661694ee57470b9067ee44d479d574cbe395eefabd7f88350eaf31071c4ed0d117b1608856e9e6beff9d7ccae592a665c8969231425dafdc43
|
|
7
|
+
data.tar.gz: c06dedd14da7798cf93d80ae0d4866928c9e2522184f453588691fdf1a3220b21cfdf953f04575f1015cc1cb58c5bcb2cb5673fd9384cf5515855d048d0bbdb3
|
data/.DS_Store
ADDED
|
Binary file
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -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 }}
|
|
37
|
-
|
|
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
|
-
|
|
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
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [v0.5.3](https://github.com/st0012/tapping_device/tree/v0.5.3) (2020-06-21)
|
|
4
|
+
|
|
5
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.5.2...v0.5.3)
|
|
6
|
+
|
|
7
|
+
**Closed issues:**
|
|
8
|
+
|
|
9
|
+
- Global Configuration [\#46](https://github.com/st0012/tapping_device/issues/46)
|
|
10
|
+
- Support write\_\* helpers [\#44](https://github.com/st0012/tapping_device/issues/44)
|
|
11
|
+
- Use Method\#source to replace Payload\#method\_head’s implementation [\#19](https://github.com/st0012/tapping_device/issues/19)
|
|
12
|
+
|
|
13
|
+
**Merged pull requests:**
|
|
14
|
+
|
|
15
|
+
- Support Global Configuration [\#48](https://github.com/st0012/tapping_device/pull/48) ([st0012](https://github.com/st0012))
|
|
16
|
+
- Support write\_\* helpers [\#47](https://github.com/st0012/tapping_device/pull/47) ([st0012](https://github.com/st0012))
|
|
17
|
+
- Hijack attr methods with `hijack\_attr\_methods` option [\#45](https://github.com/st0012/tapping_device/pull/45) ([st0012](https://github.com/st0012))
|
|
18
|
+
|
|
19
|
+
## [v0.5.2](https://github.com/st0012/tapping_device/tree/v0.5.2) (2020-06-10)
|
|
20
|
+
|
|
21
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.5.1...v0.5.2)
|
|
22
|
+
|
|
23
|
+
**Closed issues:**
|
|
24
|
+
|
|
25
|
+
- Add print\_mutations [\#41](https://github.com/st0012/tapping_device/issues/41)
|
|
26
|
+
- Add tap\_on\_mutation! [\#18](https://github.com/st0012/tapping_device/issues/18)
|
|
27
|
+
|
|
28
|
+
**Merged pull requests:**
|
|
29
|
+
|
|
30
|
+
- Print mutations [\#43](https://github.com/st0012/tapping_device/pull/43) ([st0012](https://github.com/st0012))
|
|
31
|
+
- Refactorings [\#42](https://github.com/st0012/tapping_device/pull/42) ([st0012](https://github.com/st0012))
|
|
32
|
+
|
|
33
|
+
## [v0.5.1](https://github.com/st0012/tapping_device/tree/v0.5.1) (2020-06-07)
|
|
34
|
+
|
|
35
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.5.0...v0.5.1)
|
|
36
|
+
|
|
37
|
+
**Fixed bugs:**
|
|
38
|
+
|
|
39
|
+
- Filter Out Entries From TappingDevice [\#35](https://github.com/st0012/tapping_device/issues/35)
|
|
40
|
+
|
|
41
|
+
**Merged pull requests:**
|
|
42
|
+
|
|
43
|
+
- Update GitHub Actions Configuration [\#40](https://github.com/st0012/tapping_device/pull/40) ([st0012](https://github.com/st0012))
|
|
44
|
+
- Fix typo: Guadian -\> Guardian [\#39](https://github.com/st0012/tapping_device/pull/39) ([skade](https://github.com/skade))
|
|
45
|
+
- Filter out calls about TappingDevice [\#38](https://github.com/st0012/tapping_device/pull/38) ([st0012](https://github.com/st0012))
|
|
46
|
+
- Drop tap\_sql! [\#37](https://github.com/st0012/tapping_device/pull/37) ([st0012](https://github.com/st0012))
|
|
47
|
+
- Add CollectionProxy class [\#36](https://github.com/st0012/tapping_device/pull/36) ([st0012](https://github.com/st0012))
|
|
48
|
+
|
|
49
|
+
## [v0.5.0](https://github.com/st0012/tapping_device/tree/v0.5.0) (2020-05-25)
|
|
50
|
+
|
|
51
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.11...v0.5.0)
|
|
52
|
+
|
|
53
|
+
**Closed issues:**
|
|
54
|
+
|
|
55
|
+
- Colorize output of tracing helpers [\#25](https://github.com/st0012/tapping_device/issues/25)
|
|
56
|
+
|
|
57
|
+
**Merged pull requests:**
|
|
58
|
+
|
|
59
|
+
- Update README.md [\#34](https://github.com/st0012/tapping_device/pull/34) ([st0012](https://github.com/st0012))
|
|
60
|
+
- Colorize output [\#33](https://github.com/st0012/tapping_device/pull/33) ([st0012](https://github.com/st0012))
|
|
61
|
+
- Add TappingDevice\#with to register a with condition [\#32](https://github.com/st0012/tapping_device/pull/32) ([st0012](https://github.com/st0012))
|
|
62
|
+
|
|
63
|
+
## [v0.4.11](https://github.com/st0012/tapping_device/tree/v0.4.11) (2020-04-19)
|
|
64
|
+
|
|
65
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.10...v0.4.11)
|
|
66
|
+
|
|
67
|
+
**Merged pull requests:**
|
|
68
|
+
|
|
69
|
+
- Update rake requirement from ~\> 10.0 to ~\> 13.0 [\#31](https://github.com/st0012/tapping_device/pull/31) ([dependabot[bot]](https://github.com/apps/dependabot))
|
|
70
|
+
|
|
71
|
+
## [v0.4.10](https://github.com/st0012/tapping_device/tree/v0.4.10) (2020-02-05)
|
|
72
|
+
|
|
73
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.9...v0.4.10)
|
|
74
|
+
|
|
75
|
+
**Implemented enhancements:**
|
|
76
|
+
|
|
77
|
+
- Usability improvements [\#30](https://github.com/st0012/tapping_device/pull/30) ([st0012](https://github.com/st0012))
|
|
78
|
+
|
|
79
|
+
**Merged pull requests:**
|
|
80
|
+
|
|
81
|
+
- Fix tap\_init!'s payload content [\#29](https://github.com/st0012/tapping_device/pull/29) ([st0012](https://github.com/st0012))
|
|
82
|
+
- Refactorings and fixes [\#28](https://github.com/st0012/tapping_device/pull/28) ([st0012](https://github.com/st0012))
|
|
83
|
+
|
|
84
|
+
## [v0.4.9](https://github.com/st0012/tapping_device/tree/v0.4.9) (2020-01-20)
|
|
85
|
+
|
|
86
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.8...v0.4.9)
|
|
87
|
+
|
|
88
|
+
**Implemented enhancements:**
|
|
89
|
+
|
|
90
|
+
- Improve detail\_call\_info's output format [\#27](https://github.com/st0012/tapping_device/pull/27) ([st0012](https://github.com/st0012))
|
|
91
|
+
|
|
92
|
+
## [v0.4.8](https://github.com/st0012/tapping_device/tree/v0.4.8) (2020-01-05)
|
|
93
|
+
|
|
94
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.7...v0.4.8)
|
|
95
|
+
|
|
96
|
+
**Closed issues:**
|
|
97
|
+
|
|
98
|
+
- Provide options for tapping on call or return events [\#23](https://github.com/st0012/tapping_device/issues/23)
|
|
99
|
+
|
|
100
|
+
**Merged pull requests:**
|
|
101
|
+
|
|
102
|
+
- Add tracing helpers [\#24](https://github.com/st0012/tapping_device/pull/24) ([st0012](https://github.com/st0012))
|
|
103
|
+
|
|
104
|
+
## [v0.4.7](https://github.com/st0012/tapping_device/tree/v0.4.7) (2019-12-29)
|
|
105
|
+
|
|
106
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.6...v0.4.7)
|
|
107
|
+
|
|
108
|
+
**Implemented enhancements:**
|
|
109
|
+
|
|
110
|
+
- Config test coverage for codeclimate [\#22](https://github.com/st0012/tapping_device/pull/22) ([st0012](https://github.com/st0012))
|
|
111
|
+
|
|
112
|
+
**Closed issues:**
|
|
113
|
+
|
|
114
|
+
- Support tracking ActiveRecord::Base instances by their ids [\#17](https://github.com/st0012/tapping_device/issues/17)
|
|
115
|
+
|
|
116
|
+
**Merged pull requests:**
|
|
117
|
+
|
|
118
|
+
- Refactor tests and some minor fixes [\#21](https://github.com/st0012/tapping_device/pull/21) ([st0012](https://github.com/st0012))
|
|
119
|
+
- Support track\_as\_records option [\#20](https://github.com/st0012/tapping_device/pull/20) ([st0012](https://github.com/st0012))
|
|
120
|
+
|
|
121
|
+
## [v0.4.6](https://github.com/st0012/tapping_device/tree/v0.4.6) (2019-12-25)
|
|
122
|
+
|
|
123
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.5...v0.4.6)
|
|
124
|
+
|
|
125
|
+
**Merged pull requests:**
|
|
126
|
+
|
|
127
|
+
- Add TappingDevice\#and\_print method [\#16](https://github.com/st0012/tapping_device/pull/16) ([st0012](https://github.com/st0012))
|
|
128
|
+
- Add Payload\#detail\_call\_info and improve method\_name's format [\#15](https://github.com/st0012/tapping_device/pull/15) ([st0012](https://github.com/st0012))
|
|
129
|
+
|
|
130
|
+
## [v0.4.5](https://github.com/st0012/tapping_device/tree/v0.4.5) (2019-12-15)
|
|
131
|
+
|
|
132
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.4...v0.4.5)
|
|
133
|
+
|
|
134
|
+
## [v0.4.4](https://github.com/st0012/tapping_device/tree/v0.4.4) (2019-12-15)
|
|
135
|
+
|
|
136
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.3...v0.4.4)
|
|
137
|
+
|
|
138
|
+
**Merged pull requests:**
|
|
139
|
+
|
|
140
|
+
- Implement tap\_passed! [\#14](https://github.com/st0012/tapping_device/pull/14) ([st0012](https://github.com/st0012))
|
|
141
|
+
|
|
142
|
+
## [v0.4.3](https://github.com/st0012/tapping_device/tree/v0.4.3) (2019-12-09)
|
|
143
|
+
|
|
144
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.2...v0.4.3)
|
|
145
|
+
|
|
146
|
+
## [v0.4.2](https://github.com/st0012/tapping_device/tree/v0.4.2) (2019-12-09)
|
|
147
|
+
|
|
148
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.1...v0.4.2)
|
|
149
|
+
|
|
150
|
+
**Merged pull requests:**
|
|
151
|
+
|
|
152
|
+
- Refactor tap\_sql! [\#13](https://github.com/st0012/tapping_device/pull/13) ([st0012](https://github.com/st0012))
|
|
153
|
+
- Improve tap sql [\#12](https://github.com/st0012/tapping_device/pull/12) ([st0012](https://github.com/st0012))
|
|
154
|
+
|
|
155
|
+
## [v0.4.1](https://github.com/st0012/tapping_device/tree/v0.4.1) (2019-12-06)
|
|
156
|
+
|
|
157
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.4.0...v0.4.1)
|
|
158
|
+
|
|
159
|
+
**Merged pull requests:**
|
|
160
|
+
|
|
161
|
+
- Add TappingDevice::Payload class [\#11](https://github.com/st0012/tapping_device/pull/11) ([st0012](https://github.com/st0012))
|
|
162
|
+
|
|
163
|
+
## [v0.4.0](https://github.com/st0012/tapping_device/tree/v0.4.0) (2019-11-25)
|
|
164
|
+
|
|
165
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.3.0...v0.4.0)
|
|
166
|
+
|
|
167
|
+
**Merged pull requests:**
|
|
168
|
+
|
|
169
|
+
- Support tap\_sql! [\#10](https://github.com/st0012/tapping_device/pull/10) ([st0012](https://github.com/st0012))
|
|
170
|
+
- Minor adjustment [\#9](https://github.com/st0012/tapping_device/pull/9) ([NickWarm](https://github.com/NickWarm))
|
|
171
|
+
|
|
172
|
+
## [v0.3.0](https://github.com/st0012/tapping_device/tree/v0.3.0) (2019-11-03)
|
|
173
|
+
|
|
174
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.2.0...v0.3.0)
|
|
175
|
+
|
|
176
|
+
**Implemented enhancements:**
|
|
177
|
+
|
|
178
|
+
- Largely improve performance by fixing bad design [\#8](https://github.com/st0012/tapping_device/pull/8) ([st0012](https://github.com/st0012))
|
|
179
|
+
|
|
180
|
+
## [v0.2.0](https://github.com/st0012/tapping_device/tree/v0.2.0) (2019-11-02)
|
|
181
|
+
|
|
182
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.1.1...v0.2.0)
|
|
183
|
+
|
|
184
|
+
**Implemented enhancements:**
|
|
185
|
+
|
|
186
|
+
- Add Device class [\#3](https://github.com/st0012/tapping_device/pull/3) ([st0012](https://github.com/st0012))
|
|
187
|
+
|
|
188
|
+
**Merged pull requests:**
|
|
189
|
+
|
|
190
|
+
- Remove tapping\_deivce/device.rb [\#7](https://github.com/st0012/tapping_device/pull/7) ([st0012](https://github.com/st0012))
|
|
191
|
+
- Reduce namespace [\#6](https://github.com/st0012/tapping_device/pull/6) ([st0012](https://github.com/st0012))
|
|
192
|
+
- Register and control all devices from Device class [\#5](https://github.com/st0012/tapping_device/pull/5) ([st0012](https://github.com/st0012))
|
|
193
|
+
- Support `TappingDevice::Device\#stop\_when` [\#4](https://github.com/st0012/tapping_device/pull/4) ([st0012](https://github.com/st0012))
|
|
194
|
+
|
|
195
|
+
## [v0.1.1](https://github.com/st0012/tapping_device/tree/v0.1.1) (2019-10-20)
|
|
196
|
+
|
|
197
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/v0.1.0...v0.1.1)
|
|
198
|
+
|
|
199
|
+
**Implemented enhancements:**
|
|
200
|
+
|
|
201
|
+
- More filters, Refactoring and Readme update [\#2](https://github.com/st0012/tapping_device/pull/2) ([st0012](https://github.com/st0012))
|
|
202
|
+
- Support tapping ActiveRecord class/instance [\#1](https://github.com/st0012/tapping_device/pull/1) ([st0012](https://github.com/st0012))
|
|
203
|
+
|
|
204
|
+
## [v0.1.0](https://github.com/st0012/tapping_device/tree/v0.1.0) (2019-10-19)
|
|
205
|
+
|
|
206
|
+
[Full Changelog](https://github.com/st0012/tapping_device/compare/61039c87a55c664661b788e24311e263b28a3ee8...v0.1.0)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
data/Gemfile.lock
CHANGED
|
@@ -1,36 +1,38 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
tapping_device (0.4
|
|
4
|
+
tapping_device (0.5.4)
|
|
5
5
|
activerecord (>= 5.2)
|
|
6
|
+
activesupport
|
|
7
|
+
pry
|
|
6
8
|
|
|
7
9
|
GEM
|
|
8
10
|
remote: https://rubygems.org/
|
|
9
11
|
specs:
|
|
10
|
-
activemodel (6.0.
|
|
11
|
-
activesupport (= 6.0.
|
|
12
|
-
activerecord (6.0.
|
|
13
|
-
activemodel (= 6.0.
|
|
14
|
-
activesupport (= 6.0.
|
|
15
|
-
activesupport (6.0.
|
|
12
|
+
activemodel (6.0.3.2)
|
|
13
|
+
activesupport (= 6.0.3.2)
|
|
14
|
+
activerecord (6.0.3.2)
|
|
15
|
+
activemodel (= 6.0.3.2)
|
|
16
|
+
activesupport (= 6.0.3.2)
|
|
17
|
+
activesupport (6.0.3.2)
|
|
16
18
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
17
19
|
i18n (>= 0.7, < 2)
|
|
18
20
|
minitest (~> 5.1)
|
|
19
21
|
tzinfo (~> 1.1)
|
|
20
|
-
zeitwerk (~> 2.2)
|
|
21
|
-
coderay (1.1.
|
|
22
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
|
23
|
+
coderay (1.1.3)
|
|
22
24
|
concurrent-ruby (1.1.6)
|
|
23
25
|
database_cleaner (1.7.0)
|
|
24
26
|
diff-lcs (1.3)
|
|
25
27
|
docile (1.3.2)
|
|
26
|
-
i18n (1.8.
|
|
28
|
+
i18n (1.8.3)
|
|
27
29
|
concurrent-ruby (~> 1.0)
|
|
28
30
|
json (2.3.0)
|
|
29
|
-
method_source (0.
|
|
30
|
-
minitest (5.14.
|
|
31
|
-
pry (0.
|
|
32
|
-
coderay (~> 1.1
|
|
33
|
-
method_source (~>
|
|
31
|
+
method_source (1.0.0)
|
|
32
|
+
minitest (5.14.1)
|
|
33
|
+
pry (0.13.1)
|
|
34
|
+
coderay (~> 1.1)
|
|
35
|
+
method_source (~> 1.0)
|
|
34
36
|
rake (13.0.1)
|
|
35
37
|
rspec (3.8.0)
|
|
36
38
|
rspec-core (~> 3.8.0)
|
|
@@ -54,7 +56,7 @@ GEM
|
|
|
54
56
|
thread_safe (0.3.6)
|
|
55
57
|
tzinfo (1.2.7)
|
|
56
58
|
thread_safe (~> 0.1)
|
|
57
|
-
zeitwerk (2.3.
|
|
59
|
+
zeitwerk (2.3.1)
|
|
58
60
|
|
|
59
61
|
PLATFORMS
|
|
60
62
|
ruby
|
|
@@ -62,7 +64,6 @@ PLATFORMS
|
|
|
62
64
|
DEPENDENCIES
|
|
63
65
|
bundler (~> 2.0)
|
|
64
66
|
database_cleaner
|
|
65
|
-
pry
|
|
66
67
|
rake (~> 13.0)
|
|
67
68
|
rspec (~> 3.0)
|
|
68
69
|
simplecov (= 0.17.1)
|
data/README.md
CHANGED
|
@@ -6,417 +6,292 @@
|
|
|
6
6
|
[](https://codeclimate.com/github/st0012/tapping_device/test_coverage)
|
|
7
7
|
[](https://www.codetriage.com/st0012/tapping_device)
|
|
8
8
|
|
|
9
|
-
## Related Posts
|
|
10
|
-
- [Optimize Your Debugging Process With Object-Oriented Tracing and tapping_device](http://bit.ly/object-oriented-tracing)
|
|
11
|
-
- [Debug Rails issues effectively with tapping_device](https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c)
|
|
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)
|
|
13
9
|
|
|
10
|
+
## Introduction
|
|
11
|
+
As the name states, `TappingDevice` allows you to secretly listen to different events of an object:
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
- [Track Calls that Generates SQL Queries](#track-calls-that-generates-sql-queries)
|
|
19
|
-
- [Installation](#installation)
|
|
20
|
-
- [Usages](#usages)
|
|
21
|
-
- Tracing Helpers
|
|
22
|
-
- [print_traces](#print_traces)
|
|
23
|
-
- [print_calls_in_detail](#print_calls_in_detail)
|
|
24
|
-
- Tapping Methods
|
|
25
|
-
- [tap_init!](#tap_init)
|
|
26
|
-
- [tap_on!](#tap_on)
|
|
27
|
-
- [tap_passed!](#tap_passed)
|
|
28
|
-
- [tap_assoc!](#tap_assoc)
|
|
29
|
-
- [tap_sql!](#tap_sql)
|
|
30
|
-
- [Options](#options)
|
|
31
|
-
- [Payload](#payload-of-the-call)
|
|
32
|
-
- [Advance Usages](#advance-usages)
|
|
13
|
+
- `Method Calls` - what does the object do
|
|
14
|
+
- `Traces` - how is the object used by the application
|
|
15
|
+
- `State Mutations` - what happens inside the object
|
|
33
16
|
|
|
34
|
-
|
|
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).
|
|
17
|
+
After collecting the events, `TappingDevice` will output them in a nice, readable format to either stdout or a file.
|
|
36
18
|
|
|
37
|
-
|
|
19
|
+
**Ultimately, its goal is to let you know all the information you need for debugging with just 1 line of code.**
|
|
38
20
|
|
|
39
|
-
|
|
21
|
+
## Usages
|
|
40
22
|
|
|
41
|
-
|
|
23
|
+
### Track Method Calls
|
|
42
24
|
|
|
43
|
-
|
|
44
|
-
class OrdersController < ApplicationController
|
|
45
|
-
def create
|
|
46
|
-
@cart = Cart.find(order_params[:cart_id])
|
|
47
|
-
print_traces(@cart, exclude_by_paths: [/gems/])
|
|
48
|
-
@order = OrderCreationService.new.perform(@cart)
|
|
49
|
-
end
|
|
50
|
-
```
|
|
25
|
+
By tracking an object's method calls, you'll be able to observe the object's behavior very easily
|
|
51
26
|
|
|
52
|
-
|
|
53
|
-
Passed as 'cart' in 'OrderCreationService#perform' at /Users/st0012/projects/tapping_device-demo/app/controllers/orders_controller.rb:10
|
|
54
|
-
Passed as 'cart' in 'OrderCreationService#validate_cart' at /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:8
|
|
55
|
-
Called :reserved_until FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:18
|
|
56
|
-
Called :errors FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:9
|
|
57
|
-
Passed as 'cart' in 'OrderCreationService#apply_discount' at /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:10
|
|
58
|
-
Called :apply_discount FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:24
|
|
59
|
-
……
|
|
60
|
-
```
|
|
27
|
+
<img src="https://github.com/st0012/tapping_device/blob/master/images/print_calls.png" alt="image of print_calls output" width="50%">
|
|
61
28
|
|
|
62
|
-
|
|
29
|
+
Each entry consists of 5 pieces of information:
|
|
30
|
+
- method name
|
|
31
|
+
- source of the method
|
|
32
|
+
- call site
|
|
33
|
+
- arguments
|
|
34
|
+
- return value
|
|
63
35
|
|
|
36
|
+

|
|
64
37
|
|
|
65
|
-
|
|
38
|
+
#### Helpers
|
|
66
39
|
|
|
67
|
-
|
|
68
|
-
|
|
40
|
+
- `print_calls(object)` - prints the result to stdout
|
|
41
|
+
- `write_calls(object, log_file: "file_name")` - writes the result to a file
|
|
42
|
+
- the default file is `/tmp/tapping_device.log`, but you can change it with `log_file: "new_path"` option
|
|
69
43
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
44
|
+
#### Use Cases
|
|
45
|
+
- Understand a service object/form object's behavior
|
|
46
|
+
- Debug a messy controller
|
|
73
47
|
|
|
74
|
-
|
|
48
|
+
### Track Traces
|
|
75
49
|
|
|
76
|
-
|
|
77
|
-
$ bundle
|
|
78
|
-
```
|
|
50
|
+
By tracking an object's traces, you'll be able to observe the object's journey in your application
|
|
79
51
|
|
|
80
|
-
|
|
52
|
+

|
|
81
53
|
|
|
82
|
-
|
|
83
|
-
$ gem install tapping_device
|
|
84
|
-
```
|
|
54
|
+
#### Helpers
|
|
85
55
|
|
|
86
|
-
|
|
56
|
+
- `print_traces(object)` - prints the result to stdout
|
|
57
|
+
- `write_traces(object, log_file: "file_name")` - writes the result to a file
|
|
58
|
+
- the default file is `/tmp/tapping_device.log`, but you can change it with `log_file: "new_path"` option
|
|
87
59
|
|
|
88
|
-
|
|
60
|
+
#### Use Cases
|
|
61
|
+
- Debug argument related issues
|
|
62
|
+
- Understand how a library uses your objects
|
|
89
63
|
|
|
90
|
-
|
|
64
|
+
### Track State Mutations
|
|
91
65
|
|
|
92
|
-
|
|
93
|
-
class OrdersController < ApplicationController
|
|
94
|
-
def create
|
|
95
|
-
@cart = Cart.find(order_params[:cart_id])
|
|
96
|
-
print_traces(@cart, exclude_by_paths: [/gems/])
|
|
97
|
-
@order = OrderCreationService.new.perform(@cart)
|
|
98
|
-
end
|
|
99
|
-
```
|
|
66
|
+
By tracking an object's traces, you'll be able to observe the state changes happen inside the object between each method call
|
|
100
67
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
68
|
+
<img src="https://github.com/st0012/tapping_device/blob/master/images/print_mutations.png" alt="image of print_mutations output" width="50%">
|
|
69
|
+
|
|
70
|
+
#### Helpers
|
|
71
|
+
|
|
72
|
+
- `print_mutations(object)` - prints the result to stdout
|
|
73
|
+
- `write_mutations(object, log_file: "file_name")` - writes the result to a file
|
|
74
|
+
- the default file is `/tmp/tapping_device.log`, but you can change it with `log_file: "new_path"` option
|
|
75
|
+
|
|
76
|
+
#### Use Cases
|
|
77
|
+
- Debug state related issues
|
|
78
|
+
- Debug memoization issues
|
|
79
|
+
|
|
80
|
+
### Track All Instances Of A Class
|
|
110
81
|
|
|
111
|
-
|
|
82
|
+
It's not always easy to directly access the objects we want to track, especially when they're managed by a library (e.g. `ActiveRecord::Relation`). In such cases, you can use these helpers to track the class's instances:
|
|
112
83
|
|
|
113
|
-
|
|
84
|
+
- `print_instance_calls(ObjectKlass)`
|
|
85
|
+
- `print_instance_traces(ObjectKlass)`
|
|
86
|
+
- `print_instance_mutations(ObjectKlass)`
|
|
87
|
+
- `write_instance_calls(ObjectKlass)`
|
|
88
|
+
- `write_instance_traces(ObjectKlass)`
|
|
89
|
+
- `write_instance_mutations(ObjectKlass)`
|
|
114
90
|
|
|
115
|
-
|
|
116
|
-
|
|
91
|
+
|
|
92
|
+
### Use `with_HELPER_NAME` for chained method calls
|
|
93
|
+
|
|
94
|
+
In Ruby programs, we often chain multiple methods together like this:
|
|
117
95
|
|
|
118
96
|
```ruby
|
|
119
|
-
|
|
120
|
-
def create
|
|
121
|
-
@cart = Cart.find(order_params[:cart_id])
|
|
122
|
-
service = OrderCreationService.new
|
|
123
|
-
print_calls_in_detail(service)
|
|
124
|
-
@order = service.perform(@cart)
|
|
125
|
-
end
|
|
97
|
+
SomeService.new(params).perform
|
|
126
98
|
```
|
|
127
99
|
|
|
128
|
-
|
|
129
|
-
:validate_cart # OrderCreationService
|
|
130
|
-
<= {:cart=>#<Cart id: 1, total: 10, customer_id: 1, promotion_id: nil, reserved_until: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">}
|
|
131
|
-
=> nil
|
|
132
|
-
FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:8
|
|
133
|
-
:apply_discount # OrderCreationService
|
|
134
|
-
<= {:cart=>#<Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">, :promotion=>#<Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">}
|
|
135
|
-
=> true
|
|
136
|
-
FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:10
|
|
137
|
-
:create_order # OrderCreationService
|
|
138
|
-
<= {:cart=>#<Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">}
|
|
139
|
-
=> #<Order:0x00007f9ebcb17f08>
|
|
140
|
-
FROM /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:11
|
|
141
|
-
:perform # OrderCreationService
|
|
142
|
-
<= {:cart=>#<Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">, :promotion=>#<Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-05 09:48:28", updated_at: "2020-01-05 09:48:28">}
|
|
143
|
-
=> #<Order:0x00007f9ebcb17f08>
|
|
144
|
-
FROM /Users/st0012/projects/tapping_device-demo/app/controllers/orders_controller.rb:11
|
|
145
|
-
```
|
|
100
|
+
And to debug it, we'll need to break the method chain into
|
|
146
101
|
|
|
147
|
-
|
|
102
|
+
```ruby
|
|
103
|
+
service = SomeService.new(params)
|
|
104
|
+
print_calls(service, options)
|
|
105
|
+
service.perform
|
|
106
|
+
```
|
|
148
107
|
|
|
149
|
-
|
|
108
|
+
This kind of code changes are usually annoying, and that's one of the problems I want to solve with `TappingDevice`.
|
|
150
109
|
|
|
151
|
-
|
|
110
|
+
So here's another option, just insert a `with_HELPER_NAME` call in between:
|
|
152
111
|
|
|
153
112
|
```ruby
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
calls << [payload[:method_name], payload[:arguments]]
|
|
157
|
-
end
|
|
113
|
+
SomeService.new(params).with_print_calls(options).perform
|
|
114
|
+
```
|
|
158
115
|
|
|
159
|
-
|
|
160
|
-
Student.new("Jane", 23)
|
|
116
|
+
And it'll behave exactly like
|
|
161
117
|
|
|
162
|
-
|
|
118
|
+
```ruby
|
|
119
|
+
service = SomeService.new(params)
|
|
120
|
+
print_calls(service, options)
|
|
121
|
+
service.perform
|
|
163
122
|
```
|
|
164
123
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
`tap_on!(object)` - tracks any calls received by the object.
|
|
124
|
+
## Installation
|
|
125
|
+
Add this line to your application's Gemfile:
|
|
168
126
|
|
|
169
127
|
```ruby
|
|
170
|
-
|
|
171
|
-
|
|
128
|
+
gem 'tapping_device', group: :development
|
|
129
|
+
```
|
|
172
130
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
131
|
+
And then execute:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
$ bundle
|
|
177
135
|
```
|
|
178
136
|
|
|
179
|
-
|
|
137
|
+
Or install it directly:
|
|
180
138
|
|
|
181
139
|
```
|
|
182
|
-
|
|
183
|
-
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
|
184
|
-
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
|
140
|
+
$ gem install tapping_device
|
|
185
141
|
```
|
|
186
142
|
|
|
187
|
-
|
|
143
|
+
**Depending on the size of your application, `TappingDevice` could harm the performance significantly. So make sure you don't put it inside the production group**
|
|
188
144
|
|
|
189
|
-
### tap_passed!
|
|
190
145
|
|
|
191
|
-
|
|
146
|
+
## Advance Usages & Options
|
|
147
|
+
|
|
148
|
+
### Add Conditions With `.with`
|
|
149
|
+
|
|
150
|
+
Sometimes we don't need to know all the calls or traces of an object; we just want some of them. In those cases, we can chain the helpers with `.with` to filter the calls/traces.
|
|
192
151
|
|
|
193
152
|
```ruby
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
@post = Post.new
|
|
198
|
-
|
|
199
|
-
tap_passed!(@post) do |payload|
|
|
200
|
-
puts(payload.passed_at(with_method_head: true))
|
|
201
|
-
end
|
|
202
|
-
end
|
|
153
|
+
# only prints calls with name matches /foo/
|
|
154
|
+
print_calls(object).with do |payload|
|
|
155
|
+
payload.method_name.to_s.match?(/foo/)
|
|
203
156
|
end
|
|
204
157
|
```
|
|
205
158
|
|
|
206
|
-
|
|
207
|
-
Passed as 'record' in method ':polymorphic_mapping'
|
|
208
|
-
> def polymorphic_mapping(record)
|
|
209
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionpack-6.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:131
|
|
210
|
-
Passed as 'klass' in method ':get_method_for_class'
|
|
211
|
-
> def get_method_for_class(klass)
|
|
212
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionpack-6.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:269
|
|
213
|
-
Passed as 'record' in method ':handle_model'
|
|
214
|
-
> def handle_model(record)
|
|
215
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionpack-6.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:227
|
|
216
|
-
Passed as 'record_or_hash_or_array' in method ':polymorphic_method'
|
|
217
|
-
> def self.polymorphic_method(recipient, record_or_hash_or_array, action, type, options)
|
|
218
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionpack-6.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:139
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### tap_assoc!
|
|
159
|
+
### Options
|
|
222
160
|
|
|
223
|
-
|
|
161
|
+
There are many options you can pass when using a helper method. You can list all available options and their default value with
|
|
224
162
|
|
|
225
163
|
```ruby
|
|
226
|
-
|
|
164
|
+
TappingDevice::Configurable::DEFAULTS #=> {
|
|
165
|
+
:filter_by_paths=>[],
|
|
166
|
+
:exclude_by_paths=>[],
|
|
167
|
+
:with_trace_to=>50,
|
|
168
|
+
:event_type=>:return,
|
|
169
|
+
:hijack_attr_methods=>false,
|
|
170
|
+
:track_as_records=>false,
|
|
171
|
+
:inspect=>false,
|
|
172
|
+
:colorize=>true,
|
|
173
|
+
:log_file=>"/tmp/tapping_device.log"
|
|
174
|
+
}
|
|
227
175
|
```
|
|
228
176
|
|
|
229
|
-
|
|
230
|
-
payments FROM /RUBY_PATH/gems/2.6.0/gems/jsonapi-resources-0.9.10/lib/jsonapi/resource.rb:124
|
|
231
|
-
line_items FROM /MY_PROJECT/app/models/line_item_container_helpers.rb:44
|
|
232
|
-
effective_line_items FROM /MY_PROJECT/app/models/line_item_container_helpers.rb:110
|
|
233
|
-
amending_orders FROM /MY_PROJECT/app/models/order.rb:385
|
|
234
|
-
amends_order FROM /MY_PROJECT/app/models/order.rb:432
|
|
235
|
-
```
|
|
177
|
+
Here are some commonly used options:
|
|
236
178
|
|
|
237
|
-
|
|
179
|
+
#### `colorize: false`
|
|
180
|
+
|
|
181
|
+
- default: `true`
|
|
182
|
+
|
|
183
|
+
By default `print_calls` and `print_traces` colorize their output. If you don't want the colors, you can use `colorize: false` to disable it.
|
|
238
184
|
|
|
239
|
-
`tap_sql!(anything_that_generates_sql_queries)` tracks sql queries generated from the target
|
|
240
185
|
|
|
241
186
|
```ruby
|
|
242
|
-
|
|
243
|
-
def index
|
|
244
|
-
# simulate current_user
|
|
245
|
-
@current_user = User.last
|
|
246
|
-
# reusable ActiveRecord::Relation
|
|
247
|
-
@posts = Post.all
|
|
248
|
-
|
|
249
|
-
tap_sql!(@posts) do |payload|
|
|
250
|
-
puts("Method: #{payload[:method_name]} generated sql: #{payload[:sql]} from #{payload[:filepath]}:#{payload[:line_number]}")
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
end
|
|
187
|
+
print_calls(object, colorize: false)
|
|
254
188
|
```
|
|
255
189
|
|
|
256
|
-
```erb
|
|
257
|
-
<h1>Posts (<%= @posts.count %>)</h1>
|
|
258
|
-
......
|
|
259
|
-
<% @posts.each do |post| %>
|
|
260
|
-
......
|
|
261
|
-
<% end %>
|
|
262
|
-
......
|
|
263
|
-
<p>Posts created by you: <%= @posts.where(user: @current_user).count %></p>
|
|
264
|
-
```
|
|
265
190
|
|
|
266
|
-
|
|
267
|
-
Method: count generated sql: SELECT COUNT(*) FROM "posts" from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:3
|
|
268
|
-
Method: each generated sql: SELECT "posts".* FROM "posts" from /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:16
|
|
269
|
-
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
|
|
270
|
-
```
|
|
191
|
+
#### `inspect: true`
|
|
271
192
|
|
|
193
|
+
- default: `false`
|
|
272
194
|
|
|
273
|
-
|
|
274
|
-
#### with_trace_to
|
|
275
|
-
It takes an integer as the number of traces we want to put into `trace`. Default is `nil`, so `trace` would be empty.
|
|
195
|
+
As you might have noticed, all the objects are converted into strings with `#to_s` instead of `#inspect`. This is because when used on some Rails objects, `#inspect` can generate a significantly larger string than `#to_s`. For example:
|
|
276
196
|
|
|
277
|
-
```ruby
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
stan.name
|
|
282
|
-
|
|
283
|
-
puts(device.calls.first.trace) #=>
|
|
284
|
-
/Users/st0012/projects/tapping_device/spec/tapping_device_spec.rb:287:in `block (4 levels) in <top (required)>'
|
|
285
|
-
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `instance_exec'
|
|
286
|
-
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:257:in `block in run'
|
|
287
|
-
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:503:in `block in with_around_and_singleton_context_hooks'
|
|
288
|
-
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/example.rb:460:in `block in with_around_example_hooks'
|
|
289
|
-
/Users/st0012/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/rspec-core-3.8.2/lib/rspec/core/hooks.rb:464:in `block in run'
|
|
197
|
+
``` ruby
|
|
198
|
+
post.to_s #=> #<Post:0x00007f89a55201d0>
|
|
199
|
+
post.inspect #=> #<Post id: 649, user_id: 3, topic_id: 600, post_number: 1, raw: "Hello world", cooked: "<p>Hello world</p>", created_at: "2020-05-24 08:07:29", updated_at: "2020-05-24 08:07:29", reply_to_post_number: nil, reply_count: 0, quote_count: 0, deleted_at: nil, off_topic_count: 0, like_count: 0, incoming_link_count: 0, bookmark_count: 0, score: nil, reads: 0, post_type: 1, sort_order: 1, last_editor_id: 3, hidden: false, hidden_reason_id: nil, notify_moderators_count: 0, spam_count: 0, illegal_count: 0, inappropriate_count: 0, last_version_at: "2020-05-24 08:07:29", user_deleted: false, reply_to_user_id: nil, percent_rank: 1.0, notify_user_count: 0, like_score: 0, deleted_by_id: nil, edit_reason: nil, word_count: 2, version: 1, cook_method: 1, wiki: false, baked_at: "2020-05-24 08:07:29", baked_version: 2, hidden_at: nil, self_edits: 0, reply_quoted: false, via_email: false, raw_email: nil, public_version: 1, action_code: nil, image_url: nil, locked_by_id: nil, image_upload_id: nil>
|
|
290
200
|
```
|
|
291
201
|
|
|
292
|
-
####
|
|
293
|
-
|
|
202
|
+
#### `hijack_attr_methods: true`
|
|
203
|
+
|
|
204
|
+
- default: `false`
|
|
205
|
+
- except for `tap_mutation!` and `print_mutations`
|
|
206
|
+
|
|
207
|
+
Because `TracePoint` doesn't track methods generated by `attr_*` helpers (see [this issue](https://bugs.ruby-lang.org/issues/16383) for more info), we need to redefine those methods with the normal method definition.
|
|
208
|
+
|
|
209
|
+
For example, it generates
|
|
294
210
|
|
|
295
211
|
```ruby
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
212
|
+
def name=(val)
|
|
213
|
+
@name = val
|
|
214
|
+
end
|
|
299
215
|
```
|
|
300
216
|
|
|
301
|
-
|
|
302
|
-
It takes an array of call path patterns that we want to skip. This could be very helpful when working on a large project like Rails applications.
|
|
217
|
+
for
|
|
303
218
|
|
|
304
219
|
```ruby
|
|
305
|
-
|
|
220
|
+
attr_writer :name
|
|
306
221
|
```
|
|
307
222
|
|
|
308
|
-
|
|
309
|
-
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
|
310
|
-
name FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
|
|
311
|
-
_read_attribute FROM /RUBY_PATH/gems/2.6.0/gems/activerecord-5.2.0/lib/active_record/attribute_methods/read.rb:40
|
|
312
|
-
user_id FROM /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
|
|
313
|
-
.......
|
|
223
|
+
This hack will only be applied to the target instance with `instance_eval`. So other instances of the class remain untouched.
|
|
314
224
|
|
|
315
|
-
|
|
225
|
+
The default is `false` because
|
|
316
226
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
to_param FROM /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
|
|
320
|
-
```
|
|
227
|
+
1. Checking what methods are generated by `attr_*` helpers isn't free. It's an `O(n)` operation, where `n` is the number of methods the target object has.
|
|
228
|
+
2. It's still unclear if this hack safe enough for most applications.
|
|
321
229
|
|
|
322
|
-
#### filter_by_paths
|
|
323
|
-
|
|
324
|
-
Like `exclude_by_paths`, but work in the opposite way.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
### Payload of The Call
|
|
328
|
-
All tapping methods (start with `tap_`) takes a block and yield a `Payload` object as a block argument. It responds to
|
|
329
|
-
|
|
330
|
-
- `target` - the target for `tap_x` call
|
|
331
|
-
- `receiver` - the receiver object
|
|
332
|
-
- `method_name` - method’s name (symbol)
|
|
333
|
-
- e.g. `:name`
|
|
334
|
-
- `method_object` - the method object that's being called. It might be `nil` in some edge cases.
|
|
335
|
-
- `arguments` - arguments of the method call
|
|
336
|
-
- e.g. `{name: “Stan”, age: 25}`
|
|
337
|
-
- `return_value` - return value of the method call
|
|
338
|
-
- `filepath` - path to the file that performs the method call
|
|
339
|
-
- `line_number`
|
|
340
|
-
- `defined_class` - in which class that defines the method being called
|
|
341
|
-
- `trace` - stack trace of the call. Default is an empty array unless `with_trace_to` option is set
|
|
342
|
-
- `sql` - sql that generated from the call (only present in `tap_sql!` payloads)
|
|
343
|
-
- `tp` - trace point object of this call
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
#### Symbols for Payload Helpers
|
|
347
|
-
- `FROM` for method call’s location
|
|
348
|
-
- `<=` for arguments
|
|
349
|
-
- `=>` for return value
|
|
350
|
-
- `@` for defined class
|
|
351
|
-
|
|
352
|
-
#### Payload Helpers
|
|
353
|
-
- `method_name_and_location` - `initialize FROM /PROJECT_PATH/tapping_device/spec/payload_spec.rb:7`
|
|
354
|
-
- `method_name_and_arguments` - `initialize <= {:name=>\"Stan\", :age=>25}`
|
|
355
|
-
- `method_name_and_return_value` - `ten => 10`
|
|
356
|
-
- `method_name_and_defined_class` - `initialize @ Student`
|
|
357
|
-
- `passed_at` -
|
|
358
|
-
```
|
|
359
|
-
Passed as 'object' in method ':initialize'
|
|
360
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
|
361
|
-
```
|
|
362
230
|
|
|
363
|
-
|
|
231
|
+
#### `ignore_private`
|
|
364
232
|
|
|
365
|
-
|
|
366
|
-
Passed as 'object' in method ':initialize'
|
|
367
|
-
> def initialize(template_object, object_name, method_name, object, tag_value)
|
|
368
|
-
at /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/actionview-6.0.0/lib/action_view/helpers/tags/label.rb:60
|
|
369
|
-
```
|
|
233
|
+
Sometimes we use many private methods to perform trivial operations, like
|
|
370
234
|
|
|
371
|
-
|
|
235
|
+
```ruby
|
|
236
|
+
class Operation
|
|
237
|
+
def extras
|
|
238
|
+
dig_attribute("extras")
|
|
239
|
+
end
|
|
372
240
|
|
|
373
|
-
|
|
374
|
-
initialize @ Student
|
|
375
|
-
<= {:name=>"Stan", :age=>25}
|
|
376
|
-
=> 25
|
|
377
|
-
FROM /Users/st0012/projects/tapping_device/spec/payload_spec.rb:7
|
|
378
|
-
```
|
|
241
|
+
private
|
|
379
242
|
|
|
380
|
-
|
|
243
|
+
def data
|
|
244
|
+
@data
|
|
245
|
+
end
|
|
381
246
|
|
|
382
|
-
|
|
247
|
+
def dig_attribute(attr)
|
|
248
|
+
data.dig("attributes", attr)
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
And we may not be interested in those method calls. If that's the case, you can use the `ignore_private` option
|
|
383
254
|
|
|
384
255
|
```ruby
|
|
385
|
-
|
|
386
|
-
|
|
256
|
+
operation = Operation.new(params)
|
|
257
|
+
print_calls(operation, ignore_private: true) #=> only prints the `extras` call
|
|
387
258
|
```
|
|
388
259
|
|
|
389
|
-
|
|
260
|
+
#### `only_private`
|
|
261
|
+
|
|
262
|
+
This option does the opposite of the `ignore_private` option does.
|
|
263
|
+
|
|
390
264
|
|
|
391
|
-
|
|
265
|
+
### Global Configuration
|
|
266
|
+
|
|
267
|
+
If you don't want to pass options every time you use a helper, you can use global configuration to change the default values:
|
|
268
|
+
|
|
269
|
+
```ruby
|
|
270
|
+
TappingDevice.config[:colorize] = false
|
|
271
|
+
TappingDevice.config[:hijack_attr_methods] = true
|
|
272
|
+
```
|
|
392
273
|
|
|
393
|
-
|
|
394
|
-
1. Manually calling `device.stop!`
|
|
395
|
-
2. Setting stop condition with `device.stop_when`, like
|
|
274
|
+
And if you're using Rails, you can put the configs under `config/initializers/tapping_device.rb` like this:
|
|
396
275
|
|
|
397
276
|
```ruby
|
|
398
|
-
|
|
399
|
-
|
|
277
|
+
if defined?(TappingDevice)
|
|
278
|
+
TappingDevice.config[:colorize] = false
|
|
279
|
+
TappingDevice.config[:hijack_attr_methods] = true
|
|
400
280
|
end
|
|
401
281
|
```
|
|
402
282
|
|
|
403
|
-
#### Device states & Managing Devices
|
|
404
283
|
|
|
405
|
-
|
|
284
|
+
### Lower-Level Helpers
|
|
285
|
+
`print_calls` and `print_traces` aren't the only helpers you can get from `TappingDevice`. They are actually built on top of other helpers, which you can use as well. To know more about them, please check [this page](https://github.com/st0012/tapping_device/wiki/Advance-Usages)
|
|
406
286
|
|
|
407
|
-
- `Initial` - means the instance is initialized but hasn't tapped on anything.
|
|
408
|
-
- `Enabled` - means the instance is tapping on something (has called `tap_*` methods).
|
|
409
|
-
- `Disabled` - means the instance has been disabled. It will no longer receive any call info.
|
|
410
287
|
|
|
411
|
-
|
|
288
|
+
### Related Blog Posts
|
|
289
|
+
- [Optimize Your Debugging Process With Object-Oriented Tracing and tapping_device](http://bit.ly/object-oriented-tracing)
|
|
290
|
+
- [Debug Rails issues effectively with tapping_device](https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c)
|
|
291
|
+
- [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)
|
|
412
292
|
|
|
413
|
-
- `TappingDevice.devices` - Lists all registered devices with `initial` or `enabled` state. Note that any instance that's been stopped will be removed from the list.
|
|
414
|
-
- `TappingDevice.stop_all!` - Stops all registered devices and remove them from the `devices` list.
|
|
415
|
-
- `TappingDevice.suspend_new!` - Suspends any device instance from changing their state from `initial` to `enabled`. Which means any `tap_*` calls after it will no longer work.
|
|
416
|
-
- `TappingDevice.reset!` - Cancels `suspend_new` (if called) and stops/removes all created devices. Useful to reset the environment between test cases.
|
|
417
293
|
|
|
418
294
|
## Development
|
|
419
|
-
|
|
420
295
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
421
296
|
|
|
422
297
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
@@ -432,3 +307,4 @@ The gem is available as open-source under the terms of the [MIT License](https:/
|
|
|
432
307
|
## Code of Conduct
|
|
433
308
|
|
|
434
309
|
Everyone interacting in the TappingDevice project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/tapping_device/blob/master/CODE_OF_CONDUCT.md).
|
|
310
|
+
|