Skip to content

Commit

Permalink
Change start_with and end_with matchers to take varargs.
Browse files Browse the repository at this point in the history
- Clean up rdoc, features, and specs.
- Refactor the two matchers a bit.
- Add changelog.
- #135
  • Loading branch information
dchelimsky committed Apr 10, 2012
1 parent 05d9853 commit 2e0cdbc
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 193 deletions.
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
45 changes: 22 additions & 23 deletions features/built_in_matchers/end_with.feature
Original file line number Diff line number Diff line change
@@ -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 |
54 changes: 26 additions & 28 deletions features/built_in_matchers/start_with.feature
Original file line number Diff line number Diff line change
@@ -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 |
32 changes: 16 additions & 16 deletions lib/rspec/matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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>.
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions lib/rspec/matchers/built_in.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
46 changes: 46 additions & 0 deletions lib/rspec/matchers/built_in/start_and_end_with.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module RSpec
module Matchers
module BuiltIn
class StartAndEndWith
include BaseMatcher

def initialize(*expected)
@expected = expected.length == 1 ? expected.first : expected

This comment has been minimized.

Copy link
@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.

This comment has been minimized.

Copy link
@dchelimsky

dchelimsky Apr 10, 2012

Author Contributor

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

This comment has been minimized.

Copy link
@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
61 changes: 0 additions & 61 deletions lib/rspec/matchers/built_in/start_with_end_with.rb

This file was deleted.

Loading

0 comments on commit 2e0cdbc

Please sign in to comment.