Can I enforce arity on a block passed to a method?

Your @action will be a Proc instance and Procs have an arity method so you can check how many arguments the block is supposed to have:

def perform(*args)
  if args.size != @action.arity
    raise WrongArity.new(args.size)
  end
  @action.call(*args)
end

That should take care of splatless blocks like { |a| ... } and { |a,b| ... } but things are a little more complicated with splats. If you have a block like { |*a| ... } then @action.arity will be -1 and { |a,*b| ... } will give you an arity of -2. A block with arity -1 can take any number of arguments (including none), a block with arity -2 needs at least one argument but can take more than that, and so on. A simple modification of splatless test should take care of the splatful blocks:

def perform(*args)
  if @action.arity >= 0 && args.size != @action.arity
    raise WrongArity.new(args.size)
  elsif @action.arity < 0 && args.size < -(@action.arity + 1)
    raise WrongArity.new(args.size)
  end
  @action.call(*args)
end

Tags:

Ruby

Lambda

Proc