me.stub!(:code!)

Apr 26 2009

cucumber negative expectations

*update* I forgot to include matcher block arguments… code is fixed below

A ton of my Then step definitions have this pattern:

Then %r{should( not)? be happy$} do |should_not|
  # ...
end

Dealing with the conditional should or should not got annoying, and I thought about some hardcore solutions (seen in this LH ticket)… but I ended up with a simpler solution with Andrew Vit’s help:

require 'singleton'

module NegativeExpectationsHelper
  
  class State
    
    include Singleton
    
    def is_negative?
      @negative === true
    end
    
    def is_negative!
      @negative = true
    end
    
    def restore!
      @negative = false
    end
  end
  
  module ObjectExpectations
    
    def self.included(base)
      base.class_eval do
        alias_method :original_should, :should
        alias_method :original_should_not, :should_not
        
        def should(*args, &block)
          should_if_true(!State.instance.is_negative?, *args, &block)
        end

        def should_not(*args, &block)
          should_if_true(State.instance.is_negative?, *args, &block)
        end
      end
    end
    
    private
    
    def should_if_true(cond, *args, &block)
      cond ? self.send(:original_should, *args, &block) : self.send(:original_should_not, *args, &block)
    end
  end
  
  def negative_expectations_if(cond)
    raise "expected block" unless block_given?
    State.instance.is_negative! if cond
    yield
    State.instance.restore! if cond
  end
end

class Object
  include NegativeExpectationsHelper::ObjectExpectations
end

World(NegativeExpectationsHelper)

That’s probably cumbersome (whoa, I just made a typo, “cucumbersome” and thought it would make for a nice cucumber inside joke) since I’m a little bit of a ruby meta-programming n00b. But anyway, now I can do: 

Then %r{should( not)? be happy$} do |should_not|
  negative_expectations_if(should_not) do
    should be_happy
  end
end
Comments (View)
blog comments powered by Disqus
Page 1 of 1