# с (объектом) и трюком с блоком - PullRequest
7 голосов
/ 19 августа 2011

Существует распространенная идиома использования замен:

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


UPDATE

Позже случайно я нашел именно то, что искал (решение, подобное принятому): http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/19153

ОБНОВЛЕНИЕ 2

Было добавлено в сахар с высоким содержанием / DSL в https://github.com/kristianmandrup/sugar-high

ОБНОВЛЕНИЕ 3

Проект Docille на Github очень хорошо использует эту идею.

Ответы [ 3 ]

8 голосов
/ 19 августа 2011

Если вы говорите о том, как Rails выполняет маршрутизацию, я думаю, вам нужно сделать что-то вроде этого

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

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

Вот как я могу увидеть, как это делается в исходном коде Rails, в любом случае начнем с просмотра метода draw в action_pack / lib / action_dispatch / routing / route_set

3 голосов
/ 19 августа 2011

Не твой псевдо-Рубин:

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}

Конечно, вы все равно должны назвать аргумент блока.

1 голос
/ 07 ноября 2016

Вы можете использовать встроенный рубин 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 return self, поэтому его можно объединить в цепочку:

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