Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Allow the expect change matcher to take regexps in to and from #62

Closed
wants to merge 2 commits into from

3 participants

davisre Myron Marston David Chelimsky
davisre

It would often be handy to pass a regular expression to the expect change matcher's from and to methods, when you want to verify that some portion of a string is changed but don't care about the rest.

For example, I was recently writing specs for the 'slug' of an ActiveRecord, the string that gets appended to the record ID in the URL. (In "http://www.example.com/things/23-my-thing", the part generated by #to_param is "23-my-thing" where "my-thing" is the slug, based on some attribute.) In this example, I don't care what the ID is, but I want to make sure the slug is updated when something special happens:

expect {
    thing.rename "Estes Kefauver"
}.to change { thing.to_param }.from(/krazy-and-ignatz/).to(/estes-kefauver/)

This small commit makes it possible. Does it make sense to roll up?

Rob

lib/rspec/matchers/change.rb
((6 lines not shown))
end
def matches_after?
- @given_to ? @to == @after : true
+ @given_to ? matches_pattern?(@to, @after) : true
+ end
+
+ def matches_pattern?(given, actual)
+ given.is_a?(Regexp) ? (given =~ actual) : (given == actual)
end
Myron Marston Owner

I think it would be better to use the === operator, as that has known, flexible semantics.

davisre
davisre added a note

Meaning use === in all cases instead of == with most things and =~ with Regexp? I can see that, but I wouldn't want to break any existing specs, and changing == to === feels a little broad.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
davisre

Actually, thinking about this a bit more, I like the === idea. In addition to the original regular expression example, it would allow something like

expect {
    thing.symbolize_name
}.to change { thing.name }.from(String).to(Symbol)

and other custom behaviors. I'll update the pull.

davisre davisre Instead of special-casing Regexp, use ===
for all comparison of given vs actual, which allows not only
regular expressions but also classes and custom behavior.
ce44d09
davisre

change matcher now accepts regexp in to/from

David Chelimsky dchelimsky closed this
Kenrick (Ken) Chien kchien referenced this pull request from a commit in kchien/rspec-expectations
davisre davisre change matcher now accepts regexp in to/from
- Closes #62.
5774d5c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Feb 21, 2011
  1. davisre
  2. davisre

    Instead of special-casing Regexp, use ===

    davisre authored
    for all comparison of given vs actual, which allows not only
    regular expressions but also classes and custom behavior.
This page is out of date. Refresh to see the latest.
Showing with 49 additions and 12 deletions.
  1. +17 −4 lib/rspec/matchers/change.rb
  2. +32 −8 spec/rspec/matchers/change_spec.rb
21 lib/rspec/matchers/change.rb
View
@@ -32,9 +32,9 @@ def evaluate_value_proc
end
def failure_message_for_should
- if @given_from && @before != @from
+ if @given_from && !given_matches_actual?(@from, @before)
"#{message} should have initially been #{@from.inspect}, but was #{@before.inspect}"
- elsif @given_to && @to != @after
+ elsif @given_to && !given_matches_actual?(@to, @after)
"#{message} should have been changed to #{@to.inspect}, but is now #{@after.inspect}"
elsif @amount
"#{message} should have been changed by #{@amount.inspect}, but was changed by #{actual_delta.inspect}"
@@ -101,11 +101,15 @@ def changed?
end
def matches_before?
- @given_from ? @from == @before : true
+ @given_from ? given_matches_actual?(@from, @before) : true
end
def matches_after?
- @given_to ? @to == @after : true
+ @given_to ? given_matches_actual?(@to, @after) : true
+ end
+
+ def given_matches_actual?(given, actual)
+ given === actual
end
def matches_amount?
@@ -174,6 +178,15 @@ def matches_max?
# employee.develop_great_new_social_networking_app
# }.should change(employee, :title).from("Mail Clerk").to("CEO")
#
+ # lambda {
+ # doctor.leave_office
+ # }.should change(doctor, :sign).from(/is in/).to(/is out/)
+ #
+ # user = User.new(:type => "admin")
+ # lambda {
+ # user.symbolize_type
+ # }.should change(user, :type).from(String).to(Symbol)
+ #
# == Notes
#
# Evaluates <tt>receiver.message</tt> or <tt>block</tt> before and after it
40 spec/rspec/matchers/change_spec.rb
View
@@ -273,11 +273,17 @@ class SomethingExpected
@instance.some_value = 'string'
end
- it "passes when attribute is == to expected value before executing block" do
+ it "passes when attribute is === to expected value before executing block" do
expect { @instance.some_value = "astring" }.to change(@instance, :some_value).from("string")
end
- it "fails when attribute is not == to expected value before executing block" do
+ it "compares the expected and actual values with ===" do
+ expected = "string"
+ expected.should_receive(:===).and_return true
+ expect { @instance.some_value = "astring" }.to change(@instance, :some_value).from(expected)
+ end
+
+ it "fails when attribute is not === to expected value before executing block" do
expect do
expect { @instance.some_value = "knot" }.to change(@instance, :some_value).from("cat")
end.to fail_with("some_value should have initially been \"cat\", but was \"string\"")
@@ -291,11 +297,17 @@ class SomethingExpected
@instance.some_value = 'string'
end
- it "passes when attribute is == to expected value before executing block" do
+ it "passes when attribute is === to expected value before executing block" do
expect { @instance.some_value = "astring" }.to change{@instance.some_value}.from("string")
end
- it "fails when attribute is not == to expected value before executing block" do
+ it "compares the expected and actual values with ===" do
+ expected = "string"
+ expected.should_receive(:===).and_return true
+ expect { @instance.some_value = "astring" }.to change{@instance.some_value}.from(expected)
+ end
+
+ it "fails when attribute is not === to expected value before executing block" do
expect do
expect { @instance.some_value = "knot" }.to change{@instance.some_value}.from("cat")
end.to fail_with("result should have initially been \"cat\", but was \"string\"")
@@ -325,11 +337,17 @@ class SomethingExpected
@instance.some_value = 'string'
end
- it "passes when attribute is == to expected value after executing block" do
+ it "passes when attribute is === to expected value after executing block" do
expect { @instance.some_value = "cat" }.to change(@instance, :some_value).to("cat")
end
- it "fails when attribute is not == to expected value after executing block" do
+ it "compares the expected and actual values with ===" do
+ expected = "cat"
+ expected.should_receive(:===).and_return true
+ expect { @instance.some_value = "cat" }.to change(@instance, :some_value).to(expected)
+ end
+
+ it "fails when attribute is not === to expected value after executing block" do
expect do
expect { @instance.some_value = "cat" }.to change(@instance, :some_value).from("string").to("dog")
end.to fail_with("some_value should have been changed to \"dog\", but is now \"cat\"")
@@ -343,11 +361,17 @@ class SomethingExpected
@instance.some_value = 'string'
end
- it "passes when attribute is == to expected value after executing block" do
+ it "passes when attribute is === to expected value after executing block" do
expect { @instance.some_value = "cat" }.to change{@instance.some_value}.to("cat")
end
- it "fails when attribute is not == to expected value after executing block" do
+ it "compares the expected and actual values with ===" do
+ expected = "cat"
+ expected.should_receive(:===).and_return true
+ expect { @instance.some_value = "cat" }.to change{@instance.some_value}.to(expected)
+ end
+
+ it "fails when attribute is not === to expected value after executing block" do
expect do
expect { @instance.some_value = "cat" }.to change{@instance.some_value}.from("string").to("dog")
end.to fail_with("result should have been changed to \"dog\", but is now \"cat\"")
Something went wrong with that request. Please try again.