In Ruby, Classes are processed from top to bottom. Therefore, order matters (most of the time). For example, sometimes included Modules will need to refer to constants in the including Class. So constants should be defined before Module inclusions are specified. Otherwise we’re free to organize our Classes how we want but thoughtful organization makes the story a Class tells easier to understand.
In general, let the following set of rules be your guide for class organization in Ruby Classes:
- Put more general / more important things at the top of a Class.
- Put more specific / less important things next.
- Group collaborating methods in close proximity using a top-down flow.
def my_composed_method a b end def a # ... end def b # ... end
- Note: If it is proving difficult to group collaborating methods in close proximity then that may be an indicator that the Class is doing too much. Look for secondary responsibilities that can be broken out into a new Object.
require "my_class" # Require any functionality needed for the whole Class
# MyNamespace is a context where multiple classes either interact with each other or are used in the same domain context.
# MyClass is a ... # Document the purpose of this Class
class MyNamespace::MyClass < MyNamespace::MyBaseClass # Class definition with fully qualified Superclass (when applicable)
MY_CONSTANT = "MyConstantValue".freeze # Constants; May apply to included modules as well so must come first
Error = Class.new(StandardError) # Other types of Constants like StandardError derivatives; May also be used by included modules
extend MyExtension # Extensions
include MyMixin # Mixins (Less specific than Extensions)
as_abstract_class # Important macros
before_validation # Callbacks — in callback order
before_save
after_create
attr_accessor # Virtual Attributes
attr_writer
attr_reader
belongs_to :my_associated_object # Associations
has_one :my_other_related_object # Less "important" Object associations
validates :my_attribute,
presence: true # Validations
delegate :some_method,
to: :my_associated_obj # Delegations
scope :my_scope, → { } # Scopes
def self.my_class_method... # Class Methods
def initialize... # Initialize Method
concerning :<SomeConcern>s do
# ...
end
def display_name... # Display Methods
def my_important_method... # Important Instance Methods → Less Important Instance Methods
def my_risky_method
# Code that may raise a StandardError
rescue => ex # De-dented to method level — doesn't require begin/end; Also helps encourage Single Responsibility Principle
# Log exception, etc.
end
private
def inspect... # Inspect Methods
def my_private_method... # Private Methods
class MySubClass # Classes only intended for use by the current Class
end
end
This is our team style guide. It is impartial and generally accepted by the Ruby community. So be it for us.
- Note: there will be rare exceptions on some of the guidelines. That is OK.
Also, consider the Rails Style Guide. We don't necessarily follow these 100%. But they're useful guides when in doubt.