Our Code Standards

  • Use soft-tabs with a two space indent.

  • Keep each line of code to a readable length. Unless you have a reason to, keep lines to fewer than 100 characters.

  • Never leave trailing whitespace.

  • End each file with anewline.

  • Use spaces around operators, after commas, colons and semicolons, around{and before}.

sum = 1 + 2
a, b = 1, 2
1 > 2 ? true : false; puts "Hi"
[1, 2, 3].each { |e| puts e }
  • No spaces after(,[or before],).

some(arg).other
[1, 2, 3].length
  • No spaces after!.

!array.include?(element)
  • Indentwhenas deep ascase.

case
when song.name == "Misty"
  puts "Not again!"
when song.duration > 120
  puts "Too long!"
when Time.now.hour > 21
  puts "It's too late"
else
  song.play
end

kind = case year
       when 1850..1889 then "Blues"
       when 1890..1909 then "Ragtime"
       when 1910..1929 then "New Orleans Jazz"
       when 1930..1939 then "Swing"
       when 1940..1950 then "Bebop"
       else "Jazz"
       end
Use empty lines between defs and to break up a method into logical paragraphs.
def some_method
  data = initialize(options)

  data.manipulate!

  data.result
end

def some_method
  result
end
  • Use empty lines betweendefs and to break up a method into logical paragraphs.

def some_method
  data = initialize(options)

  data.manipulate!

  data.result
end

def some_method
  result
end

Classes

  • Avoid the usage of class (@@) variables due to their unusual behavior in inheritance.

class Parent
  @@class_var = "parent"

  def self.print_class_var
    puts @@class_var
  end
end

class Child < Parent
  @@class_var = "child"
end

Parent.print_class_var # => will print "child"
As you can see all the classes in a class hierarchy actually share one
class variable. Class instance variables should usually be preferred
over class variables.
  • Use def self.methodto define singleton methods. This makes the methods more resistant to refactoring changes.

class TestClass
  # bad
  def TestClass.some_method
    # body omitted
  end

  # good
  def self.some_other_method
    # body omitted
  end
  • Avoidclass << selfexcept when necessary, e.g. single accessors and aliased attributes.

class TestClass
  # bad
  class << self
    def first_method
      # body omitted
    end

    def second_method_etc
      # body omitted
    end
  end

  # good
  class << self
    attr_accessor :per_page
    alias_method :nwo, :find_by_name_with_owner
  end

  def self.first_method
    # body omitted
  end

  def self.second_method_etc
    # body omitted
  end
end
  • Indent thepublic,protected, andprivatemethods as much the method definitions they apply to. Leave one blank line above them.

class SomeClass
  def public_method
    # ...
  end

  private
  def private_method
    # ...
  end
end
  • Avoid explicit use ofselfas the recipient of internal class or instance messages unless to specify a method shadowed by a variable.

class SomeClass
  attr_accessor :message

  def greeting(name)
    message = "Hi #{name}" # local variable in Ruby, not attribute writer
    self.message = message
  end
end

Collections

  • Prefer%wto the literal array syntax when you need an array of strings.

# bad
STATES = ["draft", "open", "closed"]

# good
STATES = %w(draft open closed)
  • UseSetinstead ofArraywhen dealing with unique elements.Setimplements a collection of unordered values with no duplicates. This is a hybrid ofArray's intuitive inter-operation facilities andHash's fast lookup.

  • Use symbols instead of strings as hash keys.

# bad
hash = { "one" => 1, "two" => 2, "three" => 3 }

# good
hash = { one: 1, two: 2, three: 3 }

Documentation

Use TomDoc to the best of your ability. It's pretty sweet:

# Public: Duplicate some text an arbitrary number of times.
#
# text  - The String to be duplicated.
# count - The Integer number of times to duplicate the text.
#
# Examples
#
#   multiplex("Tom", 4)
#   # => "TomTomTomTom"
#
# Returns the duplicated String.
def multiplex(text, count)
  text * count
end

Exceptions

  • Don't use exceptions for flow of control.

# bad
begin
  n / d
rescue ZeroDivisionError
  puts "Cannot divide by 0!"
end

# good
if d.zero?
  puts "Cannot divide by 0!"
else
  n / d
end
  • Rescue specific exceptions, notStandardErroror its superclasses.

# bad
begin
  # an exception occurs here
rescue
  # exception handling
end

# still bad
begin
  # an exception occurs here
rescue Exception
  # exception handling
end

Hashes

Use the Ruby 1.9 syntax for hash literals when all the keys are symbols:

# good
user = {
  login: "defunkt",
  name: "Chris Wanstrath"
}

# bad
user = {
  :login => "defunkt",
  :name => "Chris Wanstrath"
}

Use the 1.9 syntax when calling a method with Hash options arguments or named arguments:

# good
user = User.create(login: "jane")
link_to("Account", controller: "users", action: "show", id: user)

# bad
user = User.create(:login => "jane")
link_to("Account", :controller => "users", :action => "show", :id => user)

If you have a hash with mixed key types, use the legacy hashrocket style to avoid mixing styles within the same hash:

# good
hsh = {
  :user_id => 55,
  "followers-count" => 1000
}

# bad
hsh = {
  user_id: 55,
  "followers-count" => 1000
}

Keyword Arguments

Keyword arguments are recommended but not required when a method's arguments may otherwise be opaque or non-obvious when called. Additionally, prefer them over the old "Hash as pseudo-named args" style from pre-2.0 ruby.

So instead of this:

def remove_member(user, skip_membership_check=false)
  # ...
end

# Elsewhere: what does true mean here?
remove_member(user, true)

Do this, which is much clearer.

def remove_member(user, skip_membership_check: false)
  # ...
end

# Elsewhere, now with more clarity:
remove_member user, skip_membership_check: true

Naming

  • Usesnake_casefor methods and variables.

  • UseCamelCasefor classes and modules. (Keep acronyms like HTTP, RFC, XML uppercase.)

  • UseSCREAMING_SNAKE_CASEfor other constants.

  • The names of predicate methods (methods that return a boolean value) should end in a question mark. (i.e.Array#empty?).

  • The names of potentially "dangerous" methods (i.e. methods that modifyselfor the arguments,exit!, etc.) should end with an exclamation mark. Bang methods should only exist if a non-bang method exists. (More on this.

Percent Literals

  • Use%wfreely.

STATES = %w(draft open closed)
  • Use%()for single-line strings which require both interpolation and embedded double-quotes. For multi-line strings, prefer heredocs.

# bad (no interpolation needed)
%(<div class="text">Some text</div>)
# should be "<div class=\"text\">Some text</div>"

# bad (no double-quotes)
%(This is #{quality} style)
# should be "This is #{quality} style"

# bad (multiple lines)
%(<div>\n<span class="big">#{exclamation}</span>\n</div>)
# should be a heredoc.

# good (requires interpolation, has quotes, single line)
%(<tr><td class="name">#{name}</td>)
  • Use%ronly for regular expressions matching _more than _one '/' character.

# bad
%r(\s+)

# still bad
%r(^/(.*)$)
# should be /^\/(.*)$/

# good
%r(^/blog/2011/(.*)$)

Regular Expressions

  • Avoid using $1-9 as it can be hard to track what they contain. Named groups can be used instead.

# bad
/(regexp)/ =~ string
...
process $1

# good
/(?<meaningful_var>regexp)/ =~ string
...
process meaningful_var
  • Be careful with^and$as they match start/end of line, not string endings. If you want to match the whole string use:\Aand\z.

string = "some injection\nusername"
string[/^username$/]   # matches
string[/\Ausername\z/] # don't match
  • Use

    x

    modifier for complex regexps. This makes them more readable and you can add some useful comments. Just be careful as spaces are ignored.

regexp 
=
%r{
  start         # some text
\s
            # white space char
(group)
       # first group
(?:alt1|alt2)
 # some alternation
  end
}x

Requires

Alwaysrequiredependencies used directly in a script at the start of the same file. Resources that will get autoloaded on first use—such as Rails models, controllers, or helpers—don't need to be required.

require "set"
require "time"

%w(foo bar).to_set
Time.parse("2015-10-21")

This not only loads the necessary dependencies if they haven't already, but acts as documentation about the libraries that the current file uses.

Strings

  • Prefer string interpolation instead of string concatenation:

# bad
email_with_name = user.name + " <" + user.email + ">"

# good
email_with_name = "#{user.name} <#{user.email}>"
  • Use double-quoted strings. Interpolation and escaped characters will always work without a delimiter change, and'

    is a lot more common than"in string literals.

# bad
name = 'Bozhidar'

# good
name = "Bozhidar"
  • Avoid usingString#+when you need to construct large data chunks. Instead, useString#<<. Concatenation mutates the string instance in-place and is always faster thanString#+, which creates a bunch of new string objects.

# good and also fast
html = ""
html << "<h1>Page title</h1>"

paragraphs.each do |paragraph|
  html << "<p>#{paragraph}</p>"
end

Syntax

  • Usedefwith parentheses when there are arguments. Omit the parentheses when the method doesn't accept any arguments.

    def some_method
     # body omitted
    end
    
    def some_method_with_arguments(arg1, arg2)
     # body omitted
    end
  • Never usefor, unless you know exactly why. Most of the time iterators should be used instead.foris implemented in terms ofeach(so you're adding a level of indirection), but with a twist -fordoesn't introduce a new scope (unlikeeach) and variables defined in its block will be visible outside it.

arr = [1, 2, 3]

# bad
for elem in arr do
  puts elem
end

# good
arr.each { |elem| puts elem }
  • Never usethenfor multi-lineif/unless.

# bad
if some_condition then
  # body omitted
end

# good
if some_condition
  # body omitted
end
  • Avoid the ternary operator (?:) except in cases where all expressions are extremely trivial. However, do use the ternary operator(?:) overif/then/else/endconstructs for single line conditionals.

# bad
result = if some_condition then something else something_else end

# good
result = some_condition ? something : something_else
  • Use one expression per branch in a ternary operator. This also means that ternary operators must not be nested. Prefer

    if/elseconstructs in these cases.

# bad
some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else

# good
if some_condition
  nested_condition ? nested_something : nested_something_else
else
  something_else
end
  • Theandandorkeywords are banned. It's just not worth it. Always use&&and||instead.

  • Avoid multi-line?:(the ternary operator), useif/unlessinstead.

  • Favor modifierif/unlessusage when you have a single-line body.

# bad
if some_condition
  do_something
end

# good
do_something if some_condition
  • Never useunlesswithelse. Rewrite these with the positive case first.

# bad
unless success?
  puts "failure"
else
  puts "success"
end

# good
if success?
  puts "success"
else
  puts "failure"
end
  • Don't use parentheses around the condition of anif/unless/while.

# bad
if (x > 10)
  # body omitted
end

# good
if x > 10
  # body omitted
end
  • Prefer{...}overdo...endfor single-line blocks. Avoid using{...}for multi-line blocks (multiline chaining is always ugly). Always usedo...endfor "control flow" and "method definitions" (e.g. in Rakefiles and certain DSLs). Avoiddo...endwhen chaining.

names = ["Bozhidar", "Steve", "Sarah"]

# good
names.each { |name| puts name }

# bad
names.each do |name|
  puts name
end

# good
names.select { |name| name.start_with?("S") }.map { |name| name.upcase }

# bad
names.select do |name|
  name.start_with?("S")
end.map { |name| name.upcase }
Some will argue that multiline chaining would look OK with the use of {...}, but they should
ask themselves - is this code really readable and can't the block's contents be extracted into
nifty methods?
  • Avoidreturnwhere not required.

# bad
def some_method(some_arr)
  return some_arr.size
end

# good
def some_method(some_arr)
  some_arr.size
end
  • Use spaces around the=operator when assigning default values to method parameters:

# bad
def some_method(arg1=:default, arg2=nil, arg3=[])
  # do something...
end

# good
def some_method(arg1 = :default, arg2 = nil, arg3 = [])
  # do something...
end

While several Ruby books suggest the first style, the second is much more prominent in practice (and arguably a bit more readable).

  • Using the return value of=(an assignment) is ok.

# bad
if (v = array.grep(/foo/)) ...

# good
if v = array.grep(/foo/) ...

# also good - has correct precedence.
if (v = next_value) == "hello" ...
  • Use||=freely to initialize variables.

# set name to Bozhidar, only if it's nil or false
name ||= "Bozhidar"
  • Don't use||=to initialize boolean variables. (Consider what would happen if the current value happened to befalse.)

# bad - would set enabled to true even if it was false
enabled ||= true

# good
enabled = true if enabled.nil?
  • Avoid using Perl-style special variables (like$0-9,$, etc. ). They are quite cryptic and their use in anything but one-liner scripts is discouraged. Prefer long form versions such as$PROGRAM_NAME.

  • Never put a space between a method name and the opening parenthesis.

# bad
f (3 + 2) + 1

# good
f(3 + 2) + 1
  • If the first argument to a method begins with an open parenthesis, always use parentheses in the method invocation. For example, writef((3 + 2) + 1).

  • Use_for unused block parameters.

# bad
result = hash.map { |k, v| v + 1 }

# good
result = hash.map { |_, v| v + 1 }
  • Don't use the===(threequals) operator to check types.===is mostly an implementation detail to support Ruby features likecase, and it's not commutative. For example,String === "hi"is true and"hi" === Stringis false. Instead, useis_a?orkind_of?if you must.

    Refactoring is even better. It's worth looking hard at any code that explicitly checks types.

Last updated