Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
README.md

README.md

Prelude

Role models are important.
-- Officer Alex J. Murphy / RoboCop

This is Nulogy's Ruby Style Guide. It is derived from bbatsov with a few changes/simplifications.

Note that this is not a 'Standard', it is a guide. The difference being that this document describes how we aspire our code to look, not iron- clad rules on how it must be formatted. Be nice. It is there to show how we would like to format code so that it is less confusing to new- comers.

Table of Contents

Source Code Layout

  • Use soft-tabs with a two space indent.
  • Keep lines fewer than 80 characters.
  • Never leave trailing whitespace (if you have an automatic whitespace remover, please be considerate and make sure it only removes trailing spaces from lines you modified)
  • End each file with a blank newline.
  • Use Unix-style line endings.
  • Use spaces around operators, after commas, colons and semicolons, around block { and before block }.

    sum = 1 + 2
    a, b = 1, 2
    1 > 2 ? true : false; puts 'Hi'
    [1, 2, 3].each { |e| puts e }
  • Do not put spaces inside hash curly braces or interpolation curly braces

    {one: 1, two: 2}
    "string#{expr}"
  • No spaces after (, [ or before ], ).

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

    !array.include?(something)
  • Indent when as deep as case. I know that many would disagree with this one, but it's the style established in both "The Ruby Programming Language" and "Programming Ruby".

    # bad
    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
    
    # good
    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
  • Use empty lines between method definitions and also to break up a method into logical paragraphs internally.

    def some_method
      data = initialize(options)
    
      data.manipulate!
    
      data.result
    end
    
    def some_method
      result
    end
  • Nest classes in modules.

    # bad
    class Production::PickListFactory
    end
    
    # good
    module Production
      class PickListFactory
      end
    end

    The code in the bad example relies on the 'Production' module being defined previously. The leads to intermittent failures that depend on load ordering. The code in the good example will define the 'Production' module if it is not already defined.

Syntax

  • Use def with 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 use for, unless you know exactly why.
  • Never use then for multi-line if/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(?:) over if/then/else/end constructs for single line conditionals.

    # bad
    result = if some_condition then something else something_else end
    
    # good
    result = some_condition ? something : something_else
  • Avoid multi-line ?: (the ternary operator); use if/unless instead.

  • Use one expression per branch in a ternary operator. This also means that ternary operators must not be nested. Prefer if/else constructs 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
  • The and and or keywords are banned. It's just not worth it. Always use && and || instead.

  • Never use unless with else. 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 an if/unless/while/until.

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

      names = ['Bozhidar', 'Steve', 'Sarah']
    
      # bad
      names.each do |name|
        puts name
      end
    
      # good
      names.each { |name| puts name }
    
      # bad
      names.select do |name|
        name.start_with?('S')
      end.map { |name| name.upcase }
    
      # good
      names.select { |name| name.start_with?('S') }.map { |name| name.upcase }
  • Don't use ||= to initialize boolean variables. (Consider what would happen if the current value happened to be false.)

    # 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 $:, $;, etc. ). They are quite cryptic and their use in anything but one-liner scripts is discouraged. Use the human-friendly aliases provided by the English library.

      # bad
      $:.unshift File.dirname(__FILE__)
    
      # good
      require 'English'
      $LOAD_PATH.unshift File.dirname(__FILE__)
  • Never put a space between a method name and the opening parenthesis.

    # bad
    f (3 + 2) + 1
    
    # good
    f(3 + 2) + 1
  • Use the new lambda literal syntax for single line body blocks. Use the lambda method for multi-line blocks.

      l = ->(a, b) { a + b }
      l.call(1, 2)
    
      l = lambda do |a, b|
        tmp = a * 7
        tmp * b / 50
      end
  • Use fetch to specify default values.

    # bad
    hash.reverse_merge(key: default_value)[:key]
    
    # bad (doesn't work for booleans)
    hash[:key] || default_value
    
    # good
    hash.fetch(:key, default_value)
    
    # good (use if default_value is expensive to compute)
    hash.fetch(:key) { default_value }

Naming

  • Use snake_case for methods and variables.
  • Use CamelCase for classes and modules. (Keep acronyms like HTTP, RFC, XML uppercase.)
  • Use SCREAMING_SNAKE_CASE for 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 modify self or the arguments, exit!, etc.) should end with an exclamation mark. Bang methods should only exist if a non-bang method exists. More on this.

Classes

  • Indent the public, protected, and private methods as much the method definitions they apply to. Leave one blank line above the visibility modifier and one after.

      class SomeClass
        def public_method
          # ...
        end
    
        private
    
        def private_method
          # ...
        end
    
        def another_private_method
          # ...
        end
      end
  • Use def self.method to define singleton methods. This makes the code easier to refactor since the class name is not repeated.

      class TestClass
        # bad
        def TestClass.some_method
          # body omitted
        end
    
        # good
        def self.some_other_method
          # body omitted
        end
      end
  • Avoid class << self except 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

Exceptions

  • Avoid rescuing the Exception class. This will trap signals and calls to exit, requiring you to kill -9 the process.

      # bad
      begin
        # calls to exit and kill signals will be caught (except kill -9)
        exit
      rescue Exception
        puts "you didn't really want to exit, right?"
        # exception handling
      end
    
      # good
      begin
        # a blind rescue rescues from StandardError, not Exception as many
        # programmers assume.
      rescue => e
        # exception handling
      end

Hashes

  • Use the Ruby 1.9 hash literal syntax when your hash keys are symbols.

    # ok
    hash = {:one => 1, :two => 2, :three => 3}
    
    # better
    hash = {one: 1, two: 2, three: 3}

Strings

  • Use %w liberally

    # ok
    STATES = ['draft', 'open', 'closed']
    
    # better
    STATES = %w(draft open closed)
  • Avoid using String#+ when you need to construct large data chunks. Instead, use String#<<. Concatenation mutates the string instance in-place and is always faster than String#+, 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
  • Use %()(it's a shorthand for %Q) 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>)
  • Indent heredocs. Use strip_heredoc to strip indentation. Technically, it looks for the least indented line in the whole string, and removes that amount of leading whitespace.

      # bad
      module DialogHelper
        def dialog_buttonset(options={}, &block)
          html = <<-HTML
      <div class="dialog-buttonpane">
      </div>
      HTML
    
          html
        end
      end
    
      # good
      module DialogHelper
        def dialog_buttonset(options={}, &block)
          html = <<-HTML.strip_heredoc
            <div class="dialog-buttonpane">
            </div>
          HTML
    
          html
        end
      end

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
Something went wrong with that request. Please try again.