To add a collaborator to this project you will need to use the Relish gem to add the collaborator via a terminal command. Soon you'll be able to also add collaborators here!
More about adding a collaboratorclasses
Classes & Modules
Use a consistent structure in your class definitions.
class Person # extend and include go first extend SomeModule include AnotherModule # inner classes CustomErrorKlass = Class.new(StandardError) # constants are next SOME_CONSTANT = 20 # afterwards we have attribute macros attr_reader :name # followed by other macros (if any) validates :name # public class methods are next in line def self.some_method end # followed by public instance methods def some_method end # protected and private methods are grouped near the end protected def some_protected_method end private def some_private_method end end
Don't nest multi line classes within classes. Try to have such nested
classes each in their own file in a folder named like the containing class.# bad # foo.rb class Foo class Bar # 30 methods inside end class Car # 20 methods inside end # 30 methods inside end # good # foo.rb class Foo # 30 methods inside end # foo/bar.rb class Foo class Bar # 30 methods inside end end # foo/car.rb class Foo class Car # 20 methods inside end end
Prefer modules to classes with only class methods. Classes should be
used only when it makes sense to create instances out of them.# bad class SomeClass def self.some_method # body omitted end def self.some_other_method end end # good module SomeClass module_function def some_method # body omitted end def some_other_method end end
Favor the use of
module_function
overextend self
when you want
to turn a module's instance methods into class methods.# bad module Utilities extend self def parse_something(string) # do stuff here end def other_utility_method(number, string) # do some more stuff end end # good module Utilities module_function def parse_something(string) # do stuff here end def other_utility_method(number, string) # do some more stuff end end
When designing class hierarchies make sure that they conform to the
Liskov Substitution Principle.Try to make your classes as
SOLID
as possible.Always supply a proper
to_s
method for classes that represent
domain objects.class Person attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end def to_s "#{@first_name} #{@last_name}" end end
Use the
attr
family of functions to define trivial accessors or mutators.# bad class Person def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end def first_name @first_name end def last_name @last_name end end # good class Person attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end end
Avoid the use of
attr
. Useattr_reader
andattr_accessor
instead.# bad - creates a single attribute accessor (deprecated in 1.9) attr :something, true attr :one, :two, :three # behaves as attr_reader # good attr_accessor :something attr_reader :one, :two, :three
Consider using
Struct.new
, which defines the trivial accessors,
constructor and comparison operators for you.# good class Person attr_accessor :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end end # better Person = Struct.new(:first_name, :last_name) do end
Don't extend a
Struct.new
- it already is a new class. Extending it introduces
a superfluous class level and may also introduce weird errors if the file is
required multiple times.Consider adding factory methods to provide additional sensible ways
to create instances of a particular class.class Person def self.create(options_hash) # body omitted end end
Prefer duck-typing over inheritance.
# bad class Animal # abstract method def speak end end # extend superclass class Duck < Animal def speak puts 'Quack! Quack' end end # extend superclass class Dog < Animal def speak puts 'Bau! Bau!' end end # good class Duck def speak puts 'Quack! Quack' end end class Dog def speak puts 'Bau! Bau!' end end
Avoid the usage of class (
@@
) variables due to their "nasty" behavior in inheritance.class Parent @@class_var = 'parent' def self.print_class_var puts @@class_var end end class Child < Parent @@class_var = 'child' end Parent.print_class_var # => will print "child"
As you can see all the classes in a class hierarchy actually share one
class variable. Class instance variables should usually be preferred
over class variables.Assign proper visibility levels to methods (
private
,protected
)
in accordance with their intended usage. Don't go off leaving
everythingpublic
(which is the default). After all we're coding
in Ruby now, not in Python.Indent the
public
,protected
, andprivate
methods as much the
method definitions they apply to. Leave one blank line above the
visibility modifier
and one blank line below in order to emphasize that it applies to all
methods below it.class SomeClass def public_method # ... end private def private_method # ... end def another_private_method # ... end end
Use
def self.method
to define singleton methods. This makes the code
easier to refactor since the class name is not repeated.class TestClass # bad def TestClass.some_method # body omitted end # good def self.some_other_method # body omitted end # Also possible and convenient when you # have to define many singleton methods. class << self def first_method # body omitted end def second_method_etc # body omitted end end end
Last published almost 7 years ago by David Kariuki.