lib/rspec/matchers/built_in/exist.rb in rspec-expectations-3.0.0.beta2 vs lib/rspec/matchers/built_in/exist.rb in rspec-expectations-3.0.0.rc1

- old
+ new

@@ -1,26 +1,90 @@ module RSpec module Matchers module BuiltIn + # @api private + # Provides the implementation for `exist`. + # Not intended to be instantiated directly. class Exist < BaseMatcher def initialize(*expected) @expected = expected end + # @api private + # @return [Boolean] def matches?(actual) @actual = actual - predicates = [:exist?, :exists?].select { |p| @actual.respond_to?(p) } - existence_values = predicates.map { |p| @actual.__send__(p, *@expected) } - uniq_truthy_values = existence_values.map { |v| !!v }.uniq + @test = ExistenceTest.new @actual, @expected + @test.valid_test? && @test.actual_exists? + end - case uniq_truthy_values.size - when 0; raise NoMethodError.new("#{@actual.inspect} does not respond to either #exist? or #exists?") - when 1; existence_values.first - else raise "#exist? and #exists? returned different values:\n\n" + - " exist?: #{existence_values.first}\n" + - "exists?: #{existence_values.last}" + # @api private + # @return [Boolean] + def does_not_match?(actual) + @actual = actual + @test = ExistenceTest.new @actual, @expected + @test.valid_test? && !@test.actual_exists? + end + + # @api private + # @return [String] + def failure_message + "expected #{@actual.inspect} to exist#{@test.validity_message}" + end + + # @api private + # @return [String] + def failure_message_when_negated + "expected #{@actual.inspect} not to exist#{@test.validity_message}" + end + + private + + # @api private + # Simple class for memoizing actual/expected for this matcher + # and examining the match + class ExistenceTest < Struct.new(:actual, :expected) + + # @api private + # @return [Boolean] + def valid_test? + uniq_truthy_values.size == 1 end + + # @api private + # @return [Boolean] + def actual_exists? + existence_values.first + end + + # @api private + # @return [String] + def validity_message + case uniq_truthy_values.size + when 0 + " but it does not respond to either `exist?` or `exists?`" + when 2 + " but `exist?` and `exists?` returned different values:\n\n"\ + " exist?: #{existence_values.first}\n"\ + "exists?: #{existence_values.last}" + end + end + + private + + def uniq_truthy_values + @uniq_truthy_values ||= existence_values.map { |v| !!v }.uniq + end + + def existence_values + @existence_values ||= predicates.map { |p| actual.__send__(p, *expected) } + end + + def predicates + @predicates ||= [:exist?, :exists?].select { |p| actual.respond_to?(p) } + end end + end end end end