Skip to content

crowdtap/ruby

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 

Repository files navigation

Ruby Style Guide

This is Crowdtap's Ruby Style Guide.

It was inspired by Airbnb's styleguide.

Table of Contents

  1. Whitespace 1. Indentation 1. Inline 1. Newlines
  2. Line Length
  3. Commenting 1. File/class-level comments 1. Function comments 1. Block and inline comments 1. Punctuation, spelling, and grammar 1. TODO comments 1. Commented-out code
  4. Methods 1. Method definitions 1. Method calls
  5. Conditional Expressions 1. Conditional keywords 1. Ternary operator
  6. Syntax
  7. Naming
  8. Classes
  9. Exceptions
  10. Collections
  11. Strings
  12. Regular Expressions
  13. Percent Literals
  14. Rails 1. Separation of Concerns 1. Persistence 1. Testing Strategy
    1. Rspec 1. Scopes 1. Dates
  15. Be Consistent

Whitespace

Indentation

  • Use soft-tabs with a two space-indent.[link]

  • Indent when as deep as case. [link]

    case
    when song.name == 'Misty'
      puts 'Not again!'
    when song.duration > 120
      puts 'Too long!'
    when Time.now.hour > 21
      puts "It's too late"
    else
      song.play
    end
    
    kind = case year
           when 1850..1889 then 'Blues'
           when 1890..1909 then 'Ragtime'
           when 1910..1929 then 'New Orleans Jazz'
           when 1930..1939 then 'Swing'
           when 1940..1950 then 'Bebop'
           else 'Jazz'
           end
  • Align function parameters either all on the same line or one per line.[link]

    # good
    def self.create_translation(phrase_id,
                                phrase_key,
                                target_locale,
                                value,
                                user_id,
                                do_xss_check,
                                allow_verification)
      ...
    end
    
    # good
    def self.create_translation(
      phrase_id,
      phrase_key,
      target_locale,
      value,
      user_id,
      do_xss_check,
      allow_verification
    )
      ...
    end
    
    # bad
    def self.create_translation(phrase_id, phrase_key, target_locale,
                                value, user_id, do_xss_check, allow_verification)
      ...
    end
  • Indent succeeding lines in multi-line boolean expressions.[link]

    # good
    def is_eligible?(user)
      Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) &&
        is_in_program?(user) &&
        program_not_expired
    end
    
    # bad
    def is_eligible?(user)
      Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) &&
      is_in_program?(user) &&
      program_not_expired
    end

Inline

  • Never leave trailing whitespace. [link]

  • Use spaces around operators; after commas, colons, and semicolons; and around { and before }. [link]

    sum = 1 + 2
    a, b = 1, 2
    1 > 2 ? true : false; puts 'Hi'
    [1, 2, 3].each { |e| puts e }
  • No spaces after (, [ or before ], ). [link]

    some(arg).other
    [1, 2, 3].length

Newlines

  • Add a new line after if conditions span multiple lines to help differentiate between the conditions and the body. [link]

    if @reservation_alteration.checkin == @reservation.start_date &&
       @reservation_alteration.checkout == (@reservation.start_date + @reservation.nights)
    
      redirect_to_alteration @reservation_alteration
    end
  • Add a new line after conditionals, blocks, case statements, etc.[link]

    if robot.is_awesome?
      send_robot_present
    end
    
    robot.add_trait(:human_like_intelligence)

Line Length

  • Keep each line of code to a readable length. Unless you have a reason to, keep lines to fewer than 100 characters. (rationale) [link]

Commenting

Good code is its own best documentation. As you're about to add a comment, ask yourself, "How can I improve the code so that this comment isn't needed?" Improve the code and then document it to make it even clearer.
-- Steve McConnell

  • Write self-documenting code and ignore the rest of this section. Seriously!
  • Avoid superfluous comments.
  # bad
  counter += 1 # increments counter by one
  • Keep existing comments up-to-date or attempt to delete them with good code. An outdated is worse than no comment at all.

Good code is like a good joke - it needs no explanation.
-- Russ Olsen

  • Avoid writing comments to explain bad code. Refactor the code to make it self-explanatory.

Try not! Do or do not - there is no try.
--Yoda

TODO comments

Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect.

