rspec-expectations 2.13.0 → 3.0.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 (142) hide show
  1. checksums.yaml +15 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +413 -23
  4. data/License.txt +1 -0
  5. data/README.md +109 -80
  6. data/lib/rspec/{matchers → expectations}/configuration.rb +44 -14
  7. data/lib/rspec/expectations/expectation_target.rb +71 -38
  8. data/lib/rspec/expectations/fail_with.rb +12 -44
  9. data/lib/rspec/expectations/handler.rb +135 -35
  10. data/lib/rspec/expectations/minitest_integration.rb +16 -0
  11. data/lib/rspec/expectations/syntax.rb +60 -94
  12. data/lib/rspec/expectations/version.rb +1 -1
  13. data/lib/rspec/expectations.rb +46 -24
  14. data/lib/rspec/matchers/aliased_matcher.rb +41 -0
  15. data/lib/rspec/matchers/built_in/all.rb +78 -0
  16. data/lib/rspec/matchers/built_in/base_matcher.rb +63 -15
  17. data/lib/rspec/matchers/built_in/be.rb +170 -79
  18. data/lib/rspec/matchers/built_in/be_between.rb +77 -0
  19. data/lib/rspec/matchers/built_in/be_instance_of.rb +11 -3
  20. data/lib/rspec/matchers/built_in/be_kind_of.rb +5 -0
  21. data/lib/rspec/matchers/built_in/be_within.rb +40 -16
  22. data/lib/rspec/matchers/built_in/change.rb +275 -74
  23. data/lib/rspec/matchers/built_in/compound.rb +122 -0
  24. data/lib/rspec/matchers/built_in/contain_exactly.rb +256 -0
  25. data/lib/rspec/matchers/built_in/cover.rb +3 -0
  26. data/lib/rspec/matchers/built_in/eq.rb +60 -6
  27. data/lib/rspec/matchers/built_in/eql.rb +17 -5
  28. data/lib/rspec/matchers/built_in/equal.rb +55 -21
  29. data/lib/rspec/matchers/built_in/exist.rb +74 -10
  30. data/lib/rspec/matchers/built_in/has.rb +71 -15
  31. data/lib/rspec/matchers/built_in/include.rb +58 -29
  32. data/lib/rspec/matchers/built_in/match.rb +19 -1
  33. data/lib/rspec/matchers/built_in/operators.rb +119 -0
  34. data/lib/rspec/matchers/built_in/output.rb +150 -0
  35. data/lib/rspec/matchers/built_in/raise_error.rb +91 -33
  36. data/lib/rspec/matchers/built_in/respond_to.rb +42 -20
  37. data/lib/rspec/matchers/built_in/satisfy.rb +19 -3
  38. data/lib/rspec/matchers/built_in/start_and_end_with.rb +54 -18
  39. data/lib/rspec/matchers/built_in/throw_symbol.rb +38 -8
  40. data/lib/rspec/matchers/built_in/yield.rb +237 -55
  41. data/lib/rspec/matchers/built_in.rb +45 -33
  42. data/lib/rspec/matchers/composable.rb +179 -0
  43. data/lib/rspec/matchers/dsl.rb +362 -5
  44. data/lib/rspec/matchers/generated_descriptions.rb +13 -6
  45. data/lib/rspec/matchers/matcher_delegator.rb +37 -0
  46. data/lib/rspec/matchers/pretty.rb +33 -20
  47. data/lib/rspec/matchers.rb +450 -227
  48. data.tar.gz.sig +1 -0
  49. metadata +100 -215
  50. metadata.gz.sig +0 -0
  51. data/features/README.md +0 -49
  52. data/features/Upgrade.md +0 -53
  53. data/features/built_in_matchers/README.md +0 -90
  54. data/features/built_in_matchers/be.feature +0 -175
  55. data/features/built_in_matchers/be_within.feature +0 -48
  56. data/features/built_in_matchers/cover.feature +0 -47
  57. data/features/built_in_matchers/end_with.feature +0 -48
  58. data/features/built_in_matchers/equality.feature +0 -139
  59. data/features/built_in_matchers/exist.feature +0 -45
  60. data/features/built_in_matchers/expect_change.feature +0 -59
  61. data/features/built_in_matchers/expect_error.feature +0 -144
  62. data/features/built_in_matchers/have.feature +0 -109
  63. data/features/built_in_matchers/include.feature +0 -174
  64. data/features/built_in_matchers/match.feature +0 -52
  65. data/features/built_in_matchers/operators.feature +0 -227
  66. data/features/built_in_matchers/predicates.feature +0 -137
  67. data/features/built_in_matchers/respond_to.feature +0 -84
  68. data/features/built_in_matchers/satisfy.feature +0 -33
  69. data/features/built_in_matchers/start_with.feature +0 -48
  70. data/features/built_in_matchers/throw_symbol.feature +0 -91
  71. data/features/built_in_matchers/types.feature +0 -116
  72. data/features/built_in_matchers/yield.feature +0 -146
  73. data/features/custom_matchers/access_running_example.feature +0 -53
  74. data/features/custom_matchers/define_diffable_matcher.feature +0 -27
  75. data/features/custom_matchers/define_matcher.feature +0 -368
  76. data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
  77. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
  78. data/features/customized_message.feature +0 -22
  79. data/features/diffing.feature +0 -85
  80. data/features/implicit_docstrings.feature +0 -52
  81. data/features/step_definitions/additional_cli_steps.rb +0 -22
  82. data/features/support/env.rb +0 -5
  83. data/features/syntax_configuration.feature +0 -68
  84. data/features/test_frameworks/test_unit.feature +0 -46
  85. data/lib/rspec/expectations/deprecation.rb +0 -38
  86. data/lib/rspec/expectations/differ.rb +0 -115
  87. data/lib/rspec/expectations/errors.rb +0 -9
  88. data/lib/rspec/expectations/extensions/array.rb +0 -9
  89. data/lib/rspec/expectations/extensions/object.rb +0 -39
  90. data/lib/rspec/expectations/extensions.rb +0 -2
  91. data/lib/rspec/matchers/be_close.rb +0 -9
  92. data/lib/rspec/matchers/built_in/have.rb +0 -108
  93. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  94. data/lib/rspec/matchers/compatibility.rb +0 -14
  95. data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
  96. data/lib/rspec/matchers/matcher.rb +0 -300
  97. data/lib/rspec/matchers/method_missing.rb +0 -12
  98. data/lib/rspec/matchers/operator_matcher.rb +0 -109
  99. data/lib/rspec-expectations.rb +0 -1
  100. data/spec/rspec/expectations/differ_spec.rb +0 -170
  101. data/spec/rspec/expectations/expectation_target_spec.rb +0 -75
  102. data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
  103. data/spec/rspec/expectations/fail_with_spec.rb +0 -95
  104. data/spec/rspec/expectations/handler_spec.rb +0 -206
  105. data/spec/rspec/expectations/syntax_spec.rb +0 -97
  106. data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
  107. data/spec/rspec/matchers/be_close_spec.rb +0 -22
  108. data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
  109. data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
  110. data/spec/rspec/matchers/be_spec.rb +0 -516
  111. data/spec/rspec/matchers/be_within_spec.rb +0 -129
  112. data/spec/rspec/matchers/change_spec.rb +0 -542
  113. data/spec/rspec/matchers/configuration_spec.rb +0 -238
  114. data/spec/rspec/matchers/cover_spec.rb +0 -69
  115. data/spec/rspec/matchers/description_generation_spec.rb +0 -176
  116. data/spec/rspec/matchers/dsl_spec.rb +0 -57
  117. data/spec/rspec/matchers/eq_spec.rb +0 -60
  118. data/spec/rspec/matchers/eql_spec.rb +0 -41
  119. data/spec/rspec/matchers/equal_spec.rb +0 -78
  120. data/spec/rspec/matchers/exist_spec.rb +0 -124
  121. data/spec/rspec/matchers/has_spec.rb +0 -122
  122. data/spec/rspec/matchers/have_spec.rb +0 -445
  123. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  124. data/spec/rspec/matchers/include_spec.rb +0 -531
  125. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  126. data/spec/rspec/matchers/match_spec.rb +0 -61
  127. data/spec/rspec/matchers/matcher_spec.rb +0 -471
  128. data/spec/rspec/matchers/matchers_spec.rb +0 -37
  129. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  130. data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
  131. data/spec/rspec/matchers/raise_error_spec.rb +0 -395
  132. data/spec/rspec/matchers/respond_to_spec.rb +0 -292
  133. data/spec/rspec/matchers/satisfy_spec.rb +0 -44
  134. data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
  135. data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
  136. data/spec/rspec/matchers/yield_spec.rb +0 -437
  137. data/spec/spec_helper.rb +0 -54
  138. data/spec/support/classes.rb +0 -56
  139. data/spec/support/in_sub_process.rb +0 -38
  140. data/spec/support/matchers.rb +0 -22
  141. data/spec/support/ruby_version.rb +0 -10
  142. data/spec/support/shared_examples.rb +0 -13
@@ -0,0 +1,179 @@
1
+ RSpec::Support.require_rspec_support "fuzzy_matcher"
2
+
3
+ module RSpec
4
+ module Matchers
5
+ # Mixin designed to support the composable matcher features
6
+ # of RSpec 3+. Mix it into your custom matcher classes to
7
+ # allow them to be used in a composable fashion.
8
+ #
9
+ # @api public
10
+ module Composable
11
+ # Creates a compound `and` expectation. The matcher will
12
+ # only pass if both sub-matchers pass.
13
+ # This can be chained together to form an arbitrarily long
14
+ # chain of matchers.
15
+ #
16
+ # @example
17
+ # expect(alphabet).to start_with("a").and end_with("z")
18
+ # expect(alphabet).to start_with("a") & end_with("z")
19
+ #
20
+ # @note The negative form (`expect(...).not_to matcher.and other`)
21
+ # is not supported at this time.
22
+ def and(matcher)
23
+ BuiltIn::Compound::And.new self, matcher
24
+ end
25
+ alias & and
26
+
27
+ # Creates a compound `or` expectation. The matcher will
28
+ # pass if either sub-matcher passes.
29
+ # This can be chained together to form an arbitrarily long
30
+ # chain of matchers.
31
+ #
32
+ # @example
33
+ # expect(stoplight.color).to eq("red").or eq("green").or eq("yellow")
34
+ # expect(stoplight.color).to eq("red") | eq("green") | eq("yellow")
35
+ #
36
+ # @note The negative form (`expect(...).not_to matcher.or other`)
37
+ # is not supported at this time.
38
+ def or(matcher)
39
+ BuiltIn::Compound::Or.new self, matcher
40
+ end
41
+ alias | or
42
+
43
+ # Delegates to `#matches?`. Allows matchers to be used in composable
44
+ # fashion and also supports using matchers in case statements.
45
+ def ===(value)
46
+ matches?(value)
47
+ end
48
+
49
+ private
50
+
51
+ # This provides a generic way to fuzzy-match an expected value against
52
+ # an actual value. It understands nested data structures (e.g. hashes
53
+ # and arrays) and is able to match against a matcher being used as
54
+ # the expected value or within the expected value at any level of
55
+ # nesting.
56
+ #
57
+ # Within a custom matcher you are encouraged to use this whenever your
58
+ # matcher needs to match two values, unless it needs more precise semantics.
59
+ # For example, the `eq` matcher _does not_ use this as it is meant to
60
+ # use `==` (and only `==`) for matching.
61
+ #
62
+ # @param expected [Object] what is expected
63
+ # @param actual [Object] the actual value
64
+ #
65
+ # @!visibility public
66
+ def values_match?(expected, actual)
67
+ expected = with_matchers_cloned(expected)
68
+ Support::FuzzyMatcher.values_match?(expected, actual)
69
+ end
70
+
71
+ # Returns the description of the given object in a way that is
72
+ # aware of composed matchers. If the object is a matcher with
73
+ # a `description` method, returns the description; otherwise
74
+ # returns `object.inspect`.
75
+ #
76
+ # You are encouraged to use this in your custom matcher's
77
+ # `description`, `failure_message` or
78
+ # `failure_message_when_negated` implementation if you are
79
+ # supporting matcher arguments.
80
+ #
81
+ # @!visibility public
82
+ def description_of(object)
83
+ return object.description if Matchers.is_a_describable_matcher?(object)
84
+ object.inspect
85
+ end
86
+
87
+ # Transforms the given data structue (typically a hash or array)
88
+ # into a new data structure that, when `#inspect` is called on it,
89
+ # will provide descriptions of any contained matchers rather than
90
+ # the normal `#inspect` output.
91
+ #
92
+ # You are encouraged to use this in your custom matcher's
93
+ # `description`, `failure_message` or
94
+ # `failure_message_when_negated` implementation if you are
95
+ # supporting any arguments which may be a data structure
96
+ # containing matchers.
97
+ #
98
+ # @!visibility public
99
+ def surface_descriptions_in(item)
100
+ if Matchers.is_a_describable_matcher?(item)
101
+ DescribableItem.new(item)
102
+ elsif Hash === item
103
+ Hash[ surface_descriptions_in(item.to_a) ]
104
+ elsif enumerable?(item)
105
+ begin
106
+ item.map { |subitem| surface_descriptions_in(subitem) }
107
+ rescue IOError # STDOUT is enumerable but `map` raises an error
108
+ item.inspect
109
+ end
110
+ else
111
+ item
112
+ end
113
+ end
114
+
115
+ # @private
116
+ # Historically, a single matcher instance was only checked
117
+ # against a single value. Given that the matcher was only
118
+ # used once, it's been common to memoize some intermediate
119
+ # calculation that is derived from the `actual` value in
120
+ # order to reuse that intermediate result in the failure
121
+ # message.
122
+ #
123
+ # This can cause a problem when using such a matcher as an
124
+ # argument to another matcher in a composed matcher expression,
125
+ # since the matcher instance may be checked against multiple
126
+ # values and produce invalid results due to the memoization.
127
+ #
128
+ # To deal with this, we clone any matchers in `expected` via
129
+ # this method when using `values_match?`, so that any memoization
130
+ # does not "leak" between checks.
131
+ def with_matchers_cloned(object)
132
+ if Matchers.is_a_matcher?(object)
133
+ object.clone
134
+ elsif Hash === object
135
+ Hash[ with_matchers_cloned(object.to_a) ]
136
+ elsif enumerable?(object)
137
+ begin
138
+ object.map { |subobject| with_matchers_cloned(subobject) }
139
+ rescue IOError # STDOUT is enumerable but `map` raises an error
140
+ object
141
+ end
142
+ else
143
+ object
144
+ end
145
+ end
146
+
147
+ if String.ancestors.include?(Enumerable) # 1.8.7
148
+ # Strings are not enumerable on 1.9, and on 1.8 they are an infinitely
149
+ # nested enumerable: since ruby lacks a character class, it yields
150
+ # 1-character strings, which are themselves enumerable, composed of a
151
+ # a single 1-character string, which is an enumerable, etc.
152
+ #
153
+ # @api private
154
+ def enumerable?(item)
155
+ return false if String === item
156
+ Enumerable === item
157
+ end
158
+ else
159
+ # @api private
160
+ def enumerable?(item)
161
+ Enumerable === item
162
+ end
163
+ end
164
+ module_function :surface_descriptions_in, :enumerable?
165
+
166
+ # Wraps an item in order to surface its `description` via `inspect`.
167
+ # @api private
168
+ DescribableItem = Struct.new(:item) do
169
+ def inspect
170
+ "(#{item.description})"
171
+ end
172
+
173
+ def pretty_print(pp)
174
+ pp.text "(#{item.description})"
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -1,22 +1,379 @@
1
1
  module RSpec
2
2
  module Matchers
3
+ # Defines the custom matcher DSL.
3
4
  module DSL
4
5
  # Defines a custom matcher.
5
6
  # @see RSpec::Matchers
6
7
  def define(name, &declarations)
7
- matcher_template = RSpec::Matchers::DSL::Matcher.new(name, &declarations)
8
8
  define_method name do |*expected|
9
- matcher = matcher_template.for_expected(*expected)
10
- matcher.matcher_execution_context = @matcher_execution_context ||= self
11
- matcher
9
+ RSpec::Matchers::DSL::Matcher.new(name, declarations, self, *expected)
12
10
  end
13
11
  end
14
-
15
12
  alias_method :matcher, :define
16
13
 
17
14
  if RSpec.respond_to?(:configure)
18
15
  RSpec.configure {|c| c.extend self}
19
16
  end
17
+
18
+ # Contains the methods that are available from within the
19
+ # `RSpec::Matchers.define` DSL for creating custom matchers.
20
+ module Macros
21
+ # Stores the block that is used to determine whether this matcher passes
22
+ # or fails. The block should return a boolean value. When the matcher is
23
+ # passed to `expect(...).to` and the block returns `true`, then the expectation
24
+ # passes. Similarly, when the matcher is passed to `expect(...).not_to` and the
25
+ # block returns `false`, then the expectation passes.
26
+ #
27
+ # @example
28
+ #
29
+ # RSpec::Matchers.define :be_even do
30
+ # match do |actual|
31
+ # actual.even?
32
+ # end
33
+ # end
34
+ #
35
+ # expect(4).to be_even # passes
36
+ # expect(3).not_to be_even # passes
37
+ # expect(3).to be_even # fails
38
+ # expect(4).not_to be_even # fails
39
+ #
40
+ # @yield [Object] actual the actual value (i.e. the value wrapped by `expect`)
41
+ def match(&match_block)
42
+ define_user_override(:matches?, match_block) do |actual|
43
+ begin
44
+ @actual = actual
45
+ super(*actual_arg_for(match_block))
46
+ rescue RSpec::Expectations::ExpectationNotMetError
47
+ false
48
+ end
49
+ end
50
+ end
51
+
52
+ # Use this to define the block for a negative expectation (`expect(...).not_to`)
53
+ # when the positive and negative forms require different handling. This
54
+ # is rarely necessary, but can be helpful, for example, when specifying
55
+ # asynchronous processes that require different timeouts.
56
+ #
57
+ # @yield [Object] actual the actual value (i.e. the value wrapped by `expect`)
58
+ def match_when_negated(&match_block)
59
+ define_user_override(:does_not_match?, match_block) do |actual|
60
+ @actual = actual
61
+ super(*actual_arg_for(match_block))
62
+ end
63
+ end
64
+
65
+ # Use this instead of `match` when the block will raise an exception
66
+ # rather than returning false to indicate a failure.
67
+ #
68
+ # @example
69
+ #
70
+ # RSpec::Matchers.define :accept_as_valid do |candidate_address|
71
+ # match_unless_raises ValidationException do |validator|
72
+ # validator.validate(candidate_address)
73
+ # end
74
+ # end
75
+ #
76
+ # expect(email_validator).to accept_as_valid("person@company.com")
77
+ #
78
+ # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`)
79
+ def match_unless_raises(expected_exception=Exception, &match_block)
80
+ define_user_override(:matches?, match_block) do |actual|
81
+ @actual = actual
82
+ begin
83
+ super(*actual_arg_for(match_block))
84
+ rescue expected_exception => @rescued_exception
85
+ false
86
+ else
87
+ true
88
+ end
89
+ end
90
+ end
91
+
92
+ # Customizes the failure messsage to use when this matcher is
93
+ # asked to positively match. Only use this when the message
94
+ # generated by default doesn't suit your needs.
95
+ #
96
+ # @example
97
+ #
98
+ # RSpec::Matchers.define :have_strength do |expected|
99
+ # match { your_match_logic }
100
+ #
101
+ # failure_message do |actual|
102
+ # "Expected strength of #{expected}, but had #{actual.strength}"
103
+ # end
104
+ # end
105
+ #
106
+ # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`)
107
+ def failure_message(&definition)
108
+ define_user_override(__method__, definition)
109
+ end
110
+
111
+ # Customize the failure messsage to use when this matcher is asked
112
+ # to negatively match. Only use this when the message generated by
113
+ # default doesn't suit your needs.
114
+ #
115
+ # @example
116
+ #
117
+ # RSpec::Matchers.define :have_strength do |expected|
118
+ # match { your_match_logic }
119
+ #
120
+ # failure_message_when_negated do |actual|
121
+ # "Expected not to have strength of #{expected}, but did"
122
+ # end
123
+ # end
124
+ #
125
+ # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`)
126
+ def failure_message_when_negated(&definition)
127
+ define_user_override(__method__, definition)
128
+ end
129
+
130
+ # Customize the description to use for one-liners. Only use this when
131
+ # the description generated by default doesn't suit your needs.
132
+ #
133
+ # @example
134
+ #
135
+ # RSpec::Matchers.define :qualify_for do |expected|
136
+ # match { your_match_logic }
137
+ #
138
+ # description do
139
+ # "qualify for #{expected}"
140
+ # end
141
+ # end
142
+ #
143
+ # @yield [Object] actual the actual object (i.e. the value wrapped by `expect`)
144
+ def description(&definition)
145
+ define_user_override(__method__, definition)
146
+ end
147
+
148
+ # Tells the matcher to diff the actual and expected values in the failure
149
+ # message.
150
+ def diffable
151
+ define_method(:diffable?) { true }
152
+ end
153
+
154
+ # Declares that the matcher can be used in a block expectation.
155
+ # Users will not be able to use your matcher in a block
156
+ # expectation without declaring this.
157
+ # (e.g. `expect { do_something }.to matcher`).
158
+ def supports_block_expectations
159
+ define_method(:supports_block_expectations?) { true }
160
+ end
161
+
162
+ # Convenience for defining methods on this matcher to create a fluent
163
+ # interface. The trick about fluent interfaces is that each method must
164
+ # return self in order to chain methods together. `chain` handles that
165
+ # for you.
166
+ #
167
+ # @example
168
+ #
169
+ # RSpec::Matchers.define :have_errors_on do |key|
170
+ # chain :with do |message|
171
+ # @message = message
172
+ # end
173
+ #
174
+ # match do |actual|
175
+ # actual.errors[key] == @message
176
+ # end
177
+ # end
178
+ #
179
+ # expect(minor).to have_errors_on(:age).with("Not old enough to participate")
180
+ def chain(name, &definition)
181
+ define_user_override(name, definition) do |*args, &block|
182
+ super(*args, &block)
183
+ self
184
+ end
185
+ end
186
+
187
+ private
188
+
189
+ # Does the following:
190
+ #
191
+ # - Defines the named method usign a user-provided block
192
+ # in @user_method_defs, which is included as an ancestor
193
+ # in the singleton class in which we eval the `define` block.
194
+ # - Defines an overriden definition for the same method
195
+ # usign the provided `our_def` block.
196
+ # - Provides a default `our_def` block for the common case
197
+ # of needing to call the user's definition with `@actual`
198
+ # as an arg, but only if their block's arity can handle it.
199
+ #
200
+ # This compiles the user block into an actual method, allowing
201
+ # them to use normal method constructs like `return`
202
+ # (e.g. for a early guard statement), while allowing us to define
203
+ # an override that can provide the wrapped handling
204
+ # (e.g. assigning `@actual`, rescueing errors, etc) and
205
+ # can `super` to the user's definition.
206
+ def define_user_override(method_name, user_def, &our_def)
207
+ @user_method_defs.__send__(:define_method, method_name, &user_def)
208
+ our_def ||= lambda { super(*actual_arg_for(user_def)) }
209
+ define_method(method_name, &our_def)
210
+ end
211
+
212
+ # Defines deprecated macro methods from RSpec 2 for backwards compatibility.
213
+ # @deprecated Use the methods from {Macros} instead.
214
+ module Deprecated
215
+ # @deprecated Use {Macros#match} instead.
216
+ def match_for_should(&definition)
217
+ RSpec.deprecate("`match_for_should`", :replacement => "`match`")
218
+ match(&definition)
219
+ end
220
+
221
+ # @deprecated Use {Macros#match_when_negated} instead.
222
+ def match_for_should_not(&definition)
223
+ RSpec.deprecate("`match_for_should_not`", :replacement => "`match_when_negated`")
224
+ match_when_negated(&definition)
225
+ end
226
+
227
+ # @deprecated Use {Macros#failure_message} instead.
228
+ def failure_message_for_should(&definition)
229
+ RSpec.deprecate("`failure_message_for_should`", :replacement => "`failure_message`")
230
+ failure_message(&definition)
231
+ end
232
+
233
+ # @deprecated Use {Macros#failure_message_when_negated} instead.
234
+ def failure_message_for_should_not(&definition)
235
+ RSpec.deprecate("`failure_message_for_should_not`", :replacement => "`failure_message_when_negated`")
236
+ failure_message_when_negated(&definition)
237
+ end
238
+ end
239
+ end
240
+
241
+ # Defines default implementations of the matcher
242
+ # protocol methods for custom matchers. You can
243
+ # override any of these using the {RSpec::Matchers::DSL::Macros Macros} methods
244
+ # from within an `RSpec::Matchers.define` block.
245
+ module DefaultImplementations
246
+ # @api private
247
+ # Used internally by objects returns by `should` and `should_not`.
248
+ def diffable?
249
+ false
250
+ end
251
+
252
+ # The default description.
253
+ def description
254
+ "#{name_to_sentence}#{to_sentence expected}"
255
+ end
256
+
257
+ # The default failure message for positive expectations.
258
+ def failure_message
259
+ "expected #{actual.inspect} to #{name_to_sentence}#{to_sentence expected}"
260
+ end
261
+
262
+ # The default failure message for negative expectations.
263
+ def failure_message_when_negated
264
+ "expected #{actual.inspect} not to #{name_to_sentence}#{to_sentence expected}"
265
+ end
266
+
267
+ # Matchers do not support block expectations by default. You
268
+ # must opt-in.
269
+ def supports_block_expectations?
270
+ false
271
+ end
272
+ end
273
+
274
+ # The class used for custom matchers. The block passed to
275
+ # `RSpec::Matchers.define` will be evaluated in the context
276
+ # of the singleton class of an instance, and will have the
277
+ # {RSpec::Matchers::DSL::Macros Macros} methods available.
278
+ class Matcher
279
+ # Provides default implementations for the matcher protocol methods.
280
+ include DefaultImplementations
281
+
282
+ # Allows expectation expressions to be used in the match block.
283
+ include RSpec::Matchers
284
+
285
+ # Converts matcher name and expected args to an English expresion.
286
+ include RSpec::Matchers::Pretty
287
+
288
+ # Supports the matcher composability features of RSpec 3+.
289
+ include Composable
290
+
291
+ # Makes the macro methods available to an `RSpec::Matchers.define` block.
292
+ extend Macros
293
+ extend Macros::Deprecated
294
+
295
+ # Exposes the value being matched against -- generally the object
296
+ # object wrapped by `expect`.
297
+ attr_reader :actual
298
+
299
+ # Exposes the exception raised during the matching by `match_unless_raises`.
300
+ # Could be useful to extract details for a failure message.
301
+ attr_reader :rescued_exception
302
+
303
+ # @api private
304
+ def initialize(name, declarations, matcher_execution_context, *expected)
305
+ @name = name
306
+ @actual = nil
307
+ @expected_as_array = expected
308
+ @matcher_execution_context = matcher_execution_context
309
+
310
+ class << self
311
+ # See `Macros#define_user_override` above, for an explanation.
312
+ include(@user_method_defs = Module.new)
313
+ self
314
+ end.class_exec(*expected, &declarations)
315
+ end
316
+
317
+ # Provides the expected value. This will return an array if
318
+ # multiple arguments were passed to the matcher; otherwise it
319
+ # will return a single value.
320
+ # @see #expected_as_array
321
+ def expected
322
+ if expected_as_array.size == 1
323
+ expected_as_array[0]
324
+ else
325
+ expected_as_array
326
+ end
327
+ end
328
+
329
+ # Returns the expected value as an an array. This exists primarily
330
+ # to aid in upgrading from RSpec 2.x, since in RSpec 2, `expected`
331
+ # always returned an array.
332
+ # @see #expected
333
+ attr_reader :expected_as_array
334
+
335
+ # Adds the name (rather than a cryptic hex number)
336
+ # so we can identify an instance of
337
+ # the matcher in error messages (e.g. for `NoMethodError`)
338
+ def inspect
339
+ "#<#{self.class.name} #{name}>"
340
+ end
341
+
342
+ if RUBY_VERSION.to_f >= 1.9
343
+ # Indicates that this matcher responds to messages
344
+ # from the `@matcher_execution_context` as well.
345
+ # Also, supports getting a method object for such methods.
346
+ def respond_to_missing?(method, include_private=false)
347
+ super || @matcher_execution_context.respond_to?(method, include_private)
348
+ end
349
+ else # for 1.8.7
350
+ # Indicates that this matcher responds to messages
351
+ # from the `@matcher_execution_context` as well.
352
+ def respond_to?(method, include_private=false)
353
+ super || @matcher_execution_context.respond_to?(method, include_private)
354
+ end
355
+ end
356
+
357
+ private
358
+
359
+ def actual_arg_for(block)
360
+ block.arity.zero? ? [] : [@actual]
361
+ end
362
+
363
+ # Takes care of forwarding unhandled messages to the
364
+ # `@matcher_execution_context` (typically the current
365
+ # running `RSpec::Core::Example`). This is needed by
366
+ # rspec-rails so that it can define matchers that wrap
367
+ # Rails' test helper methods, but it's also a useful
368
+ # feature in its own right.
369
+ def method_missing(method, *args, &block)
370
+ if @matcher_execution_context.respond_to?(method)
371
+ @matcher_execution_context.__send__ method, *args, &block
372
+ else
373
+ super(method, *args, &block)
374
+ end
375
+ end
376
+ end
20
377
  end
21
378
  end
22
379
  end
@@ -1,17 +1,24 @@
1
1
  module RSpec
2
2
  module Matchers
3
3
  class << self
4
- attr_accessor :last_matcher, :last_should
4
+ # @private
5
+ attr_accessor :last_matcher, :last_expectation_handler
5
6
  end
6
7
 
8
+ # @api private
9
+ # Used by rspec-core to clear the state used to generate
10
+ # descriptions after an example.
7
11
  def self.clear_generated_description
8
12
  self.last_matcher = nil
9
- self.last_should = nil
13
+ self.last_expectation_handler = nil
10
14
  end
11
15
 
16
+ # @api private
17
+ # Generates an an example description based on the last expectation.
18
+ # Used by rspec-core's one-liner syntax.
12
19
  def self.generated_description
13
- return nil if last_should.nil?
14
- "#{last_should.to_s.gsub('_',' ')} #{last_description}"
20
+ return nil if last_expectation_handler.nil?
21
+ "#{last_expectation_handler.verb} #{last_description}"
15
22
  end
16
23
 
17
24
  private
@@ -20,11 +27,11 @@ module RSpec
20
27
  last_matcher.respond_to?(:description) ? last_matcher.description : <<-MESSAGE
21
28
  When you call a matcher in an example without a String, like this:
22
29
 
23
- specify { object.should matcher }
30
+ specify { expect(object).to matcher }
24
31
 
25
32
  or this:
26
33
 
27
- it { should matcher }
34
+ it { is_expected.to matcher }
28
35
 
29
36
  RSpec expects the matcher to have a #description method. You should either
30
37
  add a String to the example this matcher is being used in, or give it a
@@ -0,0 +1,37 @@
1
+ module RSpec
2
+ module Matchers
3
+ # Provides the necessary plumbing to wrap a matcher with a decorator.
4
+ # @private
5
+ class MatcherDelegator
6
+ attr_reader :base_matcher
7
+
8
+ def initialize(base_matcher)
9
+ @base_matcher = base_matcher
10
+ end
11
+
12
+ def method_missing(*args, &block)
13
+ base_matcher.__send__(*args, &block)
14
+ end
15
+
16
+ if ::RUBY_VERSION.to_f > 1.8
17
+ def respond_to_missing?(name, include_all=false)
18
+ super || base_matcher.respond_to?(name, include_all)
19
+ end
20
+ else
21
+ def respond_to?(name, include_all=false)
22
+ super || base_matcher.respond_to?(name, include_all)
23
+ end
24
+ end
25
+
26
+ def initialize_copy(other)
27
+ @base_matcher = @base_matcher.clone
28
+ super
29
+ end
30
+
31
+ # So `===` is delegated via `method_missing`.
32
+ undef ===
33
+ undef ==
34
+ end
35
+ end
36
+ end
37
+