Skip to content

Latest commit

 

History

History

ruby

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Ruby

  • Prefer method invocation over instance variables link

    Example
    ## Bad
    class MarkRecipe
      def initialize(recipe)
        @recipe = recipe
      end
    
      def run
        @recipe.mark
      end
    end
    
    ## Good
    class MarkRecipe
      def initialize(recipe)
        @recipe = recipe
      end
    
      def run
        recipe.mark
      end
    
      private
    
        attr_reader :recipe
    end
    
    ## Also acceptable
    class Image
      def initialize(placeholder: false)
        @placeholder = placeholder
      end
    
      def render
        if placeholder?
          # ...
        end
      end
    
      private
    
        def placeholder?
          !!@placeholder
        end
    end
    
    ## Also acceptable
    class Pager
      def initialize
        @current_page = 1
      end
    
      def run
        while continue?
          # ...
          go_to_next_page
        end
      end
    
      private
    
        attr_reader :current_page
    
        def go_to_next_page
          @current_page += 1
        end
    end
  • Avoid using ternary operator link

    Example
    ## Bad
    published? ? published_message : standard_message
    
    ## Good
    if published?
      published_message
    else
      standard_message
    end
  • Prefer short, focused methods (aim for 1-liners, longer than 5 is a red flag) link

  • Avoid method names ending in ! ("bang") without a corresponding bang-less, safe version of the method. link

    Example
    ## Bad
    def method!
      # dangerous operation, without any safe version (prima-donna)
    end
    
    ## Good
    def method
      # dangerous operation, without any safe version
    end
    
    ## Good
    def method
      # safe version
      # It’s conventional to define the non-bang method in terms of the bang one, i.e.
      dup.method!
    end
    
    def method!
      # dangerous operation, with a safe version
    end
  • Prefer small, focused classes (100+ lines is a red flag) link

  • Prefer extracting private methods over setting variables inside methods link

    Example
    ## Bad
    def method
      var_1 = # ...
      var_2 = # ...
      var_3 = # ...
      var_1 + var_2 + var_3
    end
    
    ## Good
    def method
      var_1 + var_2 + var_3
    end
    
      private
    
      def var_1
        # ...
      end
    
      def var_2
        # ...
      end
    
      def var_3
        # ...
      end
  • Prefer $stdin, $stdout, $stderr over STDIN, STDOUT, STDERR link

  • Avoid lines that end with conditionals (exception is guard clauses) link

    Example
    ## Bad
    mark_related_items(:spam) if spam_detected?
    
    ## Good
    if spam_detected?
      mark_related_items(:spam)
    end
    
    ## OK for guard clauses, separate by space
    def approve
      return if approved?
      return if unapprovable?
    
      update(approved: true)
    end
  • Describe unexplained strings/numbers using constants link

    Example
    ## Bad
    def params
      { gak: "UA-4235" }
    end
    
    ## Good
    def params
      { gak: GOOGLE_ANALYTICS_KEY }
    end
    
    ## OK - string explained by hash key
    def params
      { google_analytics_key: "UA-4235" }
    end
  • DRY multiple occurrences of values using constants link

    Example
    ## Bad
    class Logger
      def log_params
        { google_analytics_key: "UA-4235" }
      end
    end
    
    class Tracker
      def config
        { google_analytics_key: "UA-4235" }
      end
    end
    
    ## Good
    class Logger
      def log_params
        { google_analytics_key: GoogleAnalytics::KEY }
      end
    end
    
    class Tracker
      def config
        { google_analytics_key: GoogleAnalytics::KEY }
      end
    end
  • Separate multiline fetch/query methods from the memoized method link

    Example
    ## Bad
    def pizza_recipes
      @_pizza_recipes ||= Recipe.
        published.
        in_current_language.
        where("title LIKE ?", "%pizza%")
    end
    
    ## Good
    def pizza_recipes
      @_pizza_recipes ||= fetch_pizza_recipes
    end
    
    def fetch_pizza_recipes
      Recipe.
        published.
        in_current_language.
        where("title LIKE ?", "%pizza%")
    end
  • Avoid unless with boolean operator(s) in the conditional link

    Example
    ## Bad
    unless client_id.present? && client_secret.present?
      raise "Missing credentials for OauthApplication #{name}."
    end
    
    ## Good - flip to if
    if client_id.blank? || client_secret.blank?
      raise "Missing credentials for OauthApplication #{name}."
    end
    
    ## Good - extract method
    if missing_credentials?
      raise "Missing credentials for OauthApplication #{name}."
    end
    
    def missing_credentials?
      client_id.blank? || client_secret.blank?
    end
  • Prefer a custom error class over a plain raise or raising NotImplementedError in abstract methods. link

    Example
    ## Bad
    def feed_class
      raise NotImplementedError
    end
    
    def search_source
      raise "Not implemented yet"
    end
    
    ## Good
    def feed_class
      raise UnimplementedAbstractMethodError.new(self.class.name, __method__)
    end