TODOs should include the string TODO in all caps, followed by the full name of the person who can best provide context about the problem referenced by the TODO, in parentheses. A colon is optional. A comment explaining what there is to do is required. The main purpose is to have a consistent TODO format that can be searched to find the person who can provide more details upon request. A TODO is not a commitment that the person referenced will fix the problem. Thus when you create a TODO, it is almost always your name that is given.

  # bad
  # TODO(RS): Use proper namespacing for this constant.

  # bad
  # TODO(drumm3rz4lyfe): Use proper namespacing for this constant.

  # good
  # TODO(Ringo Starr): Use proper namespacing for this constant.

Commented-out code

  • Never leave commented-out code in our codebase. [link]

Methods

Method definitions

  • Use def with parentheses when there are parameters. Omit the parentheses when the method doesn't accept any parameters.[link]

    def some_method
      # body omitted
    end
    
    def some_method_with_parameters(arg1, arg2)
      # body omitted
    end
  • Do not use default arguments. Use an options hash instead.[link]

    # bad
    def obliterate(things, gently = true, except = [], at = Time.now)
      ...
    end
    
    # good
    def obliterate(things, options = {})
      default_options = {
        :gently => true, # obliterate with soft-delete
        :except => [], # skip obliterating these things
        :at => Time.now, # don't obliterate them until later
      }
      options.reverse_merge!(default_options)
    
      ...
    end

Method calls

Use parentheses for a method call:

  • If the method returns a value. [link]

    # bad
    @current_user = User.find_by_id 1964192
    
    # good
    @current_user = User.find_by_id(1964192)
  • If the first argument to the method uses parentheses.[link]

    # bad
    put! (x + y) % len, value
    
    # good
    put!((x + y) % len, value)
  • Never put a space between a method name and the opening parenthesis.[link]

    # bad
    f (3 + 2) + 1
    
    # good
    f(3 + 2) + 1
  • Omit parentheses for a method call if the method accepts no arguments.[link]

    # bad
    nil?()
    
    # good
    nil?
  • If the method doesn't return a value (or we don't care about the return), parentheses are optional. (Especially if the arguments overflow to multiple lines, parentheses may add readability.) [link]

    # okay
    render(:partial => 'foo')
    
    # okay
    render :partial => 'foo'

In either case:

  • If a method accepts an options hash as the last argument, do not use { } during invocation. [link]

    # bad
    get '/v1/reservations', { :id => 54875 }
    
    # good
    get '/v1/reservations', :id => 54875

Conditional Expressions

Conditional keywords

  • Never use then for multi-line if/unless. [link]

    # bad
    if some_condition then
      ...
    end
    
    # good
    if some_condition
      ...
    end
  • The and, or, and not keywords are banned. It's just not worth it. Always use &&, ||, and ! instead. [link]

  • Modifier if/unless usage is okay when the body is simple, the condition is simple, and the whole thing fits on one line. Otherwise, avoid modifier if/unless. [link]

    # bad - this doesn't fit on one line
    add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty?
    
    # okay
    if request_opts[:trebuchet_experiments_on_page] &&
         !request_opts[:trebuchet_experiments_on_page].empty?
    
      add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page])
    end
    
    # bad - this is complex and deserves multiple lines
    parts[i] = part.to_i(INTEGER_BASE) if !part.nil? && [0, 2, 3].include?(i)
    
    # okay
    return if reconciled?
  • Never use unless with else. Rewrite these with the positive case first.[link]

    # bad
    unless success?
      puts 'failure'
    else
      puts 'success'
    end
    
    # good
    if success?
      puts 'success'
    else
      puts 'failure'
    end
  • Avoid unless with multiple conditions.[link]

      # bad
      unless foo? && bar?
        ...
      end
    
      # okay
      if !(foo? && bar?)
        ...
      end
  • Don't use parentheses around the condition of an if/unless/while. [link]

    # bad
    if (x > 10)
      ...
    end
    
    # good
    if x > 10
      ...
    end

