Last Updated: February 25, 2016
·
1.468K
· mbillard

How to accept one or more arguments

There's often a need to accept a variable number of arguments. You might have done it like this:

def method(object_or_objects)
  if object_or_objects.respond_to? :each
    objects = object_or_objects
  else
    objects = [object_or_objects]
  end

  ...
end

Sounds familiar? Well there are a number of ways that work better with this kind of pattern.

First one accepts either 1 argument or many arguments (and can be combined with standard arguments).

# Usage:
#   method(a) or method(a, b, c)
# Traps:
#   method([a, b, c])   #=> [[a, b, c]]
#     can be solved by calling the method as follows:
#   method(*[a, b, c]) #=> [a, b, c]
def method(*objects)
  # objects is always an array
end

Second one accepts only 1 argument, but whether the argument is a single object or an array of objects, it will be treated as an array.

# Usage:
# method(a) or method([a, b, c])
# Traps:
#   method(a, b, c) #=> invalid number of arguments
def method(object_or_objects)
  objects = Array(object_or_objects) # or the less readable = [*object_or_objects]
end

There you go, now you can handle as many arguments as you like and deal with them as if they were always an array.

1 Response
Add your response

I preffer the first snippet. If you want to be sure that you're safe about your trap, you can always do this:

def method(*args)
  args.flatten!
  # blablabla
end
over 1 year ago ·