Skip to content

Coding Style

This style is used in the standard library. You can use it in your own project to make it familiar to other developers.

Naming

Type names are PascalCased. For example:

class ParseError < Exception
end

module HTTP
  class RequestHandler
  end
end

alias NumericValue = Float32 | Float64 | Int32 | Int64

lib LibYAML
end

struct TagDirective
end

enum Time::DayOfWeek
end

Method names are snake_cased. For example:

class Person
  def first_name
  end

  def date_of_birth
  end

  def homepage_url
  end
end

Variable names are snake_cased. For example:

class Greeting
  @@default_greeting = "Hello world"

  def initialize(@custom_greeting = nil)
  end

  def print_greeting
    greeting = @custom_greeting || @@default_greeting
    puts greeting
  end
end

Constants are SCREAMING_SNAKE_CASED. For example:

LUCKY_NUMBERS     = [3, 7, 11]
DOCUMENTATION_URL = "http://crystal-lang.org/docs"

Exception messages are Sentence cased, although code or acronyms may start a message in lowercase. For example:

raise ArgumentError.new("Cannot create a string with a null pointer")
raise RuntimeError.new("getpeername failed")
{% raise "Expected size to be an integer literal" %}

Acronyms

In class names, acronyms are all-uppercase. For example, HTTP, and LibXML.

In method names, acronyms are all-lowercase. For example #from_json, #to_io.

Libs

Lib names are prefixed with Lib. For example: LibC, LibEvent2.

Directory and File Names

Within a project:

  • / contains a readme, any project configurations (eg, CI or editor configs), and any other project-level documentation (eg, changelog or contributing guide).
  • src/ contains the project's source code.
  • spec/ contains the project's specs, which can be run with crystal spec.
  • bin/ contains any executables.

File paths match the namespace of their contents. Files are named after the class or namespace they define, with snake_case.

For example, HTTP::WebSocket is defined in src/http/web_socket.cr.

Indentation

Use two spaces to indent code inside namespaces, methods, blocks or other nested contexts. For example:

module Scorecard
  class Parser
    def parse(score_text)
      begin
        score_text.scan(SCORE_PATTERN) do |match|
          handle_match(match)
        end
      rescue err : ParseError
        # handle error ...
      end
    end
  end
end

Within a class, separate method definitions, constants and inner class definitions with one newline. For example:

module Money
  CURRENCIES = {
    "EUR" => 1.0,
    "ARS" => 10.55,
    "USD" => 1.12,
    "JPY" => 134.15,
  }

  class Amount
    getter :currency, :value

    def initialize(@currency, @value)
    end
  end

  class CurrencyConversion
    def initialize(@amount, @target_currency)
    end

    def amount
      # implement conversion ...
    end
  end
end