Saturday, June 26, 2010

Using Object#tap

Object#tap is new to Ruby 1.9. This new method will allow us to modify the object its called upon and, after the block finishes, will return to us the original object.

We can use this feature to make our specs a bit more concise.

Here is an example using this spec...


describe Array do
   before(:all) do
    @array = Array.new
    @array << 1
   end
   
   it "should have a length of 1" do
    @array.should have(1).element
   end   
end

We change it so.

describe Array do
   before(:all) {@array = Array.new.tap{|me| me << 1}}
   
   it "should have a length of 1" do
    @array.should have(1).element
   end   
end

This code says "create a new instance of class Array, pass it to the 'tap' block, modify it, and return the original now modified object."

@array = Array.new.tap{|me| me << 1}

Some Ruby Built In Global Variables

These maybe helpful to know:


$0 --- Returns the name of the file that ruby is executing
$: --- Returns the directories Ruby searches to load external files
$$ --- Returns the process id of the Ruby process

Friday, June 25, 2010

let, its, and subject

We're going to refactor a spec to a more concise size.


First here is our starting point:


describe Foobar do
   before(:each) do
      @foobar = Foobar.new
   end
   
   it "should not be nil"
      @foobar.should_not be_nil
   end
   
   describe "#length" do
      before(:each) do
         @length = @foobar.length
      end
    
      it "should == 10" do
         @length.should == 10
      end
   end
end


The above example uses 15 lines of code. Lets see if we can do better.


First we're going to replace the 'before' blocks with 'let' blocks.
The 'let' block returns an evaluated block. It really helps you define
players in your spec.


describe Foobar do
   let(:foobar) {Foobar.new}
   
   it "should not be nil"
      foobar.should_not be_nil
   end
   
   describe "#length" do
      let(:length) {foobar.length}
    
      it "should == 10" do
         length.should == 10
      end
   end
end


That's a bit better. We are now at 11 lines of code.
But, we can do better.

We're going to use 'subject' block. This allows us to call
'should' right within the block. We're also going to use an 'its' block.
The 'its' block will return to us the value of the message retrieved represented
by the symbol we passed to it.


describe Foobar do
   subject {Foobar.new}
   
   it {should_not be_nil}
   its(:length) {should == 10}
end


Very good. We have brought it down to 5 lines.

What does the specdoc output look like?

Here it is:


Foobar
- should not be nil
Foobar length
- should == 10

Modifying an Existing Ruby Class

First example is reopening the class and adding methods to it.


First, the original class:


class OriginalGangsta
   def shoot
      puts 'bang!' 
   end

   def flee
      puts 'run muther###'
   end
end


Now, we modify the class:


#load the original class
require 'original_gangsta'

#add some new methods
class OriginalGangsta
   def lie
      puts "he dunnit"
   end

   def dance
      puts "I'm a dancin' fool"
   end
end


We can also just modify an instance of the class:


og = OriginalGangsta.new

class << og
   def cry
      puts "I never had a good home!"
   end
end

or we can do it this way:

og = OriginalGangsta.new

def og.cry
   puts "I never had a good home!"
end