im-lost 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 39160aff2b7fa8320ae12c5d035fa40fbf6f96a2fbe0418ddfb31ac700c2bf72
4
+ data.tar.gz: 044bf4b9b4f9288f418b0cc5344cc82d1a88839d08a8ef1b8008d616ef11481c
5
+ SHA512:
6
+ metadata.gz: 5d76261aafb61289cf56c23fb2acb0c0e6a0b8cc834b4e28b72d80cf0f6dfdf7966a8b613c7a0f4e8ee005eae2ba4064fe9aeb7b7520cbd53ce8e99671e33f0f
7
+ data.tar.gz: da598803cf6e2ee4e4baa92f8e702796050f279645daf80fccffa16c2be2eaa314cee7a69742691dde5d798f44f75d610dcb7db71d223a72c0fcabb2e65c7030
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Mike Blumtritt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # ImLost ![version](https://img.shields.io/gem/v/im-lost?label=)
2
+
3
+ If you have overlooked something again and don't really understand what your code is doing. If you have to maintain this application but can't really find your way around and certainly can't track down that stupid error. If you feel lost in all that code, here's the gem to help you out!
4
+
5
+ ImLost helps you by analyzing function calls of objects, informing you about exceptions and logging your way through your code. In short, ImLost is your debugging helper!
6
+
7
+ - Gem: [rubygems.org](https://rubygems.org/gems/im-lost)
8
+ - Source: [github.com](https://github.com/mblumtritt/im-lost)
9
+ - Help: [rubydoc.info](https://rubydoc.info/gems/im-lost/ImLost)
10
+
11
+ ## Description
12
+
13
+ If you like to undertsand method call details you get a call trace with `ImLost.trace`:
14
+
15
+ ```ruby
16
+ File.open('test.txt', 'w') do |file|
17
+ ImLost.trace(file) do
18
+ file << 'hello '
19
+ file.puts(:world!)
20
+ end
21
+ end
22
+ # output will look like
23
+ # > IO#<<(?)
24
+ # /projects/test.rb:1
25
+ # > IO#write(*)
26
+ # /projects/test.rb:1
27
+ # > IO#puts(*)
28
+ # /projects/test.rb:2
29
+ # > IO#write(*)
30
+ # /projects/test.rb:2
31
+ ```
32
+
33
+ When you need to know if exceptions are raised and handled you can use `ImLost.trace_exceptions`:
34
+
35
+ ```ruby
36
+ ImLost.trace_exceptions do
37
+ File.write('/', 'test')
38
+ rescue SystemCallError
39
+ raise('something went wrong!')
40
+ end
41
+ # output will look like
42
+ # x Errno::EEXIST: File exists @ rb_sysopen - /
43
+ # /projects/test.rb:2
44
+ # ! Errno::EEXIST: File exists @ rb_sysopen - /
45
+ # /projects/test.rb:3
46
+ # x RuntimeError: something went wrong!
47
+ # /projects/test.rb:4
48
+ ```
49
+
50
+ When you like to know if and when a code point is reached, `ImLost.here` will help:
51
+
52
+ ```ruby
53
+ ImLost.here
54
+ ```
55
+
56
+ ## Example
57
+
58
+ ```ruby
59
+ require 'im-lost'
60
+
61
+ class Foo
62
+ def self.create(value:) = new(value)
63
+
64
+ attr_reader :value
65
+
66
+ def initialize(value)
67
+ @value = value
68
+ end
69
+
70
+ def foo(arg, *args, key: nil, **kw_args, &block)
71
+ @value = "#{arg}-#{key}-[#{args.join(',')}]-#{kw_args.inspect}-#{bar}"
72
+ block ? block.call(@value) : @value
73
+ end
74
+
75
+ def bar = :bar
76
+ end
77
+
78
+ ImLost.trace_results = true
79
+ ImLost.trace(Foo)
80
+
81
+ my_foo = Foo.create(value: :foo!)
82
+ ImLost.trace(my_foo)
83
+
84
+ my_foo.foo(1, key: :none)
85
+ my_foo.foo(2, :a, :b, :c, key: :some, name: :value)
86
+ my_foo.foo(3) { puts _1 }
87
+
88
+ # output will look like
89
+ # > Foo.create(:foo!)
90
+ # /projects/foo.rb:25
91
+ # > Foo.new(*)
92
+ # /projects/foo.rb:6
93
+ # < Foo.new(*)
94
+ # = #<Foo:0x0000000100902418 @value=:foo!>
95
+ # < Foo.create(:foo!)
96
+ # = #<Foo:0x0000000100902418 @value=:foo!>
97
+ # > Foo#foo(1, *[], :none, **{}, &nil)
98
+ # /projects/foo.rb:28
99
+ # > Foo#bar()
100
+ # /projects/foo.rb:15
101
+ # < Foo#bar()
102
+ # = :bar
103
+ # < Foo#foo(1, *[], :none, **{}, &nil)
104
+ # = "1-none-[]-{}-bar"
105
+ # > Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
106
+ # /projects/foo.rb:29
107
+ # > Foo#bar()
108
+ # /projects/foo.rb:15
109
+ # < Foo#bar()
110
+ # = :bar
111
+ # < Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
112
+ # = "2-some-[a,b,c]-{:name=>:value}-bar"
113
+ # > Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100900578 /projects/foo.rb:30>)
114
+ # /projects/foo.rb:30
115
+ # > Foo#bar()
116
+ # /projects/foo.rb:15
117
+ # < Foo#bar()
118
+ # = :bar
119
+ # 3--[]-{}-bar
120
+ # < Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100900578 /projects/foo.rb:30>)
121
+ # = nil
122
+ ```
123
+
124
+ See [examples dir](./examples) for more…
125
+
126
+ ## Installation
127
+
128
+ You can install the gem in your system with
129
+
130
+ ```shell
131
+ gem install im-lost
132
+ ```
133
+
134
+ or you can use [Bundler](http://gembundler.com/) to add ImLost to your own project:
135
+
136
+ ```shell
137
+ bundle add im-lost
138
+ ```
139
+
140
+ After that you only need one line of code to have everything together
141
+
142
+ ```ruby
143
+ require 'im-lost'
144
+ ```
data/examples/foo.rb ADDED
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../lib/im-lost'
4
+
5
+ class Foo
6
+ def self.create(value:) = new(value)
7
+
8
+ attr_reader :value
9
+
10
+ def initialize(value)
11
+ @value = value
12
+ end
13
+
14
+ def foo(arg, *args, key: nil, **kw_args, &block)
15
+ @value = "#{arg}-#{key}-[#{args.join(',')}]-#{kw_args.inspect}-#{bar}"
16
+ block ? block.call(@value) : @value
17
+ end
18
+
19
+ def bar = :bar
20
+ end
21
+
22
+ ImLost.trace_results = true
23
+ ImLost.trace(Foo)
24
+
25
+ my_foo = Foo.create(value: :foo!)
26
+ ImLost.trace(my_foo)
27
+
28
+ my_foo.foo(1, key: :none)
29
+ my_foo.foo(2, :a, :b, :c, key: :some, name: :value)
30
+ my_foo.foo(3) { puts _1 }
31
+
32
+ # output will look like
33
+ # > Foo.create(:foo!)
34
+ # /projects/foo.rb:25
35
+ # > Foo.new(*)
36
+ # /projects/foo.rb:6
37
+ # < Foo.new(*)
38
+ # = #<Foo:0x0000000100902418 @value=:foo!>
39
+ # < Foo.create(:foo!)
40
+ # = #<Foo:0x0000000100902418 @value=:foo!>
41
+ # > Foo#foo(1, *[], :none, **{}, &nil)
42
+ # /projects/foo.rb:28
43
+ # > Foo#bar()
44
+ # /projects/foo.rb:15
45
+ # < Foo#bar()
46
+ # = :bar
47
+ # < Foo#foo(1, *[], :none, **{}, &nil)
48
+ # = "1-none-[]-{}-bar"
49
+ # > Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
50
+ # /projects/foo.rb:29
51
+ # > Foo#bar()
52
+ # /projects/foo.rb:15
53
+ # < Foo#bar()
54
+ # = :bar
55
+ # < Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
56
+ # = "2-some-[a,b,c]-{:name=>:value}-bar"
57
+ # > Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100900578 /projects/foo.rb:30>)
58
+ # /projects/foo.rb:30
59
+ # > Foo#bar()
60
+ # /projects/foo.rb:15
61
+ # < Foo#bar()
62
+ # = :bar
63
+ # 3--[]-{}-bar
64
+ # < Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100900578 /projects/foo.rb:30>)
65
+ # = nil
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ puts <<~INFO
4
+
5
+ This example traces calls for very basic Ruby objects when a new Class is
6
+ generated and pretty_print is automatically loaded.
7
+
8
+ INFO
9
+
10
+ require 'im-lost'
11
+
12
+ ImLost.trace_results = true
13
+ ImLost.trace(Kernel, Object, Module, Class, self) do
14
+ puts '=' * 79
15
+ pp Class.new
16
+ puts '=' * 79
17
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImLost
4
+ # The version number of the gem.
5
+ VERSION = '1.0.0'
6
+ end
data/lib/im-lost.rb ADDED
@@ -0,0 +1,341 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ImLost
4
+ class << self
5
+ #
6
+ # Enables/disables to include code location into traced call information.
7
+ # This is enabled by default.
8
+ #
9
+ # @return [Boolean] whether code location will be included
10
+ #
11
+ attr_reader :caller_locations
12
+
13
+ def caller_locations=(value)
14
+ @caller_locations = value ? true : false
15
+ end
16
+
17
+ #
18
+ # The output device used to write information.
19
+ # This should be an `IO` device or any other object responding to `#puts`.
20
+ #
21
+ # `$stderr` is configured by default.
22
+ #
23
+ # @example Write to a file
24
+ # ImLost.output = File.new('./trace', 'w')
25
+ #
26
+ # @example Write temporary into a memory stream
27
+ # require 'stringio'
28
+ #
29
+ # original = ImLost.output
30
+ # begin
31
+ # ImLost.output = StringIO.new
32
+ # # ... collect trace information
33
+ # puts(ImLost.output.string) # or whatever
34
+ # ensure
35
+ # ImLost.output = original
36
+ # end
37
+ #
38
+ # @return [#puts] the output device
39
+ #
40
+ attr_reader :output
41
+
42
+ def output=(value)
43
+ return @output = value if value.respond_to?(:puts)
44
+ raise(ArgumentError, "invalid output device - #{value.inspect}")
45
+ end
46
+
47
+ #
48
+ # Enables/disables tracing of method calls.
49
+ # This is enabled by default.
50
+ #
51
+ # @attribute [r] trace_calls
52
+ # @return [Boolean] whether method calls will be traced
53
+ #
54
+ def trace_calls = @trace_calls[0].enabled?
55
+
56
+ def trace_calls=(value)
57
+ if value
58
+ @trace_calls.each(&:enable) unless trace_calls
59
+ elsif trace_calls
60
+ @trace_calls.each(&:disable)
61
+ end
62
+ end
63
+
64
+ #
65
+ # Traces execptions raised within a given block.
66
+ #
67
+ # @example Trace exception and rescue handling
68
+ # ImLost.trace_exceptions do
69
+ # File.write('/', 'test')
70
+ # rescue SystemCallError
71
+ # raise('something went wrong!')
72
+ # end
73
+ # # output will look like
74
+ # # x Errno::EEXIST: File exists @ rb_sysopen - /
75
+ # # /projects/test.rb:2
76
+ # # ! Errno::EEXIST: File exists @ rb_sysopen - /
77
+ # # /projects/test.rb:3
78
+ # # x RuntimeError: something went wrong!
79
+ # # /projects/test.rb:4
80
+ #
81
+ # @param with_locations [Boolean] wheter the locations should be included
82
+ # into the exception trace information
83
+ # @yieldreturn [Object] return result
84
+ #
85
+ def trace_exceptions(with_locations: true)
86
+ return unless block_given?
87
+ we = @trace_exceptions.enabled?
88
+ el = @exception_locations
89
+ @exception_locations = with_locations
90
+ @trace_exceptions.enable unless we
91
+ yield
92
+ ensure
93
+ @trace_exceptions.disable unless we
94
+ @exception_locations = el
95
+ end
96
+
97
+ #
98
+ # Enables/disables tracing of returned valuess of method calls.
99
+ # This is disabled by default.
100
+ #
101
+ # @attribute [r] trace_results
102
+ # @return [Boolean] whether return values will be traced
103
+ #
104
+ def trace_results = @trace_results[0].enabled?
105
+
106
+ def trace_results=(value)
107
+ if value
108
+ @trace_results.each(&:enable) unless trace_results
109
+ elsif trace_results
110
+ @trace_results.each(&:disable)
111
+ end
112
+ end
113
+
114
+ #
115
+ # Print the call location conditionally.
116
+ #
117
+ # @example simply print location
118
+ # ImLost.here
119
+ #
120
+ # @example print location when instance variable is empty
121
+ # ImLost.here(@name.empty?)
122
+ #
123
+ # @example print location when instance variable is nil or empty
124
+ # ImLost.here { @name.nil? || @name.empty? }
125
+ #
126
+ # @overload here
127
+ # Prints the caller location.
128
+ # @return [true]
129
+ #
130
+ # @overload here(test)
131
+ # Prints the caller location when given argument is truthy.
132
+ # @param test [Object]
133
+ # @return [Object] test
134
+ #
135
+ # @overload here
136
+ # Prints the caller location when given block returns a truthy result.
137
+ # @yield When the block returns a truthy result the location will be print
138
+ # @yieldreturn [Object] return result
139
+ #
140
+ def here(test = true)
141
+ return test if !test || (block_given? && !(test = yield))
142
+ loc = Kernel.caller_locations(1, 1)[0]
143
+ @output.puts(": #{loc.path}:#{loc.lineno}")
144
+ test
145
+ end
146
+
147
+ #
148
+ # Trace objects.
149
+ #
150
+ # The given arguments can be any object instance or module or class.
151
+ #
152
+ # @example trace method calls of an instance variable for a while
153
+ # ImLost.trace(@file)
154
+ # # ...
155
+ # ImLost.untrace(@file)
156
+ #
157
+ # @example temporary trace method calls
158
+ # File.open('test.txt', 'w') do |file|
159
+ # ImLost.trace(file) do
160
+ # file << 'hello '
161
+ # file.puts(:world!)
162
+ # end
163
+ # end
164
+ # output will look like
165
+ # > IO#<<(?)
166
+ # /projects/test.rb:1
167
+ # > IO#write(*)
168
+ # /projects/test.rb:1
169
+ # > IO#puts(*)
170
+ # /projects/test.rb:2
171
+ # > IO#write(*)
172
+ # /projects/test.rb:2
173
+ #
174
+ # @overload trace(*args)
175
+ # @param args [[Object]] one or more objects to be traced
176
+ # @return [[Object]] the traced object(s)
177
+ # Start tracing the given objects.
178
+ # @see untrace
179
+ # @see untrace_all!
180
+ #
181
+ #
182
+ # @overload trace(*args)
183
+ # @param args [[Object]] one or more objects to be traced
184
+ # @yieldparam args [Object] the traced object(s)
185
+ # @yieldreturn [Object] return result
186
+ # Traces the given object(s) inside the block only.
187
+ # The object(s) will not be traced any longer after the block call.
188
+ #
189
+ def trace(*args, &block)
190
+ return block&.call if args.empty?
191
+ return args.size == 1 ? _trace(args[0]) : _trace_all(args) unless block
192
+ args.size == 1 ? _trace_b(args[0], &block) : _trace_all_b(args, &block)
193
+ end
194
+
195
+ #
196
+ # Stop tracing objects.
197
+ #
198
+ # @example trace some objects for some code lines
199
+ # traced_vars = ImLost.trace(@file, @client)
200
+ # # ...
201
+ # ImLost.untrace(*traced_vars)
202
+ #
203
+ # @see trace
204
+ #
205
+ # @param args [[Object]] one or more objects which should not longer be
206
+ # traced
207
+ # @return [[Object]] the object(s) which are not longer be traced
208
+ # @return [nil] when none of the objects was traced before
209
+ #
210
+ def untrace(*args)
211
+ ret = args.filter_map { @trace.delete(_1.__id__) ? _1 : nil }
212
+ args.size == 1 ? ret[0] : ret
213
+ end
214
+
215
+ #
216
+ # Stop tracing any object.
217
+ # (When you are really lost and just like to stop tracing of all your
218
+ # objects.)
219
+ #
220
+ # @see trace
221
+ #
222
+ # @return [self] itself
223
+ #
224
+ def untrace_all!
225
+ @trace = {}.compare_by_identity
226
+ self
227
+ end
228
+
229
+ protected
230
+
231
+ def as_sig(prefix, info, args)
232
+ args = args.join(', ')
233
+ case info.self
234
+ when Class, Module
235
+ "#{prefix} #{info.self}.#{info.method_id}(#{args})"
236
+ else
237
+ "#{prefix} #{info.defined_class}##{info.method_id}(#{args})"
238
+ end
239
+ end
240
+
241
+ private
242
+
243
+ def _trace(arg)
244
+ @trace[arg.__id__] = 1 if self != arg && @output != arg
245
+ arg
246
+ end
247
+
248
+ def _trace_all(args)
249
+ args.each do |arg|
250
+ @trace[arg.__id__] = 1 if arg != self && @output != arg
251
+ end
252
+ args
253
+ end
254
+
255
+ def _trace_b(arg)
256
+ @trace[id = arg.__id__] = 1 if self != arg && @output != arg
257
+ yield(arg)
258
+ ensure
259
+ @trace.delete(id) if id
260
+ end
261
+
262
+ def _trace_all_b(args)
263
+ ids =
264
+ args.filter_map do |arg|
265
+ next if self == arg || @output == arg
266
+ @trace[id = arg.__id__] = 1
267
+ id
268
+ end
269
+ yield(args)
270
+ ensure
271
+ ids.each { @trace.delete(_1) }
272
+ end
273
+ end
274
+
275
+ ARG_SIG = { rest: '*', keyrest: '**', block: '&' }.compare_by_identity.freeze
276
+ NO_NAME = %i[* ** &].freeze
277
+ EX_PREFIX = { raise: 'x', rescue: '!' }.freeze
278
+ private_constant :ARG_SIG, :NO_NAME, :EX_PREFIX
279
+
280
+ @trace = {}.compare_by_identity
281
+ @caller_locations = true
282
+ @output = $stderr.respond_to?(:puts) ? $stderr : STDERR
283
+
284
+ @trace_calls = [
285
+ TracePoint.new(:c_call) do |tp|
286
+ next unless @trace.key?(tp.self.__id__)
287
+ @output.puts(as_sig('>', tp, tp.parameters.map { ARG_SIG[_1[0]] || '?' }))
288
+ @output.puts(" #{tp.path}:#{tp.lineno}") if @caller_locations
289
+ end,
290
+ TracePoint.new(:call) do |tp|
291
+ next unless @trace.key?(tp.self.__id__)
292
+ ctx = tp.binding
293
+ @output.puts(
294
+ as_sig(
295
+ '>',
296
+ tp,
297
+ tp.parameters.map do |kind, name|
298
+ next name if NO_NAME.include?(name)
299
+ "#{ARG_SIG[kind]}#{ctx.local_variable_get(name).inspect}"
300
+ end
301
+ )
302
+ )
303
+ next unless @caller_locations
304
+ loc = ctx.eval('caller_locations(4,1)')[0]
305
+ @output.puts(" #{loc.path}:#{loc.lineno}")
306
+ end
307
+ ]
308
+
309
+ @trace_results = [
310
+ TracePoint.new(:c_return) do |tp|
311
+ next unless @trace.key?(tp.self.__id__)
312
+ @output.puts(as_sig('<', tp, tp.parameters.map { ARG_SIG[_1[0]] || '?' }))
313
+ @output.puts(" = #{tp.return_value.inspect}")
314
+ end,
315
+ TracePoint.new(:return) do |tp|
316
+ next unless @trace.key?(tp.self.__id__)
317
+ ctx = tp.binding
318
+ @output.puts(
319
+ as_sig(
320
+ '<',
321
+ tp,
322
+ tp.parameters.map do |kind, name|
323
+ next name if %i[* ** &].include?(name)
324
+ "#{ARG_SIG[kind]}#{ctx.local_variable_get(name).inspect}"
325
+ end
326
+ )
327
+ )
328
+ @output.puts(" = #{tp.return_value.inspect}")
329
+ end
330
+ ]
331
+
332
+ supported = RUBY_VERSION >= '3.3.0' ? %i[raise rescue] : %i[raise]
333
+ @trace_exceptions =
334
+ TracePoint.new(*supported) do |tp|
335
+ ex = tp.raised_exception.inspect
336
+ @output.puts("#{EX_PREFIX[tp.event]} #{ex[0] == '#' ? ex[2..-2] : ex}")
337
+ @output.puts(" #{tp.path}:#{tp.lineno}") if @exception_locations
338
+ end
339
+
340
+ self.trace_calls = true
341
+ end
data/lib/im_lost.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'im-lost'
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: im-lost
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Mike Blumtritt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-05-12 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |
14
+ If you have overlooked something again and don't really understand what
15
+ your code is doing. If you have to maintain this application but can't
16
+ really find your way around and certainly can't track down that stupid
17
+ error. If you feel lost in all that code, here's the gem to help you out!
18
+
19
+ ImLost helps you by analyzing function calls of objects, informing you
20
+ about exceptions and logging your way through your code. In short, ImLost
21
+ is your debugging helper!
22
+ email:
23
+ executables: []
24
+ extensions: []
25
+ extra_rdoc_files:
26
+ - README.md
27
+ - LICENSE
28
+ files:
29
+ - LICENSE
30
+ - README.md
31
+ - examples/foo.rb
32
+ - examples/kernel_calls.rb
33
+ - lib/im-lost.rb
34
+ - lib/im-lost/version.rb
35
+ - lib/im_lost.rb
36
+ homepage: https://github.com/mblumtritt/im-lost
37
+ licenses:
38
+ - MIT
39
+ metadata:
40
+ source_code_uri: https://github.com/mblumtritt/im-lost
41
+ bug_tracker_uri: https://github.com/mblumtritt/im-lost/issues
42
+ documentation_uri: https://rubydoc.info/gems/im-lost
43
+ rubygems_mfa_required: 'true'
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '3.0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.5.10
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Your debugging helper.
63
+ test_files: []