Ruby 💯

Hero image for Ruby 💯

Linting

We use RuboCop for automated code checks and most of our guidelines comply with the default guidelines set by the analyzer.

Formatting

  • Use soft-tabs with a two space indent.
  • Limit each line of code to fewer than 130 characters.
  • Use a single empty line to break between statements to organize logical chunks of code.
  • End each file with a newline.

Naming

  • Use snake_case for symbols, methods and variables.
# Bad
:someSymbol
someVar = 5

def someMethod
  # some code
end

# Good
:some_symbol

some_var = 5

def some_method
  # some code
end
  • Do not separate numbers from letters on symbols, methods and variables.
# Bad
:some_sym_1
some_var_1 = 1

def some_method_1
  # some code
end

# Good
:some_sym1

some_var1 = 1

def some_method1
  # some code
end
  • Use CamelCase for classes and modules.
# Bad
class Someclass
  # some code
end

class Some_Class
  # some code
end

# Good
class SomeClass
  # some code
end
  • Use snake_case for naming files.
# Bad
HelloWorld.rb

# Good
hello_world.rb
  • Use snake_case for naming directories.
# Bad
lib/HelloWorld/hello_world.rb

# Good
lib/hello_world/hello_world.rb
  • Aim to have just a single class/module per source file. Name the file name as the class/module, but replacing CamelCase with snake_case.

  • Use SCREAMING_SNAKE_CASE for other constants.

# Bad
SomeConst = 5

# Good
SOME_CONST = 5
  • The names of predicate methods (methods that return a boolean value) should end in a question mark.
# Bad
def is_true
end

# Good
def true?
end

Collections

  • Prefer %w to the literal array syntax for an array of raw strings.
# Bad
STATES = ["draft", "open", "closed"]

# Good
STATES = %w(draft open closed)
  • Use symbols instead of strings as hash keys.
# Bad
hash = { "one" => 1, "two" => 2, "three" => 3 }

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

Methods

  • Use parentheses in method definitions only if it accepts any parameters.
def method_without_params
  # body omitted
end

def method_with_parameters(param1, param2)
  # body omitted
end
  • Avoid usage of positional arguments. Use keyword arguments or an options hash instead.
# Bad
def positional_method(a = 1, b = 2, c, d)
  # method body
end

# Good
def method_with_keyword_arguments(a:, b:, c:, d:)
end

# Good
def method_with_options(options = {})
end

Modules

  • Use modules to organize a chunk of common stateless operations.
  • Use :: only to reference constants and constructors. Do not use :: for regular method invocation.
# Bad
Klass::some_method
object::some_method

# Good
Klass.some_method
object.some_method
  • Properly choose between def self, extend self and module_function.

Let’s consider a module Math implementing a method pi.

Use def self.pi

include Math will not give you any sort of accessor to .pi, not YourClass.pi, not instance.pi, nothing. You must use Math.pi.

Use extend self with public methods

include Math will give your instances a public instance method .pi.

Use extend self with private methods

include Math will give you a private instance method .pi but Math.pi will say “private method pi called”

Use module_function :pi

include Math will give your instances a private .pi method and Math.pi still works just fine.

Classes

  • Organization
# requires
require 'dependency_filename'

class KlassName
  # extend and include
  extend SomeModule
  include AnotherModule

  # constants
  SOME_CONSTANT = '20'.freeze

  # attribute macros
  attr_reader :name

  # additional macros (if any)
  validates :name

  # public class methods
  def self.some_method
  end

  # initialization
  def initialize
  end

  # public instance methods
  def some_method
  end

  # protected methods
  protected

  def some_protected_method
  end

  # private methods
  private

  def some_private_method
  end
end
  • Avoid nesting multiple classes within classes. Instead maintain each in their own file in a folder named like the containing class.
# Bad

# parent.rb
class Parent
  class Child
  end
end

# Good

# parent.rb
class Parent
end

# parent/child.rb
class Parent
  class Child
  end
end
  • Classes should be used only when it makes sense to create instances out of them. Prefer modules to classes with only class methods.
# Bad
class SomeClass
  def self.some_method
    # body omitted
  end

  def self.some_other_method
    # body omitted
  end
end

# Good
module SomeModule
  def some_method
    # body omitted
  end

  def some_other_method
    # body omitted
  end
end
  • Try to make your classes as SOLID as possible.

  • Use the attr family of functions to define trivial accessors.

# Bad
class Klass
  def initialize(a, b)
    @a = a
    @b = b
  end

  def a
    @a
  end

  def b
    @b
  end
end

# Good
class Klass
  attr_reader :a, :b

  def initialize(a, b)
    @a = a
    @b = b
  end
end

Conventions

  • Never negate the conditional of an if block. Use unless instead.
# Bad
if !false then
end

# Good
unless false
end
  • Use the proc invocation shorthand when the invoked method is the only operation of a block.
# Bad
names.map { |name| name.upcase }

# Good
names.map(&:upcase)
  • Prefer {...} over do...end for single-line blocks. Avoid using {...} for multi-line blocks.
names = %w[Bozhidar Steve Sarah]

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

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