rspec-expectations 2.11.3 → 3.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +1 -1
  5. data/Changelog.md +1026 -21
  6. data/{License.txt → LICENSE.md} +5 -3
  7. data/README.md +174 -78
  8. data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
  9. data/lib/rspec/expectations/configuration.rb +230 -0
  10. data/lib/rspec/expectations/expectation_target.rb +130 -55
  11. data/lib/rspec/expectations/fail_with.rb +17 -33
  12. data/lib/rspec/expectations/failure_aggregator.rb +212 -0
  13. data/lib/rspec/expectations/handler.rb +163 -29
  14. data/lib/rspec/expectations/minitest_integration.rb +58 -0
  15. data/lib/rspec/expectations/syntax.rb +68 -54
  16. data/lib/rspec/expectations/version.rb +1 -1
  17. data/lib/rspec/expectations.rb +59 -24
  18. data/lib/rspec/matchers/aliased_matcher.rb +116 -0
  19. data/lib/rspec/matchers/built_in/all.rb +86 -0
  20. data/lib/rspec/matchers/built_in/base_matcher.rb +150 -20
  21. data/lib/rspec/matchers/built_in/be.rb +115 -109
  22. data/lib/rspec/matchers/built_in/be_between.rb +77 -0
  23. data/lib/rspec/matchers/built_in/be_instance_of.rb +16 -1
  24. data/lib/rspec/matchers/built_in/be_kind_of.rb +10 -1
  25. data/lib/rspec/matchers/built_in/be_within.rb +43 -17
  26. data/lib/rspec/matchers/built_in/change.rb +392 -75
  27. data/lib/rspec/matchers/built_in/compound.rb +290 -0
  28. data/lib/rspec/matchers/built_in/contain_exactly.rb +302 -0
  29. data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
  30. data/lib/rspec/matchers/built_in/cover.rb +3 -0
  31. data/lib/rspec/matchers/built_in/eq.rb +26 -8
  32. data/lib/rspec/matchers/built_in/eql.rb +19 -8
  33. data/lib/rspec/matchers/built_in/equal.rb +56 -19
  34. data/lib/rspec/matchers/built_in/exist.rb +74 -10
  35. data/lib/rspec/matchers/built_in/has.rb +141 -22
  36. data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
  37. data/lib/rspec/matchers/built_in/include.rb +175 -20
  38. data/lib/rspec/matchers/built_in/match.rb +95 -1
  39. data/lib/rspec/matchers/built_in/operators.rb +128 -0
  40. data/lib/rspec/matchers/built_in/output.rb +207 -0
  41. data/lib/rspec/matchers/built_in/raise_error.rb +212 -38
  42. data/lib/rspec/matchers/built_in/respond_to.rb +155 -29
  43. data/lib/rspec/matchers/built_in/satisfy.rb +39 -9
  44. data/lib/rspec/matchers/built_in/start_or_end_with.rb +94 -0
  45. data/lib/rspec/matchers/built_in/throw_symbol.rb +58 -14
  46. data/lib/rspec/matchers/built_in/yield.rb +252 -98
  47. data/lib/rspec/matchers/built_in.rb +47 -33
  48. data/lib/rspec/matchers/composable.rb +171 -0
  49. data/lib/rspec/matchers/dsl.rb +530 -10
  50. data/lib/rspec/matchers/english_phrasing.rb +58 -0
  51. data/lib/rspec/matchers/expecteds_for_multiple_diffs.rb +82 -0
  52. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  53. data/lib/rspec/matchers/generated_descriptions.rb +15 -10
  54. data/lib/rspec/matchers/matcher_delegator.rb +35 -0
  55. data/lib/rspec/matchers/matcher_protocol.rb +105 -0
  56. data/lib/rspec/matchers.rb +604 -252
  57. data.tar.gz.sig +0 -0
  58. metadata +178 -278
  59. metadata.gz.sig +0 -0
  60. data/features/README.md +0 -49
  61. data/features/Upgrade.md +0 -53
  62. data/features/built_in_matchers/README.md +0 -90
  63. data/features/built_in_matchers/be.feature +0 -173
  64. data/features/built_in_matchers/be_within.feature +0 -46
  65. data/features/built_in_matchers/cover.feature +0 -45
  66. data/features/built_in_matchers/end_with.feature +0 -46
  67. data/features/built_in_matchers/equality.feature +0 -145
  68. data/features/built_in_matchers/exist.feature +0 -43
  69. data/features/built_in_matchers/expect_change.feature +0 -59
  70. data/features/built_in_matchers/expect_error.feature +0 -138
  71. data/features/built_in_matchers/have.feature +0 -103
  72. data/features/built_in_matchers/include.feature +0 -121
  73. data/features/built_in_matchers/match.feature +0 -50
  74. data/features/built_in_matchers/operators.feature +0 -221
  75. data/features/built_in_matchers/predicates.feature +0 -128
  76. data/features/built_in_matchers/respond_to.feature +0 -78
  77. data/features/built_in_matchers/satisfy.feature +0 -31
  78. data/features/built_in_matchers/start_with.feature +0 -46
  79. data/features/built_in_matchers/throw_symbol.feature +0 -85
  80. data/features/built_in_matchers/types.feature +0 -114
  81. data/features/built_in_matchers/yield.feature +0 -146
  82. data/features/custom_matchers/access_running_example.feature +0 -53
  83. data/features/custom_matchers/define_diffable_matcher.feature +0 -27
  84. data/features/custom_matchers/define_matcher.feature +0 -340
  85. data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
  86. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
  87. data/features/customized_message.feature +0 -22
  88. data/features/diffing.feature +0 -85
  89. data/features/implicit_docstrings.feature +0 -52
  90. data/features/step_definitions/additional_cli_steps.rb +0 -22
  91. data/features/support/env.rb +0 -5
  92. data/features/syntax_configuration.feature +0 -68
  93. data/features/test_frameworks/test_unit.feature +0 -46
  94. data/lib/rspec/expectations/deprecation.rb +0 -38
  95. data/lib/rspec/expectations/differ.rb +0 -81
  96. data/lib/rspec/expectations/errors.rb +0 -9
  97. data/lib/rspec/expectations/extensions/array.rb +0 -9
  98. data/lib/rspec/expectations/extensions/object.rb +0 -39
  99. data/lib/rspec/expectations/extensions.rb +0 -2
  100. data/lib/rspec/matchers/be_close.rb +0 -9
  101. data/lib/rspec/matchers/built_in/have.rb +0 -108
  102. data/lib/rspec/matchers/built_in/match_array.rb +0 -45
  103. data/lib/rspec/matchers/built_in/start_and_end_with.rb +0 -48
  104. data/lib/rspec/matchers/compatibility.rb +0 -14
  105. data/lib/rspec/matchers/configuration.rb +0 -66
  106. data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
  107. data/lib/rspec/matchers/matcher.rb +0 -299
  108. data/lib/rspec/matchers/method_missing.rb +0 -12
  109. data/lib/rspec/matchers/operator_matcher.rb +0 -84
  110. data/lib/rspec/matchers/pretty.rb +0 -60
  111. data/lib/rspec-expectations.rb +0 -1
  112. data/spec/rspec/expectations/differ_spec.rb +0 -153
  113. data/spec/rspec/expectations/expectation_target_spec.rb +0 -65
  114. data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
  115. data/spec/rspec/expectations/fail_with_spec.rb +0 -70
  116. data/spec/rspec/expectations/handler_spec.rb +0 -206
  117. data/spec/rspec/matchers/base_matcher_spec.rb +0 -60
  118. data/spec/rspec/matchers/be_close_spec.rb +0 -22
  119. data/spec/rspec/matchers/be_instance_of_spec.rb +0 -40
  120. data/spec/rspec/matchers/be_kind_of_spec.rb +0 -37
  121. data/spec/rspec/matchers/be_spec.rb +0 -452
  122. data/spec/rspec/matchers/be_within_spec.rb +0 -80
  123. data/spec/rspec/matchers/change_spec.rb +0 -528
  124. data/spec/rspec/matchers/configuration_spec.rb +0 -202
  125. data/spec/rspec/matchers/cover_spec.rb +0 -69
  126. data/spec/rspec/matchers/description_generation_spec.rb +0 -176
  127. data/spec/rspec/matchers/dsl_spec.rb +0 -57
  128. data/spec/rspec/matchers/eq_spec.rb +0 -54
  129. data/spec/rspec/matchers/eql_spec.rb +0 -41
  130. data/spec/rspec/matchers/equal_spec.rb +0 -60
  131. data/spec/rspec/matchers/exist_spec.rb +0 -110
  132. data/spec/rspec/matchers/has_spec.rb +0 -118
  133. data/spec/rspec/matchers/have_spec.rb +0 -461
  134. data/spec/rspec/matchers/include_spec.rb +0 -367
  135. data/spec/rspec/matchers/match_array_spec.rb +0 -124
  136. data/spec/rspec/matchers/match_spec.rb +0 -61
  137. data/spec/rspec/matchers/matcher_spec.rb +0 -434
  138. data/spec/rspec/matchers/matchers_spec.rb +0 -31
  139. data/spec/rspec/matchers/method_missing_spec.rb +0 -24
  140. data/spec/rspec/matchers/operator_matcher_spec.rb +0 -221
  141. data/spec/rspec/matchers/raise_error_spec.rb +0 -344
  142. data/spec/rspec/matchers/respond_to_spec.rb +0 -295
  143. data/spec/rspec/matchers/satisfy_spec.rb +0 -44
  144. data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -182
  145. data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
  146. data/spec/rspec/matchers/yield_spec.rb +0 -402
  147. data/spec/spec_helper.rb +0 -27
  148. data/spec/support/classes.rb +0 -56
  149. data/spec/support/in_sub_process.rb +0 -31
  150. data/spec/support/matchers.rb +0 -22
  151. data/spec/support/ruby_version.rb +0 -10
  152. data/spec/support/shared_examples.rb +0 -13
