class RSpec::Matchers::BuiltIn::ContainExactly
Not intended to be instantiated directly.
Provides the implementation for ‘contain_exactly` and `match_array`.
@api private
rubocop:disable Metrics/ClassLength
def actual_collection_line
def actual_collection_line message_line('actual collection contained', actual) end
def best_solution
def best_solution @best_solution ||= pairings_maximizer.find_best_solution end
def convert_actual_to_an_array
def convert_actual_to_an_array if actual.respond_to?(:to_ary) @actual = actual.to_ary elsif actual.respond_to?(:to_a) && !to_a_disallowed?(actual) @actual = actual.to_a else false end end
def describe_collection(collection, surface_descriptions=false)
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
def description
-
(String)
-
Other tags:
- Api: - private
def description list = EnglishPhrasing.list(surface_descriptions_in(expected)) "contain exactly#{list}" end
def expected_collection_line
def expected_collection_line message_line('expected collection contained', expected, true) end
def extra_elements_line
def extra_elements_line message_line('the extra elements were', extra_items) end
def extra_items
def extra_items @extra_items ||= best_solution.unmatched_actual_indexes.map do |index| actual[index] end end
def failure_message
-
(String)
-
Other tags:
- Api: - private
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
def failure_message_when_negated
-
(String)
-
Other tags:
- Api: - private
def failure_message_when_negated list = EnglishPhrasing.list(surface_descriptions_in(expected)) "expected #{actual_formatted} not to contain exactly#{list}" end
def generate_failure_message
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
def match(_expected, _actual)
def match(_expected, _actual) return false unless convert_actual_to_an_array match_when_sorted? || (extra_items.empty? && missing_items.empty?) end
def match_when_sorted?
the slowness of the full matching algorithm, and in common cases this
or matchers as expected items), but it's practically free compared to
This cannot always work (e.g. when dealing with unsortable items,
def match_when_sorted? values_match?(safe_sort(expected), safe_sort(actual)) end
def matches?(actual)
def matches?(actual) @pairings_maximizer = nil @best_solution = nil @extra_items = nil @missing_items = nil super(actual) end
def message_line(prefix, collection, surface_descriptions=false)
def message_line(prefix, collection, surface_descriptions=false) "%-32s%s" % [prefix + ':', describe_collection(collection, surface_descriptions)] end
def missing_elements_line
def missing_elements_line message_line('the missing elements were', missing_items, true) end
def missing_items
def missing_items @missing_items ||= best_solution.unmatched_expected_indexes.map do |index| expected[index] end end
def pairings_maximizer
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
def safe_sort(array)
def safe_sort(array) array.sort rescue Support::AllExceptionsExceptOnesWeMustNotRescue array end
def to_a_disallowed?(object)
def to_a_disallowed?(object) case object when NilClass, String then true else Kernel == RSpec::Support.method_handle_for(object, :to_a).owner end end
def to_a_disallowed?(object)
def to_a_disallowed?(object) NilClass === object end