Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Allow custom matchers to use built-in #match #194

Merged
merged 3 commits into from

3 participants

@stevenharman

See Issue #188.

stevenharman added some commits
@stevenharman stevenharman Cleanup whitespace b36e3ca
@stevenharman stevenharman Allow custom matchers to use #match built in
Addresses problem with dispatching the #match matcher from within a
custom matcher. (Wow... what a mouthful) See Issue #188.
6442118
@myronmarston
Owner

Nice work! This looks like an appropriate fix.

I think it could benefit from some docs explaining the reason match_regex exists (e.g. as a work around when you're in a context that has another match method). Can you add that?

@stevenharman

Thanks.

I was thinking some explanation was due as well, but I'm not quite sure where to put it. Suggestions?

@myronmarston
Owner

Maybe here and in the cuke you modified?

@stevenharman

OK, I'll add some docs tomorrow - Big Nerd Ranch holiday party starts :soon:

@alindeman
Collaborator

This looks good to me now.

@myronmarston myronmarston merged commit 7fe9ec4 into rspec:master

1 check passed

Details default The Travis build passed
@myronmarston
Owner

Thanks, @stevenharman!

@eloyesp eloyesp referenced this pull request from a commit in eloyesp/rspec-expectations
@myronmarston myronmarston Rewrite custom matcher DSL.
Rather than evaling the `define` block in the
context of the matcher instance, eval the `define`
block in the context of the matcher instance's
singleton class.

* Fixes rspec#272.
  `include` in `define` has a different meaning (module inclusion)
  than `include` in the `match` block (using the `include` matcher to
  match).
* Better solution than rspec#194
  for rspec#188. There's now
  a `match` class method and a `match` instance method.
* Completely avoids issues we had to use hacks to solve before:
  rspec#29,
  rspec#38,
  rspec@fc4b66d
ec0094c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 6, 2012
  1. @stevenharman

    Cleanup whitespace

    stevenharman authored
  2. @stevenharman

    Allow custom matchers to use #match built in

    stevenharman authored
    Addresses problem with dispatching the #match matcher from within a
    custom matcher. (Wow... what a mouthful) See Issue #188.
  3. @stevenharman
This page is out of date. Refresh to see the latest.
View
28 features/custom_matchers/define_matcher.feature
@@ -338,3 +338,31 @@ Feature: define matcher
| 4 examples, 2 failures |
| expected 9 to be a multiple of 2 |
| expected 9 not to be a multiple of 3 |
+
+ Scenario: matching against a regular expression
+ Given a file named "regular_expression_matcher_spec.rb" with:
+ """ruby
+ # Due to Ruby's method dispatch mechanism, use the `#match_regex` alias
+ # rather than the `#match` matcher when defining custom matchers via the
+ # DSL.
+
+ RSpec::Matchers.define :be_valid_us_zipcode do
+ match do |actual|
+ expect(actual).to match_regex(/\A\d{5}(-\d{4})?\z/)
+ end
+ end
+
+ describe "30316" do
+ it { should be_valid_us_zipcode }
+ end
+
+ describe "30316-0001" do
+ it { should be_valid_us_zipcode }
+ end
+
+ describe "1000-61303" do
+ it { should_not be_valid_us_zipcode }
+ end
+ """
+ When I run `rspec regular_expression_matcher_spec.rb`
+ Then the stdout should contain "3 examples, 0 failures"
View
26 lib/rspec/matchers.rb
@@ -214,7 +214,7 @@ def be_nil
#
# Given true, false, or nil, will pass if actual value is true, false or
# nil (respectively). Given no args means the caller should satisfy an if
- # condition (to be or not to be).
+ # condition (to be or not to be).
#
# Predicates are any Ruby method that ends in a "?" and returns true or
# false. Given be_ followed by arbitrary_predicate (without the "?"),
@@ -246,7 +246,7 @@ def be_a(klass)
def be_an_instance_of(expected)
BuiltIn::BeAnInstanceOf.new(expected)
end
-
+
alias_method :be_instance_of, :be_an_instance_of
# Passes if actual.kind_of?(expected)
@@ -288,20 +288,20 @@ def be_within(delta)
# @example
#
# lambda {
- # team.add_player(player)
+ # team.add_player(player)
# }.should change(roster, :count)
#
# lambda {
- # team.add_player(player)
+ # team.add_player(player)
# }.should change(roster, :count).by(1)
#
# lambda {
- # team.add_player(player)
+ # team.add_player(player)
# }.should change(roster, :count).by_at_least(1)
#
# lambda {
# team.add_player(player)
- # }.should change(roster, :count).by_at_most(1)
+ # }.should change(roster, :count).by_at_most(1)
#
# string = "string"
# lambda {
@@ -311,7 +311,7 @@ def be_within(delta)
# lambda {
# person.happy_birthday
# }.should change(person, :birthday).from(32).to(33)
- #
+ #
# lambda {
# employee.develop_great_new_social_networking_app
# }.should change(employee, :title).from("Mail Clerk").to("CEO")
@@ -491,10 +491,20 @@ def include(*expected)
#
# email.should match(/^([^\s]+)((?:[-a-z0-9]+\.)+[a-z]{2,})$/i)
# email.should match("@example.com")
+ # zipcode.should match_regex(/\A\d{5}(-\d{4})?\z/)
+ # zipcode.should match_regex("90210")
+ #
+ # @note Due to Ruby's method dispatch mechanism, using the `#match` matcher
+ # within a custom matcher defined via the matcher DSL
+ # (`RSpec::Matcher.define`) will result Ruby calling the wrong `#match`
+ # method and raising an `ArgumentError`. Instead, use the aliased
+ # `#match_regex` method.
def match(expected)
BuiltIn::Match.new(expected)
end
+ alias_method :match_regex, :match
+
# With no args, matches if any error is raised.
# With a named error, matches only if that specific error is raised.
# With a named error and messsage specified as a String, matches only if both match.
@@ -523,7 +533,7 @@ def raise_error(error=Exception, message=nil, &block)
# provided. Names can be Strings or Symbols.
#
# @example
- #
+ #
def respond_to(*names)
BuiltIn::RespondTo.new(*names)
end
Something went wrong with that request. Please try again.