What is the best way to write a function (or something DSLish) that will allow me to write this code in Ruby. How would I construct the function write_pair?
Sure it is possible!
My solution tests the var by Object#object_id identity: http://codepad.org/V7TXRxmL
It's crippled in the binding passing style ...
Although it works just for local vars yet, it can be easily be made "universal" adding use of the other scope-variable-listing methods like instance_variables
etc.
# 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
This is a simple solution:
def write_pair(variable)
puts variable + eval(variable)
end
This is more readable:
def write_pair(variable)
puts 'A' * 100
puts variable + ': ' + eval(variable).inspect
puts 'Z' * 100
end
Invocation:
write_pair "variable"
# 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"
If it's possible for you to use a symbol instead of the variable name, you could do something like this:
def wp (s, &b)
puts "#{s} = #{eval(s.to_s, b.binding)}"
end
In use:
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
Note that you must pass the empty block {}
to the method or it cannot get the binding to evaluate the symbol.
Building on previous answers relating to symbols & bindings ... if passing in the variable name as a symbol works for you (who doesn't love cutting out extra keystrokes?!), try this:
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)
Console output:
> wp :aa
aa = 1
=> nil
> wp :bb
bb = "some bb string"
=> nil
> wp :os
os = #<OpenStruct z=26, y=25>
=> nil
Using ruby 2.2.2p95
(Credit to banister for getting binding of calling context)
You can't actually get a variable's name in Ruby. But you could do something like this:
data = {"username" => "tyndall"}
Or even,
username = "tyndall"
data = {"username", "password", "favorite_color"}
data.each { |param|
value = eval(param)
puts "#{param}: #{value}"
}