rspec-expectations 2.11.3 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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