Take me home

Method arguments

Published September 10, 2008

An introduction to the stuff your mom and dad didn't tell you about giving arguments to methods.

The asterisk

Capture x amount of arguments.

def silly_list(*args)
  args.join(' ') + '.'
end

silly_list 'My', 'hovercraft', 'is', 'full', 'of', 'eels'
"My hovercraft is full of eels."

You can also do it the other way around, when calling a method. This will pass each item in the array as a separate argument to the method.

def say_a_name(first, last)
  puts "#{last}, #{first}"
end

name = ['John', 'McClaine']
say_a_name(*name)
# => "McClaine, John"

name = ['John', 'Leethal', 'McClaine']
say_a_name(*name)
# => ArgumentError: wrong number of arguments (3 for 2)

The ampersand

Capture the block.

def can_has_block(&block)
  puts block.inspect
end

can_has_block
# => nil

can_has_block { "Here is a block" }
# => #<Proc:0x0008f138@-:8>

You can also do it the other way around, when calling a method. This will pass the proc to the method as if you were giving it a normal block. The last two calls are identical:

a_proc = Proc.new { puts "I am a proc" }

def call_the_block
  yield
end

call_the_block { puts "I am a block" }
# => I am a block
call_the_block { a_proc.call }
# => "I am a proc"
call_the_block(&a_proc)
# => "I am a proc"

And then, of course, without the ampersand Ruby treats the proc as any other object passed as an argument.

call_the_block(a_proc)
# => ArgumentError: wrong number of arguments (1 for 0)

Both?

Of course! Let's use every trick in the book.

def another_map(*args, &block)
  args.map(&block)
end

another_map('hello', 'there') {|i| i.upcase }
# => ["HELLO", "THERE"]

Yield

Don't forget yield, though. These two calls are identical.

def say_hello(&block)
  block.call
end

def say_hello
  yield
end

In fact, yield is much better, as Ruby doesn't have to instantize a Proc object.

Default values

You probably knew this already.

def a_default_value(value = {})
  value
end

a_default_value
# => {}

a_default_value("hello!")
# => "hello!"

Questions or comments?

Feel free to contact me on Twitter, @augustl, or e-mail me at august@augustl.com.