Ruby - print the variable name and then its value

前端 未结 8 2070
梦毁少年i
梦毁少年i 2020-11-27 05:35

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?

         


        
相关标签:
8条回答
  • 2020-11-27 05:42

    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
    
    0 讨论(0)
  • 2020-11-27 05:47

    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"
    
    0 讨论(0)
  • 2020-11-27 05:47
    # 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"
    
    0 讨论(0)
  • 2020-11-27 05:49

    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.

    0 讨论(0)
  • 2020-11-27 05:57

    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)

    0 讨论(0)
  • 2020-11-27 06:00

    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}"
    }
    
    0 讨论(0)
提交回复
热议问题