Каков наилучший способ написать функцию (или что-то DSLish), которое позволит мне написать этот код в Ruby. Как бы я построил функцию write_pair?
username = "tyndall"
write_pair username
# where write_pair username outputs
username: tyndall
Можно ли это сделать? Ищите самый простой способ сделать это.
Ответ 1
Конечно, это возможно!
Мое решение проверяет var на Object # object_id identity: http://codepad.org/V7TXRxmL
Он искалечен в стиле скрепляющего перехода...
Хотя он работает только для локальных vars, его можно легко сделать "универсальным", добавив использование других методов с перечислением переменных, таких как 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
Ответ 2
Если вы можете использовать символ вместо имени переменной, вы можете сделать что-то вроде этого:
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
Обратите внимание, что вы должны передать пустой блок {}
методу или не получить привязку для оценки символа.
Ответ 3
Я сделал макрос 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}"
Это хорошо, потому что у него нет внешних зависимостей (например, вам не нужно загружать библиотеку для ее использования).
Ответ 4
Вы не можете получить имя переменной в Ruby. Но вы можете сделать что-то вроде этого:
data = {"username" => "tyndall"}
Или даже,
username = "tyndall"
data = {"username", "password", "favorite_color"}
data.each { |param|
value = eval(param)
puts "#{param}: #{value}"
}
Ответ 5
Это одно простое решение:
def bug string
puts string + eval(string)
end
Это более читаемо:
def bug string
puts '#' * 100
puts string + ': ' + eval(string).inspect
end
Вызывается таким образом:
bug "variable"
Если вам нужно перенести с собой фактическую переменную, вам нужно ввести ее дважды, но тогда вы можете сделать ее встроенной. Таким образом:
puts "variable: #{variable}"
Ответ 6
Основываясь на предыдущих ответах, связанных с символами и привязками... если для вас используется символ имени в качестве символа (кто не любит вырезать лишние нажатия клавиш?!), попробуйте следующее:
def wp(var_name_as_sym)
# gets caller binding, which contains caller 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 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 для получение привязки контекста вызова)
Ответ 7
def write_pair var, binding
puts "#{ var } = #{ eval(var, binding)}"
end
username = "tyndall"
write_pair "username", binding
Это кажется странным, потому что привязка никогда не определяется, но она работает. Из Ruby: получение имени переменной:
Метод binding() дает объект Binding, который запоминает контекст в точке вызова метода. Затем вы передаете привязку в eval(), и он оценивает переменную в этом контексте.
Обязательно передайте строку, а не переменную.
Ответ 8
# 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"