Skip to content

Instantly share code, notes, and snippets.

@fknappe
Created February 12, 2012 05:24
Show Gist options
  • Save fknappe/1806524 to your computer and use it in GitHub Desktop.
Save fknappe/1806524 to your computer and use it in GitHub Desktop.
Eloquent Ruby Highlights

Chapter 1. Basics

Ruby style programming was built on two simple ideas:

  1. Code must be crystal clear
  2. Code must be concise

Example:

# Author: Russ Olsen
#
# Class that models a plain text document, complete with title
# and author:
#
# doc = Document.new( 'Hamlet', 'Shakespeare', 'To be or...' )
# puts doc.title
# puts doc.author
# puts doc.content
#
# Document instances know how to parse their content into words:
#
# puts doc.words
# puts doc.word_count
#
class Document
  attr_accessor :title, :author, :content
  
  def initialize(title, author, content)
    @title = title
    @author = author
    @content = content
  end

  def words
    @content.split
  end

  def word_count
    words.size
  end

  def method_to_be_overriden; end

  def document_spelling
    words.each { |n| puts "The word is #{n}" }
  end 
end

Things to note about the snippet code above:

  • Ruby indentation convention: two space per level (don't ever use tab spaces for Ruby indentation)
  • Anything following a # in the code is a comment. Multiline comments can starts with =begin and finish with =end, but Rubyst convention are to use #
  • Good Ruby code must speak for itself: don't insert comment simply because you always put a comment somewhere.
  • Use comments for how to comments: tell me how to use the thing and remember that examples are always welcome.
  • Avoid comments to explain how the code works: they tend to make a badly written code somewhat comprehensible.
  • Replace how code works comments by class, methods and variables refactoring. (Remember, good code is like a good joke: It needs no explanation).
  • Use lowercase_words_separated_by_underscores when you refer to methods, arguments and variables identifiers.
  • Use camel case when you refer to classes identifiers.
  • Camel case can be used for constants identifiers too. But a convention is to choise for ALL_UPPERCASE_WITH_UNDERSCORE
  • Use parentheses only when indeed needed. Usually for multiple arguments methods (both in method definitions and calls) or method calling with complex expression.
  • Don't use parentheses for conditional statements.
  • Use several Ruby statements onto a single line, split by semicolon between statements for empty or small classes and methods.
  • Code blocks convention: block with one statement, use parentheses to delimit code block. Otherwise, use do/end form.
  • The exception for the convention above are too long one statement blocks. For those cases, you must use do/end to delimit code block.

Chapter 2. Choose the right control structure

Ruby includes a fairly familiar set of control structures, not much different than those available in more traditional programming languages. Look at any Ruby program and you will see a bunch of ifs, elses, and whiles of your programming youth. But if you look a little closer, you will also come across some odd-looking logical constructs, things with much less familiar names.

In this chapter of the book, the author describes how to create programs full of Ruby control structures idioms and how these structures help to prevent the program logic from take the wrong way.

Example:

# Author: Russ Olsen
#
# Class that models a plain text document, complete with title
# and author.
#
# doc = Document.new( 'Hamlet', 'Shakespeare', 'To be or...' )
# puts doc.title
# puts doc.author
# puts doc.content
#
# Document instances know how to parse their content into words:
#
# puts doc.words
# puts doc.word_count
#
class Document
  attr_accessor :writable, :read_only
  attr_reader :title, :author, :content
  
  FONTS = [ 'courier', 'times roman', 'helvetica' ]

  # Much of the class omitted...
  
  def title=(new_title)
    @title = new_title unless @read_only      
  end

  def content=(new_content)
    @content ||= new_content
  end

  # Similar author= method omitted...

  def content
    @content = @content || ''
  end

  def defined?(author)
    case author
      when "Tolstoy" then true
      when "Shakspeare" then true
      else false
    end
  end

  def print_document
    document.print_next_page until document.printed?      
  end

  def available_fonts
    FONTS.each { |font| puts font }
  end

  def number_of_words
    words.each do { |count| count += 1; puts "#{count}" }
  end

  def available_titles(author)
    case author
      when 'Tolstoy' then puts 'War And Peace'
      when 'Shakespeare' then puts 'Romeo And Juliet'
      else puts "Don't know"      
  end

  def available_authors(title)
    author = case title
             when "War And Peace"
               "Tolstoy"
             when "Romeo And Juliet"
               "Shakespeare"
             else
               "Don't know"
             end
  end

  def written_by?(author)
    return self.author === author ? true : false
  end
end

Things to note about the snippet code above:

  • While working with the Ruby programming language, developers should be aware of if statements are used exclusivelly for true assertions. A more concise and idiomatic way to use negative if statements are described with unless.
  • Similarly, while statement has a doppelganger in until statement. An until loop keeps going until its conditional part becomes true.
  • REMEMBER: Writing clear code is a battle of inches, and you need to contest every extraneous character, every bit of reversed logic.
  • Use collapsed single line control structures with only one assertion for read very smoothly (Do this if that).
  • Remember, when making decision on Ruby, only false and nil are treated as false value. Everything else as true value.
  • Avoid testing true conditional value for specific values (Ruby’s treatment of booleans means that there are two things that are false and an infinite number of things that are true).
  • Use ternary operator ?: for returning values from one line if statements.
  • Idiomatic Rubyists say to use the each method rather then the for loop. (Ruby actually defines the for loop in terms of the each method, so why don't you pull the mask of and write what you mean?).
  • Ruby also sports a case statement, similar to switch statement in other languages. Case statements are most commonly used in Ruby to select one of a number of bits of code to execute (like on available_titles method). However, it can be also used for the value it compute (as show on available_authors method).
  • Case statements can be written in a more compact when / then format if they contain one assertion each.
  • The code example show us the fact everything in Ruby returns a value (case statements return the when value or the else value. Otherwise, its return a nil value). All this means that you can use the case statement for exactly what it is: a giant value-return expression.
  • Use ? at the end of method identifiers that express boolean context (not only for explicitly return true or false values). And use ! at the end of "dangerous" (unexpected) method identifiers.
  • When you are not sure about variables initialization, or you want to ensure that an instance variable is not nil, use |= operator, or for expandend expressions like expressed on content method.
  • Don't use ||= operator to initialize things to boolean.
  • Note that count += 1 is equal to count = count + 1

Chapter 3. Take Advantage of Ruby’s Smart Collections

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment