有一种常见的习惯用法,比如:
def with clazz, &block
yield clazz
clazz
end
with Hash.new |hash|
hash.merge!{:a => 1}
end
有没有办法进一步定义#with以便有可能做到:
with Hash.new |hash|
merge!{:a => 1}
end
甚至:
with Hash.new do
merge!{:a => 1}
end
更新
后来我偶然发现了我正在寻找的东西(解决方案类似于已接受的解决方案): http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/19153
更新2
它被添加到https://github.com/kristianmandrup/sugar-high
中的sugar-high / dsl中更新3
docille project on Github很好地利用了这个想法。
答案 0 :(得分:8)
如果您指的是Rails路由的方式,那么我认为你需要做这样的事情
def with(instance, &block)
instance.instance_eval(&block)
instance
end
with(Hash.new) do
merge!({:a => 1})
merge!({:b => 1})
end
这就是我在Rails源代码中看到它的方式,无论如何从action_pack/lib/action_dispatch/routing/route_set
中查看draw方法开始答案 1 :(得分:3)
不是你的伪Ruby:
with Hash.new do |hash|
merge!{:a => 1}
end
与使用1.9的tap
相同?例如:
>> x = Hash[:a, :b].tap { |h| h.merge!({:c => :d}) }
=> {:a=>:b, :c=>:d}
当然,您仍需要命名块参数。
答案 2 :(得分:1)
您可以使用ruby builtin tap
:
Hash.new.tap do |hash|
hash.merge! a: 1
end
对于多个对象,这甚至可能被“滥用”:
[one_long_name, another_long_name].tap do |(a,b)|
a.prop = b.prop
end
当然,根据您的示例,两者都没有准确地给出with
所做的事情:不会在对象的实例中评估该块。但我更喜欢将tap
用于多个对象,加上tap
返回self
,因此可以将其链接起来:
[one_long_name, another_long_name].tap {|(a,b)| a.prop = b.prop }.inspect