Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

indicative docstrings

This was a pull request (#71) from Tom Stuart that I didn't merge until several
months later, so I had to address some merge conflicts. In addition, the
original intent was to offer the end user a configuration option for the
"voice" of the message (e.g. "should be x" vs "is x"), but I made it check if
the matcher responds to new methods docstring_for_should or
docstring_for_should_not and use those. This way all the internal matchers do
the right thing, but external matchers will still work without rspec trying to
convert the mode of it's docstring.
  • Loading branch information...
commit 2f0d105694db44a4c93cafe5144e00be2f7e9b7d 1 parent d3d8672
Tom Stuart rentalcustard authored dchelimsky committed
Showing with 341 additions and 169 deletions.
  1. +12 −12 features/custom_matchers/define_matcher.feature
  2. +2 −2 features/custom_matchers/define_matcher_with_fluent_interface.feature
  3. +7 −7 features/implicit_docstrings.feature
  4. +2 −1  lib/rspec/expectations.rb
  5. +13 −9 lib/rspec/matchers.rb
  6. +44 −4 lib/rspec/matchers/built_in/be.rb
  7. +13 −5 lib/rspec/matchers/built_in/be_within.rb
  8. +7 −3 lib/rspec/matchers/built_in/change.rb
  9. +8 −1 lib/rspec/matchers/built_in/eq.rb
  10. +8 −0 lib/rspec/matchers/built_in/eql.rb
  11. +8 −0 lib/rspec/matchers/built_in/equal.rb
  12. +10 −2 lib/rspec/matchers/built_in/has.rb
  13. +6 −2 lib/rspec/matchers/built_in/have.rb
  14. +6 −2 lib/rspec/matchers/built_in/include.rb
  15. +8 −1 lib/rspec/matchers/built_in/match.rb
  16. +6 −2 lib/rspec/matchers/built_in/match_array.rb
  17. +6 −2 lib/rspec/matchers/built_in/raise_error.rb
  18. +6 −2 lib/rspec/matchers/built_in/respond_to.rb
  19. +6 −2 lib/rspec/matchers/built_in/satisfy.rb
  20. +6 −2 lib/rspec/matchers/built_in/throw_symbol.rb
  21. +12 −3 lib/rspec/matchers/generated_descriptions.rb
  22. +16 −1 lib/rspec/matchers/matcher.rb
  23. +11 −3 lib/rspec/matchers/operator_matcher.rb
  24. +16 −17 spec/rspec/matchers/be_spec.rb
  25. +3 −2 spec/rspec/matchers/be_within_spec.rb
  26. +26 −24 spec/rspec/matchers/change_spec.rb
  27. +54 −39 spec/rspec/matchers/description_generation_spec.rb
  28. +3 −2 spec/rspec/matchers/include_spec.rb
  29. +14 −16 spec/rspec/matchers/respond_to_spec.rb
  30. +2 −1  spec/rspec/matchers/satisfy_spec.rb
24 features/custom_matchers/define_matcher.feature
View
@@ -37,8 +37,8 @@ Feature: define matcher
When I run `rspec ./matcher_with_default_message_spec.rb --format documentation`
Then the exit status should not be 0
- And the output should contain "should be a multiple of 3"
- And the output should contain "should not be a multiple of 4"
+ And the output should contain "is a multiple of 3"
+ And the output should contain "is not a multiple of 4"
And the output should contain "Failure/Error: it {should be_a_multiple_of(4)}"
And the output should contain "Failure/Error: it {should_not be_a_multiple_of(3)}"
@@ -94,17 +94,19 @@ Feature: define matcher
And the stdout should contain "1 example, 1 failure"
And the stdout should contain "expected that 9 would not be a multiple of 3"
- Scenario: overriding the description
+ Scenario: overriding the docstrings
Given a file named "matcher_overriding_description_spec.rb" with:
"""
require 'rspec/expectations'
-
RSpec::Matchers.define :be_a_multiple_of do |expected|
match do |actual|
actual % expected == 0
end
- description do
- "be multiple of #{expected}"
+ docstring_for_should do
+ "is multiple of #{expected}"
+ end
+ docstring_for_should_not do
+ "is not multiple of #{expected}"
end
Myron Marston Owner

Given that we are moving away from the should/should_not syntax I think it would make sense to choose different names for these if we can come up with something that makes sense. How about:

positive_docstring do
end

negative_docstring do
end
David Chelimsky Owner

These names align w/ the existing failure_message_for_should and failure_message_for_should_not. These used to be positive_failure_message and negative_failure_message.

Whatever naming scheme we agree on, it should be consistent across docstrings and failure messages and we need to continue to support the old names for a long, long time.

Myron Marston Owner

@alindeman -- any thoughts on this? I agree with @dchelimsky that we need to be consistent here and be concerned with forwards/backwards compatibility...but it also seems very odd to add new methods that are named after deprecated methods.

David Chelimsky Owner

When I started to implement this (before you reminded me that @mortice already had), I went with descriptions[:positive] and descriptions[:negative] - we could use that and then add a similar method for the failure messages. I don't think that we can really deprecate the old methods for a long, long time though.

Myron Marston Owner

Ironically, @mortice's pull request originally started with that API as well--a method that returned a hash with :positive and :negative entries in it.

At the time, I felt like this was a bit of an awkward API: I can't think of any other API in any standard ruby libraries that return a hash of two elements with 2 keys that are always in the hash. Separate methods still makes more sense to me.

That said, if you're fine with positive and negative keys in the hash, why are you not fine with positive and negative in the method names?

David Chelimsky Owner

That said, if you're fine with positive and negative keys in the hash, why are you not fine with positive and negative in the method names?

It's not bad for the docstrings, but we want to land on a naming scheme that works equally well for docstrings and failure messages and I find negative_failure_message less confusing than failure_message[:negative] - the latter of which separates the polarity from the method name.

I'm not excited about either option at the moment, so more ideas welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
end
@@ -119,14 +121,13 @@ Feature: define matcher
When I run `rspec ./matcher_overriding_description_spec.rb --format documentation`
Then the exit status should be 0
And the stdout should contain "2 examples, 0 failures"
- And the stdout should contain "should be multiple of 3"
- And the stdout should contain "should not be multiple of 4"
+ And the stdout should contain "is multiple of 3"
+ And the stdout should contain "is not multiple of 4"
Scenario: with no args
Given a file named "matcher_with_no_args_spec.rb" with:
"""
require 'rspec/expectations'
-
RSpec::Matchers.define :have_7_fingers do
match do |thing|
thing.fingers.length == 7
@@ -144,13 +145,12 @@ Feature: define matcher
When I run `rspec ./matcher_with_no_args_spec.rb --format documentation`
Then the exit status should be 0
And the stdout should contain "1 example, 0 failures"
- And the stdout should contain "should have 7 fingers"
+ And the stdout should contain "has 7 fingers"
Scenario: with multiple args
Given a file named "matcher_with_multiple_args_spec.rb" with:
"""
require 'rspec/expectations'
-
RSpec::Matchers.define :be_the_sum_of do |a,b,c,d|
match do |sum|
a + b + c + d == sum
@@ -164,7 +164,7 @@ Feature: define matcher
When I run `rspec ./matcher_with_multiple_args_spec.rb --format documentation`
Then the exit status should be 0
And the stdout should contain "1 example, 0 failures"
- And the stdout should contain "should be the sum of 1, 2, 3, and 4"
+ And the stdout should contain "is the sum of 1, 2, 3, and 4"
Scenario: with helper methods
Given a file named "matcher_with_internal_helper_spec.rb" with:
4 features/custom_matchers/define_matcher_with_fluent_interface.feature
View
@@ -1,7 +1,7 @@
Feature: define matcher with fluent interface
Use the chain() method to define matchers with a fluent interface.
-
+
Scenario: chained method with argumetn
Given a file named "between_spec.rb" with:
"""
@@ -21,4 +21,4 @@ Feature: define matcher with fluent interface
"""
When I run `rspec between_spec.rb --format documentation`
Then the output should contain "1 example, 0 failures"
- And the output should contain "should be bigger than 4"
+ And the output should contain "is bigger than 4"
14 features/implicit_docstrings.feature
View
@@ -20,9 +20,9 @@ Feature: implicit docstrings
When I run `rspec ./implicit_docstrings_spec.rb -fdoc`
- Then the output should contain "should be < 5"
- And the output should contain "should include 2"
- And the output should contain "should respond to #size"
+ Then the output should contain "is < 5"
+ And the output should contain "includes 2"
+ And the output should contain "responds to #size"
Scenario: run failing examples
Given a file named "failing_implicit_docstrings_spec.rb" with:
@@ -46,7 +46,7 @@ Feature: implicit docstrings
When I run `rspec ./failing_implicit_docstrings_spec.rb -fdoc`
- Then the output should contain "should equal 2"
- And the output should contain "should be > 5"
- And the output should contain "should include 4"
- And the output should contain "should not respond to #size"
+ Then the output should contain "equals 2"
+ And the output should contain "is > 5"
+ And the output should contain "includes 4"
+ And the output should contain "does not respond to #size"
3  lib/rspec/expectations.rb
View
@@ -1,3 +1,4 @@
+require 'rspec/core'
require 'rspec/expectations/extensions'
require 'rspec/matchers'
require 'rspec/expectations/expectation_target'
@@ -37,7 +38,7 @@ module RSpec
# `eq.failure_message_for_should_not`.
#
# rspec-expectations ships with a standard set of useful matchers, and writing
- # your own matchers is quite simple.
+ # your own matchers is quite simple.
#
# See [RSpec::Matchers](../RSpec/Matchers) for more information about the
# built-in matchers that ship with rspec-expectations, and how to write your
22 lib/rspec/matchers.rb
View
@@ -93,7 +93,11 @@ module RSpec
# # generate and return the appropriate string.
# end
#
- # description do
+ # docstring_for_should do
+ # # generate and return the appropriate string.
+ # end
+ #
+ # docstring_for_should_not do
# # generate and return the appropriate string.
# end
# end
@@ -214,7 +218,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 +250,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 +292,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 +315,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")
@@ -523,7 +527,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
48 lib/rspec/matchers/built_in/be.rb
View
@@ -15,6 +15,14 @@ def failure_message_for_should
def failure_message_for_should_not
"expected: non-true value\n got: #{actual.inspect}"
end
+
+ def docstring_for_should
+ "is true"
+ end
+
+ def docstring_for_should_not
+ "is not true"
+ end
end
class BeFalse < BaseMatcher
@@ -29,6 +37,14 @@ def failure_message_for_should
def failure_message_for_should_not
"expected: non-false value\n got: #{actual.inspect}"
end
+
+ def docstring_for_should
+ "is false"
+ end
+
+ def docstring_for_should_not
+ "is not false"
+ end
end
class BeNil < BaseMatcher
@@ -43,6 +59,14 @@ def failure_message_for_should
def failure_message_for_should_not
"expected: not nil\n got: nil"
end
+
+ def docstring_for_should
+ "is nil"
+ end
+
+ def docstring_for_should_not
+ "is not nil"
+ end
end
class Be < BaseMatcher
@@ -62,6 +86,14 @@ def failure_message_for_should_not
"expected #{@actual.inspect} to evaluate to false"
end
+ def docstring_for_should
+ "is"
+ end
+
+ def docstring_for_should_not
+ "is not"
+ end
+
[:==, :<, :<=, :>=, :>, :===].each do |operator|
define_method operator do |operand|
BeComparedTo.new(operand, operator)
@@ -117,8 +149,12 @@ def failure_message_for_should_not
"It might be more clearly expressed in the positive?")
end
- def description
- "be #{@operator} #{expected_to_sentence}#{args_to_sentence}"
+ def docstring_for_should
+ "is #{@operator} #{expected_to_sentence}#{args_to_sentence}"
+ end
+
+ def docstring_for_should_not
+ "is not #{@operator} #{expected_to_sentence}#{args_to_sentence}"
end
end
@@ -152,8 +188,12 @@ def failure_message_for_should_not
"expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}"
end
- def description
- "#{prefix_to_sentence}#{expected_to_sentence}#{args_to_sentence}"
+ def docstring_for_should
+ "is #{expected_to_sentence}#{args_to_sentence}"
+ end
+
+ def docstring_for_should_not
+ "is not #{expected_to_sentence}#{args_to_sentence}"
end
private
18 lib/rspec/matchers/built_in/be_within.rb
View
@@ -8,7 +8,7 @@ def initialize(delta)
def matches?(actual)
@actual = actual
- raise needs_expected unless defined? @expected
+ raise needs_expected unless defined? @expected
raise needs_subtractable unless @actual.respond_to? :-
(@actual - @expected).abs <= @delta
end
@@ -20,19 +20,27 @@ def of(expected)
end
def failure_message_for_should
- "expected #{@actual} to #{description}"
+ "expected #{@actual} to be #{docstring}"
end
def failure_message_for_should_not
- "expected #{@actual} not to #{description}"
+ "expected #{@actual} not to be #{docstring}"
end
- def description
- "be within #{@delta} of #{@expected}"
+ def docstring_for_should
+ "is #{docstring}"
+ end
+
+ def docstring_for_should_not
+ "is not #{docstring}"
end
private
+ def docstring
+ "within #{@delta} of #{@expected}"
+ end
+
def needs_subtractable
ArgumentError.new "The actual value (#{@actual.inspect}) must respond to `-`"
end
10 lib/rspec/matchers/built_in/change.rb
View
@@ -72,7 +72,7 @@ def by_at_least(minimum)
def by_at_most(maximum)
@maximum = maximum
self
- end
+ end
def to(to)
@eval_after = true
@@ -86,8 +86,12 @@ def from (before)
self
end
- def description
- "change ##{message}"
+ def docstring_for_should
+ "changes ##{message}"
+ end
+
+ def docstring_for_should_not
+ "does not change ##{message}"
end
private
9 lib/rspec/matchers/built_in/eq.rb
View
@@ -14,9 +14,16 @@ def failure_message_for_should_not
"\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n"
end
+ def docstring_for_should
+ "eq #{expected.inspect}"
+ end
+
+ def docstring_for_should_not
+ "does not eq #{expected.inspect}"
+ end
+
def diffable?; true; end
end
end
end
end
-
8 lib/rspec/matchers/built_in/eql.rb
View
@@ -14,6 +14,14 @@ def failure_message_for_should_not
"\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n"
end
+ def docstring_for_should
+ "eql #{expected.inspect}"
+ end
+
+ def docstring_for_should_not
+ "does not eql #{expected.inspect}"
+ end
+
def diffable?
true
end
8 lib/rspec/matchers/built_in/equal.rb
View
@@ -31,6 +31,14 @@ def failure_message_for_should_not
MESSAGE
end
+ def docstring_for_should
+ "equals #{expected.inspect}"
+ end
+
+ def docstring_for_should_not
+ "does not equal #{expected.inspect}"
+ end
+
def diffable?; true; end
private
12 lib/rspec/matchers/built_in/has.rb
View
@@ -19,12 +19,20 @@ def failure_message_for_should_not
"expected ##{predicate(@expected)}#{failure_message_args_description} to return false, got true"
end
- def description
- [method_description(@expected), args_description].compact.join(' ')
+ def docstring_for_should
+ docstring.sub(/have/, "has")
+ end
+
+ def docstring_for_should_not
+ "not #{docstring}"
end
private
+ def docstring
+ [method_description(@expected), args_description].compact.join(' ')
+ end
+
def predicate(sym)
"#{sym.to_s.sub("have_","has_")}?".to_sym
end
8 lib/rspec/matchers/built_in/have.rb
View
@@ -79,8 +79,12 @@ def failure_message_for_should_not
end
end
- def description
- "have #{relative_expectation} #{@collection_name}"
+ def docstring_for_should
+ "has #{relative_expectation} #{@collection_name}"
+ end
+
+ def docstring_for_should_not
+ "does not have #{relative_expectation} #{@collection_name}"
end
def respond_to?(m)
8 lib/rspec/matchers/built_in/include.rb
View
@@ -16,8 +16,12 @@ def does_not_match?(actual)
perform_match(:none?, :any?, @actual, @expected)
end
- def description
- "include#{expected_to_sentence}"
+ def docstring_for_should
+ "includes#{expected_to_sentence}"
+ end
+
+ def docstring_for_should_not
+ "does not include#{expected_to_sentence}"
end
def diffable?
9 lib/rspec/matchers/built_in/match.rb
View
@@ -2,10 +2,17 @@ module RSpec
module Matchers
module BuiltIn
class Match < BaseMatcher
-
def match(expected, actual)
actual.match expected
end
+
+ def docstring_for_should
+ "matches #{expected.inspect}"
+ end
+
+ def docstring_for_should_not
+ "does not match #{expected.inspect}"
+ end
end
end
end
8 lib/rspec/matchers/built_in/match_array.rb
View
@@ -20,8 +20,12 @@ def failure_message_for_should_not
"Matcher does not support should_not"
end
- def description
- "contain exactly #{_pretty_print(expected)}"
+ def docstring_for_should
+ "contains exactly #{_pretty_print(@expected)}"
+ end
+
+ def docstring_for_should_not
+ "does not contain exactly #{_pretty_print(@expected)}"
end
private
8 lib/rspec/matchers/built_in/raise_error.rb
View
@@ -70,8 +70,12 @@ def failure_message_for_should_not
"expected no #{expected_error}#{given_error}"
end
- def description
- "raise #{expected_error}"
+ def docstring_for_should
+ "raises #{expected_error}"
+ end
+
+ def docstring_for_should_not
+ "does not raise #{expected_error}"
end
private
8 lib/rspec/matchers/built_in/respond_to.rb
View
@@ -24,8 +24,12 @@ def failure_message_for_should_not
failure_message_for_should.sub(/to respond to/, 'not to respond to')
end
- def description
- "respond to #{pp_names}#{with_arity}"
+ def docstring_for_should
+ "responds to #{pp_names}#{with_arity}"
+ end
+
+ def docstring_for_should_not
+ "does not respond to #{pp_names}#{with_arity}"
end
def with(n)
8 lib/rspec/matchers/built_in/satisfy.rb
View
@@ -21,8 +21,12 @@ def failure_message_for_should_not
"expected #{@actual} not to satisfy block"
end
- def description
- "satisfy block"
+ def docstring_for_should
+ "satisfies block"
+ end
+
+ def docstring_for_should_not
+ "does not satisfy block"
end
end
end
8 lib/rspec/matchers/built_in/throw_symbol.rb
View
@@ -61,8 +61,12 @@ def failure_message_for_should_not
"expected #{expected('no Symbol')}#{' not' if @expected_symbol} to be thrown, got #{caught}"
end
- def description
- "throw #{expected}"
+ def docstring_for_should
+ "throws #{expected}"
+ end
+
+ def docstring_for_should_not
+ "does not throw #{expected}"
end
private
15 lib/rspec/matchers/generated_descriptions.rb
View
@@ -11,13 +11,22 @@ def self.clear_generated_description
def self.generated_description
return nil if last_should.nil?
- "#{last_should.to_s.gsub('_',' ')} #{last_description}"
+ mode = last_should.to_s =~ /not/ ? :negative : :positive
+ if mode == :positive && last_matcher.respond_to?(:docstring_for_should)
+ last_matcher.docstring_for_should
+ elsif mode == :negative && last_matcher.respond_to?(:docstring_for_should_not)
+ last_matcher.docstring_for_should_not
+ elsif last_matcher.respond_to?(:description)
+ "#{last_should.to_s.gsub('_',' ')} #{last_matcher.description}"
+ else
+ no_description_message
+ end
end
private
- def self.last_description
- last_matcher.respond_to?(:description) ? last_matcher.description : <<-MESSAGE
+ def self.no_description_message
+ return <<-MESSAGE
When you call a matcher in an example without a String, like this:
specify { object.should matcher }
17 lib/rspec/matchers/matcher.rb
View
@@ -159,7 +159,6 @@ def failure_message_for_should_not(&block)
cache_or_call_cached(:failure_message_for_should_not, &block)
end
-
# Customize the description to use for one-liners. Only use this when
# the description generated by default doesn't suit your needs.
#
@@ -176,6 +175,14 @@ def description(&block)
cache_or_call_cached(:description, &block)
end
+ def docstring_for_should(&block)
+ cache_or_call_cached(:docstring_for_should, &block)
+ end
+
+ def docstring_for_should_not(&block)
+ cache_or_call_cached(:docstring_for_should_not, &block)
+ end
+
# Tells the matcher to diff the actual and expected values in the failure
# message.
def diffable
@@ -280,6 +287,14 @@ def default_description
"#{name_to_sentence}#{expected_to_sentence}"
end
+ def default_docstring_for_should
+ default_description.sub(/^be/, 'is').sub(/^have/, 'has')
+ end
+
+ def default_docstring_for_should_not
+ default_description.sub(/^be/, 'is not').sub(/^have/, 'does not have')
+ end
+
def default_failure_message_for_should
"expected #{actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"
end
14 lib/rspec/matchers/operator_matcher.rb
View
@@ -47,12 +47,20 @@ def fail_with_message(message)
RSpec::Expectations.fail_with(message, @expected, @actual)
end
- def description
- "#{@operator} #{@expected.inspect}"
+ def docstring_for_should
+ docstring
+ end
+
+ def docstring_for_should_not
+ "does not #{docstring}"
end
private
+ def docstring
+ "#{@operator} #{@expected.inspect}"
+ end
+
def eval_match(actual, operator, expected)
::RSpec::Matchers.last_matcher = self
@operator, @expected = operator, expected
@@ -66,7 +74,7 @@ def __delegate_operator(actual, operator, expected)
if actual.__send__(operator, expected)
true
elsif ['==','===', '=~'].include?(operator)
- fail_with_message("expected: #{expected.inspect}\n got: #{actual.inspect} (using #{operator})")
+ fail_with_message("expected: #{expected.inspect}\n got: #{actual.inspect} (using #{operator})")
else
fail_with_message("expected: #{operator} #{expected.inspect}\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
end
33 spec/rspec/matchers/be_spec.rb
View
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "should be_predicate" do
+describe "should be_predicate" do
it "passes when actual returns true for :predicate?" do
actual = stub("actual", :happy? => true)
actual.should be_happy
@@ -17,20 +17,20 @@
actual.should be_happy
}.should fail_with("expected happy? to return true, got false")
end
-
+
it "fails when actual returns false for :predicate?" do
actual = stub("actual", :happy? => nil)
lambda {
actual.should be_happy
}.should fail_with("expected happy? to return true, got nil")
end
-
+
it "fails when actual does not respond to :predicate?" do
lambda {
Object.new.should be_happy
}.should raise_error(NameError, /happy\?/)
end
-
+
it "fails on error other than NameError" do
actual = stub("actual")
actual.should_receive(:foo?).and_raise("aaaah")
@@ -38,7 +38,7 @@
actual.should be_foo
}.should raise_error(/aaaah/)
end
-
+
it "fails on error other than NameError (with the present tense predicate)" do
actual = Object.new
actual.should_receive(:foos?).and_raise("aaaah")
@@ -53,12 +53,12 @@
actual = stub("actual", :happy? => false)
actual.should_not be_happy
end
-
+
it "passes when actual returns nil for :sym?" do
actual = stub("actual", :happy? => nil)
actual.should_not be_happy
end
-
+
it "fails when actual returns true for :sym?" do
actual = stub("actual", :happy? => true)
lambda {
@@ -87,7 +87,7 @@
actual.should be_older_than(3)
}.should fail_with("expected older_than?(3) to return true, got false")
end
-
+
it "fails when actual does not respond to :predicate?" do
lambda {
Object.new.should be_older_than(3)
@@ -101,7 +101,7 @@
actual.should_receive(:older_than?).with(3).and_return(false)
actual.should_not be_older_than(3)
end
-
+
it "fails when actual returns true for :predicate?(*args)" do
actual = mock("actual")
actual.should_receive(:older_than?).with(3).and_return(true)
@@ -291,7 +291,7 @@
end
it "describes itself" do
- be.<(4).description.should == "be < 4"
+ be.<(4).docstring_for_should.should eq "is < 4"
end
end
@@ -370,7 +370,7 @@
end
it "describes itself" do
- be.description.should == "be"
+ be.description.should eq "be"
end
end
@@ -401,10 +401,10 @@
describe "'should be' with operator" do
it "includes 'be' in the description" do
- (be > 6).description.should =~ /be > 6/
- (be >= 6).description.should =~ /be >= 6/
- (be <= 6).description.should =~ /be <= 6/
- (be < 6).description.should =~ /be < 6/
+ (be > 6).docstring_for_should.should =~ /is > 6/
+ (be >= 6).docstring_for_should.should =~ /is >= 6/
+ (be <= 6).docstring_for_should.should =~ /is <= 6/
+ (be < 6).docstring_for_should.should =~ /is < 6/
end
end
@@ -444,9 +444,8 @@ def large?
it "passes when direct class matches" do
5.should be_an_instance_of(Fixnum)
end
-
+
it "fails when class is higher up hierarchy" do
5.should_not be_an_instance_of(Numeric)
end
end
-
5 spec/rspec/matchers/be_within_spec.rb
View
@@ -57,10 +57,11 @@ module Matchers
Time.now.should be_within(0.1).of(Time.now)
end
- it "provides a description" do
+ it "provides docstrings" do
matcher = be_within(0.5).of(5.0)
matcher.matches?(5.1)
- matcher.description.should == "be within 0.5 of 5.0"
+ matcher.docstring_for_should.should eq "is within 0.5 of 5.0"
+ matcher.docstring_for_should_not.should eq "is not within 0.5 of 5.0"
end
it "raises an error if no expected value is given" do
50 spec/rspec/matchers/change_spec.rb
View
@@ -22,9 +22,10 @@ class SomethingExpected
expect {}.to change(@instance, :some_value)
end.to fail_with("some_value should have changed, but is still 5")
end
-
- it "provides a #description" do
- change(@instance, :some_value).description.should == "change #some_value"
+
+ it "provides docstrings" do
+ change(@instance, :some_value).docstring_for_should.should eq "changes #some_value"
+ change(@instance, :some_value).docstring_for_should_not.should eq "does not change #some_value"
end
end
@@ -173,15 +174,16 @@ def ==(other)
expect {}.to change{ @instance.some_value }
end.to fail_with("result should have changed, but is still 5")
end
-
+
it "warns if passed a block using do/end instead of {}" do
expect do
expect {}.to change do; end
end.to raise_error(SyntaxError, /block passed to should or should_not/)
end
-
- it "provides a #description" do
- change { @instance.some_value }.description.should == "change #result"
+
+ it "provides docstrings" do
+ change { @instance.some_value }.docstring_for_should.should eq "changes #result"
+ change { @instance.some_value }.docstring_for_should_not.should eq "does not change #result"
end
end
@@ -200,7 +202,7 @@ def ==(other)
expect {@instance.some_value = 6}.to_not change { @instance.some_value }
end.to fail_with("result should not have changed, but did change from 5 to 6")
end
-
+
it "warns if passed a block using do/end instead of {}" do
expect do
expect {}.to_not change do; end
@@ -267,10 +269,10 @@ def ==(other)
it "passes when attribute is changed by greater than the expected amount" do
expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_least(1)
end
-
+
it "passes when attribute is changed by the expected amount" do
expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_least(2)
- end
+ end
it "fails when the attribute is changed by less than the expected amount" do
expect do
@@ -289,10 +291,10 @@ def ==(other)
it "passes when attribute is changed by greater than expected amount" do
expect { @instance.some_value += 2 }.to change{@instance.some_value}.by_at_least(1)
end
-
+
it "passes when attribute is changed by the expected amount" do
expect { @instance.some_value += 2 }.to change{@instance.some_value}.by_at_least(2)
- end
+ end
it "fails when the attribute is changed by less than the unexpected amount" do
expect do
@@ -311,10 +313,10 @@ def ==(other)
it "passes when attribute is changed by less than the expected amount" do
expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_most(3)
end
-
+
it "passes when attribute is changed by the expected amount" do
expect { @instance.some_value += 2 }.to change(@instance, :some_value).by_at_most(2)
- end
+ end
it "fails when the attribute is changed by greater than the expected amount" do
expect do
@@ -333,10 +335,10 @@ def ==(other)
it "passes when attribute is changed by less than expected amount" do
expect { @instance.some_value += 2 }.to change{@instance.some_value}.by_at_most(3)
end
-
+
it "passes when attribute is changed by the expected amount" do
expect { @instance.some_value += 2 }.to change{@instance.some_value}.by_at_most(2)
- end
+ end
it "fails when the attribute is changed by greater than the unexpected amount" do
expect do
@@ -415,7 +417,7 @@ def ==(other)
@instance = SomethingExpected.new
@instance.some_value = true
end
-
+
it "passes when attribute is == to expected value after executing block" do
expect { @instance.some_value = false }.to change(@instance, :some_value).to(false)
end
@@ -431,7 +433,7 @@ def ==(other)
@instance = SomethingExpected.new
@instance.some_value = 'string'
end
-
+
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
@@ -455,7 +457,7 @@ def ==(other)
@instance = SomethingExpected.new
@instance.some_value = 'string'
end
-
+
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
@@ -478,7 +480,7 @@ def ==(other)
@instance = SomethingExpected.new
@instance.some_value = 'string'
end
-
+
it "passes when #to comes before #from" do
expect { @instance.some_value = "cat" }.to change(@instance, :some_value).to("cat").from("string")
end
@@ -486,13 +488,13 @@ def ==(other)
it "passes when #from comes before #to" do
expect { @instance.some_value = "cat" }.to change(@instance, :some_value).from("string").to("cat")
end
-
+
it "shows the correct messaging when #after and #to are different" 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\"")
end
-
+
it "shows the correct messaging when #before and #from are different" do
expect do
expect { @instance.some_value = "cat" }.to change(@instance, :some_value).from("not_string").to("cat")
@@ -505,7 +507,7 @@ def ==(other)
@instance = SomethingExpected.new
@instance.some_value = 'string'
end
-
+
it "passes when #to comes before #from" do
expect { @instance.some_value = "cat" }.to change{@instance.some_value}.to("cat").from("string")
end
@@ -520,7 +522,7 @@ def ==(other)
@instance = SomethingExpected.new
@instance.some_value = "string"
def @instance.send(*args); raise "DOH! Library developers shouldn't use #send!" end
-
+
expect {
expect { @instance.some_value = "cat" }.to change(@instance, :some_value)
}.to_not raise_error
93 spec/rspec/matchers/description_generation_spec.rb
View
@@ -1,79 +1,84 @@
require 'spec_helper'
-describe "Matchers should be able to generate their own descriptions" do
+describe "Matchers generate their own descriptions" do
after(:each) do
RSpec::Matchers.clear_generated_description
end
- it "should eq expected" do
- "this".should eq "this"
- RSpec::Matchers.generated_description.should eq "should eq \"this\""
+ it "should == expected" do
+ "this".should == "this"
+ RSpec::Matchers.generated_description.should == "== \"this\""
end
- it "should not eq expected" do
- "this".should_not eq "that"
- RSpec::Matchers.generated_description.should eq "should not eq \"that\""
+ it "should not == expected" do
+ "this".should_not == "that"
+ RSpec::Matchers.generated_description.should == "does not == \"that\""
end
it "should be empty (arbitrary predicate)" do
[].should be_empty
- RSpec::Matchers.generated_description.should eq "should be empty"
+ RSpec::Matchers.generated_description.should == "is empty"
end
it "should not be empty (arbitrary predicate)" do
[1].should_not be_empty
- RSpec::Matchers.generated_description.should eq "should not be empty"
+ RSpec::Matchers.generated_description.should == "is not empty"
end
it "should be true" do
true.should be_true
- RSpec::Matchers.generated_description.should eq "should be true"
+ RSpec::Matchers.generated_description.should == "is true"
end
it "should be false" do
false.should be_false
- RSpec::Matchers.generated_description.should eq "should be false"
+ RSpec::Matchers.generated_description.should == "is false"
end
it "should be nil" do
nil.should be_nil
- RSpec::Matchers.generated_description.should eq "should be nil"
+ RSpec::Matchers.generated_description.should == "is nil"
end
it "should be > n" do
5.should be > 3
- RSpec::Matchers.generated_description.should eq "should be > 3"
+ RSpec::Matchers.generated_description.should == "is > 3"
end
it "should be predicate arg1, arg2 and arg3" do
5.0.should be_between(0,10)
- RSpec::Matchers.generated_description.should eq "should be between 0 and 10"
+ RSpec::Matchers.generated_description.should == "is between 0 and 10"
+ end
+
+ it "should not be predicate arg1, arg2 and arg3" do
+ 5.0.should_not be_between(0, 1)
+ RSpec::Matchers.generated_description.should == "is not between 0 and 1"
end
it "should equal" do
expected = "expected"
expected.should equal(expected)
- RSpec::Matchers.generated_description.should eq "should equal \"expected\""
+ RSpec::Matchers.generated_description.should == "equals \"expected\""
end
it "should_not equal" do
5.should_not equal(37)
- RSpec::Matchers.generated_description.should eq "should not equal 37"
+ RSpec::Matchers.generated_description.should == "does not equal 37"
end
it "should eql" do
"string".should eql("string")
- RSpec::Matchers.generated_description.should eq "should eql \"string\""
+ RSpec::Matchers.generated_description.should == "eql \"string\""
end
it "should not eql" do
"a".should_not eql(:a)
- RSpec::Matchers.generated_description.should eq "should not eql :a"
+ RSpec::Matchers.generated_description.should == "does not eql :a"
end
it "should have_key" do
{:a => "a"}.should have_key(:a)
- RSpec::Matchers.generated_description.should eq "should have key :a"
+ RSpec::Matchers.generated_description.should == "has key :a"
end
it "should have_some_method" do
@@ -81,7 +86,7 @@
def object.has_eyes_closed?; true; end
object.should have_eyes_closed
- RSpec::Matchers.generated_description.should eq 'should have eyes closed'
+ RSpec::Matchers.generated_description.should == 'has eyes closed'
end
it "should have_some_method(args*)" do
@@ -89,78 +94,88 @@ def object.has_eyes_closed?; true; end
def object.has_taste_for?(*args); true; end
object.should have_taste_for("wine", "cheese")
- RSpec::Matchers.generated_description.should eq 'should have taste for "wine", "cheese"'
+ RSpec::Matchers.generated_description.should == 'has taste for "wine", "cheese"'
end
it "should have n items" do
team.should have(3).players
- RSpec::Matchers.generated_description.should eq "should have 3 players"
+ RSpec::Matchers.generated_description.should == "has 3 players"
end
it "should have at least n items" do
team.should have_at_least(2).players
- RSpec::Matchers.generated_description.should eq "should have at least 2 players"
+ RSpec::Matchers.generated_description.should == "has at least 2 players"
end
it "should have at most n items" do
team.should have_at_most(4).players
- RSpec::Matchers.generated_description.should eq "should have at most 4 players"
+ RSpec::Matchers.generated_description.should == "has at most 4 players"
end
it "should include" do
[1,2,3].should include(3)
- RSpec::Matchers.generated_description.should eq "should include 3"
+ RSpec::Matchers.generated_description.should == "includes 3"
end
it "array.should =~ [1,2,3]" do
[1,2,3].should =~ [1,2,3]
- RSpec::Matchers.generated_description.should eq "should contain exactly 1, 2 and 3"
+ RSpec::Matchers.generated_description.should == "contains exactly 1, 2 and 3"
end
it "should match" do
"this string".should match(/this string/)
- RSpec::Matchers.generated_description.should eq "should match /this string/"
+ RSpec::Matchers.generated_description.should == "matches /this string/"
end
it "should raise_error" do
lambda { raise }.should raise_error
- RSpec::Matchers.generated_description.should eq "should raise Exception"
+ RSpec::Matchers.generated_description.should == "raises Exception"
end
it "should raise_error with type" do
lambda { raise }.should raise_error(RuntimeError)
- RSpec::Matchers.generated_description.should eq "should raise RuntimeError"
+ RSpec::Matchers.generated_description.should == "raises RuntimeError"
end
it "should raise_error with type and message" do
lambda { raise "there was an error" }.should raise_error(RuntimeError, "there was an error")
- RSpec::Matchers.generated_description.should eq "should raise RuntimeError with \"there was an error\""
+ RSpec::Matchers.generated_description.should == "raises RuntimeError with \"there was an error\""
+ end
+
+ it "should not raise_error with type and message" do
+ lambda { "Innocuous" }.should_not raise_error(RuntimeError, "there was an error")
+ RSpec::Matchers.generated_description.should == "does not raise RuntimeError with \"there was an error\""
end
it "should respond_to" do
[].should respond_to(:insert)
- RSpec::Matchers.generated_description.should eq "should respond to #insert"
+ RSpec::Matchers.generated_description.should == "responds to #insert"
end
it "should throw symbol" do
lambda { throw :what_a_mess }.should throw_symbol
- RSpec::Matchers.generated_description.should eq "should throw a Symbol"
+ RSpec::Matchers.generated_description.should == "throws a Symbol"
end
it "should throw symbol (with named symbol)" do
lambda { throw :what_a_mess }.should throw_symbol(:what_a_mess)
- RSpec::Matchers.generated_description.should eq "should throw :what_a_mess"
+ RSpec::Matchers.generated_description.should == "throws :what_a_mess"
end
- def team
- Class.new do
- def players
- [1,2,3]
- end
- end.new
+ it "should == expected" do
+ 3.should == 3
+ RSpec::Matchers.generated_description.should == "== 3"
end
end
+def team
+ Class.new do
+ def players
+ [1,2,3]
+ end
+ end.new
+end
+
describe "a Matcher with no description" do
def matcher
Class.new do
5 spec/rspec/matchers/include_spec.rb
View
@@ -60,9 +60,10 @@
end
describe "should include(with, multiple, args)" do
- it "has a description" do
+ it "has docstrings" do
matcher = include("a")
- matcher.description.should eq("include \"a\"")
+ matcher.docstring_for_should.should eq("includes \"a\"")
+ matcher.docstring_for_should_not.should eq("does not include \"a\"")
end
context "for a string target" do
it "passes if target includes all items" do
30 spec/rspec/matchers/respond_to_spec.rb
View
@@ -4,17 +4,16 @@
it_behaves_like "an RSpec matcher", :valid_value => "s", :invalid_value => 5 do
let(:matcher) { respond_to(:upcase) }
end
-
+
it "passes if target responds to :sym" do
Object.new.should respond_to(:methods)
end
-
+
it "fails if target does not respond to :sym" do
lambda {
"this string".should respond_to(:some_method)
}.should fail_with(%q|expected "this string" to respond to :some_method|)
end
-
end
describe "should respond_to(:sym).with(1).argument" do
@@ -35,14 +34,14 @@ def obj.foo(*args); end
def obj.foo(a, *args); end
obj.should respond_to(:foo).with(1).argument
end
-
+
it "fails if target does not respond to :sym" do
obj = Object.new
lambda {
obj.should respond_to(:some_method).with(1).argument
}.should fail_with(/expected .* to respond to :some_method/)
end
-
+
it "fails if :sym expects 0 args" do
obj = Object.new
def obj.foo; end
@@ -50,7 +49,7 @@ def obj.foo; end
obj.should respond_to(:foo).with(1).argument
}.should fail_with(/expected #<Object.*> to respond to :foo with 1 argument/)
end
-
+
it "fails if :sym expects 2 args" do
obj = Object.new
def obj.foo(arg, arg2); end
@@ -69,23 +68,23 @@ def obj.foo(arg, arg2, *args); end
end
describe "should respond_to(message1, message2)" do
-
+
it "passes if target responds to both messages" do
Object.new.should respond_to('methods', 'inspect')
end
-
+
it "fails if target does not respond to first message" do
lambda {
Object.new.should respond_to('method_one', 'inspect')
}.should fail_with(/expected #<Object:.*> to respond to "method_one"/)
end
-
+
it "fails if target does not respond to second message" do
lambda {
Object.new.should respond_to('inspect', 'method_one')
}.should fail_with(/expected #<Object:.*> to respond to "method_one"/)
end
-
+
it "fails if target does not respond to either message" do
lambda {
Object.new.should respond_to('method_one', 'method_two')
@@ -117,14 +116,14 @@ def obj.foo(a, *args); end
def obj.foo(a, b, *args); end
obj.should respond_to(:foo).with(2).arguments
end
-
+
it "fails if target does not respond to :sym" do
obj = Object.new
lambda {
obj.should respond_to(:some_method).with(2).arguments
}.should fail_with(/expected .* to respond to :some_method/)
end
-
+
it "fails if :sym expects 0 args" do
obj = Object.new
def obj.foo; end
@@ -132,7 +131,7 @@ def obj.foo; end
obj.should respond_to(:foo).with(2).arguments
}.should fail_with(/expected #<Object.*> to respond to :foo with 2 arguments/)
end
-
+
it "fails if :sym expects 1 args" do
obj = Object.new
def obj.foo(arg); end
@@ -151,17 +150,16 @@ def obj.foo(arg, arg2, arg3, *args); end
end
describe "should_not respond_to(:sym)" do
-
+
it "passes if target does not respond to :sym" do
Object.new.should_not respond_to(:some_method)
end
-
+
it "fails if target responds to :sym" do
lambda {
Object.new.should_not respond_to(:methods)
}.should fail_with(/expected #<Object:.*> not to respond to :methods/)
end
-
end
describe "should_not respond_to(:sym).with(1).argument" do
3  spec/rspec/matchers/satisfy_spec.rb
View
@@ -6,7 +6,8 @@
end
it "describes itself" do
- satisfy.description.should eq("satisfy block")
+ satisfy.docstring_for_should.should eq("satisfies block")
+ satisfy.docstring_for_should_not.should eq("does not satisfy block")
end
it "passes if block returns true" do
Myron Marston

Given that we are moving away from the should/should_not syntax I think it would make sense to choose different names for these if we can come up with something that makes sense. How about:

positive_docstring do
end

negative_docstring do
end
David Chelimsky

These names align w/ the existing failure_message_for_should and failure_message_for_should_not. These used to be positive_failure_message and negative_failure_message.

Whatever naming scheme we agree on, it should be consistent across docstrings and failure messages and we need to continue to support the old names for a long, long time.

Myron Marston

@alindeman -- any thoughts on this? I agree with @dchelimsky that we need to be consistent here and be concerned with forwards/backwards compatibility...but it also seems very odd to add new methods that are named after deprecated methods.

David Chelimsky

When I started to implement this (before you reminded me that @mortice already had), I went with descriptions[:positive] and descriptions[:negative] - we could use that and then add a similar method for the failure messages. I don't think that we can really deprecate the old methods for a long, long time though.

Myron Marston

Ironically, @mortice's pull request originally started with that API as well--a method that returned a hash with :positive and :negative entries in it.

At the time, I felt like this was a bit of an awkward API: I can't think of any other API in any standard ruby libraries that return a hash of two elements with 2 keys that are always in the hash. Separate methods still makes more sense to me.

That said, if you're fine with positive and negative keys in the hash, why are you not fine with positive and negative in the method names?

David Chelimsky

That said, if you're fine with positive and negative keys in the hash, why are you not fine with positive and negative in the method names?

It's not bad for the docstrings, but we want to land on a naming scheme that works equally well for docstrings and failure messages and I find negative_failure_message less confusing than failure_message[:negative] - the latter of which separates the polarity from the method name.

I'm not excited about either option at the moment, so more ideas welcome.

Please sign in to comment.
Something went wrong with that request. Please try again.