module RSpec::Matchers::Composable
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.
@api public
Constants
- DescribableItem
-
Wraps an item in order to surface its ‘description` via `inspect`. @api private
Public Class Methods
@api private We should enumerate arrays as long as they are not recursive.
# File rspec-expectations/lib/rspec/matchers/composable.rb, line 142 def should_enumerate?(item) Array === item && item.none? { |subitem| subitem.equal?(item) } end
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.
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.
@!visibility public
# File rspec-expectations/lib/rspec/matchers/composable.rb, line 98 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 || unreadable_io?(item) RSpec::Support::ObjectFormatter.format(item) elsif should_enumerate?(item) item.map { |subitem| surface_descriptions_in(subitem) } else item end end
@api private
# File rspec-expectations/lib/rspec/matchers/composable.rb, line 147 def unreadable_io?(object) return false unless IO === object object.each {} # STDOUT is enumerable but raises an error false rescue IOError true end
Public Instance Methods
Delegates to ‘#matches?`. Allows matchers to be used in composable fashion and also supports using matchers in case statements.
# File rspec-expectations/lib/rspec/matchers/composable.rb, line 45 def ===(value) matches?(value) end
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.
@example
expect(alphabet).to start_with("a").and end_with("z") expect(alphabet).to start_with("a") & end_with("z")
@note The negative form (‘expect(…).not_to matcher.and other`)
is not supported at this time.
# File rspec-expectations/lib/rspec/matchers/composable.rb, line 22 def and(matcher) BuiltIn::Compound::And.new self, matcher end
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.
@example
expect(stoplight.color).to eq("red").or eq("green").or eq("yellow") expect(stoplight.color).to eq("red") | eq("green") | eq("yellow")
@note The negative form (‘expect(…).not_to matcher.or other`)
is not supported at this time.
# File rspec-expectations/lib/rspec/matchers/composable.rb, line 38 def or(matcher) BuiltIn::Compound::Or.new self, matcher end