diff --git a/lib/spec/matchers/be.rb b/lib/spec/matchers/be.rb index 896ac58ca..c629f9906 100644 --- a/lib/spec/matchers/be.rb +++ b/lib/spec/matchers/be.rb @@ -1,36 +1,136 @@ require 'spec/matchers/dsl' Spec::Matchers.define :be_true do - match do |actual| - !!actual - end + match {|actual| !!actual} end Spec::Matchers.define :be_false do - match do |actual| - !actual - end + match {|actual| !actual} +end + +Spec::Matchers.define :be_nil do + match {|actual| actual.nil?} + + failure_message_for_should { + "expected nil, got #{actual.inspect}" + } + + failure_message_for_should_not { + "expected not nil, got nil" + } end module Spec module Matchers - + class Be #:nodoc: include Spec::Matchers::Pretty def initialize(*args, &block) - @expected = args.empty? ? true : set_expected(args.shift) + @expected = :__truthy @args = args - @block = block - @comparison_method = nil end def matches?(actual) @actual = actual - handling_predicate? ? run_predicate_on(actual) : match_or_compare(actual) + !!@actual + end + + def failure_message_for_should + "expected #{@actual.inspect} to evaluate to true" + end + + def failure_message_for_should_not + "expected #{@actual.inspect} to evaluate to false" + end + + def description + "#{prefix_to_sentence}#{comparison} #{expected_to_sentence}#{args_to_sentence}".gsub(/\s+/,' ') + end + + [:==, :<, :<=, :>=, :>, :===].each do |operator| + define_method operator do |operand| + BeComparedTo.new(operand, operator) + end + end + + private + + def args_to_s + @args.empty? ? "" : parenthesize(inspected_args.join(', ')) + end + + def parenthesize(string) + return "(#{string})" + end + + def inspected_args + @args.collect{|a| a.inspect} + end + + def comparison + @operator.nil? ? " " : "be #{@operator.to_s} " + end + + def expected_to_sentence + split_words(@expected) + end + + def prefix_to_sentence + split_words(@prefix) + end + + def args_to_sentence + to_sentence(@args) + end + + end + + class BeComparedTo < Be + + def initialize(operand, operator) + @expected, @operator = operand, operator + @args = [] + end + + def matches?(actual) + @actual = actual + @actual.__send__(operator, @expected) + end + + def failure_message_for_should + "expected #{@operator} #{@expected}, got #{@actual.inspect}" + end + + def failure_message_for_should_not + message = <<-MESSAGE +'should_not be #{@operator} #{@expected}' not only FAILED, +it is a bit confusing. + MESSAGE + + raise message << ([:===,:==].include?(@operator) ? + "It might be more clearly expressed without the \"be\"?" : + "It might be more clearly expressed in the positive?") + end + + private + + def operator + @operator ||= :equal? + end + + end + + class BePredicate < Be + + def initialize(*args, &block) + @expected = parse_expected(args.shift) + @args = args + @block = block end - def run_predicate_on(actual) + def matches?(actual) + @actual = actual begin return @result = actual.__send__(predicate, *@args, &@block) rescue NameError => predicate_missing_error @@ -45,140 +145,55 @@ def run_predicate_on(actual) end def failure_message_for_should - if handling_predicate? - if predicate == :nil? - "expected nil, got #{@actual.inspect}" - else - "expected #{predicate}#{args_to_s} to return true, got #{@result.inspect}" - end - else - "expected #{@comparison_method} #{expected}, got #{@actual.inspect}".gsub(' ',' ') - end + "expected #{predicate}#{args_to_s} to return true, got #{@result.inspect}" end def failure_message_for_should_not - if handling_predicate? - if predicate == :nil? - "expected not nil, got nil" - else - "expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}" - end - else - message = <<-MESSAGE -'should_not be #{@comparison_method} #{expected}' not only FAILED, -it is a bit confusing. - MESSAGE - - raise message << ([:===,:==].include?(@comparison_method) ? - "It might be more clearly expressed without the \"be\"?" : - "It might be more clearly expressed in the positive?") - end - end - - def description - "#{prefix_to_sentence}#{comparison} #{expected_to_sentence}#{args_to_sentence}".gsub(/\s+/,' ') + "expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}" end - [:==, :<, :<=, :>=, :>, :===].each do |method| - define_method method do |expected| - compare_to(expected, :using => method) - self - end - end + private - private - def match_or_compare(actual) - TrueClass === @expected ? @actual : @actual.__send__(comparison_method, @expected) - end + def predicate + "#{@expected.to_s}?".to_sym + end - def comparison_method - @comparison_method || :equal? - end + def present_tense_predicate + "#{@expected.to_s}s?".to_sym + end - def expected - @expected - end - - def compare_to(expected, opts) - @expected, @comparison_method = expected, opts[:using] - end + def parse_expected(expected) + @prefix, expected = prefix_and_expected(expected) + expected + end - def set_expected(expected) - Symbol === expected ? parse_expected(expected) : expected - end - - def parse_expected(expected) - ["be_an_","be_a_","be_"].each do |prefix| - handling_predicate! - if expected.to_s =~ /^#{prefix}/ - set_prefix(prefix) - expected = expected.to_s.sub(prefix,"") - return expected.to_sym - end - end - end - - def set_prefix(prefix) - @prefix = prefix - end - - def prefix - # FIXME - this is a bit goofy - but we get failures - # if just defining @prefix = nil in initialize - @prefix = nil unless defined?(@prefix) - @prefix - end + def prefix_and_expected(symbol) + symbol.to_s =~ /^(be_(an?_)?)(.*)/ + return $1, $3 + end - def handling_predicate! - @handling_predicate = true - end - - def handling_predicate? - return false if [true, false, nil].include?(expected) - # FIXME - this is a bit goofy - but we get failures - # if just defining @handling_predicate = nil or false in initialize - return defined?(@handling_predicate) ? @handling_predicate : nil - end + end - def predicate - "#{@expected.to_s}?".to_sym - end - - def present_tense_predicate - "#{@expected.to_s}s?".to_sym - end - - def args_to_s - @args.empty? ? "" : parenthesize(inspected_args.join(', ')) - end - - def parenthesize(string) - return "(#{string})" - end - - def inspected_args - @args.collect{|a| a.inspect} - end - - def comparison - @comparison_method.nil? ? " " : "be #{@comparison_method.to_s} " - end - - def expected_to_sentence - split_words(expected) - end - - def prefix_to_sentence - split_words(prefix) - end + class BeSameAs < Be + + def initialize(*args, &block) + @expected = args.shift + @args = args + end + + def matches?(actual) + @actual = actual + @actual.equal?(@expected) + end - def args_to_sentence - to_sentence(@args) - end - - end + def failure_message_for_should + "expected #{@expected}, got #{@actual.inspect}" + end + + def failure_message_for_should_not + "expected not #{@expected}, got #{@actual.inspect}" + end - class BePredicate < Be end # :call-seq: @@ -211,8 +226,10 @@ class BePredicate < Be # collection.should be_empty #passes if target.empty? # target.should_not be_empty #passes unless target.empty? # target.should_not be_old_enough(16) #passes unless target.old_enough?(16) - def be(*args, &block) - Matchers::Be.new(*args, &block) + def be(*args) + args.empty? ? + Matchers::Be.new : + Matchers::BeSameAs.new(*args) end # passes if target.kind_of?(klass) diff --git a/spec/spec/matchers/be_spec.rb b/spec/spec/matchers/be_spec.rb index 143d323c3..0d5412f32 100644 --- a/spec/spec/matchers/be_spec.rb +++ b/spec/spec/matchers/be_spec.rb @@ -352,17 +352,28 @@ end describe "should be" do - it "should pass if actual is true or a set value" do + it "should pass if actual is truthy" do true.should be 1.should be end it "should fail if actual is false" do - lambda {false.should be}.should fail_with("expected true, got false") + lambda {false.should be}.should fail_with("expected false to evaluate to true") end it "should fail if actual is nil" do - lambda {nil.should be}.should fail_with("expected true, got nil") + lambda {nil.should be}.should fail_with("expected nil to evaluate to true") + end +end + +describe "should_not be" do + it "should pass if actual is falsy" do + false.should_not be + nil.should_not be + end + + it "should fail on true" do + lambda {true.should_not be}.should fail_with("expected true to evaluate to false") end end @@ -375,6 +386,15 @@ end end +describe "should_not be(value)" do + it "should pass if !actual.equal?(value)" do + 5.should_not be(6) + end + it "should fail if !actual.equal?(value)" do + lambda { 5.should_not be(5) }.should fail_with("expected not 5, got 5") + end +end + describe "'should be' with operator" do it "should include 'be' in the description" do (be > 6).description.should =~ /be > 6/