What a clean way to allow a block to handle a variable number of arguments?

I have encountered this situation before, and something tells me how I deal with this at all, it’s not the cleanest or the most idiomatic.

Suppose I have a function that takes a block, which in turn can take 1 or 2 (say) parameters.

def with_arguments(&block)
  case block.arity
  when 1
    block.call("foo")
  when 2
    block.call("foo", "bar")
  end
end

with_arguments do |x|
  puts "Here the argument I was given: #{x}"
end

with_arguments do |x, y|
  puts "Here are the arguments I was given: #{x}, #{y}"
end

The inclusion arityseems pretty hacked. Is there a more standard Ruby way to achieve this kind of thing?

+3
source share
3 answers

This is how I would pass arbitrary arguments to lambda:

def with_arguments(&block)
  args = %w(foo bar)
  n = block.arity
  block.call *(n < 0 ? args : args.take(n))
end

with_arguments &lambda { |foo| }
with_arguments &lambda { |foo, bar| }
with_arguments &lambda { |*args| }
with_arguments &lambda { |foo, *args| }
with_arguments &lambda { |foo, bar, *args| }

n , lambda . (n + 1).abs . , , .

lambda , n args. , .

lambda , args :

with_arguments &lambda { |foo, bar, baz, *args| }
# ArgumentError: wrong number of arguments (2 for 3)

:

def with_arguments(&block)
  block.call 'foo', 'bar'
end

with_arguments { |x| puts x }              # y is not used
with_arguments { |x, y| puts x, y }        # All arguments are used
with_arguments { |x, y, z| puts x, y, z }  # z will be nil

, nil.

, Proc s - lambda , . , , Proc#lambda?

, , yield:

def with_arguments
  yield 'foo', 'bar'
end
+5

...

  • 2 , nil
  • , . : - , ,
0
def bar(&block)
    puts 'In bar'
    block.call(1) if block
    puts 'Back in bar'
    block.call(1,2) if block
end

1.9.3p392 :043 > bar do |*b| puts b.length end
In bar
1
Back in bar
2
0
source

All Articles