Ruby - 打印变量名称,然后打印其值

时间:2010-04-08 21:34:15

标签: ruby function metaprogramming

编写一个允许我在Ruby中编写此代码的函数(或DSLish)的最佳方法是什么。我将如何构造函数write_pair?

username = "tyndall"
write_pair username
# where write_pair username outputs 
username: tyndall

有可能吗?寻找最简单的方法来做到这一点。

8 个答案:

答案 0 :(得分:21)

当然有可能!

我的解决方案通过Object#object_id身份测试var:http://codepad.org/V7TXRxmL
它在绑定传递方式上瘫痪......
虽然它仅适用于本地变量,但它可以很容易地“通用”,增加使用其他范围变量列表方法,如instance_variables等。

# the function must be defined in such a place 
# ... so as to "catch" the binding of the vars ... cheesy
# otherwise we're kinda stuck with the extra param on the caller
@_binding = binding
def write_pair(p, b = @_binding)
  eval("
    local_variables.each do |v| 
      if eval(v.to_s + \".object_id\") == " + p.object_id.to_s + "
        puts v.to_s + ': ' + \"" + p.to_s + "\"
      end
    end
  " , b)
end

# if the binding is an issue just do here:
# write_pair = lambda { |p| write_pair(p, binding) }

# just some test vars to make sure it works
username1 = "tyndall"
username  = "tyndall"
username3 = "tyndall"

# the result:
write_pair(username)
# username: tyndall

答案 1 :(得分:14)

如果您可以使用符号而不是变量名称,则可以执行以下操作:

def wp (s, &b)
  puts "#{s} = #{eval(s.to_s, b.binding)}"
end

使用中:

irb(main):001:0> def wp (s, &b)
irb(main):002:1>   puts "#{s} = #{eval(s.to_s, b.binding)}"
irb(main):003:1> end
=> nil
irb(main):004:0> var = 3
=> 3
irb(main):005:0> wp(:var) {}
var = 3

请注意,您必须将空块{}传递给方法,否则无法获取绑定来评估符号。

答案 2 :(得分:4)

我为此制作了一个vim宏:

" Inspect the variable on the current line (in Ruby)
autocmd FileType ruby nmap ,i ^"oy$Iputs "<esc>A: #{(<esc>"opA).inspect}"<esc>

将您想要检查的变量单独放在一行上,然后在正常模式下键入,i(逗号,然后是i)。它转过来了:

foo

进入这个:

puts "foo: #{(foo).inspect}"

这很好,因为它没有任何外部依赖项(例如,您不必加载库来使用它)。

答案 3 :(得分:4)

这是一个简单的解决方案:

  def bug string
    puts string + eval(string)
  end

这更具可读性:

 def bug string
    puts '#' * 100
    puts string + ': ' + eval(string).inspect
 end

因此被调用:

bug "variable"

如果你需要携带实际变量,你必须输入两次,但是你可以内联。因此:

puts "variable: #{variable}"

答案 4 :(得分:4)

以前有关符号和答案的答案为基础绑定...如果传入变量名作为符号适合你(谁不喜欢削减额外的击键?!),试试这个:

def wp(var_name_as_sym)
  # gets caller binding, which contains caller's execution environment
  parent_binding = RubyVM::DebugInspector.open{|i| i.frame_binding(2) }
  # now puts the symbol as string + the symbol executed as a variable in the caller's binding
  puts %Q~#{var_name_as_sym.to_s} = #{eval("#{var_name_as_sym.to_s}.inspect", parent_binding)}~
end

aa=1
bb='some bb string'
os = OpenStruct.new(z:26, y:25)

控制台输出:

> wp :aa
aa = 1
=> nil
> wp :bb
bb = "some bb string"
=> nil
> wp :os
os = #<OpenStruct z=26, y=25>
=> nil

使用ruby 2.2.2p95

(感谢banister getting binding调用上下文)

答案 5 :(得分:3)

你实际上无法在Ruby中获得变量的名称。但你可以这样做:

data = {"username" => "tyndall"}

甚至,

username = "tyndall"
data = {"username", "password", "favorite_color"}
data.each { |param|
   value = eval(param)
   puts "#{param}: #{value}"
}

答案 6 :(得分:2)

def write_pair var, binding
  puts "#{ var } = #{ eval(var, binding)}"
end


username = "tyndall"
write_pair "username", binding

这看起来很奇怪,因为从未定义绑定,但它可以工作。来自Ruby: getting variable name

  

binding()方法给出了一个记住的Binding对象   调用该方法时的上下文。然后传递绑定   进入eval(),它会在该上下文中计算变量。

确保传递字符串,而不是变量。

答案 7 :(得分:1)

# make use of dynamic scoping via methods and instance vars
@_binding = binding
def eval_debug(expr, binding = @_binding)
   "#{expr} => #{eval(expr, binding)}"
end

# sample invocation:
x = 10
puts eval_debug "x"
puts eval_debug "x**x"