The Elements of (Ruby) Style

I've been working with Ruby a lot lately, and have come to enjoy the expressive succinctness of the language. It is credited as a language that strives to make programming enjoyable, and minimize the amount of work the programmer must do. To accomplish those goals, Ruby allows the flexibility to do things in many different ways. This approach, in contrast with the "one right and obvious way" mentality, allows the programmer to use a style suited to their way of approaching the problem at hand. The resulting syntactic flexibility is a double edged sword, however, and can lead to concise and beautiful code in the right hands, or utterly incomprehensible code in the wrong ones.

In that regard, Ruby seems quite similar to English. Both are complex, multifaceted languages, which take time to perfect, and must be studied before they can be applied effectively. One of the seminal works regarding English writing style is a book by William Strunk Jr. and E. B. White called "The Elements of Style". Instead of a comprehensive guide, the short book presents a few powerful rules that greatly enhance the quality of most writing. This post is my attempt at creating a similar style guide for Ruby. For a more wholistic Ruby style guide, see:


Create Importable Scripts

class Utility
    # utility class logic

if __FILE__ == $0
    # code in this block is only executed if the file is run from the command line

Prefer Iterators (and blocks) to For Loops

# perform an action a certian number of times
5.times {|index| ... }
(1..10).each{|i| ...}

# looping through collections
wines.each {|wine| wine.pour} # use each for side effects {|wine| wine.vintage} # use map to transform an enumerable {|wine| wine.type == :merlot}
wines.reject {|wine| wine.price > 30}

Prefer String Interpolation

s = "strings"
# Bad
puts "Concatenated " + s + " example"
puts "Hello World"

# Good
puts "Concatenated #{s} example"
puts 'Hello World'

Favor End of Line Modifiers

# Bad
if !wine.corked?

# Good
drink(wine) unless wine.corked?

Utilize Method Qualifiers

cellar.empty? # should return boolean value
cellar.clear! # modifies the state of the cellar

Favor "Or Equal" Idiom over nil Checks

# Bad
if a.nil?
    a = b

# Less Bad
a = b if a.nil?

# Good
a ||= b

Favor Block Yielding Methods

# Bad
    file ="/tmp/filename", "w")
    file.write("some text")
rescue IOError => e
    # need to ensure that the file handle gets closed even if an error occurs

# Good'/tmp/filename', 'w') {|file| file.write("some text")} # file handle closed once block exits

Prefer Hash for Optional Args

# Bad
def foo(required_param, opt_arg1 = 'default1', opt_arg2 = 'default2', opt_arg3 = 'default3')
    # ...

# Good
def foo(required_param, optional_params = {})
    opts = {:arg1 => 'default1',
    :arg2 => 'default2',
    :arg3 => 'default3'}.merge(optional_params)
    # ...

Forgo Explicit Returns

# Bad
def fib(n)
    return 1 if n < 2 # usage of return here is ok
    return fib(n-1) + fib(n-2) # the return here is unnecessary

# Good
def fib(n)
    (0..n).inject([1,0]) { |(a,b), _| [b, a+b] }.first

No Empty Parentheses

Proper Block Semantics

# Bracket style block{|w|}.sort

# Do style block
cellars.each do |cellar|
    cellar.wines.each do |wine|
        wine.pour! if desired_wines.include?(wine)

And, Or vs &&, ||

# boolean expression example
if condition1 && condition2

# control flow example
buy_wine and open_wine and drink_wine

# example of the differences
a = true && false
#=> false (a == false) # the && operator takes precedence
a = true and false
#=> false (a == true) # the = operator takes precedence

Prefer Static Methods, and a Functional Approach

class Test
    # static method
    def self.method1

    # instance method
    def method2

keys = [k1, k2, k3, ...]
values = [v1, v2, v3, ...]

# Bad
result = {}
keys.each_with_index do |key, index|
    result[k] = values[index]

# Good
result = Hash[]

Prefer Self-documenting Code to Comments

Favor Small, Succient, Well Named Methods


Quality Ruby code should be simple, readable, and DRY. The rules above are solid guidelines that will lead to better code if followed properly. That being said, as with any set of rules, there are always exceptions, so be judicious in their application. As Ralph Waldo Emerson once said,

"A foolish consistency is the hobgoblin of little minds"