Permalink
Browse files

Change start_with and end_with matchers to take varargs.

- Clean up rdoc, features, and specs.
- Refactor the two matchers a bit.
- Add changelog.
- #135
  • Loading branch information...
1 parent 05d9853 commit 2e0cdbc8867a190d10455fee0e0b847ecdf6c4a7 @dchelimsky dchelimsky committed Apr 9, 2012
View
@@ -1,6 +1,10 @@
### dev
[full changelog](http://github.com/rspec/rspec-expectations/compare/v2.9.1...master)
+Enhancements
+
+* Add new `start_with` and `end_with` matchers (Jeremy Wadsack)
+
Bug fixes
* Fix `be_within` matcher to be inclusive of delta.
@@ -1,47 +1,46 @@
Feature: end_with matcher
- The end_with matcher is mostly sugar to make your string tests
- read better
+ Use the `end_with` matcher to specify that a string or array ends with the
+ expected characters or elements.
- "A test string".should end_with "string"
- "A test string".should_not end_with "Something"
-
- The test is case sensitive.
+ "this string".should end_with "string"
+ "this string".should_not end_with "stringy"
+ [0, 1, 2].should end_with 1, 2
Scenario: string usage
- Given a file named "string_end_with_matcher_spec.rb" with:
+ Given a file named "example_spec.rb" with:
"""
- describe "A test string" do
+ describe "this string" do
it { should end_with "string" }
- it { should_not end_with "Something" }
+ it { should_not end_with "stringy" }
# deliberate failures
it { should_not end_with "string" }
- it { should end_with "Something" }
+ it { should end_with "stringy" }
end
"""
- When I run `rspec string_end_with_matcher_spec.rb`
+ When I run `rspec example_spec.rb`
Then the output should contain all of these:
- | 4 examples, 2 failures |
- | expected "A test string" not to end with "string" |
- | expected "A test string" to end with "Something" |
+ | 4 examples, 2 failures |
+ | expected "this string" not to end with "string" |
+ | expected "this string" to end with "stringy" |
Scenario: array usage
- Given a file named "array_end_with_matcher_spec.rb" with:
+ Given a file named "example_spec.rb" with:
"""
describe [0, 1, 2, 3, 4] do
it { should end_with 4 }
- it { should end_with [3, 4] }
- it { should_not end_with "Something" }
- it { should_not end_with [0, 1, 2, 3, 4, 5] }
+ it { should end_with 3, 4 }
+ it { should_not end_with 3 }
+ it { should_not end_with 0, 1, 2, 3, 4, 5 }
# deliberate failures
it { should_not end_with 4 }
- it { should end_with "Something" }
+ it { should end_with 3 }
end
"""
- When I run `rspec array_end_with_matcher_spec.rb`
+ When I run `rspec example_spec.rb`
Then the output should contain all of these:
- | 6 examples, 2 failures |
- | expected [0, 1, 2, 3, 4] not to end with 4 |
- | expected [0, 1, 2, 3, 4] to end with "Something" |
+ | 6 examples, 2 failures |
+ | expected [0, 1, 2, 3, 4] not to end with 4 |
+ | expected [0, 1, 2, 3, 4] to end with 3 |
@@ -1,48 +1,46 @@
Feature: start_with matcher
- The start_with matcher is mostly sugar to make your string tests
- read better
+ Use the `start_with` matcher to specify that a string or array starts with
+ the expected characters or elements.
- "A test string".should start_with "A test"
- "A test string".should_not start_with "Something"
+ "this string".should start_with("this")
+ "this string".should_not start_with("that")
+ [0,1,2].should start_with(0, 1)
- The test is case sensitive.
-
- Scenario: string usage
- Given a file named "string_start_with_matcher_spec.rb" with:
+ Scenario: with a string
+ Given a file named "example_spec.rb" with:
"""
- describe "A test string" do
- it { should start_with "A test" }
- it { should_not start_with "Something" }
+ describe "this string" do
+ it { should start_with "this" }
+ it { should_not start_with "that" }
# deliberate failures
- it { should_not start_with "A test" }
- it { should start_with "Something" }
+ it { should_not start_with "this" }
+ it { should start_with "that" }
end
"""
- When I run `rspec string_start_with_matcher_spec.rb`
+ When I run `rspec example_spec.rb`
Then the output should contain all of these:
- | 4 examples, 2 failures |
- | expected "A test string" not to start with "A test" |
- | expected "A test string" to start with "Something" |
+ | 4 examples, 2 failures |
+ | expected "this string" not to start with "this" |
+ | expected "this string" to start with "that" |
- Scenario: array usage
- Given a file named "array_start_with_matcher_spec.rb" with:
+ Scenario: with an array
+ Given a file named "example_spec.rb" with:
"""
describe [0, 1, 2, 3, 4] do
it { should start_with 0 }
- it { should start_with [0, 1] }
- it { should_not start_with "Something" }
- it { should_not start_with [0, 1, 2, 3, 4, 5] }
+ it { should start_with(0, 1)}
+ it { should_not start_with(2) }
+ it { should_not start_with(0, 1, 2, 3, 4, 5) }
# deliberate failures
it { should_not start_with 0 }
- it { should start_with "Something" }
+ it { should start_with 3 }
end
"""
- When I run `rspec array_start_with_matcher_spec.rb`
+ When I run `rspec example_spec.rb`
Then the output should contain all of these:
- | 6 examples, 2 failures |
- | expected [0, 1, 2, 3, 4] not to start with 0 |
- | expected [0, 1, 2, 3, 4] to start with "Something" |
-
+ | 6 examples, 2 failures |
+ | expected [0, 1, 2, 3, 4] not to start with 0 |
+ | expected [0, 1, 2, 3, 4] to start with 3 |
View
@@ -355,18 +355,18 @@ def cover(*values)
BuiltIn::Cover.new(*values)
end if (1..2).respond_to?(:cover?)
- # Matches if the target ends with the expected value. In the case
- # of strings tries to match the last expected.length characters of
- # target. In the case of an array tries to match the last expected.length
- # elements of target.
+ # Matches if the actual value ends with the expected value(s). In the case
+ # of a string, matches against the last `expected.length` characters of the
+ # actual string. In the case of an array, matches against the last
+ # `expected.length` elements of the actual array.
#
# @example
#
- # "A test string".should end_with 'string'
+ # "this string".should end_with "string"
# [0, 1, 2, 3, 4].should end_with 4
- # [0, 2, 3, 4, 4].should end_with [3, 4]
- def end_with(expected)
- BuiltIn::EndWith.new(expected)
+ # [0, 2, 3, 4, 4].should end_with 3, 4
+ def end_with(*expected)
+ BuiltIn::EndWith.new(*expected)
end
# Passes if <tt>actual == expected</tt>.
@@ -548,18 +548,18 @@ def satisfy(&block)
BuiltIn::Satisfy.new(&block)
end
- # Matches if the target starts with the expected value. In the case
- # of strings tries to match the first expected.length characters of
- # target. In the case of an array tries to match the first expected.length
- # elements of target.
+ # Matches if the actual value starts with the expected value(s). In the
+ # case of a string, matches against the first `expected.length` characters
+ # of the actual string. In the case of an array, matches against the first
+ # `expected.length` elements of the actual array.
#
# @example
#
- # "A test string".should start_with 'A test'
+ # "this string".should start_with "this s"
# [0, 1, 2, 3, 4].should start_with 0
- # [0, 2, 3, 4, 4].should start_with [0, 1]
- def start_with(expected)
- BuiltIn::StartWith.new(expected)
+ # [0, 2, 3, 4, 4].should start_with 0, 1
+ def start_with(*expected)
+ BuiltIn::StartWith.new(*expected)
end
# Given no argument, matches if a proc throws any Symbol.
@@ -24,8 +24,8 @@ module BuiltIn
autoload :MatchArray, 'rspec/matchers/built_in/match_array'
autoload :RaiseError, 'rspec/matchers/built_in/raise_error'
autoload :RespondTo, 'rspec/matchers/built_in/respond_to'
- autoload :StartWith, 'rspec/matchers/built_in/start_with_end_with'
- autoload :EndWith, 'rspec/matchers/built_in/start_with_end_with'
+ autoload :StartWith, 'rspec/matchers/built_in/start_and_end_with'
+ autoload :EndWith, 'rspec/matchers/built_in/start_and_end_with'
autoload :Satisfy, 'rspec/matchers/built_in/satisfy'
autoload :ThrowSymbol, 'rspec/matchers/built_in/throw_symbol'
end
@@ -0,0 +1,46 @@
+module RSpec
+ module Matchers
+ module BuiltIn
+ class StartAndEndWith
+ include BaseMatcher
+
+ def initialize(*expected)
+ @expected = expected.length == 1 ? expected.first : expected
@jeremywadsack

jeremywadsack Apr 10, 2012

Contributor

If expected doesn't respond to #length this will raise an error that would not get caught by the check under #matches below.

@dchelimsky

dchelimsky Apr 10, 2012

Owner

expected is varargs, which is always an Array and always responds to length.

@jeremywadsack

jeremywadsack Apr 10, 2012

Contributor

Oh, right. Was still thinking of an array or string. :)

