@api private Provides the implementation for `contain_exactly` and `match_array`. Not intended to be instantiated directly.
@api private @return [String]
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 28 def description list = EnglishPhrasing.list(surface_descriptions_in(expected)) "contain exactly#{list}" end
@api private @return [String]
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 10 def failure_message if Array === actual generate_failure_message else "expected a collection that can be converted to an array with " "`#to_ary` or `#to_a`, but got #{actual_formatted}" end end
@api private @return [String]
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 21 def failure_message_when_negated list = EnglishPhrasing.list(surface_descriptions_in(expected)) "expected #{actual_formatted} not to contain exactly#{list}" end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 47 def actual_collection_line message_line('actual collection contained', actual) end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 113 def best_solution @best_solution ||= pairings_maximizer.find_best_solution end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 85 def convert_actual_to_an_array if actual.respond_to?(:to_ary) @actual = actual.to_ary elsif should_enumerate?(actual) && actual.respond_to?(:to_a) @actual = actual.to_a else return false end end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 59 def describe_collection(collection, surface_descriptions=false) if surface_descriptions "#{description_of(safe_sort(surface_descriptions_in collection))}\n" else "#{description_of(safe_sort(collection))}\n" end end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 43 def expected_collection_line message_line('expected collection contained', expected, true) end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 55 def extra_elements_line message_line('the extra elements were', extra_items) end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 107 def extra_items @extra_items ||= best_solution.unmatched_actual_indexes.map do |index| actual[index] end end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 35 def generate_failure_message message = expected_collection_line message += actual_collection_line message += missing_elements_line unless missing_items.empty? message += extra_elements_line unless extra_items.empty? message end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 72 def match(_expected, _actual) return false unless convert_actual_to_an_array match_when_sorted? || (extra_items.empty? && missing_items.empty?) end
This cannot always work (e.g. when dealing with unsortable items, or matchers as expected items), but it's practically free compared to the slowness of the full matching algorithm, and in common cases this works, so it's worth a try.
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 81 def match_when_sorted? values_match?(safe_sort(expected), safe_sort(actual)) end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 67 def message_line(prefix, collection, surface_descriptions=false) "%-32s%s" % [prefix + ':', describe_collection(collection, surface_descriptions)] end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 51 def missing_elements_line message_line('the missing elements were', missing_items, true) end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 101 def missing_items @missing_items ||= best_solution.unmatched_expected_indexes.map do |index| expected[index] end end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 117 def pairings_maximizer @pairings_maximizer ||= begin expected_matches = Hash[Array.new(expected.size) { |i| [i, []] }] actual_matches = Hash[Array.new(actual.size) { |i| [i, []] }] expected.each_with_index do |e, ei| actual.each_with_index do |a, ai| next unless values_match?(e, a) expected_matches[ei] << ai actual_matches[ai] << ei end end PairingsMaximizer.new(expected_matches, actual_matches) end end
# File lib/rspec/matchers/built_in/contain_exactly.rb, line 95 def safe_sort(array) array.sort rescue Support::AllExceptionsExceptOnesWeMustNotRescue array end