Contains the methods that are available from within the `RSpec::Matchers.define` DSL for creating custom matchers.
Convenience for defining methods on this matcher to create a fluent interface. The trick about fluent interfaces is that each method must return self in order to chain methods together. `chain` handles that for you.
@example
RSpec::Matchers.define :have_errors_on do |key| chain :with do |message| @message = message end match do |actual| actual.errors[key] == @message end end expect(minor).to have_errors_on(:age).with("Not old enough to participate")
# File lib/rspec/matchers/dsl.rb, line 180 def chain(name, &definition) define_user_override(name, definition) do |*args, &block| super(*args, &block) self end end
Customize the description to use for one-liners. Only use this when the description generated by default doesn't suit your needs.
@example
RSpec::Matchers.define :qualify_for do |expected| match { your_match_logic } description do "qualify for #{expected}" end end
@yield [Object] actual the actual object (i.e. the value wrapped by `expect`)
# File lib/rspec/matchers/dsl.rb, line 144 def description(&definition) define_user_override(__method__, definition) end
Tells the matcher to diff the actual and expected values in the failure message.
# File lib/rspec/matchers/dsl.rb, line 150 def diffable define_method(:diffable?) { true } end
Customizes the failure messsage to use when this matcher is asked to positively match. Only use this when the message generated by default doesn't suit your needs.
@example
RSpec::Matchers.define :have_strength do |expected| match { your_match_logic } failure_message do |actual| "Expected strength of #{expected}, but had #{actual.strength}" end end
@yield [Object] actual the actual object (i.e. the value wrapped by `expect`)
# File lib/rspec/matchers/dsl.rb, line 107 def failure_message(&definition) define_user_override(__method__, definition) end
Customize the failure messsage to use when this matcher is asked to negatively match. Only use this when the message generated by default doesn't suit your needs.
@example
RSpec::Matchers.define :have_strength do |expected| match { your_match_logic } failure_message_when_negated do |actual| "Expected not to have strength of #{expected}, but did" end end
@yield [Object] actual the actual object (i.e. the value wrapped by `expect`)
# File lib/rspec/matchers/dsl.rb, line 126 def failure_message_when_negated(&definition) define_user_override(__method__, definition) end
Stores the block that is used to determine whether this matcher passes or fails. The block should return a boolean value. When the matcher is passed to `expect(…).to` and the block returns `true`, then the expectation passes. Similarly, when the matcher is passed to `expect(…).not_to` and the block returns `false`, then the expectation passes.
@example
RSpec::Matchers.define :be_even do match do |actual| actual.even? end end expect(4).to be_even # passes expect(3).not_to be_even # passes expect(3).to be_even # fails expect(4).not_to be_even # fails
@yield [Object] actual the actual value (i.e. the value wrapped by `expect`)
# File lib/rspec/matchers/dsl.rb, line 41 def match(&match_block) define_user_override(:matches?, match_block) do |actual| begin @actual = actual super(*actual_arg_for(match_block)) rescue RSpec::Expectations::ExpectationNotMetError false end end end
Use this instead of `match` when the block will raise an exception rather than returning false to indicate a failure.
@example
RSpec::Matchers.define :accept_as_valid do |candidate_address| match_unless_raises ValidationException do |validator| validator.validate(candidate_address) end end expect(email_validator).to accept_as_valid("person@company.com")
@yield [Object] actual the actual object (i.e. the value wrapped by `expect`)
# File lib/rspec/matchers/dsl.rb, line 79 def match_unless_raises(expected_exception=Exception, &match_block) define_user_override(:matches?, match_block) do |actual| @actual = actual begin super(*actual_arg_for(match_block)) rescue expected_exception => @rescued_exception false else true end end end
Use this to define the block for a negative expectation (`expect(…).not_to`) when the positive and negative forms require different handling. This is rarely necessary, but can be helpful, for example, when specifying asynchronous processes that require different timeouts.
@yield [Object] actual the actual value (i.e. the value wrapped by `expect`)
# File lib/rspec/matchers/dsl.rb, line 58 def match_when_negated(&match_block) define_user_override(:does_not_match?, match_block) do |actual| @actual = actual super(*actual_arg_for(match_block)) end end
Declares that the matcher can be used in a block expectation. Users will not be able to use your matcher in a block expectation without declaring this. (e.g. `expect { do_something }.to matcher`).
# File lib/rspec/matchers/dsl.rb, line 158 def supports_block_expectations define_method(:supports_block_expectations?) { true } end
Does the following:
Defines the named method usign a user-provided block in @user_method_defs, which is included as an ancestor in the singleton class in which we eval the `define` block.
Defines an overriden definition for the same method usign the provided `our_def` block.
Provides a default `our_def` block for the common case of needing to call the user's definition with `@actual` as an arg, but only if their block's arity can handle it.
This compiles the user block into an actual method, allowing them to use normal method constructs like `return` (e.g. for a early guard statement), while allowing us to define an override that can provide the wrapped handling (e.g. assigning `@actual`, rescueing errors, etc) and can `super` to the user's definition.
# File lib/rspec/matchers/dsl.rb, line 206 def define_user_override(method_name, user_def, &our_def) @user_method_defs.__send__(:define_method, method_name, &user_def) our_def ||= lambda { super(*actual_arg_for(user_def)) } define_method(method_name, &our_def) end