Skip to content

Commit

Permalink
split out BeXXX classes
Browse files Browse the repository at this point in the history
  • Loading branch information
dchelimsky committed Dec 29, 2009
1 parent bad2131 commit 1a3ef9b
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 138 deletions.
287 changes: 152 additions & 135 deletions 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
Expand All @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
26 changes: 23 additions & 3 deletions spec/spec/matchers/be_spec.rb
Expand Up @@ -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

Expand All @@ -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/
Expand Down

0 comments on commit 1a3ef9b

Please sign in to comment.