@@ -1,47 +1,82 @@
1
- require 'rspec/expectations/extensions'
1
+ require 'rspec/support'
2
+ RSpec::Support.require_rspec_support "caller_filter"
3
+ RSpec::Support.require_rspec_support "warnings"
4
+ RSpec::Support.require_rspec_support "object_formatter"
5
+
2
6
  require 'rspec/matchers'
3
- require 'rspec/expectations/expectation_target'
4
- require 'rspec/matchers/configuration'
5
- require 'rspec/expectations/fail_with'
6
- require 'rspec/expectations/errors'
7
- require 'rspec/expectations/deprecation'
8
- require 'rspec/expectations/handler'
9
- require 'rspec/expectations/version'
10
- require 'rspec/expectations/differ'
7
+
8
+ RSpec::Support.define_optimized_require_for_rspec(:expectations) { |f| require_relative(f) }
9
+
10
+ %w[
11
+ expectation_target
12
+ configuration
13
+ fail_with
14
+ handler
15
+ version
16
+ ].each { |file| RSpec::Support.require_rspec_expectations(file) }
11
17
 
12
18
  module RSpec
13
- # RSpec::Expectations adds two instance methods to every object:
19
+ # RSpec::Expectations provides a simple, readable API to express
20
+ # the expected outcomes in a code example. To express an expected
21
+ # outcome, wrap an object or block in `expect`, call `to` or `to_not`
22
+ # (aliased as `not_to`) and pass it a matcher object:
14
23
  #
