#with (object) & block trick

There is a general idiom for using substitutions such as:

def with clazz, &block yield clazz clazz end with Hash.new |hash| hash.merge!{:a => 1} end 

Is there a way to go further and define # to be able to do:

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

or even:

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

?


UPDATE

Later, I accidentally found what I was looking for (the solution seems to be accepted): http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/19153

UPDATE 2

It was added to sugar-high / dsl at https://github.com/kristianmandrup/sugar-high

UPDATE 3

The docille project on Github uses this idea very well.

+7
source share
3 answers

If you are talking about how Rails does routing, I think you need to do something like this

 def with(instance, &block) instance.instance_eval(&block) instance end with(Hash.new) do merge!({:a => 1}) merge!({:b => 1}) end 

Here's how I can make sure that this is done in the Rails source anyway, starting with looking at the draw method in action_pack / lib / action_dispatch / routing / route_set

+7
source

Not your pseudo-Ruby:

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

Same as using 1.9 tap ? For example:

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

You should still specify a block argument.

+3
source

You can use the built-in ruby ​​tap:

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

It can even be an “abuse” for several objects:

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

Of course, both do not give you exactly what with will do according to your example: the block will not be evaluated on the object instance. But I prefer to use tap with multiple objects, plus tap return self , so it can be bound:

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

All Articles