2011-08-19 28 views
7

Có một thành ngữ phổ biến của việc sử dụng thay thế như:#with (object) & chặn lừa

def with clazz, &block 
    yield clazz 
    clazz 
end 

with Hash.new |hash| 
    hash.merge!{:a => 1} 
end 

Có cách nào để đi xa hơn và xác định #with để có một khả năng thực hiện:

with Hash.new |hash| 
    merge!{:a => 1} 
end 

hoặc thậm chí:

with Hash.new do 
    merge!{:a => 1} 
end 

?


CẬP NHẬT

Sau đó vô tình tôi tìm thấy chính xác những gì tôi đang tìm kiếm (giải pháp tương tự như chấp nhận một): http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/19153

UPDATE 2

Nó đã được bổ sung vào đường cao/dsl trong https://github.com/kristianmandrup/sugar-high

CẬP NHẬT 3

docille project on Github khai thác ý tưởng này rất độc đáo.

+0

cái gì? Bạn có thể chọn biến khối của bạn ngắn như bạn muốn. Bạn sẽ tiết kiệm được những gì? Và nhân tiện, bạn đã bỏ lỡ 'do'. –

+0

Tập trung vào câu hỏi, vui lòng! Cuối cùng có thể không? –

+3

"Có một thành ngữ phổ biến của việc sử dụng các thay thế như" - '[trích dẫn cần thiết]'. –

Trả lời

7

Nếu bạn đang đề cập đến cách thức mà Rails không định tuyến sau đó tôi nghĩ rằng bạn cần phải làm điều gì đó như thế này

def with(instance, &block) 
    instance.instance_eval(&block) 
    instance 
end 

with(Hash.new) do 
    merge!({:a => 1}) 
    merge!({:b => 1}) 
end 

Đây là cách tôi có thể nhìn thấy nó được thực hiện trong Rails nguồn nào bắt đầu bằng cách tìm kiếm ở phương pháp bốc thăm trong action_pack/lib/action_dispatch/routing/route_set

3

Không phải là bạn giả Ruby:

with Hash.new do |hash| 
    merge!{:a => 1} 
end 

Điều tương tự như sử dụng 1.9 của tap? Ví dụ:

>> x = Hash[:a, :b].tap { |h| h.merge!({:c => :d}) } 
=> {:a=>:b, :c=>:d} 

Bạn vẫn phải đặt tên cho đối số khối của khóa học.

+0

Bạn nói đúng. Chúng rất giống nhau. Nhưng tôi muốn tránh các cuộc gọi trên biến được chuyển tới chặn, nhưng trực tiếp! như Hash [: a,: b] .some_cool_method {merge! ({: c =>: d})} –

1

Bạn có thể sử dụng ruby ​​BUILTIN tap:

Hash.new.tap do |hash| 
    hash.merge! a: 1 
end 

này thậm chí có thể "bị lạm dụng" cho nhiều o bjects:

[one_long_name, another_long_name].tap do |(a,b)| 
    a.prop = b.prop 
end 

Tất nhiên cả hai không cho bạn biết chính xác những gì with sẽ làm theo ví dụ của bạn: Khối sẽ không được đánh giá trong trường hợp của đối tượng. Nhưng tôi thích rất nhiều để sử dụng tap với nhiều đối tượng, cộng với tap trở self, vì vậy nó có thể được xích:

[one_long_name, another_long_name].tap {|(a,b)| a.prop = b.prop }.inspect