Skip to content

Commit

Permalink
Add ImLost.vars to inspect local or instance variables
Browse files Browse the repository at this point in the history
  • Loading branch information
mblumtritt committed May 12, 2024
1 parent 39bd8b7 commit 4d8869d
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 82 deletions.
80 changes: 47 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,28 @@ When you like to know if and when a code point is reached, `ImLost.here` will he
ImLost.here
```

If you like to know the instance variables values of an object, use
`ImLost.vars`:

```ruby
ImLost.vars(self)
```

Or you can print the current local variables:

```ruby
ImLost.vars(binding)
```

See the [online help](https://rubydoc.info/gems/im-lost/ImLost) for more!

## Example

```ruby
require 'im-lost'

require_relative '../lib/im-lost'

class Foo
def self.create(value:) = new(value)

Expand All @@ -82,43 +99,40 @@ my_foo = Foo.create(value: :foo!)
ImLost.trace(my_foo)

my_foo.foo(1, key: :none)
ImLost.vars(my_foo)

my_foo.foo(2, :a, :b, :c, key: :some, name: :value)
ImLost.vars(my_foo)

my_foo.foo(3) { puts _1 }
ImLost.vars(my_foo)

# output will look like
# > Foo.create(:foo!)
# /projects/foo.rb:25
# > Foo.new(*)
# /projects/foo.rb:6
# < Foo.new(*)
# = #<Foo:0x0000000100902418 @value=:foo!>
# < Foo.create(:foo!)
# = #<Foo:0x0000000100902418 @value=:foo!>
# > Foo#foo(1, *[], :none, **{}, &nil)
# /projects/foo.rb:28
# > Foo#bar()
# /projects/foo.rb:15
# < Foo#bar()
# = :bar
# < Foo#foo(1, *[], :none, **{}, &nil)
# = "1-none-[]-{}-bar"
# > Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
# /projects/foo.rb:29
# > Foo#bar()
# /projects/foo.rb:15
# < Foo#bar()
# = :bar
# < Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
# = "2-some-[a,b,c]-{:name=>:value}-bar"
# > Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100900578 /projects/foo.rb:30>)
# /projects/foo.rb:30
# > Foo#bar()
# /projects/foo.rb:15
# < Foo#bar()
# = :bar
# 3--[]-{}-bar
# < Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100900578 /projects/foo.rb:30>)
# = nil
# > Foo.create(:foo!)
# /projects/foo.rb25
# > Foo.new(*)
# /projects/foo.rb6
# < Foo.new(*)
# = #<Foo:0x0000000100ab1188 @value=:foo!>
# < Foo.create(:foo!)
# = #<Foo:0x0000000100ab1188 @value=:foo!>
# > Foo#foo(1, *[], :none, **{}, &nil)
# /projects/foo.rb28
# > Foo#bar()
# /projects/foo.rb15
# < Foo#bar()
# = :bar
# < Foo#foo(1, *[], :none, **{}, &nil)
# = "1-none-[]-{}-bar"
# = /projects/foo.rb29
# instance variables:
# @value: "1-none-[]-{}-bar"
# = /projects/foo.rb32
# instance variables:
# @value: "2-some-[a,b,c]-{:name=>:value}-bar"
# = /projects/foo.rb35
# instance variables:
# @value: "3--[]-{}-bar"
```

See [examples dir](./examples) for more…
Expand Down
63 changes: 30 additions & 33 deletions examples/foo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,37 @@ def bar = :bar
ImLost.trace(my_foo)

my_foo.foo(1, key: :none)
ImLost.vars(my_foo)

my_foo.foo(2, :a, :b, :c, key: :some, name: :value)
ImLost.vars(my_foo)

my_foo.foo(3) { puts _1 }
ImLost.vars(my_foo)

# output will look like
# > Foo.create(:foo!)
# /projects/foo.rb:25
# > Foo.new(*)
# /projects/foo.rb:6
# < Foo.new(*)
# = #<Foo:0x0000000100902418 @value=:foo!>
# < Foo.create(:foo!)
# = #<Foo:0x0000000100902418 @value=:foo!>
# > Foo#foo(1, *[], :none, **{}, &nil)
# /projects/foo.rb:28
# > Foo#bar()
# /projects/foo.rb:15
# < Foo#bar()
# = :bar
# < Foo#foo(1, *[], :none, **{}, &nil)
# = "1-none-[]-{}-bar"
# > Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
# /projects/foo.rb:29
# > Foo#bar()
# /projects/foo.rb:15
# < Foo#bar()
# = :bar
# < Foo#foo(2, *[:a, :b, :c], :some, **{:name=>:value}, &nil)
# = "2-some-[a,b,c]-{:name=>:value}-bar"
# > Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100900578 /projects/foo.rb:30>)
# /projects/foo.rb:30
# > Foo#bar()
# /projects/foo.rb:15
# < Foo#bar()
# = :bar
# 3--[]-{}-bar
# < Foo#foo(3, *[], nil, **{}, &#<Proc:0x0000000100900578 /projects/foo.rb:30>)
# = nil
# > Foo.create(:foo!)
# /projects/foo.rb25
# > Foo.new(*)
# /projects/foo.rb6
# < Foo.new(*)
# = #<Foo:0x0000000100ab1188 @value=:foo!>
# < Foo.create(:foo!)
# = #<Foo:0x0000000100ab1188 @value=:foo!>
# > Foo#foo(1, *[], :none, **{}, &nil)
# /projects/foo.rb28
# > Foo#bar()
# /projects/foo.rb15
# < Foo#bar()
# = :bar
# < Foo#foo(1, *[], :none, **{}, &nil)
# = "1-none-[]-{}-bar"
# = /projects/foo.rb29
# instance variables:
# @value: "1-none-[]-{}-bar"
# = /projects/foo.rb32
# instance variables:
# @value: "2-some-[a,b,c]-{:name=>:value}-bar"
# = /projects/foo.rb35
# instance variables:
# @value: "3--[]-{}-bar"
58 changes: 54 additions & 4 deletions lib/im-lost.rb
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,28 @@ def untrace_all!
self
end

#
# Print internal variables.
#
# @overload vars(object)
# Print instance variables of given object.
# @param object [Object] which instance variables should be print
# @return [Object] the given object
#
# @overload vars(binding)
# Print local variables of given Binding.
# @param binding [Binding] which local variables should be print
# @return [self] itself
#
def vars(object)
traced = @trace.delete(object.__id__)
return _local_vars(object) if object.is_a?(Binding)
return unless object.respond_to?(:instance_variables)
_vars(object, Kernel.caller_locations(1, 1)[0])
ensure
@trace[traced] = 1 if traced
end

protected

def as_sig(prefix, info, args)
Expand Down Expand Up @@ -270,6 +292,34 @@ def _trace_all_b(args)
ensure
ids.each { @trace.delete(_1) }
end

def _vars(obj, location)
@output.puts("= #{location.path}:#{location.lineno}")
vars = obj.instance_variables
if vars.empty?
@output.puts(' <no instance variables defined>')
else
@output.puts(' instance variables:')
vars.sort!.each do |name|
@output.puts(" #{name}: #{obj.instance_variable_get(name).inspect}")
end
end
obj
end

def _local_vars(binding)
@output.puts("= #{binding.source_location.join(':')}")
vars = binding.local_variables
if vars.empty?
@output.puts(' <no local variables>')
else
@output.puts(' local variables:')
vars.sort!.each do |name|
@output.puts(" #{name}: #{binding.local_variable_get(name).inspect}")
end
end
self
end
end

ARG_SIG = { rest: '*', keyrest: '**', block: '&' }.compare_by_identity.freeze
Expand All @@ -283,12 +333,12 @@ def _trace_all_b(args)

@trace_calls = [
TracePoint.new(:c_call) do |tp|
next unless @trace.key?(tp.self.__id__)
next if !@trace.key?(tp.self.__id__) || tp.path == __FILE__
@output.puts(as_sig('>', tp, tp.parameters.map { ARG_SIG[_1[0]] || '?' }))
@output.puts(" #{tp.path}:#{tp.lineno}") if @caller_locations
end,
TracePoint.new(:call) do |tp|
next unless @trace.key?(tp.self.__id__)
next if !@trace.key?(tp.self.__id__) || tp.path == __FILE__
ctx = tp.binding
@output.puts(
as_sig(
Expand All @@ -308,12 +358,12 @@ def _trace_all_b(args)

@trace_results = [
TracePoint.new(:c_return) do |tp|
next unless @trace.key?(tp.self.__id__)
next if !@trace.key?(tp.self.__id__) || tp.path == __FILE__
@output.puts(as_sig('<', tp, tp.parameters.map { ARG_SIG[_1[0]] || '?' }))
@output.puts(" = #{tp.return_value.inspect}")
end,
TracePoint.new(:return) do |tp|
next unless @trace.key?(tp.self.__id__)
next if !@trace.key?(tp.self.__id__) || tp.path == __FILE__
ctx = tp.binding
@output.puts(
as_sig(
Expand Down
Loading

0 comments on commit 4d8869d

Please sign in to comment.