tapping_device 0.5.2 → 0.5.7
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/CHANGELOG.md +210 -0
- data/Gemfile.lock +16 -11
- data/README.md +178 -127
- data/lib/tapping_device.rb +45 -31
- data/lib/tapping_device/configurable.rb +27 -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 +166 -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 +2 -3
- data/lib/tapping_device/trackable.rb +78 -19
- data/lib/tapping_device/trackers/initialization_tracker.rb +28 -2
- data/lib/tapping_device/trackers/mutation_tracker.rb +3 -23
- data/lib/tapping_device/version.rb +1 -1
- data/tapping_device.gemspec +2 -0
- metadata +38 -3
- data/lib/tapping_device/output_payload.rb +0 -173
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28a848cfef98c43315488230c1593aba48ef1b3ee91dc7a495a6cee7cb406771
|
4
|
+
data.tar.gz: 30601c6039343512d3d7c157bd0c8e5645b8005aa37a4b365458018cb477c2d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2540416f3d4ece8dfb76ee567030d3f4ab9da497c9ae97e9d7418b952d7ce0552453aad33278344ce683dc89a393244d74aef20bc6c6cf9847f0198911999a20
|
7
|
+
data.tar.gz: b417c4c17f18a152ce0bbc4135657bc41cb90b70788b971debb4242a1d35a9189c21621420af5f5bf06e9aa76148f9a49c6e2fb786000769a193c57765de45d1
|
data/.DS_Store
CHANGED
Binary file
|
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,34 +1,38 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
tapping_device (0.5.
|
4
|
+
tapping_device (0.5.7)
|
5
5
|
activerecord (>= 5.2)
|
6
|
+
activesupport
|
7
|
+
pastel
|
6
8
|
pry
|
7
9
|
|
8
10
|
GEM
|
9
11
|
remote: https://rubygems.org/
|
10
12
|
specs:
|
11
|
-
activemodel (6.0.3.
|
12
|
-
activesupport (= 6.0.3.
|
13
|
-
activerecord (6.0.3.
|
14
|
-
activemodel (= 6.0.3.
|
15
|
-
activesupport (= 6.0.3.
|
16
|
-
activesupport (6.0.3.
|
13
|
+
activemodel (6.0.3.2)
|
14
|
+
activesupport (= 6.0.3.2)
|
15
|
+
activerecord (6.0.3.2)
|
16
|
+
activemodel (= 6.0.3.2)
|
17
|
+
activesupport (= 6.0.3.2)
|
18
|
+
activesupport (6.0.3.2)
|
17
19
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
18
20
|
i18n (>= 0.7, < 2)
|
19
21
|
minitest (~> 5.1)
|
20
22
|
tzinfo (~> 1.1)
|
21
23
|
zeitwerk (~> 2.2, >= 2.2.2)
|
22
24
|
coderay (1.1.3)
|
23
|
-
concurrent-ruby (1.1.
|
25
|
+
concurrent-ruby (1.1.7)
|
24
26
|
database_cleaner (1.7.0)
|
25
27
|
diff-lcs (1.3)
|
26
28
|
docile (1.3.2)
|
27
|
-
i18n (1.8.
|
29
|
+
i18n (1.8.5)
|
28
30
|
concurrent-ruby (~> 1.0)
|
29
31
|
json (2.3.0)
|
30
32
|
method_source (1.0.0)
|
31
|
-
minitest (5.14.
|
33
|
+
minitest (5.14.2)
|
34
|
+
pastel (0.8.0)
|
35
|
+
tty-color (~> 0.5)
|
32
36
|
pry (0.13.1)
|
33
37
|
coderay (~> 1.1)
|
34
38
|
method_source (~> 1.0)
|
@@ -53,9 +57,10 @@ GEM
|
|
53
57
|
simplecov-html (0.10.2)
|
54
58
|
sqlite3 (1.4.1)
|
55
59
|
thread_safe (0.3.6)
|
60
|
+
tty-color (0.5.2)
|
56
61
|
tzinfo (1.2.7)
|
57
62
|
thread_safe (~> 0.1)
|
58
|
-
zeitwerk (2.
|
63
|
+
zeitwerk (2.4.0)
|
59
64
|
|
60
65
|
PLATFORMS
|
61
66
|
ruby
|
data/README.md
CHANGED
@@ -8,172 +8,118 @@
|
|
8
8
|
|
9
9
|
|
10
10
|
## Introduction
|
11
|
-
|
11
|
+
As the name states, `TappingDevice` allows you to secretly listen to different events of an object:
|
12
12
|
|
13
|
-
|
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
|
14
16
|
|
15
|
-
|
17
|
+
After collecting the events, `TappingDevice` will output them in a nice, readable format to either stdout or a file.
|
16
18
|
|
17
|
-
|
18
|
-
- `print_traces(object)` to see how the object interacts with other objects (like used as an argument)
|
19
|
-
- `print_mutations(object)` to see what actions changed the object's state (instance variables)
|
19
|
+
**Ultimately, its goal is to let you know all the information you need for debugging with just 1 line of code.**
|
20
20
|
|
21
|
-
|
21
|
+
## Usages
|
22
22
|
|
23
|
-
###
|
23
|
+
### Track Method Calls
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
```ruby
|
28
|
-
def create
|
29
|
-
@manager_params = create_params
|
30
|
-
@manager_params[:first_post_checks] = !is_api?
|
31
|
-
|
32
|
-
manager = NewPostManager.new(current_user, @manager_params)
|
33
|
-
|
34
|
-
if is_api?
|
35
|
-
memoized_payload = DistributedMemoizer.memoize(signature_for(@manager_params), 120) do
|
36
|
-
result = manager.perform
|
37
|
-
MultiJson.dump(serialize_data(result, NewPostResultSerializer, root: false))
|
38
|
-
end
|
39
|
-
|
40
|
-
parsed_payload = JSON.parse(memoized_payload)
|
41
|
-
backwards_compatible_json(parsed_payload, parsed_payload['success'])
|
42
|
-
else
|
43
|
-
result = manager.perform
|
44
|
-
json = serialize_data(result, NewPostResultSerializer, root: false)
|
45
|
-
backwards_compatible_json(json, result.success?)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
```
|
49
|
-
|
50
|
-
As you can see, it doesn't even exist in the controller action, which makes tracking it by reading code very hard to do.
|
51
|
-
|
52
|
-
But with `TappingDevice`. You can use `print_calls` to show what method calls the object performs
|
53
|
-
|
54
|
-
```ruby
|
55
|
-
def create
|
56
|
-
# you can retrieve the current guardian object by calling guardian in the controller
|
57
|
-
print_calls(guardian)
|
58
|
-
@manager_params = create_params
|
59
|
-
|
60
|
-
# .....
|
61
|
-
```
|
62
|
-
|
63
|
-
Now, if you execute the code, like via tests:
|
64
|
-
|
65
|
-
```shell
|
66
|
-
$ rspec spec/requests/posts_controller_spec.rb:603
|
67
|
-
```
|
68
|
-
|
69
|
-
You can get all the method calls it performs with basically everything you need to know
|
25
|
+
By tracking an object's method calls, you'll be able to observe the object's behavior very easily
|
70
26
|
|
71
27
|
<img src="https://github.com/st0012/tapping_device/blob/master/images/print_calls.png" alt="image of print_calls output" width="50%">
|
72
28
|
|
73
|
-
|
74
|
-
- method name
|
75
|
-
-
|
29
|
+
Each entry consists of 5 pieces of information:
|
30
|
+
- method name
|
31
|
+
- source of the method
|
76
32
|
- call site
|
77
33
|
- arguments
|
78
34
|
- return value
|
79
35
|
|
80
36
|

|
81
37
|
|
82
|
-
|
38
|
+
#### Helpers
|
83
39
|
|
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
|
84
43
|
|
85
|
-
|
44
|
+
#### Use Cases
|
45
|
+
- Understand a service object/form object's behavior
|
46
|
+
- Debug a messy controller
|
86
47
|
|
87
|
-
|
48
|
+
### Track Traces
|
88
49
|
|
89
|
-
|
90
|
-
def create
|
91
|
-
@manager_params = create_params
|
92
|
-
@manager_params[:first_post_checks] = !is_api?
|
93
|
-
|
94
|
-
manager = NewPostManager.new(current_user, @manager_params)
|
95
|
-
|
96
|
-
print_traces(manager)
|
97
|
-
# .....
|
98
|
-
```
|
50
|
+
By tracking an object's traces, you'll be able to observe the object's journey in your application
|
99
51
|
|
100
|
-
|
52
|
+

|
101
53
|
|
102
|
-
|
103
|
-
$ rspec spec/requests/posts_controller_spec.rb:603
|
104
|
-
```
|
54
|
+
#### Helpers
|
105
55
|
|
106
|
-
|
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
|
107
59
|
|
108
|
-
|
60
|
+
#### Use Cases
|
61
|
+
- Debug argument related issues
|
62
|
+
- Understand how a library uses your objects
|
109
63
|
|
110
|
-
###
|
64
|
+
### Track State Mutations
|
111
65
|
|
112
|
-
|
66
|
+
By tracking an object's traces, you'll be able to observe the state changes happen inside the object between each method call
|
113
67
|
|
114
|
-
|
68
|
+
<img src="https://github.com/st0012/tapping_device/blob/master/images/print_mutations.png" alt="image of print_mutations output" width="50%">
|
115
69
|
|
116
|
-
|
117
|
-
# app/controllers/posts_controller.rb
|
118
|
-
class PostsController
|
119
|
-
def update
|
120
|
-
# ......
|
121
|
-
revisor = PostRevisor.new(post, topic)
|
122
|
-
revisor.revise!(current_user, changes, opts)
|
123
|
-
# ......
|
124
|
-
end
|
125
|
-
end
|
126
|
-
```
|
70
|
+
#### Helpers
|
127
71
|
|
128
|
-
|
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
|
129
75
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
@editor = editor
|
134
|
-
@fields = fields.with_indifferent_access
|
135
|
-
@opts = opts
|
76
|
+
#### Use Cases
|
77
|
+
- Debug state related issues
|
78
|
+
- Debug memoization issues
|
136
79
|
|
137
|
-
|
138
|
-
|
139
|
-
# ......
|
80
|
+
### Track All Instances Of A Class
|
140
81
|
|
141
|
-
|
142
|
-
@last_version_at = @post.last_version_at || Time.now
|
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:
|
143
83
|
|
144
|
-
|
145
|
-
|
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)`
|
146
90
|
|
147
|
-
@validate_post = true
|
148
|
-
# ......
|
149
|
-
end
|
150
|
-
```
|
151
91
|
|
152
|
-
|
92
|
+
### Use `with_HELPER_NAME` for chained method calls
|
153
93
|
|
154
|
-
|
94
|
+
In Ruby programs, we often chain multiple methods together like this:
|
155
95
|
|
156
96
|
```ruby
|
157
|
-
|
158
|
-
class PostsController
|
159
|
-
def update
|
160
|
-
# ......
|
161
|
-
revisor = PostRevisor.new(post, topic)
|
162
|
-
print_mutations(revisor)
|
163
|
-
revisor.revise!(current_user, changes, opts)
|
164
|
-
# ......
|
165
|
-
end
|
166
|
-
end
|
97
|
+
SomeService.new(params).perform
|
167
98
|
```
|
168
99
|
|
169
|
-
And
|
100
|
+
And to debug it, we'll need to break the method chain into
|
170
101
|
|
171
|
-
|
102
|
+
```ruby
|
103
|
+
service = SomeService.new(params)
|
104
|
+
print_calls(service, options)
|
105
|
+
service.perform
|
106
|
+
```
|
107
|
+
|
108
|
+
This kind of code changes are usually annoying, and that's one of the problems I want to solve with `TappingDevice`.
|
172
109
|
|
173
|
-
|
110
|
+
So here's another option, just insert a `with_HELPER_NAME` call in between:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
SomeService.new(params).with_print_calls(options).perform
|
114
|
+
```
|
174
115
|
|
175
|
-
|
116
|
+
And it'll behave exactly like
|
176
117
|
|
118
|
+
```ruby
|
119
|
+
service = SomeService.new(params)
|
120
|
+
print_calls(service, options)
|
121
|
+
service.perform
|
122
|
+
```
|
177
123
|
|
178
124
|
## Installation
|
179
125
|
Add this line to your application's Gemfile:
|
@@ -197,9 +143,9 @@ $ gem install tapping_device
|
|
197
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**
|
198
144
|
|
199
145
|
|
200
|
-
|
146
|
+
## Advance Usages & Options
|
201
147
|
|
202
|
-
|
148
|
+
### Add Conditions With `.with`
|
203
149
|
|
204
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.
|
205
151
|
|
@@ -210,7 +156,29 @@ print_calls(object).with do |payload|
|
|
210
156
|
end
|
211
157
|
```
|
212
158
|
|
213
|
-
|
159
|
+
### Options
|
160
|
+
|
161
|
+
There are many options you can pass when using a helper method. You can list all available options and their default value with
|
162
|
+
|
163
|
+
```ruby
|
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
|
+
}
|
175
|
+
```
|
176
|
+
|
177
|
+
Here are some commonly used options:
|
178
|
+
|
179
|
+
#### `colorize: false`
|
180
|
+
|
181
|
+
- default: `true`
|
214
182
|
|
215
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.
|
216
184
|
|
@@ -220,7 +188,9 @@ print_calls(object, colorize: false)
|
|
220
188
|
```
|
221
189
|
|
222
190
|
|
223
|
-
#### `inspect: true`
|
191
|
+
#### `inspect: true`
|
192
|
+
|
193
|
+
- default: `false`
|
224
194
|
|
225
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:
|
226
196
|
|
@@ -229,6 +199,87 @@ post.to_s #=> #<Post:0x00007f89a55201d0>
|
|
229
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>
|
230
200
|
```
|
231
201
|
|
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
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
def name=(val)
|
213
|
+
@name = val
|
214
|
+
end
|
215
|
+
```
|
216
|
+
|
217
|
+
for
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
attr_writer :name
|
221
|
+
```
|
222
|
+
|
223
|
+
This hack will only be applied to the target instance with `instance_eval`. So other instances of the class remain untouched.
|
224
|
+
|
225
|
+
The default is `false` because
|
226
|
+
|
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.
|
229
|
+
|
230
|
+
|
231
|
+
#### `ignore_private`
|
232
|
+
|
233
|
+
Sometimes we use many private methods to perform trivial operations, like
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
class Operation
|
237
|
+
def extras
|
238
|
+
dig_attribute("extras")
|
239
|
+
end
|
240
|
+
|
241
|
+
private
|
242
|
+
|
243
|
+
def data
|
244
|
+
@data
|
245
|
+
end
|
246
|
+
|
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
|
254
|
+
|
255
|
+
```ruby
|
256
|
+
operation = Operation.new(params)
|
257
|
+
print_calls(operation, ignore_private: true) #=> only prints the `extras` call
|
258
|
+
```
|
259
|
+
|
260
|
+
#### `only_private`
|
261
|
+
|
262
|
+
This option does the opposite of the `ignore_private` option does.
|
263
|
+
|
264
|
+
|
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
|
+
```
|
273
|
+
|
274
|
+
And if you're using Rails, you can put the configs under `config/initializers/tapping_device.rb` like this:
|
275
|
+
|
276
|
+
```ruby
|
277
|
+
if defined?(TappingDevice)
|
278
|
+
TappingDevice.config[:colorize] = false
|
279
|
+
TappingDevice.config[:hijack_attr_methods] = true
|
280
|
+
end
|
281
|
+
```
|
282
|
+
|
232
283
|
|
233
284
|
### Lower-Level Helpers
|
234
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)
|