2010-04-08 48 views
21

Cách tốt nhất để viết một hàm (hoặc cái gì đó DSLish) mà sẽ cho phép tôi viết mã này trong Ruby. Làm thế nào tôi sẽ xây dựng hàm write_pair?Ruby - in tên biến và sau đó giá trị của nó

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

Có thể làm được không? Tìm cách đơn giản nhất để làm điều này.

+0

Trình mô tả không chỉ có thể thực hiện việc này mà còn in ra 'list.first: 1'. –

Trả lời

21

Chắc chắn nó có thể!

Giải pháp của tôi kiểm tra các var bởi Object # object_id sắc: http://codepad.org/V7TXRxmL
Nó làm tê liệt trong phong cách đi qua ràng buộc ...
Mặc dù nó hoạt động chỉ dành riêng cho vars địa phương nêu ra, nó có thể dễ dàng được thực hiện "phổ quát" thêm sử dụng trong những phương pháp phạm vi biến niêm yết khác như instance_variables, vv

# 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

nơi tôi có thể đọc thêm về ràng buộc này (theo cách bạn đang sử dụng thuật ngữ)? đây là nơi tôi bị lạc. – BuddyJoe

+0

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

+9

Tôi rất muốn bị làm tổn thương bất cứ ai thực sự sẽ sử dụng mã này trong một dự án. – molf

2

Bạn thực sự không thể có tên của biến trong Ruby. Nhưng bạn có thể làm điều gì đó như thế này:

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

Hoặc thậm chí,

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

Chắc chắn bạn có thể nhưng nó khó khăn! – clyfe

14

Nếu nó có thể để bạn có thể sử dụng một biểu tượng thay cho tên biến, bạn có thể làm một cái gì đó như thế này:

def wp (s, &b) 
    puts "#{s} = #{eval(s.to_s, b.binding)}" 
end 

Trong sử dụng:

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 

Lưu ý rằng bạn phải vượt qua khối rỗng {} để phương pháp này hoặc nó không thể có được những ràng buộc để đánh giá biểu tượng.

+0

Nếu bạn định gọi .to_s, tại sao không truyền trực tiếp chuỗi? Bằng cách này, bạn thậm chí có thể sử dụng các biểu thức phức tạp hơn. Bên cạnh đó, tại sao bạn sử dụng b.send (: binding) thay vì b.binding rõ ràng hơn? (Tôi là người mới đối với Ruby). Dù sao, nó hoạt động tốt và đơn giản hơn nhiều so với giải pháp khác (cái gọi là write_pair), mà tôi thậm chí không thể hiểu được – marcus

+0

Có, bạn có thể chuyển một chuỗi thay vì ký hiệu (không cần sửa đổi), dòng đầu tiên trong giải pháp chỉ đề cập đến thực tế là bạn không thể gõ một cái gì đó 'wp (var)' (như trong câu hỏi). Không biết/nhớ lý do tại sao tôi chọn biểu tượng thay vì chuỗi, hoặc tại sao tôi đặt trong '.ndnd (: binding)' thay vì '.binding' - có lẽ là do suy nghĩ của một số giải pháp khác trước tiên và phát triển từ đó. =) – Arkku

3

tôi đã thực hiện một macro vim cho việc này:

" Inspect the variable on the current line (in Ruby) 
autocmd FileType ruby nmap ,i ^"oy$Iputs "<esc>A: #{(<esc>"opA).inspect}"<esc> 

Đặt biến bạn muốn kiểm tra trên một dòng riêng của mình, sau đó gõ ,i (dấu phẩy sau đó i) trong chế độ bình thường. Nó quay này:

foo 

vào đây:

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

này là tốt đẹp bởi vì nó không có bất kỳ phụ thuộc bên ngoài (ví dụ như bạn không cần phải có một thư viện tải lên để sử dụng nó) .

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


username = "tyndall" 
write_pair "username", binding 

Điều này có vẻ kỳ lạ vì ràng buộc không bao giờ được xác định, nhưng nó hoạt động. Từ Ruby: getting variable name:

Phương thức binding() cho đối tượng Binding ghi lại ngữ cảnh tại điểm được gọi. Sau đó, bạn chuyển một ràng buộc vào eval() và nó đánh giá biến trong ngữ cảnh đó.

Đảm bảo chuyển một chuỗi chứ không phải biến.

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

Đây là một giải pháp đơn giản:

def bug string 
    puts string + eval(string) 
    end 

Đây là dễ đọc hơn:

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

Nó được gọi như sau:

bug "variable" 

Nếu bạn cần phải thực hiện các biến thực sự với bạn, bạn phải t ype nó hai lần, nhưng sau đó bạn có thể làm điều đó nội tuyến. Như vậy:

puts "variable: #{variable}" 
2

Dựa trên câu trả lời trước liên quan đến những biểu tượng & bindings ... nếu đi qua trong tên biến như một biểu tượng làm việc cho bạn (những người không yêu cắt ra tổ hợp phím thêm ?!), thử điều này:

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) 

điều khiển đầu ra:

> wp :aa 
aa = 1 
=> nil 
> wp :bb 
bb = "some bb string" 
=> nil 
> wp :os 
os = #<OpenStruct z=26, y=25> 
=> nil 

Sử dụng ruby ​​2.2.2p95

(Tín dụng cho banister cho getting binding ngữ cảnh gọi)

Các vấn đề liên quan