Accepting or Passing a Variable Number of Arguments

Problem

You want to write a method that can accept any number of arguments. Or maybe you want to pass the contents of an array as arguments into such a method, rather than passing in the array itself as a single argument.

Solution

To accept any number of arguments to your method, prefix the last argument name with an asterisk. When the method is called, all the "extra" arguments will be collected in a list and passed in as that argument:

	def sum(*numbers)
	 puts "I'm about to sum the array #{numbers.inspect}"
	 numbers.inject(0) { |sum, x| sum += x }
	end

	sum(1, 2, 10)
	# I'm about to sum the array [1, 2, 10]
	# => 13

	sum(2, -2, 2, -2, 2, -2, 2, -2, 2)
	# I'm about to sum the array [2, -2, 2, -2, 2, -2, 2, -2, 2]
	# => 2
	
	sum
	# I'm about to sum the array []
	# => 0

To pass an array of arguments into a method, use the asterisk signifier before the array you want to be turned into "extra" arguments:

	to_sum = []
	1.upto(10) { |x| to_sum << x }
	sum(*to_sum)
	# I'm about to sum the array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
	# => 55

Bad things happen if you forget the asterisk: your entire array is treated as a single "extra" argument:

	sum(to_sum)
	# I'm about to sum the array [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
	# TypeError: Array can't be coerced into Fixnum

 

Discussion

Why make a method take a variable number of arguments, instead of just having it take a single array? It's basically for the convenience of the user. Consider the Kernel#printf method, which takes one fixed argument (a format string), and then a variable number of inputs to the format string:

	printf('%s | %s', 'left', 'right')
	# left | right

It's very rare that the caller of printf already has her inputs lying around in an array. Fortunately, Ruby is happy to create the array on the user's behalf. If the caller does already have an array of inputs, it's easy to pass the contents of that array as "extra" arguments by sticking the asterisk onto the appropriate variable name:

	inputs = ['left', 'right']
	printf('%s | %s', *inputs)
	# left | right

As you can see, a method can take a fixed number of "normal" arguments and then a variable number of "extra" arguments. When defining such a method, just make sure that the last argument is the one you prefix with the asterisk:

	def format_list(header, footer='', *data)
	 puts header
	 puts (line = '-' * header.size)
	 puts data.join("
")
	 puts line
	 puts footer
	end
	cozies = 21
	gaskets = 10
	format_list("Yesterday's productivity numbers:", 'Congratulations!',
	 "#{cozies} slime mold cozies", "#{gaskets} Sierpinski gaskets")
	# Yesterday's productivity numbers:
	# --------------------------------
	# 21 slime mold cozies
	# 10 Sierpinski gaskets
	# --------------------------------
	# Congratulations!

You can use the asterisk trick to call methods that don't take a variable number of arguments. You just need to make sure that the array you're using has enough elements to provide values for all of the method's required arguments.

You'll find this especially useful for constructors that take many arguments. The following code initializes four Range objects from four arrays of constructor arguments:

	 ranges = [[1, 10], [1, 6, true], [25, 100, false], [6, 9]]
	 ranges.collect { |l| Range.new(*l) }
	 # => [1..10, 1…6, 25..100, 6..9]



Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net