15
- # should(matcher=nil)
16
- # should_not(matcher=nil)
24
+ # expect(order.total).to eq(Money.new(5.55, :USD))
25
+ # expect(list).to include(user)
26
+ # expect(message).not_to match(/foo/)
27
+ # expect { do_something }.to raise_error
17
28
  #
18
- # Both methods take an optional matcher object (See
19
- # [RSpec::Matchers](../RSpec/Matchers)). When `should` is invoked with a
20
- # matcher, it turns around and calls `matcher.matches?(self)`. For example,
29
+ # The last form (the block form) is needed to match against ruby constructs
30
+ # that are not objects, but can only be observed when executing a block
31
+ # of code. This includes raising errors, throwing symbols, yielding,
32
+ # and changing values.
33
+ #
34
+ # When `expect(...).to` is invoked with a matcher, it turns around
35
+ # and calls `matcher.matches?(<object wrapped by expect>)`. For example,
21
36
  # in the expression:
22
37
  #
23
- # order.total.should eq(Money.new(5.55, :USD))
38
+ # expect(order.total).to eq(Money.new(5.55, :USD))
24
39
  #
25
- # the `should` method invokes the equivalent of `eq.matches?(order.total)`. If
26
- # `matches?` returns true, the expectation is met and execution continues. If
27
- # `false`, then the spec fails with the message returned by
28
- # `eq.failure_message_for_should`.
40
+ # ...`eq(Money.new(5.55, :USD))` returns a matcher object, and it results
41
+ # in the equivalent of `eq.matches?(order.total)`. If `matches?` returns
42
+ # `true`, the expectation is met and execution continues. If `false`, then
43
+ # the spec fails with the message returned by `eq.failure_message`.
29
44
  #
