123456789_123456789_123456789_123456789_123456789_

Class: RSpec::Matchers::BuiltIn::ContainExactly Private

Do not use. This class is for internal use only.
Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, BaseMatcher
Instance Chain:
Inherits: RSpec::Matchers::BuiltIn::BaseMatcher
Defined in: rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb

Overview

Provides the implementation for ‘contain_exactly` and RSpec::Matchers#match_array. Not intended to be instantiated directly.

Constant Summary

BaseMatcher - Inherited

UNDEFINED

Class Method Summary

BaseMatcher - Inherited

.matcher_name, .new,
.underscore

Borrowed from ActiveSupport.

Instance Attribute Summary

BaseMatcher - Inherited

#actual,
#diffable?

::RSpec::Matchers are not diffable by default.

#expected, #expects_call_stack_jump?, #matcher_name, #matcher_name=, #rescued_exception,
#supports_block_expectations?

Most matchers are value matchers (i.e. meant to work with ‘expect(value)`) rather than block matchers (i.e. meant to work with `expect { }`), so this defaults to false.

#supports_value_expectations?

BaseMatcher::StringEncodingFormatting - Included

Instance Method Summary

BaseMatcher - Inherited

#actual_formatted,
#description

Generates a description using ::RSpec::Matchers::EnglishPhrasing.

#expected_formatted,
#match_unless_raises

Used to wrap a block of code that will indicate failure by raising one of the named exceptions.

#matches?

Indicates if the match is successful.

#assert_ivars,
#present_ivars

:nocov:

BaseMatcher::DefaultFailureMessages - Included

#failure_message

Provides a good generic failure message.

#failure_message_when_negated

Provides a good generic negative failure message.

BaseMatcher::StringEncodingFormatting - Included

#format_encoding

Formats a String’s encoding as a human readable string.

BaseMatcher::HashFormatting - Included

#improve_hash_formatting

‘{ :a => 5, :b => 2 }.inspect` produces:

::RSpec::Matchers::Composable - Included

#&

Alias for Composable#and.

#===

Delegates to ‘#matches?`.

#and

Creates a compound ‘and` expectation.

#description_of

Returns the description of the given object in a way that is aware of composed matchers.

#or

Creates a compound ‘or` expectation.

#values_match?

This provides a generic way to fuzzy-match an expected value against an actual value.

#|

Alias for Composable#or.

#should_enumerate?

We should enumerate arrays as long as they are not recursive.

#surface_descriptions_in

Transforms the given data structure (typically a hash or array) into a new data structure that, when ‘#inspect` is called on it, will provide descriptions of any contained matchers rather than the normal #inspect output.

#unreadable_io?,
#with_matchers_cloned

Historically, a single matcher instance was only checked against a single value.

Instance Attribute Details

#match_when_sorted?Boolean (readonly, private)

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.

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 90

def match_when_sorted?
  values_match?(safe_sort(expected), safe_sort(actual))
end

Instance Method Details

#actual_collection_line (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 56

def actual_collection_line
  message_line('actual collection contained', actual)
end

#best_solution (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 135

def best_solution
  @best_solution ||= pairings_maximizer.find_best_solution
end

#convert_actual_to_an_array (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 94

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

#describe_collection(collection, surface_descriptions = false) (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 68

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

#descriptionString

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 29

def description
  list = EnglishPhrasing.list(surface_descriptions_in(expected))
  "contain exactly#{list}"
end

#expected_collection_line (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 52

def expected_collection_line
  message_line('expected collection contained', expected, true)
end

#extra_elements_line (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 64

def extra_elements_line
  message_line('the extra elements were', extra_items)
end

#extra_items (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 129

def extra_items
  @extra_items ||= best_solution.unmatched_actual_indexes.map do |index|
    actual[index]
  end
end

#failure_messageString

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 11

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

#failure_message_when_negatedString

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 22

def failure_message_when_negated
  list = EnglishPhrasing.list(surface_descriptions_in(expected))
  "expected #{actual_formatted} not to contain exactly#{list}"
end

#generate_failure_message (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 44

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

#match(_expected, _actual) (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 81

def match(_expected, _actual)
  return false unless convert_actual_to_an_array
  match_when_sorted? || (extra_items.empty? && missing_items.empty?)
end

#matches?(actual) ⇒ Boolean

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 34

def matches?(actual)
  @pairings_maximizer = nil
  @best_solution = nil
  @extra_items = nil
  @missing_items = nil
  super(actual)
end

#message_line(prefix, collection, surface_descriptions = false) (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 76

def message_line(prefix, collection, surface_descriptions=false)
  "%-32s%s" % [prefix + ':',
               describe_collection(collection, surface_descriptions)]
end

#missing_elements_line (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 60

def missing_elements_line
  message_line('the missing elements were', missing_items, true)
end

#missing_items (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 123

def missing_items
  @missing_items ||= best_solution.unmatched_expected_indexes.map do |index|
    expected[index]
  end
end

#pairings_maximizer (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 139

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

#safe_sort(array) (private)

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 104

def safe_sort(array)
  array.sort
rescue Support::AllExceptionsExceptOnesWeMustNotRescue
  array
end

#to_a_disallowed?(object) (private)

See additional method definition at line 111.

[ GitHub ]

  
# File 'rspec-expectations/lib/rspec/matchers/built_in/contain_exactly.rb', line 118

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