im-lost 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +36 -29
- data/examples/foo.rb +29 -22
- data/examples/kernel_calls.rb +0 -1
- data/lib/im-lost/version.rb +1 -1
- data/lib/im-lost.rb +233 -136
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38b1a5b729438621357238f12f64f1d397ee56e18174c2cc1ec60067dd0ab15e
|
4
|
+
data.tar.gz: 157e15bcf3c9e9539467347e9cac31b5ed40adf9953bc6ab28dab6d163907288
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ad0cc365f318ef0113d6f099618204b11ecd547a84d525893cc2691a59a5159594c8606de34bad9268867751708cf98f03102a1b0feefbab6cefa41c2436449
|
7
|
+
data.tar.gz: eb0a3abf3fffc2273593741c880c9aa5b4461d2b14877e324834216327d9ec427a80eaf2b075381df601b920477b50c8b95190c34ae9cc73fb3d1b25407aa4a1
|
data/README.md
CHANGED
@@ -22,13 +22,13 @@ end
|
|
22
22
|
|
23
23
|
# output will look like
|
24
24
|
# > IO#<<(?)
|
25
|
-
# /
|
25
|
+
# /examples/test.rb:1
|
26
26
|
# > IO#write(*)
|
27
|
-
# /
|
27
|
+
# /examples/test.rb:1
|
28
28
|
# > IO#puts(*)
|
29
|
-
# /
|
29
|
+
# /examples/test.rb:2
|
30
30
|
# > IO#write(*)
|
31
|
-
# /
|
31
|
+
# /examples/test.rb:2
|
32
32
|
```
|
33
33
|
|
34
34
|
When you need to know if exceptions are raised and handled you can use `ImLost.trace_exceptions`:
|
@@ -42,11 +42,11 @@ end
|
|
42
42
|
|
43
43
|
# output will look like
|
44
44
|
# x Errno::EEXIST: File exists @ rb_sysopen - /
|
45
|
-
# /
|
45
|
+
# /examples/test.rb:2
|
46
46
|
# ! Errno::EEXIST: File exists @ rb_sysopen - /
|
47
|
-
# /
|
47
|
+
# /examples/test.rb:3
|
48
48
|
# x RuntimeError: something went wrong!
|
49
|
-
# /
|
49
|
+
# /examples/test.rb:4
|
50
50
|
```
|
51
51
|
|
52
52
|
When you like to know if a code point is reached, `ImLost.here` will help:
|
@@ -94,7 +94,6 @@ class Foo
|
|
94
94
|
def bar = :bar
|
95
95
|
end
|
96
96
|
|
97
|
-
ImLost.trace_results = true
|
98
97
|
ImLost.trace(Foo)
|
99
98
|
|
100
99
|
my_foo = Foo.create(value: :foo!)
|
@@ -111,47 +110,55 @@ ImLost.vars(my_foo)
|
|
111
110
|
|
112
111
|
# output will look like
|
113
112
|
# > Foo.create(:foo!)
|
114
|
-
# /
|
113
|
+
# /examples/foo.rb:24
|
115
114
|
# > Foo.new(*)
|
116
|
-
# /
|
115
|
+
# /examples/foo.rb:6
|
117
116
|
# < Foo.new(*)
|
118
|
-
#
|
117
|
+
# /examples/foo.rb:6
|
118
|
+
# = #<Foo:0x00000001006448c0 @value=:foo!>
|
119
119
|
# < Foo.create(:foo!)
|
120
|
-
#
|
120
|
+
# /examples/foo.rb:24
|
121
|
+
# = #<Foo:0x00000001006448c0 @value=:foo!>
|
121
122
|
# > Foo#foo(1, *[], :none, **{}, &nil)
|
122
|
-
# /
|
123
|
+
# /examples/foo.rb:27
|
123
124
|
# > Foo#bar()
|
124
|
-
# /
|
125
|
+
# /examples/foo.rb:15
|
125
126
|
# < Foo#bar()
|
127
|
+
# /examples/foo.rb:15
|
126
128
|
# = :bar
|
127
129
|
# < Foo#foo(1, *[], :none, **{}, &nil)
|
130
|
+
# /examples/foo.rb:27
|
128
131
|
# = "1-none-[]-{}-bar"
|
129
|
-
#
|
130
|
-
# instance variables
|
131
|
-
#
|
132
|
+
# * /examples/foo.rb:28
|
133
|
+
# > instance variables
|
134
|
+
# @value: "1-none-[]-{}-bar"
|
132
135
|
# > Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
|
133
|
-
# /
|
136
|
+
# /examples/foo.rb:30
|
134
137
|
# > Foo#bar()
|
135
|
-
# /
|
138
|
+
# /examples/foo.rb:15
|
136
139
|
# < Foo#bar()
|
140
|
+
# /examples/foo.rb:15
|
137
141
|
# = :bar
|
138
142
|
# < Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
|
143
|
+
# /examples/foo.rb:30
|
139
144
|
# = "2-some-[a,b,c]-{:name=>:value}-bar"
|
140
|
-
#
|
141
|
-
# instance variables
|
142
|
-
#
|
143
|
-
# > Foo#foo(3, *[], nil, **{}, &#<Proc:
|
144
|
-
# /
|
145
|
+
# * /examples/foo.rb:31
|
146
|
+
# > instance variables
|
147
|
+
# @value: "2-some-[a,b,c]-{:name=>:value}-bar"
|
148
|
+
# > Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100641d28 /examples/foo.rb:33>)
|
149
|
+
# /examples/foo.rb:33
|
145
150
|
# > Foo#bar()
|
146
|
-
# /
|
151
|
+
# /examples/foo.rb:15
|
147
152
|
# < Foo#bar()
|
153
|
+
# /examples/foo.rb:15
|
148
154
|
# = :bar
|
149
155
|
# 3--[]-{}-bar
|
150
|
-
# < Foo#foo(3, *[], nil, **{}, &#<Proc:
|
156
|
+
# < Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100641d28 /examples/foo.rb:33>)
|
157
|
+
# /examples/foo.rb:33
|
151
158
|
# = nil
|
152
|
-
#
|
153
|
-
# instance variables
|
154
|
-
#
|
159
|
+
# * /examples/foo.rb:34
|
160
|
+
# > instance variables
|
161
|
+
# @value: "3--[]-{}-bar"
|
155
162
|
```
|
156
163
|
|
157
164
|
See [examples dir](./examples) for more…
|
data/examples/foo.rb
CHANGED
@@ -19,7 +19,6 @@ class Foo
|
|
19
19
|
def bar = :bar
|
20
20
|
end
|
21
21
|
|
22
|
-
ImLost.trace_results = true
|
23
22
|
ImLost.trace(Foo)
|
24
23
|
|
25
24
|
my_foo = Foo.create(value: :foo!)
|
@@ -36,44 +35,52 @@ ImLost.vars(my_foo)
|
|
36
35
|
|
37
36
|
# output will look like
|
38
37
|
# > Foo.create(:foo!)
|
39
|
-
# /
|
38
|
+
# /examples/foo.rb:24
|
40
39
|
# > Foo.new(*)
|
41
|
-
# /
|
40
|
+
# /examples/foo.rb:6
|
42
41
|
# < Foo.new(*)
|
43
|
-
#
|
42
|
+
# /examples/foo.rb:6
|
43
|
+
# = #<Foo:0x00000001006448c0 @value=:foo!>
|
44
44
|
# < Foo.create(:foo!)
|
45
|
-
#
|
45
|
+
# /examples/foo.rb:24
|
46
|
+
# = #<Foo:0x00000001006448c0 @value=:foo!>
|
46
47
|
# > Foo#foo(1, *[], :none, **{}, &nil)
|
47
|
-
# /
|
48
|
+
# /examples/foo.rb:27
|
48
49
|
# > Foo#bar()
|
49
|
-
# /
|
50
|
+
# /examples/foo.rb:15
|
50
51
|
# < Foo#bar()
|
52
|
+
# /examples/foo.rb:15
|
51
53
|
# = :bar
|
52
54
|
# < Foo#foo(1, *[], :none, **{}, &nil)
|
55
|
+
# /examples/foo.rb:27
|
53
56
|
# = "1-none-[]-{}-bar"
|
54
|
-
#
|
55
|
-
# instance variables
|
56
|
-
#
|
57
|
+
# * /examples/foo.rb:28
|
58
|
+
# > instance variables
|
59
|
+
# @value: "1-none-[]-{}-bar"
|
57
60
|
# > Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
|
58
|
-
# /
|
61
|
+
# /examples/foo.rb:30
|
59
62
|
# > Foo#bar()
|
60
|
-
# /
|
63
|
+
# /examples/foo.rb:15
|
61
64
|
# < Foo#bar()
|
65
|
+
# /examples/foo.rb:15
|
62
66
|
# = :bar
|
63
67
|
# < Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
|
68
|
+
# /examples/foo.rb:30
|
64
69
|
# = "2-some-[a,b,c]-{:name=>:value}-bar"
|
65
|
-
#
|
66
|
-
# instance variables
|
67
|
-
#
|
68
|
-
# > Foo#foo(3, *[], nil, **{}, &#<Proc:
|
69
|
-
# /
|
70
|
+
# * /examples/foo.rb:31
|
71
|
+
# > instance variables
|
72
|
+
# @value: "2-some-[a,b,c]-{:name=>:value}-bar"
|
73
|
+
# > Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100641d28 /examples/foo.rb:33>)
|
74
|
+
# /examples/foo.rb:33
|
70
75
|
# > Foo#bar()
|
71
|
-
# /
|
76
|
+
# /examples/foo.rb:15
|
72
77
|
# < Foo#bar()
|
78
|
+
# /examples/foo.rb:15
|
73
79
|
# = :bar
|
74
80
|
# 3--[]-{}-bar
|
75
|
-
# < Foo#foo(3, *[], nil, **{}, &#<Proc:
|
81
|
+
# < Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100641d28 /examples/foo.rb:33>)
|
82
|
+
# /examples/foo.rb:33
|
76
83
|
# = nil
|
77
|
-
#
|
78
|
-
# instance variables
|
79
|
-
#
|
84
|
+
# * /examples/foo.rb:34
|
85
|
+
# > instance variables
|
86
|
+
# @value: "3--[]-{}-bar"
|
data/examples/kernel_calls.rb
CHANGED
data/lib/im-lost/version.rb
CHANGED
data/lib/im-lost.rb
CHANGED
@@ -26,9 +26,10 @@ module ImLost
|
|
26
26
|
|
27
27
|
#
|
28
28
|
# The output device used to write information.
|
29
|
-
# This should be an `IO` device or any other object responding to
|
29
|
+
# This should be an `IO` device or any other object responding to `#<<`
|
30
|
+
# like a Logger.
|
30
31
|
#
|
31
|
-
#
|
32
|
+
# `STDERR` is configured by default.
|
32
33
|
#
|
33
34
|
# @example Write to a file
|
34
35
|
# ImLost.output = File.new('./trace', 'w')
|
@@ -50,8 +51,13 @@ module ImLost
|
|
50
51
|
attr_reader :output
|
51
52
|
|
52
53
|
def output=(value)
|
53
|
-
return @output = value if
|
54
|
-
raise(
|
54
|
+
return @output = value if defined?(value.<<)
|
55
|
+
raise(
|
56
|
+
NoMethodError,
|
57
|
+
"undefined method `<<' for an instance of #{
|
58
|
+
Kernel.instance_method(:class).bind(value).call
|
59
|
+
}"
|
60
|
+
)
|
55
61
|
end
|
56
62
|
|
57
63
|
#
|
@@ -89,11 +95,11 @@ module ImLost
|
|
89
95
|
#
|
90
96
|
# # output will look like
|
91
97
|
# # x Errno::EEXIST: File exists @ rb_sysopen - /
|
92
|
-
# #
|
98
|
+
# # /examples/test.rb:2
|
93
99
|
# # ! Errno::EEXIST: File exists @ rb_sysopen - /
|
94
|
-
# #
|
100
|
+
# # /examples/test.rb:3
|
95
101
|
# # x RuntimeError: something went wrong!
|
96
|
-
# #
|
102
|
+
# # /examples/test.rb:4
|
97
103
|
#
|
98
104
|
# @param with_locations [Boolean] wheter the locations should be included
|
99
105
|
# into the exception trace information
|
@@ -113,7 +119,7 @@ module ImLost
|
|
113
119
|
|
114
120
|
#
|
115
121
|
# Enables/disables tracing of returned valuess of method calls.
|
116
|
-
# This is
|
122
|
+
# This is enabled by default.
|
117
123
|
#
|
118
124
|
# @attribute [r] trace_results
|
119
125
|
# @return [Boolean] whether return values will be traced
|
@@ -131,33 +137,33 @@ module ImLost
|
|
131
137
|
#
|
132
138
|
# Print the call location conditionally.
|
133
139
|
#
|
134
|
-
# @example
|
140
|
+
# @example Print current location
|
135
141
|
# ImLost.here
|
136
142
|
#
|
137
|
-
# @example
|
143
|
+
# @example Print current location when instance variable is empty
|
138
144
|
# ImLost.here(@name.empty?)
|
139
145
|
#
|
140
|
-
# @example
|
146
|
+
# @example Print current location when instance variable is nil or empty
|
141
147
|
# ImLost.here { @name.nil? || @name.empty? }
|
142
148
|
#
|
143
149
|
# @overload here
|
144
|
-
# Prints the
|
150
|
+
# Prints the call location.
|
145
151
|
# @return [true]
|
146
152
|
#
|
147
153
|
# @overload here(test)
|
148
|
-
# Prints the
|
154
|
+
# Prints the call location when given argument is truthy.
|
149
155
|
# @param test [Object]
|
150
156
|
# @return [Object] test
|
151
157
|
#
|
152
158
|
# @overload here
|
153
|
-
# Prints the
|
159
|
+
# Prints the call location when given block returns a truthy result.
|
154
160
|
# @yield When the block returns a truthy result the location will be print
|
155
161
|
# @yieldreturn [Object] return result
|
156
162
|
#
|
157
163
|
def here(test = true)
|
158
164
|
return test if !test || (block_given? && !(test = yield))
|
159
165
|
loc = Kernel.caller_locations(1, 1)[0]
|
160
|
-
@output
|
166
|
+
@output << "* #{loc.path}:#{loc.lineno}\n"
|
161
167
|
test
|
162
168
|
end
|
163
169
|
|
@@ -166,12 +172,12 @@ module ImLost
|
|
166
172
|
#
|
167
173
|
# The given arguments can be any object instance or module or class.
|
168
174
|
#
|
169
|
-
# @example
|
175
|
+
# @example Trace method calls of an instance variable for a while
|
170
176
|
# ImLost.trace(@file)
|
171
177
|
# # ...
|
172
178
|
# ImLost.untrace(@file)
|
173
179
|
#
|
174
|
-
# @example
|
180
|
+
# @example Temporary trace method calls
|
175
181
|
# File.open('test.txt', 'w') do |file|
|
176
182
|
# ImLost.trace(file) do
|
177
183
|
# file << 'hello '
|
@@ -181,17 +187,17 @@ module ImLost
|
|
181
187
|
#
|
182
188
|
# # output will look like
|
183
189
|
# # > IO#<<(?)
|
184
|
-
# # /
|
190
|
+
# # /examples/test.rb:1
|
185
191
|
# # > IO#write(*)
|
186
|
-
# # /
|
192
|
+
# # /examples/test.rb:1
|
187
193
|
# # > IO#puts(*)
|
188
|
-
# # /
|
194
|
+
# # /examples/test.rb:2
|
189
195
|
# # > IO#write(*)
|
190
|
-
# # /
|
196
|
+
# # /examples/test.rb:2
|
191
197
|
#
|
192
198
|
# @overload trace(*args)
|
193
199
|
# @param args [[Object]] one or more objects to be traced
|
194
|
-
# @return [
|
200
|
+
# @return [Array<Object>] the traced object(s)
|
195
201
|
# Start tracing the given objects.
|
196
202
|
# @see untrace
|
197
203
|
# @see untrace_all!
|
@@ -209,30 +215,37 @@ module ImLost
|
|
209
215
|
args.size == 1 ? _trace_b(args[0], &block) : _trace_all_b(args, &block)
|
210
216
|
end
|
211
217
|
|
218
|
+
#
|
219
|
+
# Test if a given object is currently traced.
|
220
|
+
#
|
221
|
+
# @param arg [Object] object to be tested
|
222
|
+
# @return [Boolean] wheter the object is beeing traced
|
223
|
+
#
|
224
|
+
def traced?(obj) = @trace.key?(obj)
|
225
|
+
|
212
226
|
#
|
213
227
|
# Stop tracing objects.
|
214
228
|
#
|
215
|
-
# @example
|
216
|
-
#
|
229
|
+
# @example Trace some objects for some code lines
|
230
|
+
# traced_obj = ImLost.trace(@file, @client)
|
217
231
|
# # ...
|
218
|
-
# ImLost.untrace(*
|
232
|
+
# ImLost.untrace(*traced_obj)
|
219
233
|
#
|
220
234
|
# @see trace
|
221
235
|
#
|
222
|
-
# @param args [[Object]] one or more objects which should not longer be
|
236
|
+
# @param args [[]Object]] one or more objects which should not longer be
|
223
237
|
# traced
|
224
|
-
# @return [
|
238
|
+
# @return [Array<Object>] the object(s) which are not longer be traced
|
225
239
|
# @return [nil] when none of the objects was traced before
|
226
240
|
#
|
227
241
|
def untrace(*args)
|
228
|
-
|
229
|
-
args.size
|
242
|
+
args = args.filter_map { @trace.delete(_1) }
|
243
|
+
args.size < 2 ? args[0] : args
|
230
244
|
end
|
231
245
|
|
232
246
|
#
|
233
|
-
# Stop tracing any object.
|
234
|
-
#
|
235
|
-
# objects.)
|
247
|
+
# Stop tracing any object. When you are really lost and just like to stop
|
248
|
+
# tracing of all your objects.
|
236
249
|
#
|
237
250
|
# @see trace
|
238
251
|
#
|
@@ -244,101 +257,147 @@ module ImLost
|
|
244
257
|
end
|
245
258
|
|
246
259
|
#
|
247
|
-
# Inspect internal variables.
|
260
|
+
# Inspect internal variables of a given object.
|
261
|
+
#
|
262
|
+
# @note The dedictaed handling of `Fiber` is platform dependend!
|
263
|
+
#
|
264
|
+
# @example Inspect current instance variables
|
265
|
+
# @a = 22
|
266
|
+
# b = 20
|
267
|
+
# c = @a + b
|
268
|
+
# ImLost.vars(self)
|
269
|
+
# # => print value of `@a`
|
270
|
+
#
|
271
|
+
# @example Inspect local variables
|
272
|
+
# @a = 22
|
273
|
+
# b = 20
|
274
|
+
# c = @a + b
|
275
|
+
# ImLost.vars(binding)
|
276
|
+
# # => print values of `b` and 'c'
|
277
|
+
#
|
278
|
+
# @example Inspect a thread's variables
|
279
|
+
# th = Thread.new { th[:var1] += 20 }
|
280
|
+
# th[:var1] = 22
|
281
|
+
# ImLost.vars(th)
|
282
|
+
# # => print value of `var1`
|
283
|
+
# th.join
|
284
|
+
# ImLost.vars(th)
|
285
|
+
#
|
286
|
+
# @example Inspect the current fiber's storage
|
287
|
+
# Fiber[:var1] = 22
|
288
|
+
# Fiber[:var2] = 20
|
289
|
+
# Fiber[:var3] = Fiber[:var1] + Fiber[:var2]
|
290
|
+
# ImLost.vars(Fiber.current)
|
291
|
+
#
|
292
|
+
# When the given object is
|
293
|
+
#
|
294
|
+
# - a `Binding` it prints the local variables of the binding
|
295
|
+
# - a `Thread` it prints the fiber-local and thread variables
|
296
|
+
# - the current `Fiber` it prints the fibers' storage
|
248
297
|
#
|
249
|
-
#
|
250
|
-
# Inspect local variables of given Binding.
|
251
|
-
# @param binding [Binding] which local variables should be print
|
252
|
-
# @return [self] itself
|
298
|
+
# Be aware that only the current fiber can be inspected.
|
253
299
|
#
|
254
|
-
#
|
255
|
-
#
|
256
|
-
#
|
257
|
-
#
|
300
|
+
# When the given object can not be inspected it prints an error message.
|
301
|
+
#
|
302
|
+
# @param object [Object] which instance variables should be print
|
303
|
+
# @return [Object] the given object
|
258
304
|
#
|
259
305
|
def vars(object)
|
260
|
-
|
261
|
-
|
262
|
-
return
|
263
|
-
|
306
|
+
out = Out.new
|
307
|
+
traced = @trace.delete(object)
|
308
|
+
return _local_vars(out, object) if Binding === object
|
309
|
+
location = Kernel.caller_locations(1, 1)[0]
|
310
|
+
out << "* #{location.path}:#{location.lineno}"
|
311
|
+
return _thread_vars(out, object) if Thread === object
|
312
|
+
return _fiber_vars(out, object) if @fiber_supported && Fiber === object
|
313
|
+
return _instance_vars(out, object) if defined?(object.instance_variables)
|
314
|
+
out << ' !!! unable to retrieve vars'
|
315
|
+
object
|
264
316
|
ensure
|
265
317
|
@trace[traced] = traced if traced
|
318
|
+
out.flush(@output)
|
266
319
|
end
|
267
320
|
|
268
321
|
private
|
269
322
|
|
270
|
-
def
|
271
|
-
|
272
|
-
case info.self
|
273
|
-
when Class, Module
|
274
|
-
"#{prefix} #{info.self}.#{info.method_id}(#{args})"
|
275
|
-
else
|
276
|
-
"#{prefix} #{info.defined_class}##{info.method_id}(#{args})"
|
277
|
-
end
|
323
|
+
def _can_trace?(arg)
|
324
|
+
(id = arg.__id__) != __id__ && id != @output.__id__
|
278
325
|
end
|
279
326
|
|
280
327
|
def _trace(arg)
|
281
|
-
|
282
|
-
@trace[id] = id if __id__ != id && @output.__id__ != id
|
328
|
+
@trace[arg] = arg if _can_trace?(arg)
|
283
329
|
arg
|
284
330
|
end
|
285
331
|
|
286
332
|
def _trace_all(args)
|
287
|
-
args.each
|
288
|
-
arg = arg.__id__
|
289
|
-
@trace[arg] = arg if __id__ != arg && @output.__id__ != arg
|
290
|
-
end
|
333
|
+
args.each { |arg| @trace[arg] = arg if _can_trace?(arg) }
|
291
334
|
args
|
292
335
|
end
|
293
336
|
|
294
337
|
def _trace_b(arg)
|
295
|
-
|
296
|
-
return yield(arg) if __id__ == id || @output.__id__ == id
|
338
|
+
return yield(arg) if @trace.key?(arg) || !_can_trace?(arg)
|
297
339
|
begin
|
298
|
-
@trace[
|
340
|
+
@trace[arg] = arg
|
299
341
|
yield(arg)
|
300
342
|
ensure
|
301
|
-
@trace.delete(
|
343
|
+
@trace.delete(arg)
|
302
344
|
end
|
303
345
|
end
|
304
346
|
|
305
347
|
def _trace_all_b(args)
|
306
|
-
|
348
|
+
temp =
|
307
349
|
args.filter_map do |arg|
|
308
|
-
arg = arg.
|
309
|
-
@trace[arg] = arg if __id__ != arg && @output.__id__ != arg
|
350
|
+
@trace[arg] = arg if !@trace.key?(arg) && _can_trace?(arg)
|
310
351
|
end
|
311
352
|
yield(args)
|
312
353
|
ensure
|
313
|
-
|
354
|
+
temp.each { @trace.delete(_1) }
|
314
355
|
end
|
315
356
|
|
316
|
-
def
|
317
|
-
|
318
|
-
vars
|
319
|
-
|
320
|
-
@output.puts(' <no instance variables defined>')
|
321
|
-
return obj
|
357
|
+
def _local_vars(out, binding)
|
358
|
+
out << "* #{binding.source_location.join(':')}"
|
359
|
+
out.vars('local variables', binding.local_variables) do |name|
|
360
|
+
binding.local_variable_get(name)
|
322
361
|
end
|
323
|
-
|
324
|
-
|
325
|
-
|
362
|
+
binding
|
363
|
+
end
|
364
|
+
|
365
|
+
def _thread_vars(out, thread)
|
366
|
+
out << " #{_thread_identifier(thread)}"
|
367
|
+
flv = thread.keys
|
368
|
+
out.vars('fiber-local variables', flv) { thread[_1] } unless flv.empty?
|
369
|
+
out.vars('thread variables', thread.thread_variables) do |name|
|
370
|
+
thread.thread_variable_get(name)
|
326
371
|
end
|
327
|
-
|
372
|
+
thread
|
328
373
|
end
|
329
374
|
|
330
|
-
def
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
375
|
+
def _fiber_vars(out, fiber)
|
376
|
+
if Fiber.current == fiber
|
377
|
+
storage = fiber.storage || {}
|
378
|
+
out.vars('fiber storage', storage.keys) { storage[_1] }
|
379
|
+
else
|
380
|
+
out << ' !!! given Fiber is not the current Fiber' <<
|
381
|
+
" #{fiber.inspect}"
|
336
382
|
end
|
337
|
-
|
338
|
-
|
339
|
-
|
383
|
+
fiber
|
384
|
+
end
|
385
|
+
|
386
|
+
def _instance_vars(out, object)
|
387
|
+
out.vars('instance variables', object.instance_variables) do |n|
|
388
|
+
object.instance_variable_get(n)
|
340
389
|
end
|
341
|
-
|
390
|
+
object
|
391
|
+
end
|
392
|
+
|
393
|
+
def _thread_identifier(thread)
|
394
|
+
"#{THREAD_STATE[thread.status] || thread.status} Thread #{
|
395
|
+
if defined?(thread.native_thread_id)
|
396
|
+
thread.native_thread_id
|
397
|
+
else
|
398
|
+
thread.__id__
|
399
|
+
end
|
400
|
+
} #{thread.name}".rstrip
|
342
401
|
end
|
343
402
|
end
|
344
403
|
|
@@ -365,7 +424,7 @@ module ImLost
|
|
365
424
|
# # the timer with name 'my_test' is not longer valid now
|
366
425
|
#
|
367
426
|
#
|
368
|
-
# @example Use an anonymous timer
|
427
|
+
# @example Use an anonymous timer
|
369
428
|
# tmr = ImLost.timer.create
|
370
429
|
#
|
371
430
|
# # ...your code here...
|
@@ -440,7 +499,7 @@ module ImLost
|
|
440
499
|
end
|
441
500
|
|
442
501
|
#
|
443
|
-
# Print the ID or name and the runtime since timer was created.
|
502
|
+
# Print the ID or name and the runtime since a timer was created.
|
444
503
|
# It includes the location.
|
445
504
|
#
|
446
505
|
# @param id_or_name [Integer, #to_s] the identifier or the name of the timer
|
@@ -476,80 +535,118 @@ module ImLost
|
|
476
535
|
end
|
477
536
|
end
|
478
537
|
|
538
|
+
class Out
|
539
|
+
def initialize(*lines) = (@lines = lines)
|
540
|
+
def <<(str) = @lines << str
|
541
|
+
def location(loc) = @lines << " #{loc.path}:#{loc.lineno}"
|
542
|
+
def flush(dev) = dev << (@lines << nil).join("\n")
|
543
|
+
|
544
|
+
def sig(prefix, info, args)
|
545
|
+
args = args.join(', ')
|
546
|
+
@lines << case info.self
|
547
|
+
when Class, Module
|
548
|
+
"#{prefix} #{info.self}.#{info.method_id}(#{args})"
|
549
|
+
else
|
550
|
+
"#{prefix} #{info.defined_class}##{info.method_id}(#{args})"
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
def vars(kind, names)
|
555
|
+
return @lines << " <no #{kind} defined>" if names.empty?
|
556
|
+
@lines << " > #{kind}"
|
557
|
+
names.sort!.each { @lines << " #{_1}: #{yield(_1).inspect}" }
|
558
|
+
end
|
559
|
+
end
|
560
|
+
private_constant :Out
|
561
|
+
|
479
562
|
ARG_SIG = { rest: '*', keyrest: '**', block: '&' }.compare_by_identity.freeze
|
480
563
|
NO_NAME = { :* => 1, :** => 1, :& => 1 }.compare_by_identity.freeze
|
481
|
-
|
564
|
+
THREAD_STATE = {
|
565
|
+
false => 'terminated',
|
566
|
+
nil => 'aborted'
|
567
|
+
}.compare_by_identity.freeze
|
568
|
+
private_constant :ARG_SIG, :NO_NAME, :THREAD_STATE
|
482
569
|
|
483
570
|
@trace = {}.compare_by_identity
|
484
|
-
@caller_locations = true
|
485
|
-
@output =
|
486
|
-
|
487
|
-
@timer =
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
" #{location.path}:#{location.lineno}"
|
492
|
-
)
|
493
|
-
end
|
571
|
+
@caller_locations = @exception_locations = true
|
572
|
+
@output = STDERR
|
573
|
+
|
574
|
+
@timer = TimerStore.new { |title, location, time| @output << <<~TIMER_MSG }
|
575
|
+
T #{title}: #{time ? "#{time} sec." : 'created'}
|
576
|
+
#{location.path}:#{location.lineno}
|
577
|
+
TIMER_MSG
|
494
578
|
TimerStore.private_class_method(:new)
|
495
579
|
|
496
580
|
@trace_calls = [
|
497
581
|
TracePoint.new(:c_call) do |tp|
|
498
|
-
next if !@trace.key?(tp.self
|
499
|
-
|
500
|
-
|
582
|
+
next if !@trace.key?(tp.self) || tp.path == __FILE__
|
583
|
+
out = Out.new
|
584
|
+
out.sig('>', tp, tp.parameters.map { ARG_SIG[_1[0]] || '?' })
|
585
|
+
out.location(tp) if @caller_locations
|
586
|
+
out.flush(@output)
|
501
587
|
end,
|
502
588
|
TracePoint.new(:call) do |tp|
|
503
|
-
next if !@trace.key?(tp.self
|
589
|
+
next if !@trace.key?(tp.self) || tp.path == __FILE__
|
504
590
|
ctx = tp.binding
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
)
|
591
|
+
out = Out.new
|
592
|
+
out.sig(
|
593
|
+
'>',
|
594
|
+
tp,
|
595
|
+
tp.parameters.map do |kind, name|
|
596
|
+
next name if NO_NAME.key?(name)
|
597
|
+
"#{ARG_SIG[kind]}#{ctx.local_variable_get(name).inspect}"
|
598
|
+
end
|
514
599
|
)
|
515
|
-
|
516
|
-
|
517
|
-
@output.puts(" #{loc.path}:#{loc.lineno}")
|
600
|
+
out.location(ctx.eval('caller_locations(4,1)')[0]) if @caller_locations
|
601
|
+
out.flush(@output)
|
518
602
|
end
|
519
603
|
]
|
520
604
|
|
521
605
|
@trace_results = [
|
522
606
|
TracePoint.new(:c_return) do |tp|
|
523
|
-
next if !@trace.key?(tp.self
|
524
|
-
|
525
|
-
|
607
|
+
next if !@trace.key?(tp.self) || tp.path == __FILE__
|
608
|
+
out = Out.new
|
609
|
+
out.sig('<', tp, tp.parameters.map { ARG_SIG[_1[0]] || '?' })
|
610
|
+
out.location(tp) if @caller_locations
|
611
|
+
out << " = #{tp.return_value.inspect}"
|
612
|
+
out.flush(@output)
|
526
613
|
end,
|
527
614
|
TracePoint.new(:return) do |tp|
|
528
|
-
next if !@trace.key?(tp.self
|
615
|
+
next if !@trace.key?(tp.self) || tp.path == __FILE__
|
529
616
|
ctx = tp.binding
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
)
|
617
|
+
out = Out.new
|
618
|
+
out.sig(
|
619
|
+
'<',
|
620
|
+
tp,
|
621
|
+
tp.parameters.map do |kind, name|
|
622
|
+
next name if NO_NAME.key?(name)
|
623
|
+
"#{ARG_SIG[kind]}#{ctx.local_variable_get(name).inspect}"
|
624
|
+
end
|
539
625
|
)
|
540
|
-
|
626
|
+
out.location(ctx.eval('caller_locations(4,1)')[0]) if @caller_locations
|
627
|
+
out << " = #{tp.return_value.inspect}"
|
628
|
+
out.flush(@output)
|
541
629
|
end
|
542
630
|
]
|
543
631
|
|
544
632
|
supported = RUBY_VERSION.to_f < 3.3 ? %i[raise] : %i[raise rescue]
|
545
633
|
@trace_exceptions =
|
546
634
|
TracePoint.new(*supported) do |tp|
|
547
|
-
ex = tp.raised_exception
|
548
|
-
|
549
|
-
|
550
|
-
)
|
551
|
-
|
635
|
+
ex = tp.raised_exception
|
636
|
+
mark, parent = tp.event == :rescue ? ['!', ex.cause] : 'x'
|
637
|
+
ex = ex.inspect
|
638
|
+
out = Out.new("#{mark} #{ex[0] == '#' ? ex[2..-2] : ex}")
|
639
|
+
while parent
|
640
|
+
ex = parent.inspect
|
641
|
+
out << " [#{ex[0] == '#' ? ex[2..-2] : ex}]"
|
642
|
+
parent = parent.cause
|
643
|
+
end
|
644
|
+
out.location(tp) if @exception_locations
|
645
|
+
out.flush(@output)
|
552
646
|
end
|
553
647
|
|
554
|
-
|
648
|
+
@fiber_supported =
|
649
|
+
!!(defined?(Fiber.current) && defined?(Fiber.current.storage))
|
650
|
+
|
651
|
+
self.trace_calls = self.trace_results = true
|
555
652
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: im-lost
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Blumtritt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
If you have overlooked something again and don't really understand what
|
@@ -57,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
57
|
- !ruby/object:Gem::Version
|
58
58
|
version: '0'
|
59
59
|
requirements: []
|
60
|
-
rubygems_version: 3.5.
|
60
|
+
rubygems_version: 3.5.13
|
61
61
|
signing_key:
|
62
62
|
specification_version: 4
|
63
63
|
summary: Your debugging helper.
|