30
45
  # Given the expression:
31
46
  #
32
- # order.entries.should_not include(entry)
47
+ # expect(order.entries).not_to include(entry)
33
48
  #
34
- # the `should_not` method invokes the equivalent of
49
+ # ...the `not_to` method (also available as `to_not`) invokes the equivalent of
35
50
  # `include.matches?(order.entries)`, but it interprets `false` as success, and
36
51
  # `true` as a failure, using the message generated by
37
- # `eq.failure_message_for_should_not`.
52
+ # `include.failure_message_when_negated`.
38
53
  #
39
54
  # rspec-expectations ships with a standard set of useful matchers, and writing
40
- # your own matchers is quite simple.
55
+ # your own matchers is quite simple.
41
56
  #
42
57
  # See [RSpec::Matchers](../RSpec/Matchers) for more information about the
43
58
  # built-in matchers that ship with rspec-expectations, and how to write your
44
59
  # own custom matchers.
45
60
  module Expectations
61
+ # Exception raised when an expectation fails.
62
+ #
63
+ # @note We subclass Exception so that in a stub implementation if
64
+ # the user sets an expectation, it can't be caught in their
65
+ # code by a bare `rescue`.
66
+ # @api public
67
+ class ExpectationNotMetError < Exception
68
+ end
69
+
70
+ # Exception raised from `aggregate_failures` when multiple expectations fail.
71
+ #
72
+ # @note The constant is defined here but the extensive logic of this class
73
+ # is lazily defined when `FailureAggregator` is autoloaded, since we do
74
+ # not need to waste time defining that functionality unless
75
+ # `aggregate_failures` is used.
76
+ class MultipleExpectationsNotMetError < ExpectationNotMetError
77
+ end
78
+
79
+ autoload :BlockSnippetExtractor, "rspec/expectations/block_snippet_extractor"
80
+ autoload :FailureAggregator, "rspec/expectations/failure_aggregator"
46
81
  end
47
82
  end
