2010-04-08 3 views
21

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

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

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

+0

Exemplor может не только это сделать, но даже распечатать 'list.first: 1'. –

ответ

21

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

Мое решения проверяет вар на 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 
+0

где я могу узнать больше об этой привязке (в том смысле, что вы используете термин)? здесь я теряюсь. – BuddyJoe

+0

http://ruby-doc.org/core/classes/Binding.html http://onestepback.org/index.cgi/Tech/Ruby/RubyBindings.rdoc/style/print – clyfe

+9

У меня было бы серьезное искушение ранить любой, кто действительно использовал бы этот код в проекте. – molf

2

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

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

или даже

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

Конечно, вы можете, но это сложно! – clyfe

14

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

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 

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

+0

Если вы хотите позвонить .to_s, почему бы не передать строку напрямую? Таким образом, вы можете использовать более сложные выражения. Кроме того, почему вы используете b.send (: binding) вместо более очевидного b.binding? (Я новичок в Ruby). Во всяком случае, он отлично работает и намного проще, чем другое решение (которое называется write_pair), которое я даже не понимаю. – marcus

+0

Да, вы можете передать строку вместо символа (без изменений), первая строка в решение просто ссылается на то, что вы не можете ввести что-то 'wp (var)' (как в вопросе). Не знаю/не помню, почему я выбрал символ вместо строки, или почему я ввел '.send (: binding)' вместо '.binding' - возможно, из-за того, что сначала подумал о каком-то другом решении и развился из этого. знак равно – Arkku

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 (запятая, то я) в обычном режиме. Получается так:

foo 

в этом:

puts "foo: #{(foo).inspect}" 

Это хорошо, потому что он не имеет каких-либо внешних зависимостей (например, вы не должны иметь библиотеку нагрузили использовать) ,

1
def write_pair var, binding 
    puts "#{ var } = #{ eval(var, binding)}" 
end 


username = "tyndall" 
write_pair "username", binding 

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

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

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

1
# 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" 
2

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

def bug string 
    puts string + eval(string) 
    end 

Это более читаемым:

def bug string 
    puts '#' * 100 
    puts string + ': ' + eval(string).inspect 
end 

Он вызывается таким образом:

bug "variable" 

Если вам нужно нести фактическая переменная с вами, вам нужно t ype это дважды, но тогда вы можете сделать это inline. Таким образом:

puts "variable: #{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 

Использование рубинового 2.2.2p95

(кредит banister для getting binding контекста вызова)

Смежные вопросы