Ruby Style Guidelines

Comprehensive style guide for writing clean, maintainable Ruby code at Kalkomey.

Source Code Layout

Indentation and Spacing

  • Use 2 spaces for indentation. No tabs.
  • Keep lines under 120 characters.
  • No trailing whitespace.
  • End each file with a newline.
# Good
class Person
  def initialize(name)
    @name = name
  end
end

# Bad - wrong indentation
class Person
    def initialize(name)
        @name = name
    end
end

Line Breaks

  • Add empty lines between method definitions.
  • Add empty lines between logical paragraphs.
  • Don't add empty lines after method opening or before method ending.
# Good
class Person
  def full_name
    [first_name, last_name].compact.join(' ')
  end

  def age
    Time.current.year - birth_year
  end

  private

  attr_reader :birth_year
end

# Bad - no separation between methods
class Person
  def full_name
    [first_name, last_name].compact.join(' ')
  end
  def age
    Time.current.year - birth_year
  end
  private
  attr_reader :birth_year
end

Alignment

  • Align multiline parameters with the first parameter.
  • Align multiline array elements and hash key-value pairs.
# Good
def send_mail(to:,
             subject:,
             body:)
  # Method body
end

# Good
hash = {
  foo:    'bar',
  bazz:   'qux',
  quux:   'corge'
}

# Bad
hash = {
  foo: 'bar',
    bazz: 'qux',
      quux: 'corge'
}

Naming Conventions

General Guidelines

  • Use snake_case for methods and variables.
  • Use CamelCase for classes and modules.
  • Use SCREAMING_SNAKE_CASE for constants.
# Good
class UserAuthentication
  MAXIMUM_ATTEMPTS = 3

  def authenticate_user
    check_credentials
  end

  private

  def check_credentials
    # Implementation
  end
end

# Bad
class userAuthentication
  MaximumAttempts = 3

  def AuthenticateUser
    CheckCredentials
  end
end

Method Names

  • Use question mark suffix for boolean methods.
  • Use exclamation mark suffix for destructive methods.
  • Use verb phrases for method names that perform actions.
# Good
class User
  def active?
    status == 'active'
  end

  def activate!
    self.status = 'active'
    save!
  end

  def calculate_age
    Time.current.year - birth_year
  end
end

# Bad
class User
  def is_active
    status == 'active'
  end

  def activate
    self.status = 'active'
    save!
  end

  def age
    Time.current.year - birth_year
  end
end

Variable Names

  • Choose descriptive and unambiguous names for variables.
  • Use short names for temporary variables, such as i for loop counters.
  • Use prefixes like min_ or max_ to clarify range variables.
# Good
min_age = 18
max_age = 65
loop_index = 0

# Bad
x = 18
y = 65
i = 0

Syntax

Parentheses

  • Use parentheses around method arguments when not clear without them.
  • Omit parentheses for DSLs and methods that are clear without them.
# Good
puts('Hello, World!')

# Bad
puts 'Hello, World!'

# Good in DSLs
validates :email, presence: true

Literals

  • Use symbols instead of strings for keys in hashes.
  • Use %w or %i for arrays of words or symbols.
# Good
hash = { name: 'John', age: 30 }
array = %w[apple banana cherry]

# Bad
hash = { 'name' => 'John', 'age' => 30 }
array = ['apple', 'banana', 'cherry']

Classes & Modules

Class Definitions

  • Use class keyword for class definitions.
  • Use module keyword for modules.
# Good - class definition with inheritance and module inclusion.
class Person < ApplicationRecord
                                               include Addressable

                                               # Implementation
                                               end
                                    

Class Inheritance

  • Use < for class inheritance and include for module inclusion.
  • Use prepend for module inclusion when overriding methods.

Control Structures

Conditionals

  • Use `if` for general conditions; use `unless` only for negative conditions.
  • Prefer single-line conditionals for simple statements.
# Good
return if completed?

# Bad
if !completed?
  return
end

Case Statements

  • Use `case` for multiple conditions.
  • Avoid deeply nested case statements.
# Good
case role
when 'admin'
  access_admin_panel
when 'user'
  access_dashboard
else
  deny_access
end

Collections

Enumerables

  • Use `each`, `map`, and `select` instead of `for` loops.
  • Prefer `reduce` for aggregations.
# Good
names = users.map(&:name)
admins = users.select(&:admin?)

# Bad
names = []
for user in users
  names << user.name
                                           end

Regular Expressions

Best Practices

  • Use `/x` flag for readability in complex patterns.
  • Escape special characters to avoid unintended behavior.
# Good
regex = /
  ^\d{3}-       # Area code
  \d{3}-        # Prefix
  \d{4}$        # Line number
/x

# Bad
regex = /^\d{3}-\d{3}-\d{4}$/

Metaprogramming

When to Use

  • Use sparingly for reducing boilerplate code.
  • Document metaprogramming constructs clearly.
# Good
class Person
  ATTRIBUTES = %i[first_name last_name]

  ATTRIBUTES.each do |attr|
    define_method(attr) do
      instance_variable_get("@#{attr}")
    end
  end
end