@@ -0,0 +1,116 @@
1
+ module RSpec
2
+ module Matchers
3
+ # Decorator that wraps a matcher and overrides `description`
4
+ # using the provided block in order to support an alias
5
+ # of a matcher. This is intended for use when composing
6
+ # matchers, so that you can use an expression like
7
+ # `include( a_value_within(0.1).of(3) )` rather than
8
+ # `include( be_within(0.1).of(3) )`, and have the corresponding
9
+ # description read naturally.
10
+ #
11
+ # @api private
12
+ class AliasedMatcher < MatcherDelegator
13
+ def initialize(base_matcher, description_block)
14
+ @description_block = description_block
15
+ super(base_matcher)
16
+ end
17
+
18
+ # Forward messages on to the wrapped matcher.
19
+ # Since many matchers provide a fluent interface
20
+ # (e.g. `a_value_within(0.1).of(3)`), we need to wrap
21
+ # the returned value if it responds to `description`,
22
+ # so that our override can be applied when it is eventually
23
+ # used.
24
+ def method_missing(*)
25
+ return_val = super
26
+ return return_val unless RSpec::Matchers.is_a_matcher?(return_val)
27
+ self.class.new(return_val, @description_block)
28
+ end
29
+
30
+ # Provides the description of the aliased matcher. Aliased matchers
31
+ # are designed to behave identically to the original matcher except
32
+ # for the description and failure messages. The description is different
33
+ # to reflect the aliased name.
34
+ #
35
+ # @api private
36
+ def description
37
+ @description_block.call(super)
38
+ end
39
+
40
+ # Provides the failure_message of the aliased matcher. Aliased matchers
41
+ # are designed to behave identically to the original matcher except
42
+ # for the description and failure messages. The failure_message is different
43
+ # to reflect the aliased name.
44
+ #
45
+ # @api private
46
+ def failure_message
47
+ @description_block.call(super)
48
+ end
49
+
50
+ # Provides the failure_message_when_negated of the aliased matcher. Aliased matchers
51
+ # are designed to behave identically to the original matcher except
52
+ # for the description and failure messages. The failure_message_when_negated is different
53
+ # to reflect the aliased name.
54
+ #
55
+ # @api private
56
+ def failure_message_when_negated
57
+ @description_block.call(super)
58
+ end
59
+ end
60
+
61
+ # Decorator used for matchers that have special implementations of
62
+ # operators like `==` and `===`.
63
+ # @private
64
+ class AliasedMatcherWithOperatorSupport < AliasedMatcher
65
+ # We undef these so that they get delegated via `method_missing`.
66
+ undef ==
67
+ undef ===
68
+ end
69
+
70
+ # @private
71
+ class AliasedNegatedMatcher < AliasedMatcher
72
+ def matches?(*args, &block)
73
+ if @base_matcher.respond_to?(:does_not_match?)
74
+ @base_matcher.does_not_match?(*args, &block)
75
+ else
76
+ !super
77
+ end
78
+ end
79
+
80
+ def does_not_match?(*args, &block)
81
+ @base_matcher.matches?(*args, &block)
82
+ end
83
+
84
+ def failure_message
85
+ optimal_failure_message(__method__, :failure_message_when_negated)
86
+ end
87
+
88
+ def failure_message_when_negated
89
+ optimal_failure_message(__method__, :failure_message)
90
+ end
91
+
92
+ private
93
+
94
+ DefaultFailureMessages = BuiltIn::BaseMatcher::DefaultFailureMessages
95
+
96
+ # For a matcher that uses the default failure messages, we prefer to
97
+ # use the override provided by the `description_block`, because it
98
+ # includes the phrasing that the user has expressed a preference for
99
+ # by going through the effort of defining a negated matcher.
100
+ #
101
+ # However, if the override didn't actually change anything, then we
102
+ # should return the opposite failure message instead -- the overriden
103
+ # message is going to be confusing if we return it as-is, as it represents
104
+ # the non-negated failure message for a negated match (or vice versa).
105
+ def optimal_failure_message(same, inverted)
106
+ if DefaultFailureMessages.has_default_failure_messages?(@base_matcher)
107
+ base_message = @base_matcher.__send__(same)
108
+ overriden = @description_block.call(base_message)
109
+ return overriden if overriden != base_message
110
+ end
111
+
112
+ @base_matcher.__send__(inverted)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,86 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ # @api private
5
+ # Provides the implementation for `all`.
6
+ # Not intended to be instantiated directly.
7
+ class All < BaseMatcher
8
+ # @private
9
+ attr_reader :matcher, :failed_objects
10
+
11
+ def initialize(matcher)
12
+ @matcher = matcher
13
+ @failed_objects = {}
14
+ end
15
+
16
+ # @private
17
+ def does_not_match?(_actual)
18
+ raise NotImplementedError, '`expect().not_to all( matcher )` is not supported.'
19
+ end
20
+
21
+ # @api private
22
+ # @return [String]
23
+ def failure_message
24
+ unless iterable?
25
+ return "#{improve_hash_formatting(super)}, but was not iterable"
26
+ end
27
+
28
+ all_messages = [improve_hash_formatting(super)]
29
+ failed_objects.each do |index, matcher_failure_message|
30
+ all_messages << failure_message_for_item(index, matcher_failure_message)
31
+ end
32
+ all_messages.join("\n\n")
33
+ end
34
+
35
+ # @api private
36
+ # @return [String]
37
+ def description
38
+ improve_hash_formatting "all #{description_of matcher}"
39
+ end
40
+
41
+ private
42
+
43
+ def match(_expected, _actual)
44
+ return false unless iterable?
45
+
46
+ index_failed_objects
47
+ failed_objects.empty?
48
+ end
49
+
50
+ def index_failed_objects
51
+ actual.each_with_index do |actual_item, index|
52
+ cloned_matcher = matcher.clone
53
+ matches = cloned_matcher.matches?(actual_item)
54
+ failed_objects[index] = cloned_matcher.failure_message unless matches
55
+ end
56
+ end
57
+
58
+ def failure_message_for_item(index, failure_message)
59
+ failure_message = indent_multiline_message(add_new_line_if_needed(failure_message))
60
+ indent_multiline_message("object at index #{index} failed to match:#{failure_message}")
61
+ end
62
+
63
+ def add_new_line_if_needed(message)
64
+ message.start_with?("\n") ? message : "\n#{message}"
65
+ end
66
+
67
+ def indent_multiline_message(message)
68
+ message = message.sub(/\n+\z/, '')
69
+ message.lines.map do |line|
70
+ line =~ /\S/ ? ' ' + line : line
71
+ end.join
72
+ end
73
+
74
+ def initialize_copy(other)
75
+ @matcher = @matcher.clone
76
+ @failed_objects = @failed_objects.clone
77
+ super
78
+ end
79
+
80
+ def iterable?
81
+ @actual.respond_to?(:each_with_index)
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -4,27 +4,46 @@ module RSpec
4
4
  # @api private