Ternary operator

  • Avoid the ternary operator (?:) except in cases where all expressions are extremely trivial. However, do use the ternary operator(?:) over if/then/else/end constructs for single line conditionals.[link]

    # bad
    result = if some_condition then something else something_else end
    
    # good
    result = some_condition ? something : something_else
  • Use one expression per branch in a ternary operator. This also means that ternary operators must not be nested. Prefer if/else constructs in these cases.[link]

    # bad
    some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else
    
    # good
    if some_condition
      nested_condition ? nested_something : nested_something_else
    else
      something_else
    end
  • Avoid multiple conditions in ternaries. Ternaries are best used with single conditions. [link]

  • Avoid multi-line ?: (the ternary operator), use if/then/else/end instead. [link]

    # bad
    some_really_long_condition_that_might_make_you_want_to_split_lines ?
      something : something_else
    
    # good
    if some_really_long_condition_that_might_make_you_want_to_split_lines
      something
    else
      something_else
    end

Syntax

  • Never use for, unless you know exactly why. Most of the time iterators should be used instead. for is implemented in terms of each (so you're adding a level of indirection), but with a twist - for doesn't introduce a new scope (unlike each) and variables defined in its block will be visible outside it.[link]

    arr = [1, 2, 3]
    
    # bad
    for elem in arr do
      puts elem
    end
    
    # good
    arr.each { |elem| puts elem }
  • Prefer {...} over do...end for single-line blocks. Avoid using {...} for multi-line blocks (multiline chaining is always ugly). Always use do...end for "control flow" and "method definitions" (e.g. in Rakefiles and certain DSLs). Avoid do...end when chaining.[link]

    names = ["Bozhidar", "Steve", "Sarah"]
    
    # good
    names.each { |name| puts name }
    
    # bad
    names.each do |name| puts name end
    
    # good
    names.select { |name| name.start_with?("S") }.map { |name| name.upcase }
    
    # good
    names.each do |name|
      puts name
      do_something_with(name)
    end
    
    # bad
    names.select do |name|
      name.start_with?("S")
    end.map { |name| name.upcase }

    Some will argue that multiline chaining would look okay with the use of {...}, but they should ask themselves if this code is really readable and whether the block's content can be extracted into nifty methods.

  • Avoid return where not required. [link]

    # bad
    def some_method(some_arr)
      return some_arr.size
    end
    
    # good
    def some_method(some_arr)
      some_arr.size
    end
  • Don't use the return value of = in conditionals[link]

    # bad - shows intended use of assignment
    if (v = array.grep(/foo/))
      ...
    end
    
    # bad
    if v = array.grep(/foo/)
      ...
    end
    
    # good
    v = array.grep(/foo/)
    if v
      ...
    end
  • Use ||= freely to initialize variables. [link]

    # set name to Bozhidar, only if it's nil or false
    name ||= 'Bozhidar'
  • Don't use ||= to initialize boolean variables. (Consider what would happen if the current value happened to be false.)[link]

    # bad - would set enabled to true even if it was false
    enabled ||= true
    
    # good
    enabled = true if enabled.nil?
  • Avoid using Perl-style special variables (like $0-9, $, etc. ). They are quite cryptic and their use in anything but one-liner scripts is discouraged. Prefer long form versions such as $PROGRAM_NAME.[link]

  • Use _ for unused block arguments. [link]

    # bad
    result = hash.map { |k, v| v + 1 }
    
    # good
    result = hash.map { |_, v| v + 1 }
  • When a method block takes only one argument, and the body consists solely of reading an attribute or calling one method with no arguments, use the &: shorthand. [link]

    # bad
    bluths.map { |bluth| bluth.occupation }
    bluths.select { |bluth| bluth.blue_self? }
    
    # good
    bluths.map(&:occupation)
    bluths.select(&:blue_self?)
  • Prefer some_method over self.some_method when calling a method on the current instance.[link]

    # bad
    def end_date
      self.start_date + self.nights
    end
    
    # good
    def end_date
      start_date + nights
    end

    In the following three common cases, self. is required by the language and is good to use:

    1. When defining a class method: def self.some_method.
    2. The left hand side when calling an assignment method, including assigning an attribute when self is an ActiveRecord model: self.guest = user.
    3. Referencing the current instance's class: self.class.

Naming

  • Use snake_case for methods and variables. [link]

  • Use CamelCase for classes and modules. (Keep acronyms like HTTP, RFC, XML uppercase.) [link]

  • Use SCREAMING_SNAKE_CASE for other constants.[link]

  • The names of predicate methods (methods that return a boolean value) should end in a question mark. (i.e. Array#empty?).[link]

  • The names of potentially "dangerous" methods (i.e. methods that modify self or the arguments, exit!, etc.) should end with an exclamation mark. Bang methods should only exist if a non-bang method exists. (More on this.) [link]

  • Name throwaway variables _. [link]

    payment, _ = Payment.complete_paypal_payment!(params[:token],
                                                  native_currency,
                                                  created_at)

Classes

  • Avoid the usage of class (@@) variables due to their "nasty" behavior in inheritance. [link]

    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.

  • Use def self.method to define singleton methods. This makes the methods more resistant to refactoring changes. [link]

    class TestClass
      # bad
      def TestClass.some_method
        ...
      end
    
      # good
      def self.some_other_method
        ...
      end
  • Avoid class << self except when necessary, e.g. single accessors and aliased attributes. [link]

    class TestClass
      # bad
      class << self
        def first_method
          ...
        end
    
        def second_method_etc
          ...
        end
      end
    
      # good
      class << self
        attr_accessor :per_page
        alias_method :nwo, :find_by_name_with_owner
      end
    
      def self.first_method
        ...
      end
    
      def self.second_method_etc
        ...
      end
    end
  • Indent the public, protected, and private methods as much the method definitions they apply to. Leave one blank line above and below them.[link]

    class SomeClass
      def public_method
        # ...
      end
    
      private
    
      def private_method
        # ...
      end
    end

Exceptions

  • Don't use exceptions for flow of control. [link]

    # bad
    begin
      n / d
    rescue ZeroDivisionError
      puts "Cannot divide by 0!"
    end
    
    # good
    if d.zero?
      puts "Cannot divide by 0!"
    else
      n / d
    end
  • Avoid rescuing the Exception class. [link]

    # bad
    begin
      # an exception occurs here
    rescue Exception
      # exception handling
    end
    
    # good
    begin
      # an exception occurs here
    rescue StandardError
      # exception handling
    end
    
    # acceptable
    begin
      # an exception occurs here
    rescue
      # exception handling
    end

Collections

  • Use Set instead of Array when dealing with unique elements. Set implements a collection of unordered values with no duplicates. This is a hybrid of Array's intuitive inter-operation facilities and Hash's fast lookup.[link]

  • Prefer map over collect.[link]

  • Prefer detect over find. The use of find is ambiguous with regard to ActiveRecord's find method - detect makes clear that you're working with a Ruby collection, not an AR object. [link]

  • Prefer reduce over inject. [link]

  • Prefer size over either length or count for performance reasons.[link]

  • Use hashrocket syntax instead of JSON syntax for hashes. Hashrocket works no matter what type the key is, and symbol keys + symbol values look wonky in the JSON syntax.

    # bad
    hash = { one: 1, two: 2, action: :update }
    
    # good
    hash = { :one => 1, :two => 2, :action => :update }
  • Use symbols instead of strings as hash keys.

    # bad
    hash = { 'one' => 1, 'two' => 2, 'three' => 3 }
    
    # good
    hash = { :one => 1, :two => 2, :three => 3 }
  • Use multi-line hashes when it makes the code more readable, and use trailing commas to ensure that parameter changes don't cause extraneous diff lines when the logic has not otherwise changed. [link]

    hash = {
      :action => :set_password,
      :controller => :users,
      :only_path => false,
      :protocol => 'https',
      :redirect => @redirect_url,
      :secret => @secret,
    }
  • Use a trailing comma in an Array that spans more than 1 line[link]

    # good
    array = [1, 2, 3]
    
    # good
    array = [
      "car",
      "bear",
      "plane",
      "zoo",
    ]
  • When listing out a bunch of items whose order doesn't necessarily matter, list them in alphabetical order. [link]

    # good
    hash = {
      :action => :set_password,
      :controller => :users,
      :only_path => false,
      :protocol => 'https',
      :redirect => @redirect_url,
      :secret => @secret,
    }
    
    # good
    field :action
    field :brand_id
    field :first_name
    field :last_name
    field :title

Strings

  • Prefer string interpolation instead of string concatenation:[link]

    # bad
    email_with_name = user.name + ' <' + user.email + '>'
    
    # good
    email_with_name = "#{user.name} <#{user.email}>"

    Furthermore, keep in mind Ruby 1.9-style interpolation. Let's say you are composing cache keys like this:

    CACHE_KEY = '_store'
    
    cache.write(@user.id + CACHE_KEY)

    Prefer string interpolation instead of string concatenation:

    CACHE_KEY = '%d_store'
    
    cache.write(CACHE_KEY % @user.id)
  • Avoid using String#+ when you need to construct large data chunks. Instead, use String#<<. Concatenation mutates the string instance in-place and is always faster than String#+, which creates a bunch of new string objects.[link]

    # good and also fast
    html = ''
    html << '<h1>Page title</h1>'
    
    paragraphs.each do |paragraph|
      html << "<p>#{paragraph}</p>"
    end

Regular Expressions

  • Avoid using $1-9 as it can be hard to track what they contain. Named groups can be used instead. [link]

    # bad
    /(regexp)/ =~ string
    ...
    process $1
    
    # good
    /(?<meaningful_var>regexp)/ =~ string
    ...
    process meaningful_var
  • Be careful with ^ and $ as they match start/end of line, not string endings. If you want to match the whole string use: \A and \z.[link]

    string = "some injection\nusername"
    string[/^username$/]   # matches
    string[/\Ausername\z/] # don't match
  • Use x modifier for complex regexps. This makes them more readable and you can add some useful comments. Just be careful as spaces are ignored.[link]

    regexp = %r{
      start         # some text
      \s            # white space char
      (group)       # first group
      (?:alt1|alt2) # some alternation
      end
    }x

Percent Literals

  • Use %w freely.[link]

    STATES = %w(draft open closed)
  • Use %() for single-line strings which require both interpolation and embedded double-quotes. For multi-line strings, prefer heredocs.[link]

    # bad - no interpolation needed
    %(<div class="text">Some text</div>)
    # should be '<div class="text">Some text</div>'
    
    # bad - no double-quotes
    %(This is #{quality} style)
    # should be "This is #{quality} style"
    
    # bad - multiple lines
    %(<div>\n<span class="big">#{exclamation}</span>\n</div>)
    # should be a heredoc.
    
    # good - requires interpolation, has quotes, single line
    %(<tr><td class="name">#{name}</td>)
  • Use %r only for regular expressions matching more than one '/' character.[link]

    # bad
    %r(\s+)
    
    # still bad
    %r(^/(.*)$)
    # should be /^\/(.*)$/
    
    # good
    %r(^/blog/2011/(.*)$)

Rails

  • When immediately returning after calling render or redirect_to, put return on the next line, not the same line. [link]

    # bad
    render :text => 'Howdy' and return
    
    # good
    render :text => 'Howdy'
    return
    
    # still bad
    render :text => 'Howdy' and return if foo.present?
    
    # good
    if foo.present?
      render :text => 'Howdy'
      return
    end

Separation of Concerns

  • The responsibilities of a controller include accepting HTTP requests, handling authentication and authorization, and rendering a response in the appropriate format.[link]

    1. Performing operations on records as the result of a request is business logic and belongs outside of the controller.
    2. Preparing a view model for the response is presentation logic and belongs outside of the controller.
    3. When making changes to a controller, extract as much complexity as possible into other entities, such as services, helper objects, and models. 1. This makes it easier to separate and test various types of logic and write reusable code.
    # bad
    class V2::ShareController < BaseController
      def create
        participation = Participation.where(:brand_action_id => params[:id], :member_id => current_member.id).first
    
        social_network_share = SocialNetworkShare.where(
                                 :brand_action_id  => params[:id],
                                 :member           => current_member,
                                 :participation    => participation
                               ).first
        social_network_share ||= SocialNetworkShare.initialize_from(participation)
        social_network_share.messages.merge!(params[:share_media_platforms])
    
        if social_network_share.save
          params[:share_media_platforms].each do |key, value|
            participation.share_media_platforms["#{key}"] = value
          end
          participation.save
          head :created
        else
          render :json   => {"errors" => social_network_share.errors.messages},
                 :status => :unprocessable_entity
        end
      end
    end
    
    # good
    class V2::ShareController < BaseController
      def create
        service = CreateShareService.new(params)
    
        if service.run
          @share = service.share
          render :show, :status => :created
        else
          render :json => service.errors, :status => :unprocessable_entity
        end
      end
    end
    1. The service interface should: 1. Allow you to instantiate the service with a set of hash options 2. Expose a single instance method as the entry point 3. Expose a read-only attribute to access encountered errors 4. Expose a read-only attribute to access the result of a successful run
      1. Ex: If making a create endpoint, this can be the new record
    # example service
    class CreateShareService
      attr_reader :errors, :share
    
      def initialize(params)
        self.errors = []
    
        @participation_id = params[:participation_id]
        ...
      end
    
      def run
        return false unless valid?
        create_share
        true
      rescue Mongoid::Errors::Validations => error
        errors.push(...)
        false
      end
    
      private
    
      def create_share
        share = SocialNetworkShare.create!(...)
      end
    
      def valid?
        errors.push(error) if ...
        errors.empty?
      end
    end
  • Business logic should be in models and services, not controllers or views.[link]

  • Extract service objects to manage complex interactions across models.[link]

  • In general, extract basic ruby object to wrap complex logic and keep rails objects at a consistent level of abstraction.(More on this.)[link]

Persistence

  • Prefer save!, create!, and update_attributes! over the non-bangy versions of those methods unless explicitly handling when the save fails.[link]

    # bad
    class BlogPostService
      def self.create_with_score(blog_post_params)
        BlogPost.create(blog_post_params)
        Score.create(:blog_post => blog_post)
      end
    end
    
    # good
    class BlogPostService
      def self.create_with_score(blog_post_params)
        blog_post = BlogPost.create!(blog_post_params)
        Score.create!(:blog_post => blog_post)
      end
    end
    
    # good
    class BlogPostsController
      def create
        @blog_post = BlogPost.new(blog_post_params)
    
        if blog_post.save
          redirect_to @blog_post
        else
          render :new, :status => :unprocessable_entity
        end
      end
    end
  • Do not skip model validations (with e.g. inc or update_attribute) unless you're solving a measured performance bottleneck.[link]

Testing Strategy

  • Integration test status codes and responses for the main happy path and sad path for an action. Check that the correct redirects are made or the correct content is rendered. [link]

  • Controller test all happy and sad paths for an action. Check that the correct redirects are made or the correct content is rendered. [link]

  • Unit test all public methods.[link]

  • Do not test the existence of fields on models. Instead, test the intended behavior associated with those fields [link]

  • If a public method on a model uses other public methods owned by the same model, stub the other methods to avoid double testing.[link]

  • Models should have 100% test coverage just from running model specs.[link]

  • Assertions in each example should be at the same level of abstraction. If this is challenging, it's likely an object should be extracted to handle one of those abstraction layers. [link]

  • Do not directly test private methods. [link]

  • Do not stub database interactions. They are not tested elsewhere.[link]

    #bad
    it "sets the admin flag to true" do
      user.make_admin!
    
      expect(user).to have_received(:update_attributes!).with(:admin => true)
    end
    
    #good
    it "sets the admin flag to true" do
      user.make_admin!
    
      expect(user.reload.admin).to eq(true)
    end

####Rspec

  • Avoid stubbing on any_instance. Prefer dependency injection (i.e. stub find to return a specific instance or a stub). [link]

  • Prefer expect(foo).to have_received(:message) over expect(foo).to_receive(:message). In general, prefer forms that allow tests to flow sequentially from setup to assertions to teardown. [link]

Scopes

  • When defining ActiveRecord model scopes, wrap the relation in a lambda. A naked relation forces a database connection to be established at class load time (instance startup). [link]

    # bad
    scope :foo, where(:bar => 1)
    
    # good
    scope :foo, -> { where(:bar => 1) }

Dates

  • When trying to set the current date or time, make use .current instead of .today. Date.today doesn't account for timezones and hence can cause issues. [link]

    # bad
    Timecop.freeze(Date.today) do
      ...
    end
    
    # bad
    now = Time.now
    
    # good
    Timecop.freeze(Date.current) do
      ...
    end
    
    # good
    now = Time.current

Be Consistent

If you're editing code, take a few minutes to look at the code around you and determine its style. If they use spaces around all their arithmetic operators, you should too. If their comments have little boxes of hash marks around them, make your comments have little boxes of hash marks around them too.

The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you're saying rather than on how you're saying it. We present global style rules here so people know the vocabulary, but local style is also important. If code you add to a file looks drastically different from the existing code around it, it throws readers out of their rhythm when they go to read it. Avoid this.

Google C++ Style Guide

Releases

No releases published

Packages

No packages published