+ end
+
+ def matches?(actual)
+ @actual = actual.respond_to?(:[]) ? actual : (raise ArgumentError.new("#{actual.inspect} does not respond to :[]"))
+ @expected.respond_to?(:length) ? subset_matches?(@expected, @actual) : element_matches?(@expected, @actual)
+ end
+
+ def failure_message_for_should
+ "expected #{@actual.inspect} to #{self.class.name.split('::').last.sub(/With/,'').downcase} with #{@expected.inspect}"
+ end
+
+ def failure_message_for_should_not
+ "expected #{@actual.inspect} not to #{self.class.name.split('::').last.sub(/With/,'').downcase} with #{@expected.inspect}"
+ end
+ end
+
+ class StartWith < StartAndEndWith
+ def subset_matches?(expected, actual)
+ actual[0, expected.length] == expected
+ end
+
+ def element_matches?(expected, actual)
+ @actual[0] == @expected
+ end
+ end
+
+ class EndWith < StartAndEndWith
+ def subset_matches?(expected, actual)
+ actual[-expected.length, expected.length] == expected
+ end
+
+ def element_matches?(expected, actual)
+ actual[-1] == expected
+ end
+ end
+ end
+ end
+end
@@ -1,61 +0,0 @@
-module RSpec
- module Matchers
- module BuiltIn
- class StartWith
- include BaseMatcher
- def initialize(expected)
- @expected = expected
- end
-
- def matches?(actual)
- @actual = actual
- if @actual.respond_to?(:[])
- if @expected.respond_to?(:length)
- @actual[0, @expected.length] == @expected
- else
- @actual[0] == @expected
- end
- else
- raise ArgumentError.new("#{@expected.inspect} does not respond to :[]")
- end
- end
-
- def failure_message_for_should
- "expected #{@actual.inspect} to start with #{@expected.inspect}"
- end
-
- def failure_message_for_should_not
- "expected #{@actual.inspect} not to start with #{@expected.inspect}"
- end
- end
-
- class EndWith
- include BaseMatcher
- def initialize(expected)
- @expected = expected
- end
-
- def matches?(actual)
- @actual = actual
- if @actual.respond_to?(:[])
- if @expected.respond_to?(:length)
- @actual[-@expected.length, @expected.length] == @expected
- else
- @actual[-1] == @expected
- end
- else
- raise ArgumentError.new("#{@expected.inspect} does not respond to :[]")
- end
- end
-
- def failure_message_for_should
- "expected #{@actual.inspect} to end with #{@expected.inspect}"
- end
-
- def failure_message_for_should_not
- "expected #{@actual.inspect} not to end with #{@expected.inspect}"
- end
- end
- end
- end
-end
Oops, something went wrong.

0 comments on commit 2e0cdbc

Please sign in to comment.