5
5
  #
6
6
  # Used _internally_ as a base class for matchers that ship with
7
- # rspec-expectations.
7
+ # rspec-expectations and rspec-rails.
8
8
  #
9
9
  # ### Warning:
10
10
  #
11
- # This class is for internal use, and subject to change without notice. We
12
- # strongly recommend that you do not base your custom matchers on this
11
+ # This class is for internal use, and subject to change without notice.
12
+ # We strongly recommend that you do not base your custom matchers on this
13
13
  # class. If/when this changes, we will announce it and remove this warning.
14
14
  class BaseMatcher
15
- include RSpec::Matchers::Pretty
15
+ include RSpec::Matchers::Composable
16
16
 
17
+ # @api private
18
+ # Used to detect when no arg is passed to `initialize`.
19
+ # `nil` cannot be used because it's a valid value to pass.
20
+ UNDEFINED = Object.new.freeze
21
+
22
+ # @private
17
23
  attr_reader :actual, :expected, :rescued_exception
18
24
 
19
- def initialize(expected = nil)
20
- @expected = expected
25
+ # @private
26
+ attr_writer :matcher_name
27
+
28
+ def initialize(expected=UNDEFINED)
29
+ @expected = expected unless UNDEFINED.equal?(expected)
21
30
  end
22
31
 
32
+ # @api private
33
+ # Indicates if the match is successful. Delegates to `match`, which
34
+ # should be defined on a subclass. Takes care of consistently
35
+ # initializing the `actual` attribute.
23
36
  def matches?(actual)
24
37
  @actual = actual
25
38
  match(expected, actual)
26
39
  end
27
40
 
41
+ # @api private
42
+ # Used to wrap a block of code that will indicate failure by
43
+ # raising one of the named exceptions.
44
+ #
45
+ # This is used by rspec-rails for some of its matchers that
46
+ # wrap rails' assertions.
28
47
  def match_unless_raises(*exceptions)
29
48
  exceptions.unshift Exception if exceptions.empty?
30
49
  begin
@@ -35,33 +54,144 @@ module RSpec
35
54
  end
36
55
  end
37
56
 
38
- def failure_message_for_should
39
- assert_ivars :@actual, :@expected
40
- "expected #{@actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"
57
+ # @api private
58
+ # Generates a description using {EnglishPhrasing}.
59
+ # @return [String]
60
+ def description
61
+ desc = EnglishPhrasing.split_words(self.class.matcher_name)
62
+ desc << EnglishPhrasing.list(@expected) if defined?(@expected)
63
+ desc
41
64
  end
42
65
 
43
- def failure_message_for_should_not
44
- assert_ivars :@actual, :@expected
45
- "expected #{@actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}"
66
+ # @api private
67
+ # Matchers are not diffable by default. Override this to make your
68
+ # subclass diffable.
69
+ def diffable?
70
+ false
46
71
  end
47
72
 
