Wisdom from Eloquent Ruby: From Oh? to Oh Yeah!, Part 1

Wisdom from Eloquent Ruby: From Oh? to Oh Yeah!, Part 1

I started my Hawaiian vacation off this week with the stellar book Eloquent Ruby by Russ Olsen. I’ve read a few Ruby books and they usually take one of two forms:

  1. They are tutorial type books that show you how to build something. I enjoy these books but the knowledge gained to page turned ratio feels pretty low, only because I don’t veer too far off the path given to me and explore on my own.
  2. They are tomes of knowledge reference type books like the Pickaxe. These are generally packed to the gills with knowledge but my focus comes in two chapter bursts.

Eloquent Ruby is written in a much different fashion, keeping to the info that you should definitely know and written in a conversational manner that has a nice rhythm to it. Remember those cool teachers in school that actually seemed to want to be there? It feels like you’re reading a book written by one of them. So I can’t recommend picking up your own copy enough.

My first man crush.

Anyway, I wanted to keep an easy-to-reference log of the highlights I made in my Kindle version of the book. Some of this is fundamental but I wanted to hammer it home and some of this stuff is completely new to me, and I want to make sure I remember it.

Chapter 1: Write Code That Looks Like Ruby

  • Blocks with single statements should be put into a single line delimited with braces. Multiline blocks should be in a do/end sandwich. (loc. 526)
  • Using ! to append a method does not automatically make it an in-place substitution method. Pragmatically, Ruby programmers use it to to warn of methods that do something unexpected or dangerous. (loc. 567)

Chapter 2: Choose the Right Control Structure

  • Write clear code! An example of this that hit home for me is to stop using ! to create not conditions in if statements. Use the positive condition with an unless statement. Use until for while loops. (loc. 623)
  • If you are looking for nil and there is any possibility of false turning up, then look for nil explicitly. How can things go wrong?
    while some_object = get_an_object
    # code's doing stuff
    end

    If we’re hoping that the loop will only terminate on nil and get_an_object ends up being false, we’re boned. (loc. 708)

  • ||= expands to @variable = @variable || @other_variable. In English, set @variable to the old value of @variable, unless that is nil, in which case, set @variable to @other_variable. (loc. 729)
    foo = find_something()
    => nil
    foo ||= some_default
    => some_default
  • But don’t try to use ||= to initialize booleans! (loc. 744)
    foo = false
    => false
    foo ||= true
    => true         # defaulted to true even through we wanted the false

Chapter 3: Take Advantage of Ruby’s Smart Collections

  • Lots of strings in your array? (loc. 769)
    array = %w[ this looks cleaner than a ton of quotes ]
    => ["this", "looks", "cleaner", "than", "a", "ton", "of", "quotes"]
  • Use *, the splat, to accept an arbitrary amount of arguments. (loc. 805)
  • The map method calls the block on each element in a collection, and returns a new transformed array. (loc. 839)
  • The injectmethod passes in two arguments to the block, taking the first argument as the initial “result”, running the block, and using the result of that as the next “result” for the next element in the collection. (loc. 851)
    def average_word_length
      total = words.inject(0.0) { |result, word| word.size + result }
      total / word_count
    end
  • Need a collection that doesn’t allow duplicates but gives you the answer to ”Is this object in there?” Use sets. require 'set' needs to be in the code. (loc. 953)

Chapter 4: Take Advantage of Ruby’s Smart Strings

  • Just a cool quote from Russ talking about numbers being a part of programming: “It ain’t  called computing for nothing.” (loc. 966)
  • Ugly string full of escaped quotation marks?
    string = %q{ ""You miss 100% of the shots you don't take" - Wayne Gretzky"
    - Michael Scott }

    You can use any special characters as your delimiter. (loc. 998)

  • Lower case q, %q, is limited to the single quote interpretation (so no interpolation.) With %Q, the string acts more like a double quoted string (interpolation!) (loc. 1013)
  • To avoid multi-line strings getting interpreted with a newline use a \.
    (loc. 1018)

    %Q{ That's what she said \
    - Michael Scott }
  • If the string is very long, use a here document. Here’s an example from Russ (loc. 1022):
    string = <<EOF
    This is the beginning of the here document.
    And this is the end.
    EOF
  • Treat strings like other mutable data structures! Get in the habit of doing this (loc. 1112):
    expletive = expletive.upcase

    instead of this:

    expletive.upcase!

Chapter 5: Find the Right String with Regular Expressions

  • The most widely used of all regular expressions is .*, or find any character and find zero or more of them.

Chapter 6: Use Symbols to Stand for Something

  • The same symbol twice is the always the same instance of that symbol, unlike strings. (loc. 1404)
    "foo".object_id      # => 2152374980
    "foo".object_id      # => 2152194440
    :bar.object_id       # => 456488
    :bar.object_id       # => 456488
  • Symbols are immutable. (loc. 1423) Basically, symbols are awesome and useful.

Chapter 7: Treat Everything Like An Object – Because Everything Is

  • Using a method that is called on self in a class, don’t use self.method_name when just plain method_name will do. (loc. 1500)
  • If you don’t specify a superclass, the class automatically becomes a direct subclass of Object. (loc. 1505)
  • Being a instance of Object makes available a method called eval, which executes a string as if it were Ruby code. Neat! (loc. 1545)
  • Public, Private, Protected:
    • Public means a method is callable by code anywhere. (loc. 1563)
    • Private means you can not call a method with an explicit object reference. This ensures that private methods can only be called within the class that defined them or any of its subclasses, because this method still has an implicit receiver and will still work because of the inheritance chain.  Thanks for the catch Trent. (loc. 1568)
    • Protected means any instance of a class can call a protected method on any other instance of the class. (loc. 1577)

Chapter 8: Embrace Dynamic Typing

  • Ruby assumes that if an object has the right methods, then it is the right kind of object. This philosophy is called duck typing. Haha, I just got that as I wrote this. (loc. 1682)
  • One of the advantages of dynamic typing is that it allows for decoupling. Since we’re not declaring classes of variables and parameters, we gain flexibility in our code. If we have a method that accepts a parameter, as long as that parameter can work inside the method, it will work! Life. is. good. (loc. 1704)

Chapter 9: Writing Specs

  • If I decide to use the Test::Unit toolkit, these are some of my tools (loc. 1861)
    • assert_equal, assert_not_equal
    • assert_nil, assert_not_nil
    • assert_match accepts regex
    • assert_instance_of
    • assert_raise, assert_nothing_thrown accepts exceptions
  • If I decide to use Rspec (and chances are I will), the tests will take a form similar to this (loc. 1886):
    describe ClassName do
      it 'should return something that isn't false or nil' do
        class_instance.return_something.should == true
      end
    end
  • Setup/teardown code uses before and after method and can use :each or :all as the argument. (loc. 1916)
  • Stubs! An object that can be temporarily injected into a test to fill in any needed calls and their returns. (loc. 1937) For instance, in Rspec:
    it 'should explode on impact' do
      stub_roseanne = stub :tripped? => true
      @johngoodman.shield_face?( stub_roseanne ).should == true
    end
  • Mocks! Mocks can know what returns to call (like a stub) but also knows which methods should be called and with what arguments. (loc. 1956)
  • Tests are important. Even if you can only do the bare minimum in testing, do it. (loc. 2015)

 

There are three parts to Russ’ book so I’ll be doing this in three posts.  Next week I’ll post my highlights from chapters 10 through 19, which are about classes, modules, and blocks. It’s exciting stuff!