Level Up Your Ruby Skillz: Writing Compact Code
Tags: ruby, beginners, tips, tutorial
Published: 2019-05-29 13:15:59

---
title: Level Up Your Ruby Skillz: Writing Compact Code
published: true
description: How to write more succinct Ruby code.
tags: ruby, beginners, tips, tutorial 
cover_image: https://thepracticaldev.s3.amazonaws.com/i/xprdsqvl4mh6n5bjfctr.png
series: Level Up Your Ruby Skillz
---

We have all been there, we issue a Pull Request(PR) that we feel is super tight and awesome. It gets stamped "Approved", but there is a catch. Our code isn't actually as tight as we thought. We open up our PR to a bunch of very nice suggestions on how we could tighten up our code even more. 

This is VERY common when you are starting out and it is actually how I learned many of these tricks. Thanks to a lot of very good senior devs reading and commenting on my code from the very beginning, I have learned how to write pretty succinct code. But I will let you in on a secret, it never ends. I have been doing this for 7 years and I STILL get suggestions for how I can write better code. 

Below are some common ways that you can take basic Ruby logic and tighten it up with some of the [syntactic sugar](https://en.wikipedia.org/wiki/Syntactic_sugar). Syntactic sugar is syntax within a programming language, like Ruby, that is designed to make things easier to read or to express.

* [Booleans/Conditionals](#booleans)
* [Variable Assignment](#assignment)
* [Guard Clauses](#guard_clause)
* [Calling Methods](#calling_methods)
* [Safety Navigator](#safety_navigator)
* [Hashes and Arrays](#hashes_arrays)


<a name="booleans"></a>
# Booleans/Conditionals
### Ternary Operator
Let's start with some basic boolean logic in order to set a variable. If `y` is even we want to set `x` equal to 1, if `y` is odd we want to set `x` equal to 2. Here is how we are taught to do it when starting Ruby.
```ruby
if y.even?
  x = 1
else
  x = 2
end
```
The above gives us two assignment statements. This means if we have to change our variable x, we have to make the change in two places, which is not ideal. One way we could simplify the code is by doing this:
```ruby
x = if y.even?
  1
else 
  2
end
```
Now, we only are making our `x` assignment once, which is a little more simple. But even with the above, we are taking up 5 lines to do it. Let's see how we can take it down to one line. 
```ruby
x = y.even? ? 1 : 2
```
`?` is called a [Ternary operator](https://www.w3resource.com/ruby/ruby-ternary-operator.php). The Ternary operator logic uses "(condition) ? (true return value) : (false return value)" statements to shorten your if/else structure. It first evaluates an expression as a true or false value and then executes one of the two given statements depending upon the result of the evaluation. Here is the syntax:
```
test-expression ? if-true-expression : if-false-expression
```
This can be extremely useful when it comes to tightening up logic statements.

### Inline Booleans/Conditionals  
In addition to the slick ternary operator, let's look at another way we can condense some boolean logic into a single line. Here is a basic method with some boolean logic.
```ruby
def say_number_type(number)
  if number.even?
    puts "I am even!"
  end
end
```
To make this more compact we can write that boolean like this:
```ruby
def say_number_type(number)
  puts "I am even!" if number.even?
end
```
The same can be done with `unless`
```ruby
def say_number_type(number)
  puts "I am even!" unless number.odd?
end
```
NOTE: Using inline booleans or conditionals is sometimes referred to as using "modifier syntax". 

<a name="assignment"></a>
# Variable Assignment 
Let's say we have a scenario where we want to assign a variable to another based on if the other variable is present. For example, we have variable `a` and `b` below. If `a` is present(not nil) we want to set `x` equal to `a`. If `a` is nil, we want to set `x` equal to `b`. We could do something like this. 
```ruby
if a.nil?
  x = b
else 
  x = a
end
```
Or, given what we learned above we could do
```ruby
x = a.nil? ? b : a
```
However, when dealing with possible nil values we can make this even more succinct by using the pipe operator like this:
```ruby 
x = a || b
```
If `a` is not nil, that assignment statement will assign the value of `a` to `x`. If `a` is nil, it will assign the value of `b` to x. Checkout the console examples below. 
```
irb(main)> a = 1
=> 1
irb(main)> b = 2
=> 2
irb(main)> x = a || b
=> 1

irb(main)> a = nil
=> nil
irb(main)> x = a || b
=> 2
```
We can use the pipe operator between two variables and we can use it with an equals. Let's say we want to set `x` equal to `a` but only if `x` is nil. If `x` is not nil we want to preserve the value of `x`. In order to accomplish this we would do:
```ruby
x ||= a
```
Here is a console example showing exactly how this works:
```
irb(main)> x = 1
=> 1
irb(main)> a = 2
=> 2
irb(main)> x ||= a
=> 1
irb(main)> x = nil
=> nil
irb(main)> x ||= a
=> 2
```
This is telling ruby to assign the value of `a` to `x` only if `x` is nil. This can be helpful when you are expecting a default but can't rely on it being there. Let's say you have the below method
```ruby
def add_one(number)
  number + 1
end
```
If `number` is nil then we will get a `NoMethodError` when we try to add one to it. We can avoid raising an error by doing something like this
```ruby
def add_one(number)
  number ||= 0
  number + 1
end
```
`number ||= 0` will ensure that if `number` is not defined our method will not raise an error because it will be set to 0. If you want to take this one step further, you can put the assignment operator IN with the argument! 🤯
```ruby
def add_one(number = 0)
  number + 1
end
```
When you are calling this method, if you do not pass it a number, ruby will set number equal to 0.
```irb
irb(main)> add_one
=> 1
irb(main)> add_one(1)
=> 2
```

<a name="guard_clause"></a>
# Guard Clause 
A [Guard Clause](https://medium.com/the-code-review/en-garde-how-you-can-refactor-nested-ifs-with-guard-clauses-in-ruby-1ff728b7a0cd) is a premature exit from a method if certain conditions are met. Guard clauses can help you condense your method logic and write more optimized code. Let's look at an example of when we might use one. Say you have the below method `tester`
```ruby 
def tester(arg)
  if arg == 1
    # logic
  else
   'error'
  end
end
```
In this case, if our argument, `arg`, is not equal to 1 then we will return a string that says 'error'. We can simplify this `tester` method by using a guard clause which is shown below.
```ruby 
def tester(arg)
 return 'error' unless arg == 1 # Guard Clause
 # logic
end
```
When we start our method we immediately check if the value of `arg` is equal to 1. If it is, we return immediately. No need to fumble around with everything else in the method since we know what we want to do. This can be especially helpful when it comes to optimizing code. For example, keep an eye out for situations like this: 
```ruby 
def tester(arg)
  user = User.find(123)
  event = Event.find(123)

  if arg == 1
    # logic
  else
    'error'
  end
end
```
Here, we are gathering data and executing logic before we even get to our if/else boolean. In the end, if `arg` is not equal to 1, then we just wasted a lot of time and resources gathering data we didn't need. A guard clause can ensure that none of these resources are wasted by checking your condition in the first line of your method.

One more tidbit I want to add is if you want to use a guard clause to return nil based on a condition, you can do this:
```ruby
def tester(arg)
  return unless arg == 1
  # logic
end
```
In the above case, `return` alone is the same as if you wrote `return nil`. 
```ruby
def tester(arg)
  # nil is unnecessary 
  return nil unless arg == 1
  # logic
end
```
In Ruby, however, you don't need to explicitly define nil in this case. The first example, `return unless arg == 1` is how you will want to write it and how you will likely see it written by others.

<a name="calling_methods"></a>
# Calling Methods
Let's say you are working with a set of objects that respond to a method and you want to collect the result of that method using a method like `map`. Normally, you would do something like this:
```ruby
a = [1, 2, 3, 4]
string_list = a.map{|obj| obj.to_s}
# string_list = ["1", "2", "3", "4"]
```
We can simplify this even more using a little syntactic sugar and still get the same result. 
```ruby
string_list = a.map(&:to_s)
# string_list = ["1", "2", "3", "4"]
```
Any method that our set of objects, in this case integers, respond to can be called on each object using `&:method` syntax. If you want to understand what Ruby is doing under the hood, I recommended giving this [blog post](https://www.brianstorti.com/understanding-ruby-idiom-map-with-symbol/) a read.

<a name="safety_navigator"></a>
# Safety Navigator 
How many of you have written code like this before? ✋ I definitely have! 
```ruby
def friends_name(user)
  return unless user.present?
  friend = user.friend
  if friend.present?
    friend.name
  end
end
```
There is a lot of presence checking going on here just to ensure we are never calling a method on a nil object and getting the dreaded `# NoMethodError`. Rather than doing all of this checking, we can use Ruby's Safety Navigator! The [Safety Navigator](https://rubyinrails.com/2017/11/17/safe-navigation-operator-ampersand-dot-in-ruby/) will simply return nil if the method is called on a nil object. This means we can simplify our method to this:  
```ruby
def friends_name(user)
  user&.friend&.name
end
```
If any object in that chain is missing we will simply get nil back. Here is another simple console example that will hopefully help further clarify how the safety navigator works. 
```
irb> [].last.to_s
=> ""
irb> [].last.even?
NoMethodError: undefined method `even?' for nil:NilClass
	from (irb):3
	from /usr/bin/irb:11:in `<main>'
irb> [].last&.even?
=> nil
```

<a name="hashes_arrays"></a>
# Hashes and Arrays
### Brackets vs do/end
In my [Hashes](https://dev.to/molly_struve/level-up-your-ruby-skillz-working-with-hashes-4bid) and [Arrays](https://dev.to/molly_struve/level-up-your-ruby-skillz-working-with-arrays-hnn) tutorials I chose to use a lot of do/end block notation to help make it clear what logic was taking place. However, bracket notation is a great way to write more compact code. As we saw in the tutorials, it is a great way to chain together a bunch of logic. 

```ruby
result = [1, 2, 3, 4].map{|n| n + 2}.select{|n| n.even?}.reject{|n| n == 6} 
# result = [4]
```

Now you might be thinking given all these options, how do I know what to use?! Usually, a good rule of thumb is:
* If one line of code is being executed in the block then use brackets.
* If your logic is more than one line, use do/end notation.

Single line bracket example:
```ruby
a = [1, 2, 3]
a.map{|number| number + 10}
```

Multi line do/end example:
```ruby
a = [1, 2, 3]
a.map do |number|
  if number.even?
    puts "I am even"
    number/2
  else
    puts "I am odd"
    number
  end
end
```

Keep in mind that some places or people might have a different style. Always be aware when you are starting at a new place what others are doing. You will likely want to follow their lead when you are starting out. As you gain more experience you will develop your own style and habits.

### Chaining

Really quick I want to loop back to the chaining example I used above: 
```ruby
result = [1, 2, 3, 4].map{|n| n + 2}.select{|n| n.even?}.reject{|n| n == 6} 
# result = [4]
```
This code is pretty straight forward, which is why chaining each step is a great choice to make it more compact. However, there will be times you actually might want to split them up for readability if the logic in each step is complicated. Here is an example of how you would split it up for readability.
```ruby
plus_two_array = [1, 2, 3, 4].map{|n| n + 2}
even_numbers_array = plus_two_array.select{|n| n.even?}
remove_the_sixes_array = even_numbers_array.reject{|n| n == 6} 
```
Each step and its result are clearly defined which can make more complicated logic easier to follow and understand. The reason I want to point this out is because there will be times when writing the most compact code is not best for a situation. **All these strategies are great, but be aware there will be times when you might want to sacrifice compact code for readability.** 

# But Wait, There's More! 
![](https://thepracticaldev.s3.amazonaws.com/i/ydyqwc602h0ydzuoc9s9.gif)

Obviously, there are tons more ways you can write more concise and compact code. This is only a very small list, but I think it is a great place to start. If you have found other tricks that have helped you improve your code feel free to drop them in the comments. As always, if you have questions or anything needs clarification please don't hesitate to ask!

If you want a quick reference for these methods I made a [handy cheatsheet](https://paper.dropbox.com/doc/Tricks-For-Writing-Compact-Ruby-Code--AeAl8FR15SMDlf_JW9BrymB1AQ-IAfGvmx5cKZ6s38UM4Rrl) with just the code from each example.