【问题标题】:Ruby - print the variable name and then its valueRuby - 打印变量名,然后是它的值
【发布时间】:2011-02-05 21:54:15
【问题描述】:

编写函数(或 DSLish)的最佳方法是什么,可以让我用 Ruby 编写此代码。如何构造函数 write_pair?

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

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

【问题讨论】:

  • Exemplor 不仅可以做到这一点,甚至可以打印出list.first: 1

标签: ruby function metaprogramming


【解决方案1】:

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

  def write_pair(variable)
    puts variable + eval(variable)
  end

这更具可读性:

 def write_pair(variable)
    puts 'A' * 100
    puts variable + ': ' + eval(variable).inspect
    puts 'Z' * 100
 end

调用:

write_pair "variable"

【讨论】:

    【解决方案2】:

    基于先前与符号和绑定相关的答案...如果将变量名称作为符号传递对您有用(谁不喜欢减少额外的击键?!),试试这个:

    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

    【讨论】:

      【解决方案3】:

      当然可以!

      我的解决方案通过 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
      

      【讨论】:

      【解决方案4】:
      # 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"
      

      【讨论】:

        【解决方案5】:
        def write_pair var, binding
          puts "#{ var } = #{ eval(var, binding)}"
        end
        
        
        username = "tyndall"
        write_pair "username", binding
        

        这看起来很奇怪,因为绑定从未定义过,但它确实有效。来自Ruby: getting variable name

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

        一定要传递一个字符串,而不是变量。

        【讨论】:

          【解决方案6】:

          如果您可以使用符号代替变量名,您可以这样做:

          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
          

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

          【讨论】:

          • 如果要调用.to_s,为什么不直接传一个字符串呢?这样您甚至可以使用更复杂的表达式。此外,为什么你使用 b.send(:binding) 而不是更明显的 b.binding? (我是 Ruby 新手)。无论如何,它工作得很好,并且比其他解决方案(称为 write_pair 的解决方案)简单得多,我什至无法理解
          • 是的,你可以传递一个字符串而不是符号(不需要修改),解决方案中的第一行只是指你不能输入 wp(var) 的事实(就像在题)。不知道/不记得我为什么选择符号而不是字符串,或者为什么我输入 .send(:binding) 而不是 .binding — 可能是因为首先考虑了其他一些解决方案并从中发展。 =)
          【解决方案7】:

          我为此做了一个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}"
          

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

          【讨论】:

            【解决方案8】:

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

            data = {"username" =&gt; "tyndall"}

            甚至,

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-04-28
              • 1970-01-01
              • 1970-01-01
              • 2011-03-30
              • 2021-02-14
              • 2021-11-09
              • 2023-03-31
              • 1970-01-01
              相关资源
              最近更新 更多