48
- def description
49
- expected ? "#{name_to_sentence} #{@expected.inspect}" : name_to_sentence
73
+ # @api private
74
+ # Most matchers are value matchers (i.e. meant to work with `expect(value)`)
75
+ # rather than block matchers (i.e. meant to work with `expect { }`), so
76
+ # this defaults to false. Block matchers must override this to return true.
77
+ def supports_block_expectations?
78
+ false
50
79
  end
51
80
 
52
- def diffable?
81
+ # @private
82
+ def supports_value_expectations?
83
+ true
84
+ end
85
+
86
+ # @api private
87
+ def expects_call_stack_jump?
53
88
  false
54
89
  end
55
90
 
56
- def ==(other)
57
- matches?(other)
91
+ # @private
92
+ def expected_formatted
93
+ RSpec::Support::ObjectFormatter.format(@expected)
58
94
  end
59
95
 
60
- private
96
+ # @private
97
+ def actual_formatted
98
+ RSpec::Support::ObjectFormatter.format(@actual)
99
+ end
61
100
 
62
- def assert_ivars *ivars
63
- raise "#{self.class.name} needs to supply #{to_sentence ivars}" unless ivars.all? { |v| instance_variables.map(&:intern).include? v }
101
+ # @private
102
+ def self.matcher_name
103
+ @matcher_name ||= underscore(name.split('::').last)
104
+ end
105
+
106
+ # @private
107
+ def matcher_name
108
+ if defined?(@matcher_name)
109
+ @matcher_name
110
+ else
111
+ self.class.matcher_name
112
+ end
64
113
  end
114
+
115
+ # @private
116
+ # Borrowed from ActiveSupport.
117
+ def self.underscore(camel_cased_word)
118
+ word = camel_cased_word.to_s.dup
119
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
120
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
121
+ word.tr!('-', '_')
122
+ word.downcase!
123
+ word
124
+ end
125
+ private_class_method :underscore
126
+
127
+ private
128
+
129
+ def assert_ivars(*expected_ivars)
130
+ return unless (expected_ivars - present_ivars).any?
131
+ ivar_list = EnglishPhrasing.list(expected_ivars)
132
+ raise "#{self.class.name} needs to supply#{ivar_list}"
133
+ end
134
+
135
+ if RUBY_VERSION.to_f < 1.9
136
+ # :nocov:
137
+ def present_ivars
138
+ instance_variables.map(&:to_sym)
139
+ end
140
+ # :nocov:
141
+ else
142
+ alias present_ivars instance_variables
143
+ end
144
+
145
+ # @private
146
+ module HashFormatting
147
+ # `{ :a => 5, :b => 2 }.inspect` produces:
148
+ #
149
+ # {:a=>5, :b=>2}
150
+ #
151
+ # ...but it looks much better as:
152
+ #
153
+ # {:a => 5, :b => 2}
154
+ #
155
+ # This is idempotent and safe to run on a string multiple times.
156
+ def improve_hash_formatting(inspect_string)
157
+ inspect_string.gsub(/(\S)=>(\S)/, '\1 => \2')
158
+ end
159
+ module_function :improve_hash_formatting
160
+ end
161
+
162
+ include HashFormatting
163
+
164
+ # @api private
165
+ # Provides default implementations of failure messages, based on the `description`.
166
+ module DefaultFailureMessages
167
+ # @api private
168
+ # Provides a good generic failure message. Based on `description`.
169
+ # When subclassing, if you are not satisfied with this failure message
170
+ # you often only need to override `description`.
171
+ # @return [String]
172
+ def failure_message
173
+ "expected #{description_of @actual} to #{description}".dup
174
+ end
175
+
176
+ # @api private
177
+ # Provides a good generic negative failure message. Based on `description`.
178
+ # When subclassing, if you are not satisfied with this failure message
179
+ # you often only need to override `description`.
180
+ # @return [String]
181
+ def failure_message_when_negated
182
+ "expected #{description_of @actual} not to #{description}".dup
183
+ end
184
+
185
+ # @private
186
+ def self.has_default_failure_messages?(matcher)
187
+ matcher.method(:failure_message).owner == self &&
188
+ matcher.method(:failure_message_when_negated).owner == self
189
+ rescue NameError
190
+ false
191
+ end
192
+ end
193
+
194
+ include DefaultFailureMessages
65
195
  end
66
196
  end
67
197
  end