Module: RSpec::Matchers::Composable

Included in:
BuiltIn::BaseMatcher, BuiltIn::RaiseError, BuiltIn::ThrowSymbol, DSL::Matcher
Defined in:
lib/rspec/matchers/composable.rb

Overview

Mixin designed to support the composable matcher features of RSpec 3+. Mix it into your custom matcher classes to allow them to be used in a composable fashion.

Defined Under Namespace

Classes: DescribableItem

Class Method Summary (collapse)

Instance Method Summary (collapse)

Class Method Details

+ (Boolean) enumerable?(item)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)
164
165
166
167
# File 'lib/rspec/matchers/composable.rb', line 164
def enumerable?(item)
  return false if String === item
  Enumerable === item
end

+ (Object) surface_descriptions_in(item)

Transforms the given data structue (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.

You are encouraged to use this in your custom matcher's description, failure_message or failure_message_when_negated implementation if you are supporting any arguments which may be a data structure containing matchers.

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rspec/matchers/composable.rb', line 99
def surface_descriptions_in(item)
  if Matchers.is_a_describable_matcher?(item)
    DescribableItem.new(item)
  elsif Hash === item
    Hash[surface_descriptions_in(item.to_a)]
  elsif Struct === item
    item.inspect
  elsif enumerable?(item)
    begin
      item.map { |subitem| surface_descriptions_in(subitem) }
    rescue IOError # STDOUT is enumerable but `map` raises an error
      item.inspect
    end
  else
    item
  end
end

Instance Method Details

- (Object) ===(value)

Delegates to #matches?. Allows matchers to be used in composable fashion and also supports using matchers in case statements.

45
46
47
# File 'lib/rspec/matchers/composable.rb', line 45
def ===(value)
  matches?(value)
end

- (Object) and(matcher) Also known as: &

Note:

The negative form (expect(...).not_to matcher.and other) is not supported at this time.

Creates a compound and expectation. The matcher will only pass if both sub-matchers pass. This can be chained together to form an arbitrarily long chain of matchers.

Examples:

expect(alphabet).to start_with("a").and end_with("z")
expect(alphabet).to start_with("a") & end_with("z")
22
23
24
# File 'lib/rspec/matchers/composable.rb', line 22
def and(matcher)
  BuiltIn::Compound::And.new self, matcher
end

- (Object) description_of(object)

Returns the description of the given object in a way that is aware of composed matchers. If the object is a matcher with a description method, returns the description; otherwise returns object.inspect.

You are encouraged to use this in your custom matcher's description, failure_message or failure_message_when_negated implementation if you are supporting matcher arguments.

82
83
84
85
# File 'lib/rspec/matchers/composable.rb', line 82
def description_of(object)
  return object.description if Matchers.is_a_describable_matcher?(object)
  object.inspect
end

- (Object) or(matcher) Also known as: |

Note:

The negative form (expect(...).not_to matcher.or other) is not supported at this time.

Creates a compound or expectation. The matcher will pass if either sub-matcher passes. This can be chained together to form an arbitrarily long chain of matchers.

Examples:

expect(stoplight.color).to eq("red").or eq("green").or eq("yellow")
expect(stoplight.color).to eq("red") | eq("green") | eq("yellow")
38
39
40
# File 'lib/rspec/matchers/composable.rb', line 38
def or(matcher)
  BuiltIn::Compound::Or.new self, matcher
end

- (Boolean) values_match?(expected, actual)

This provides a generic way to fuzzy-match an expected value against an actual value. It understands nested data structures (e.g. hashes and arrays) and is able to match against a matcher being used as the expected value or within the expected value at any level of nesting.

Within a custom matcher you are encouraged to use this whenever your matcher needs to match two values, unless it needs more precise semantics. For example, the eq matcher does not use this as it is meant to use == (and only ==) for matching.

Parameters:

  • expected (Object)

    what is expected

  • actual (Object)

    the actual value

Returns:

  • (Boolean)
66
67
68
69
# File 'lib/rspec/matchers/composable.rb', line 66
def values_match?(expected, actual)
  expected = with_matchers_cloned(expected)
  Support::FuzzyMatcher.values_match?(expected, actual)
end