cult3

Working with Ruby Methods

May 20, 2015

Table of contents:

  1. Working with Methods
  2. Implicit returns
  3. You don’t need to use parenthesis
  4. Keyword arguments
  5. The Splat Operator
  6. The Double Splat Operator
  7. Conclusion

So far in this Ruby series we have already touched upon using classes and methods a number of times, but we haven’t really looked at writing our own.

A class is like the blueprint of an object and describes it’s properties and behaviours.

If you are already familiar with object-oriented programming, using classes and methods will seem like second nature to you.

However, if you’re new to object-oriented programming, understanding the importances of classes and methods can open the door to a whole new world of understanding.

Before we get into looking at classes, today we will be looking at writing Ruby methods.

Working with Methods

def hello_world
  puts 'Hello World'
end

The code above is a Ruby method that will print the string "Hello World" to the screen. A Method is defined used the def..end syntax.

In other programming languages, a method usually refers to the function of an object. However because everything is an object in Ruby, what normally looks like a function, is actually also a method.

Implicit returns

The first thing to understand about Ruby methods is that the last line of the method will automatically be returned.

So for example:

def book(name)
  return name
end

The method above does not need the returnkeyword as the name variable will automatically be returned:

def book(name)
  name
end

puts book("Harrington on Hold'em")
# => "Harrington on Hold'em"

You don’t need to use parenthesis

If you’re coming to Ruby from a language like PHP, one of the things that might catch you out is the fact that Ruby does not require that you use parenthesis when you call a method.

For example, to call the method above, we can simply write:

hello_world

If we were to change the method to accept a parameter:

def hello_world(name)
  puts "Hello #{name}"
end

We can still call the method without the parenthesis:

hello_world 'Philip'

There are certain conventions in Ruby for when you should and should not use things like parenthesis. Over time you will pick up these conventions, but if you want a head start, I’d recommend having a read of this Ruby Style Guide.

Keyword arguments

Imagine we have the following method that creates a new Hash that represents a book:

def book(name, publisher = nil, tags = [])
  { name: name, publisher: publisher, tags: tags }
end

In this method we have a required parameter of name, an optional parameter of publisher and an optional tags parameter, which defaults to an empty Array.

We can call this method in the following ways:

puts book 'The 4 Hour Work Week'
puts book "The Innovator's Dilemma", 'HBS'
puts book 'Zero to One', 'Random House', ['business']
puts book 'The Long Tail', nil, ['business']

This works fine for the first three calls to this method, but when we want to supply a tags Array, and not a publisher things start to fall apart because you need to also send the nil placeholder.

Another downside of defining arguments like this is that you need to memorise the order in which they should be supplied. This is obviously going to be impossible once you have hundreds of methods and so you will find yourself wasting a lot of time looking up the order of the arguments.

Traditionally this problem was solved in Ruby by using an options Hash:

def book(name, options = {})
  publisher = options[:publisher] || nil
  tags = options[:tags] || []

  { name: name, publisher: publisher, tags: tags }
end

puts book 'The 4 Hour Work Week'
puts book "The Inovator's Dilemma", { publisher: 'HBS' }
puts book 'Zero to One', { publisher: 'Random House', tags: ['business'] }
puts book 'The Long Tail', { tags: ['business'] }

This works fine, but can be annoying if you want to set default values for the arguments in the hash.

Ruby 2.0 introduced a better way to deal with this problem in keyword arguments:

def book(name, publisher: nil, tags: [])
  { name: name, publisher: publisher, tags: tags }
end

puts book 'The 4 Hour Work Week'
puts book "The Innovator's Dilemma", publisher: 'HBS'
puts book 'Zero to One', publisher: 'Random House', tags: ['business']
puts book 'The Long Tail', tags: ['business']

This method definition is using the new Ruby Hash syntax that looks a lot like JSON. Remember, publisher: and tags: are simply Ruby symbols.

With this syntax you can set the defaults as part of the method definition.

You can also pass the options hash in any order, so you don’t need to memorise the order of the arguments:

puts book 'The Black Swan', tags: ['investing'], publisher: 'Penguin'

The Splat Operator

Sometimes you will need to write a method that should accept an arbitrary number of arguments.

For example, image we needed to accept the name of a book and one or more tags.

You could implement that using the Splat Operator:

def book(name, *tags)
  { name: name, tags: tags }
end

In this method definition, all arguments after the name argument will be scooped up and placed into the tags Array.

We can call this method like this:

puts book 'The Lean Startup', 'Business', 'Startups'

The Splat Operator allows you to accept an Array of parameters without having the method be passed an Array when it is called.

The Double Splat Operator

In Ruby 2.0 the double splat operator was introduced. This works in a similar way to the single splat operator, but it is for creating a Hash of arguments, rather than an Array.

For example, image we have the following method:

def book(name, *tags, **meta)
  { name: name, tags: tags, meta: meta }
end

The *tags will scoop up normal arguments and place them in the the tags Array and the **meta will scoop up the keyword arguments and place them in the meta Hash.

You can see this in action by making the following calls to the method:

puts book 'The Art of the Start'
# => {:name=>"The Art of the Start", :tags=>[], :meta=>{}}

If we call the method with only a name, the tags Array and the meta Hash are empty.

puts book 'Little Bets', 'Business', 'Technology'
# => {:name=>"Little Bets", :tags=>["Business", "Technology"], :meta=>{}}

If we call the method with a name and two random arguments, those arguments will be scooped up and placed into the tags Array.

puts book 'Linchpin', 'Business', author: 'Seth Godin'
# => {:name=>"Linchpin", :tags=>["Business"], :meta=>{:author=>"Seth Godin"}}

If we call the method and pass keyword arguments they will be scooped up and placed into the meta Hash.

Conclusion

As with all programming languages there are many interesting and unique characteristics of Ruby.

However in the grand scheme of things, it’s important that you get the basics down and then cross each bridge as you come to it.

I prefer to think about programming as learning how to use a tool. Once you’ve got the basics down, you need to start using the tool.

As we progress with learning Ruby we will likely encounter a whole load more of interesting things to do with methods.

But for now, we will move on to the next topic. In next week’s tutorial we will look at writing Ruby classes.

Philip Brown

@philipbrown

© Yellow Flag Ltd 2024.