Adding ‘given a’ to rspec

Over the past few months I have grown to like the ‘given a’ syntax more and more (described here). So when I recently reactivated my Ruby On rails home project (see brikeyard deployed on heroku), I thought I would add that syntax to my rspec examples rather than use before(:each).

I have not spent too much time thinking about where to put this code. Nor did I spend much time peeling away the nested modules inside rspec. Ideas to make this better are very welcomed. I would also love to collect some feedback on this before I make a fool of myself by proposing its inclusion in rspec proper. Thanks in advance for your help !

Here is how the setup looks like in one of the specs:

describe :something do
    given {
      a StatisticalControl
      a WorkItem, {:lead_time => 1}
      another WorkItem, {:lead_time => 3}
      a ProcessStage, {:work_in_process => [a_work_item, another_work_item]}
      a ControlChart
      @project = Project.new
      @project.stub!(:lead_time_control).and_return(a_statistical_control)
      @project.stub!(:closed_stage).and_return(a_process_stage)
    }

    it "should do something useful" do
		(...)
    end
end

And here is what I added to my spec_helper.rb file:

def a(type, stubs ={})
  stub = mock_model(type, stubs)
  member_name = type.name.gsub(/[A-Z]/) {|match|
    "_#{match.downcase}"
  }
  instance_eval("
        @a#{member_name} = stub
          def a#{member_name}
            return @a#{member_name}
          end
      ")
end

def another(type, stubs ={})
  stub = mock_model(type, stubs)
  member_name = type.name.gsub(/[A-Z]/) {|match|
    "_#{match.downcase}"
  }
  instance_eval("
        @another#{member_name} = stub
          def another#{member_name}
            return @another#{member_name}
          end
      ")
end

class Spec::Rails::Example::FunctionalExampleGroup
  class << self
    def given &block
      before(:each, &block)
    end
  end
end

class Spec::Rails::Example::ModelExampleGroup
  class << self
    def given &block
      before(:each, &block)
    end
  end
end

Please let me know what you think. I welcome suggestions to improve.

Post to Twitter

Leave a Reply