Ruby - вывести имя переменной и затем ее значение - PullRequest
23 голосов
/ 09 апреля 2010

Какой лучший способ написать функцию (или что-то DSLish), которая позволит мне писать этот код на Ruby. Как бы я построил функцию write_pair?

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

Возможно ли это сделать? Ищите самый простой способ сделать это.

Ответы [ 8 ]

21 голосов
/ 09 апреля 2010

Конечно, это возможно!

Мое решение проверяет переменную с помощью идентификатора Object # object_id: 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
14 голосов
/ 09 апреля 2010

Если вы можете использовать символ вместо имени переменной, вы можете сделать что-то вроде этого:

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

Обратите внимание, что вы должны передать пустой блок {} методу, иначе невозможно получить привязку для оценки символа.

4 голосов
/ 19 октября 2017

Основываясь на предыдущих ответах, относящихся к символам и привязкам ... если передача имени переменной как символа работает для вас (кому не нравится вырезать дополнительные нажатия клавиш ?!), попробуйте это:

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 для получения привязки контекста вызова)

4 голосов
/ 08 марта 2017

Это одно простое решение:

  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 голосов
/ 28 июня 2010

Я сделал макрос 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 голосов
/ 09 апреля 2010

Вы не можете получить имя переменной в Ruby. Но вы могли бы сделать что-то вроде этого:

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

Или даже

username = "tyndall"
data = {"username", "password", "favorite_color"}
data.each { |param|
   value = eval(param)
   puts "#{param}: #{value}"
}
2 голосов
/ 04 февраля 2014
def write_pair var, binding
  puts "#{ var } = #{ eval(var, binding)}"
end


username = "tyndall"
write_pair "username", binding

Это кажется странным, потому что привязка никогда не определяется, но она работает. От Ruby: получение имени переменной :

Метод binding () дает объект Binding, который запоминает контекст в точке, где был вызван метод. Затем вы передаете обязательный в eval (), и он оценивает переменную в этом контексте.

Обязательно передайте строку, а не переменную.

1 голос
/ 17 марта 2015
# 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"
...