Logo: Relish

  1. Sign in

Project: Ruby-style-guide

syntax

  • Use :: only to reference constants(this includes classes and
    modules) and constructors (like Array() or Nokogiri::HTML()).
    Never use :: for regular method invocation.

    # bad
    SomeClass::some_method
    some_object::some_method
    
    # good
    SomeClass.some_method
    some_object.some_method
    SomeModule::SomeClass::SOME_CONST
    SomeModule::SomeClass()
    
  • Use def with parentheses when there are arguments. Omit the
    parentheses when the method doesn't accept any arguments.

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

    arr = [1, 2, 3]
    
    # bad
    for elem in arr do
      puts elem
    end
    
    # note that elem is accessible outside of the for loop
    elem #=> 3
    
    # good
    arr.each { |elem| puts elem }
    
    # elem is not accessible outside each's block
    elem #=> NameError: undefined local variable or method `elem'
    
  • Never use then for multi-line if/unless.

    # bad
    if some_condition then
      # body omitted
    end
    
    # good
    if some_condition
      # body omitted
    end
    
  • Always put the condition on the same line as the if/unless in a multi-line conditional.

    # bad
    if
      some_condition
      do_something
      do_something_else
    end
    
    # good
    if some_condition
      do_something
      do_something_else
    end
    
  • Favor the ternary operator(?:) over if/then/else/end constructs.
    It's more common and obviously more concise.

    # 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/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
    
  • Never use if x: ... - as of Ruby 1.9 it has been removed. Use
    the ternary operator instead.

    # bad
    result = if some_condition: something else something_else end
    
    # good
    result = some_condition ? something : something_else
    
  • Never use if x; .... Use the ternary operator instead.

  • Leverage the fact that if and case are expressions which return a result.

    # bad
    if condition
      result = x
    else
      result = y
    end
    
    # good
    result =
      if condition
        x
      else
        y
      end
    
  • Use when x then ... for one-line cases. The alternative syntax
    when x: ... has been removed as of Ruby 1.9.

  • Never use when x; .... See the previous rule.

  • Use ! instead of not.

    # bad - braces are required because of op precedence
    x = (not something)
    
    # good
    x = !something
    
  • Avoid the use of !!.

    # bad
    x = 'test'
    # obscure nil check
    if !!x
      # body omitted
    end
    
    x = false
    # double negation is useless on booleans
    !!x # => false
    
    # good
    x = 'test'
    unless x.nil?
      # body omitted
    end
    
  • The and and or keywords are banned. It's just not worth
    it. Always use && and || instead.

    # bad
    # boolean expression
    if some_condition and some_other_condition
      do_something
    end
    
    # control flow
    document.saved? or document.save!
    
    # good
    # boolean expression
    if some_condition && some_other_condition
      do_something
    end
    
    # control flow
    document.saved? || document.save!
    
  • Avoid multi-line ?: (the ternary operator); use if/unless instead.

  • Favor modifier if/unless usage when you have a single-line
    body. Another good alternative is the usage of control flow &&/||.

    # bad
    if some_condition
      do_something
    end
    
    # good
    do_something if some_condition
    
    # another good option
    some_condition && do_something
    
  • Avoid modifier if/unless usage at the end of a
    non-trivial multi-line block.

    # bad
    10.times do
      # multi-line body omitted
    end if some_condition
    
    # good
    if some_condition
      10.times do
        # multi-line body omitted
      end
    end
    
  • Favor unless over if for negative conditions (or control
    flow ||).

    # bad
    do_something if !some_condition
    
    # bad
    do_something if not some_condition
    
    # good
    do_something unless some_condition
    
    # another good option
    some_condition || do_something
    
  • 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
    
  • Never use while/until condition do for multi-line while/until.

    # bad
    while x > 5 do
      # body omitted
    end
    
    until x > 5 do
      # body omitted
    end
    
    # good
    while x > 5
      # body omitted
    end
    
    until x > 5
      # body omitted
    end
    
  • Favor modifier while/until usage when you have a single-line
    body.

    # bad
    while some_condition
      do_something
    end
    
    # good
    do_something while some_condition
    
  • Favor until over while for negative conditions.

    # bad
    do_something while !some_condition
    
    # good
    do_something until some_condition
    
  • Use Kernel#loop instead of while/until when you need an infinite loop.

    # bad
    while true
      do_something
    end
    
    until false
      do_something
    end
    
    # good
    loop do
      do_something
    end
    
  • Use Kernel#loop with break rather than begin/end/until or begin/end/while for post-loop tests.

    # bad
    begin
      puts val
      val += 1
    end while val < 0
    
    # good
    loop do
      puts val
      val += 1
      break unless val < 0
    end
    
  • Omit parentheses around parameters for methods that are part of an
    internal DSL (e.g. Rake, Rails, RSpec), methods that have
    "keyword" status in Ruby (e.g. attr_reader, puts) and attribute
    access methods. Use parentheses around the arguments of all other
    method invocations.

    class Person
      attr_reader :name, :age
    
      # omitted
    end
    
    temperance = Person.new('Temperance', 30)
    temperance.name
    
    puts temperance.age
    
    x = Math.sin(y)
    array.delete(e)
    
    bowling.score.should == 0
    
  • Omit the outer braces around an implicit options hash.

    # bad
    user.set({ name: 'John', age: 45, permissions: { read: true } })
    
    # good
    user.set(name: 'John', age: 45, permissions: { read: true })
    
  • Omit both the outer braces and parentheses for methods that are
    part of an internal DSL.

    class Person < ActiveRecord::Base
      # bad
      validates(:name, { presence: true, length: { within: 1..10 } })
    
      # good
      validates :name, presence: true, length: { within: 1..10 }
    end
    
  • Omit parentheses for method calls with no arguments.

    # bad
    Kernel.exit!()
    2.even?()
    fork()
    'test'.upcase()
    
    # good
    Kernel.exit!
    2.even?
    fork
    'test'.upcase
    
  • 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 }
    

    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 the blocks' contents be extracted into
    nifty methods?

  • Consider using explicit block argument to avoid writing block
    literal that just passes its arguments to another block. Beware of
    the performance impact, though, as the block gets converted to a
    Proc.

    require 'tempfile'
    
    # bad
    def with_tmp_dir
      Dir.mktmpdir do |tmp_dir|
        Dir.chdir(tmp_dir) { |dir| yield dir }  # block just passes arguments
      end
    end
    
    # good
    def with_tmp_dir(&block)
      Dir.mktmpdir do |tmp_dir|
        Dir.chdir(tmp_dir, &block)
      end
    end
    
    with_tmp_dir do |dir|
      puts "dir is accessible as a parameter and pwd is set: #{dir}"
    end
    
  • Avoid return where not required for flow of control.

    # bad
    def some_method(some_arr)
      return some_arr.size
    end
    
    # good
    def some_method(some_arr)
      some_arr.size
    end
    
  • Avoid self where not required. (It is only required when calling a self write accessor.)

    # bad
    def ready?
      if self.last_reviewed_at > self.last_updated_at
        self.worker.update(self.content, self.options)
        self.status = :in_progress
      end
      self.status == :verified
    end
    
    # good
    def ready?
      if last_reviewed_at > last_updated_at
        worker.update(content, options)
        self.status = :in_progress
      end
      status == :verified
    end
    
  • As a corollary, avoid shadowing methods with local variables unless they are both equivalent.

    class Foo
      attr_accessor :options
    
      # ok
      def initialize(options)
        self.options = options
        # both options and self.options are equivalent here
      end
    
      # bad
      def do_something(options = {})
        unless options[:when] == :later
          output(self.options[:message])
        end
      end
    
      # good
      def do_something(params = {})
        unless params[:when] == :later
          output(options[:message])
        end
      end
    end
    
  • Don't use the return value of = (an assignment) in conditional
    expressions unless the assignment is wrapped in parentheses. This is
    a fairly popular idiom among Rubyists that's sometimes referred to as
    safe assignment in condition.

    # bad (+ a warning)
    if v = array.grep(/foo/)
      do_something(v)
      ...
    end
    
    # good (MRI would still complain, but RuboCop won't)
    if (v = array.grep(/foo/))
      do_something(v)
      ...
    end
    
    # good
    v = array.grep(/foo/)
    if v
      do_something(v)
      ...
    end
    
  • Use shorthand self assignment operators whenever applicable.

    # bad
    x = x + y
    x = x * y
    x = x**y
    x = x / y
    x = x || y
    x = x && y
    
    # good
    x += y
    x *= y
    x **= y
    x /= y
    x ||= y
    x &&= y
    
  • Use ||= to initialize variables only if they're not already initialized.

    # bad
    name = name ? name : 'Bozhidar'
    
    # bad
    name = 'Bozhidar' unless name
    
    # good - 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 be false.)

    # bad - would set enabled to true even if it was false
    enabled ||= true
    
    # good
    enabled = true if enabled.nil?
    
  • Use &&= to preprocess variables that may or may not exist. Using
    &&= will change the value only if it exists, removing the need to
    check its existence with if.

    # bad
    if something
      something = something.downcase
    end
    
    # bad
    something = something ? nil : something.downcase
    
    # ok
    something = something.downcase if something
    
    # good
    something = something && something.downcase
    
    # better
    something &&= something.downcase
    
  • Avoid explicit use of the case equality operator ===. As its name
    implies it is meant to be used implicitly by case expressions and
    outside of them it yields some pretty confusing code.

    # bad
    Array === something
    (1..100) === 7
    /something/ === some_string
    
    # good
    something.is_a?(Array)
    (1..100).include?(7)
    some_string =~ /something/
    
  • 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
    
  • If the first argument to a method begins with an open parenthesis,
    always use parentheses in the method invocation. For example, write
    f((3 + 2) + 1).

  • Always run the Ruby interpreter with the -w option so it will warn
    you if you forget either of the rules above!

  • Use the new lambda literal syntax for single line body blocks. Use the
    lambda method for multi-line blocks.

    # bad
    l = lambda { |a, b| a + b }
    l.call(1, 2)
    
    # correct, but looks extremely awkward
    l = ->(a, b) do
      tmp = a * 7
      tmp * b / 50
    end
    
    # good
    l = ->(a, b) { a + b }
    l.call(1, 2)
    
    l = lambda do |a, b|
      tmp = a * 7
      tmp * b / 50
    end
    
  • Prefer proc over Proc.new.

    # bad
    p = Proc.new { |n| puts n }
    
    # good
    p = proc { |n| puts n }
    
  • Prefer proc.call() over proc[] or proc.() for both lambdas and procs.

    # bad - looks similar to Enumeration access
    l = ->(v) { puts v }
    l[1]
    
    # also bad - uncommon syntax
    l = ->(v) { puts v }
    l.(1)
    
    # good
    l = ->(v) { puts v }
    l.call(1)
    
  • Prefix with _ unused block parameters and local variables. It's
    also acceptable to use just _ (although it's a bit less
    descriptive). This convention is recognized by the Ruby interpreter
    and tools like RuboCop and will suppress their unused variable warnings.

    # bad
    result = hash.map { |k, v| v + 1 }
    
    def something(x)
      unused_var, used_var = something_else(x)
      # ...
    end
    
    # good
    result = hash.map { |_k, v| v + 1 }
    
    def something(x)
      _unused_var, used_var = something_else(x)
      # ...
    end
    
    # good
    result = hash.map { |_, v| v + 1 }
    
    def something(x)
      _, used_var = something_else(x)
      # ...
    end
    
  • Use $stdout/$stderr/$stdin instead of
    STDOUT/STDERR/STDIN. STDOUT/STDERR/STDIN are constants, and
    while you can actually reassign (possibly to redirect some stream)
    constants in Ruby, you'll get an interpreter warning if you do so.

  • Use warn instead of $stderr.puts. Apart from being more concise
    and clear, warn allows you to suppress warnings if you need to (by
    setting the warn level to 0 via -W0).

  • Favor the use of sprintf and its alias format over the fairly
    cryptic String#% method.

    # bad
    '%d %d' % [20, 10]
    # => '20 10'
    
    # good
    sprintf('%d %d', 20, 10)
    # => '20 10'
    
    # good
    sprintf('%{first} %{second}', first: 20, second: 10)
    # => '20 10'
    
    format('%d %d', 20, 10)
    # => '20 10'
    
    # good
    format('%{first} %{second}', first: 20, second: 10)
    # => '20 10'
    
  • Favor the use of Array#join over the fairly cryptic Array#* with
    a string argument.

    # bad
    %w(one two three) * ', '
    # => 'one, two, three'
    
    # good
    %w(one two three).join(', ')
    # => 'one, two, three'
    
  • Use [*var] or Array() instead of explicit Array check, when dealing with a
    variable you want to treat as an Array, but you're not certain it's
    an array.

    # bad
    paths = [paths] unless paths.is_a? Array
    paths.each { |path| do_something(path) }
    
    # good
    [*paths].each { |path| do_something(path) }
    
    # good (and a bit more readable)
    Array(paths).each { |path| do_something(path) }
    
  • Use ranges or Comparable#between? instead of complex comparison logic when possible.

    # bad
    do_something if x >= 1000 && x <= 2000
    
    # good
    do_something if (1000..2000).include?(x)
    
    # good
    do_something if x.between?(1000, 2000)
    
  • Favor the use of predicate methods to explicit comparisons with
    ==. Numeric comparisons are OK.

    # bad
    if x % 2 == 0
    end
    
    if x % 2 == 1
    end
    
    if x == nil
    end
    
    # good
    if x.even?
    end
    
    if x.odd?
    end
    
    if x.nil?
    end
    
    if x.zero?
    end
    
    if x == 0
    end
    
  • Don't do explicit non-nil checks unless you're dealing with boolean values.

    # bad
    do_something if !something.nil?
    do_something if something != nil
    
    # good
    do_something if something
    
    # good - dealing with a boolean
    def value_set?
      [email protected]_boolean.nil?
    end
    
  • Avoid the use of BEGIN blocks.

  • Never use END blocks. Use Kernel#at_exit instead.

    # bad
    END { puts 'Goodbye!' }
    
    # good
    at_exit { puts 'Goodbye!' }
    
  • Avoid the use of flip-flops.

  • Avoid use of nested conditionals for flow of control.

    Prefer a guard clause when you can assert invalid data. A guard clause
    is a conditional statement at the top of a function that bails out as
    soon as it can.

    # bad
    def compute_thing(thing)
      if thing[:foo]
        update_with_bar(thing)
        if thing[:foo][:bar]
          partial_compute(thing)
        else
          re_compute(thing)
        end
      end
    end
    
    # good
    def compute_thing(thing)
      return unless thing[:foo]
      update_with_bar(thing[:foo])
      return re_compute(thing) unless thing[:foo][:bar]
      partial_compute(thing)
    end
    

    Prefer next in loops instead of conditional blocks.

    # bad
    [0, 1, 2, 3].each do |item|
      if item > 1
        puts item
      end
    end
    
    # good
    [0, 1, 2, 3].each do |item|
      next unless item > 1
      puts item
    end
    

Last published about 3 years ago by David Kariuki.