Ruby - Print the Variable Name and Then Its Value

Ruby - print the variable name and then its value

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

How to print variable's name?

Print a Symbol

If you already know the name of the variable, you can simply print the variable's symbol. Ruby will convert this to a string automagically for you when invoking puts. For example:

asdf = Hash.new
puts :asdf

will print:

asdf

and return nil, because Kernel#puts always returns nil.

Return a String

If you prefer to return the name of the variable instead of just printing it, then you need to convert the Symbol to a String. For example:

asdf = Hash.new
:asdf.to_s
#=> "asdf"

Ruby: getting variable name

First, you cannot implement a puti and directly call puti a_var to get the output as a_var = value of a_var. At the body of puti, Ruby sees only the formal parameter names of puti, it cannot infer the actual parameter names.

In some other language like C/C++, you can use Macro to implement your puti. That's another story.

However, you can implement put :a_var, with the help of Continuation. In another question "Can you eval code in the context of a caller in Ruby?", Sony Santos has provided a caller_binding implementation to get the binding of the caller (something like the perl caller function).

The implementation should be altered a bit, because callcc returns the return value of the block at its first returning. So you'll get an instance of Continuation rather than nil. Here is the updated version:

require 'continuation' if RUBY_VERSION >= '1.9.0'

def caller_binding
cc = nil # must be present to work within lambda
count = 0 # counter of returns

set_trace_func lambda { |event, file, lineno, id, binding, klass|
# First return gets to the caller of this method
# (which already know its own binding).
# Second return gets to the caller of the caller.
# That's we want!
if count == 2
set_trace_func nil
# Will return the binding to the callcc below.
cc.call binding
elsif event == "return"
count += 1
end
}
# First time it'll set the cc and return nil to the caller.
# So it's important to the caller to return again
# if it gets nil, then we get the second return.
# Second time it'll return the binding.
return callcc { |cont| cc = cont; nil }
end

# Example of use:

def puti *vars
return unless bnd = caller_binding
vars.each do |s|
value = eval s.to_s, bnd
puts "#{s} = #{value.inspect}"
end
end

a = 1
b = 2
puti :a, :b
e = 1 # place holder...

# => a = 1
# b = 2

Note the puti should not be the last statement of your program, otherwise the ruby interpreter will terminate immediately and the trace function has no chance to run. So that's the point of the last "place holder" line.

How can I print a variable name and its value without typing the name twice?

Here's a very general, but slightly ugly way to do it in D, using compile time function evaluation (CTFE) to generate the code as a string literal, and a mixin statement to evaluate it:

import std.stdio, std.math;

// CTFE function that generates trace code.
string trace(string varName) {
return "writeln(\"" ~ varName ~ ": \", " ~ varName ~ ");";
}

void main() {
// Trace a function call.
mixin(trace("sqrt(5)"));

// Trace a variable.
int foo = 5;
mixin(trace("foo"));
}

The only problems are that manually typing mixin everywhere is verbose and whatever you want to trace needs to be inside an ugly string literal.

Note that there are two kinds of mixins in D. Template mixins are better behaved in many ways, but string mixins (used in this example) are about as general as it gets, in that any code can in principle be generated via CTFE and then mixed in.

Can I get the variable name from it's assignee?

Technically yes, sort of.

But you'd have to recursively search through all the instance_variables of every object. And, as Cary points out, an object can be assigned to more than one variable at a time.

Don't do that.

The reason I was looking for this behavior was to use the variable name but also as a position within a grid of data. So if had a 2 dimensional Grid the variable names would be like "AA", "AB", "BC", etc. It is knew its name it would also know its position.

What you're describing is an "action at a distance" anti-pattern where changes to one part of a program change another part of a program with no obvious connection. This violates encapsulation; good encapsulation allows you to understand a single piece of a system by just looking at its inputs and outputs. Violating encapsulation means in order to understand one part of the system you have to understand every part of the system leading to a maintenance nightmare. Modern languages and practices strive to avoid this as much as possible.

For example, a variable's name should never matter to the behavior of the program. You should be able to safely perform a Rename Variable refactoring to name a variable according to what makes sense to the user of the object. In your example this would alter the behavior of the program violating the Principle of Least Astonishment.

Instead you'd have an object to represent your Grid and this would manage the relationships between Nodes in the Grid. Rather than passing around individual Nodes you'd pass around the Grid.

Or each Node can know who their neighboring Nodes are. An example of this would be a traditional Tree, Graph, or Linked List structure. The advantage here is there is no fixed position and the data structure can grow or shrink in any direction. Any Node can be passed around and it knows its position within the structure.

Can we print the value of a local variable by using its corresponding symbol in Ruby?

Use eval.

eval("name") # "john"

How to print out value and name of each arg from a splat argument list

Using Mark's suggestion in regard to this SO question, the following works

  def puts_auto (*args, &b)
str = args.map { |arg| "#{arg} = #{eval(arg.to_s, b.binding)}" }.join(', ')
puts str
end

so

puts_auto(:a, :b){} # outputs `a = a string, b = 3`


Related Topics



Leave a reply



Submit