开发者

Get The Name Of A Local Variable

When developing & debugging, I sometimes wish I could write a 1-liner that dumped the names, types & values of a bunch of variables. The problem is I don't know how to access the name of a variable, if I can at all.

Here is a first attempt:

foo = 1
bar = "42"
baz = Hash.new

[开发者_如何学运维foo, bar, baz].each do |v|
    puts "#{v.???} = (#{v.class}) #{v}"
    end

I'd like the output of this program to be something like:

foo = (Fixnum) 1 
bar = (String) 42 
baz = (Hash) ...

I don't know what ??? should be above. Can this be done?


foo = 1
bar = "42"
baz = Hash.new

%w(foo bar baz).each do |vn|
    v = eval(vn)
    puts "#{vn} = (#{v.class}) #{v}"
end

But this, of course, doesn't help you if you want a method with 1 argument.


Here's a little bit of debug code I use all over the place (I stick it in a separate file so that it can be required wherever needed). It can be used two ways. Passed one or more values, it simply inspects them and writes the result to $stderr. But passed a block which returns one or more things, it writes them out with their names.

#!/usr/bin/ruby1.8

def q(*stuff, &block)
  if block
    s = Array(block[]).collect do |expression|
      value = eval(expression.to_s, block.binding).inspect
      "#{expression} = #{value}"
    end.join(', ')
    $stderr.puts s
  else
    stuff.each do
      |thing| $stderr.print(thing.inspect + "\n")
    end
  end
end

i = 1
q i       # => 1
q {:i}    # => i = 1

name = "Fred"
q [name, name.length]         # => ["Fred", 4]
q {[:name, 'name.length']}    # => name = "Fred", name.length = 4

Note: The q function, and more, is now available in the cute_print gem.


No, because foo/bar/baz are not instance variables in your code. They are local variables (instance variables start with a @). There is a way to do it with instance variables and the Object#instance_variables method, though:

@foo = 1
@bar = 2
@baz = 3

instance_variables.each do |var|
  value = instance_variable_get var
  puts "#{var} = (#{value.class}) #{value}"
end

# outputs:
# @foo = (Fixnum) 1
# @bar = (Fixnum) 2
# @baz = (Fixnum) 3

To get the name of a particular instance variable, loop through all of the instance variables until you find one with a value that matches your instance variable.


foo = 1
bar = "42"
baz = Hash.new

Varspec = Struct.new(:name, :type, :value, :inspect_str) do
  def to_s
    "#{name} = (#{type}) #{inspect_str}"
  end
end

lvars = local_variables.map {|lvar|
  lvar = lvar.to_s
  val = eval(lvar)
  val = val.dup rescue val
  Varspec.new(lvar, val.class, val, val.inspect)
}

puts lvars
# baz = (Hash) {}
# bar = (String) "42"
# foo = (Fixnum) 1

Or, you could just use a debugger. That's what they were invented for, after all.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