named_let

The named_let can be used to make the rspec's output easier to read. It's wrapper function of let.

named_let(:name){ obj } changes the value which returns 'obj#to_s' and 'obj#inspect' to :name, then output message of 'rspec -format d' be improved more readable.

Usage

add require 'named_let' to your spec_helper.rb or * _spec.rb.

describe 'named_let' do
  context 'symbol only' do
    named_let(:foo) { Object.new }
    it { foo.to_s should == "foo" }
    it { foo.inspect.should == "foo" }
  end

  context 'with label strings' do
    named_let(:foo,"label for display"){ Object.new }
    it { foo.to_s should == "label for display" }
    it { foo.inspect.should == "label for display" }
   end
end

You can use name_let! to force the method's invocation before each example, like original let!.

Why named_let?

RSpec uses 'Object#inspect' for generating output message from value of specified by let. This will generates unexpected output like 'should == #Object:0x2aaaaf8a0870A', it's not human readable.

Now let's use named_let instead of let.The generaed output will be more readable like 'should == "label for display'.

Example

For Example, now writing specs for CanCan like bellow,

require 'spec_helper'
require "cancan/matchers"

describe Ability do
  context 'an user' do
    let(:user)          { Factory.create(:user) }

    let(:article)     { Factory.create(:article) }
    let(:own_article) { Factory.create(:article, :user => user) }

    subject { Ability.new(user) }

    it { should be_able_to(:read, article) }
    it { should be_able_to(:update, own_article) }
  end
end

This specs generates outputs is ...

$ bundle exec rspec -c --format d spec/models/ability_spec.rb

Ability
  an user
    should be able to :read #<Article id: 44, title: "The Test Article 1", body: "This is test article!!", created_at: "2012-02-23 14:19:26", updated_at: "2012-02-23 14:19:26", user_id: nil>
    should be able to :update #<Article id: 45, title: "The Test Article 2", body: "This is test article!!", created_at: "2012-02-23 14:19:26", updated_at: "2012-02-23 14:19:26", user_id: 31>

Finished in 0.26158 seconds
2 examples, 0 failures

OMG, It's not human readable. so,let's change let to named_let.

    named_let(:article)     { Factory.create(:article) }
    named_let(:own_article) { Factory.create(:article, :user => user) }

again, execute rspec --format d ...

$ bundle exec rspec -c --format d spec/models/ability_spec.rb

Ability
  an user
    should be able to :read article
    should be able to :update own article

Finished in 0.25375 seconds
2 examples, 0 failures

okay, it's readable!!!

For debugging

If the specs is fail, You will want to know original outputs of 'Object#inspect'. But named_let hides actual outputs of "Object#inspect".

Failures:

  1) Ability an user
     Failure/Error: it { should_not be_able_to(:update, own_article) }
       expected not to be able to :update own article

For debugging spec, if given -d option to rspec command or $DEBUG flag is true, named_let append orignal result of Object#inspect to returns value.

given -d option, then...

Failures:

  1) Ability an user
     Failure/Error: it { should_not be_able_to(:update, own_article) }
       expected not to be able to :update own article (#<Article id: 113, title: "The Test Article 3", body: "This is test article!!", created_at: "2012-02-24 05:53:17", updated_at: "2012-02-24 05:53:17", user_id: 90>)

NOTE:

Requires ruby-debug to using -d option. run gem install ruby-debug. If your Ruby-Runtime is 1.9+, see "https://github.com/mark-moseley/ruby-debug".