Splat operator and different options to pass a block

Hello,

I’m currently experimenting a bit in Ruby, to get a feeling of how the
language works. Out of curiosity, I wanted to have a method which would
accept a Proc ( or block/ lambda/ Method ) both passed attached or as an
explicit parameter. My idea to realise this was:

def test( block_as_parameter= nil, &block_attached )
block = block_attached || block_as_parameter
block.call
end

test { puts “Foo” } #=> Foo
test( Proc.new { puts “Foo” } ) #=> Foo

So far, so good (I even think that this is the easiest way to achieve
said functionality). This works as long as I don’t have the splat
operator in my parameter list. There are - afaict - two reasons for
this:
1.: After the splat operator it is not possible to specify optional
parameters (and even if we had the block_as_parameter parameter before
the splat, it would take precedence over it, resulting in 2. - also, it
would destroy interface consistency).
2.: The block_as_parameter parameter will be filled with one of the
parameters which we wanted the splat operator to gather.

My code to solve this problem is as follows:

def test2( foo, *args, block_as_param, &block_attached )
block = #this is where the magic happens
if block_attached
args << block_as_param
block_attached
else
block_as_param
end
p foo
p args
block.call
end

test2( “FirstParam”, “SecondParam” ) { puts “Foo” }
#=> “FirstParam”

[“SecondParam”]

Foo

test2( “FirstParam”, “SecondParam”, “ThirdParam” ) { puts “Foo” }
#=> “FirstParam”

[“SecondParam”, “ThirdParam”]

Foo

test2( “FirstParam”, “SecondParam”, “ThirdParam”, Proc.new { puts
“Foo” } )
#=> “FirstParam”

[“SecondParam”, “ThirdParam”]

Foo

This solution works as I want it to work, so that’s good. But now I’m
curious: Is there another, easier way to achieve what I want? I’m aware
that this has not that many real-life usages, but I think it’s an
interesting scenario to think about.

Thanks in advance for all your ideas!

P.S.: Tested in Ruby 1.9.3, so I can’t tell if this would behave any
different in Ruby 1.8.

Hi,

First of all, this isn’t really a useful technique, because Ruby already
allows you to pass a Proc/Lambda as a block by prepending “&”:

prc = proc {|x| puts x}
[1, 2, 3].each(&prc)

In other words: There’s simply no need to do this magic inside a method.

Secondly, why do you need a separate parameter for the proc argument?
Why not simply pull it out of the args array?

def test2(foo, *args, &block)
block ||= args.last
block[]
end

test2(‘xyz’) {puts 1}
test2(‘xyz’, proc {puts 1})

Hi,

thanks for your answer. I really appreciate it.

First of all, this isn’t really a useful technique, because Ruby already
allows you to pass a Proc/Lambda as a block:

prc = proc {|x| puts x}
[1, 2, 3].each(&prc)
Didn’t know that was possible, that’s really useful.
Secondly, why do you need a separate parameter for the proc argument?
Why not simply pull it out of the args array?

def test2(foo, *args, &block)
block ||= args.last
block[]
end

test2(‘xyz’) {puts 1}
test2(‘xyz’, proc {puts 1})
D’oh, didn’t think of that. Clearly a much nicer solution. I’m coming
from Java, that’s why I’m sometimes struggling to find these shortcuts
on my own - I’m not fully accustomed to this degree of freedom. :wink:

Cheers!