rspec-sleeping_king_studios 2.0.0.beta.0 → 2.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +84 -13
  3. data/DEVELOPMENT.md +16 -0
  4. data/README.md +203 -100
  5. data/lib/rspec/sleeping_king_studios/all.rb +4 -0
  6. data/lib/rspec/sleeping_king_studios/configuration.rb +42 -0
  7. data/lib/rspec/sleeping_king_studios/examples/all.rb +5 -0
  8. data/lib/rspec/sleeping_king_studios/examples/property_examples.rb +58 -0
  9. data/lib/rspec/sleeping_king_studios/examples/rspec_matcher_examples.rb +105 -0
  10. data/lib/rspec/sleeping_king_studios/examples/shared_example_group.rb +62 -0
  11. data/lib/rspec/sleeping_king_studios/examples.rb +8 -0
  12. data/lib/rspec/sleeping_king_studios/matchers/active_model/all.rb +5 -0
  13. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/error_expectation.rb +0 -1
  14. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/message_expectation.rb +1 -2
  15. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors.rb +75 -24
  16. data/lib/rspec/sleeping_king_studios/matchers/active_model.rb +6 -3
  17. data/lib/rspec/sleeping_king_studios/matchers/all.rb +5 -0
  18. data/lib/rspec/sleeping_king_studios/matchers/base_matcher.rb +20 -1
  19. data/lib/rspec/sleeping_king_studios/matchers/built_in/all.rb +5 -0
  20. data/lib/rspec/sleeping_king_studios/matchers/built_in/be_kind_of.rb +16 -10
  21. data/lib/rspec/sleeping_king_studios/matchers/built_in/include.rb +14 -9
  22. data/lib/rspec/sleeping_king_studios/matchers/built_in/respond_to.rb +45 -31
  23. data/lib/rspec/sleeping_king_studios/matchers/built_in.rb +5 -3
  24. data/lib/rspec/sleeping_king_studios/matchers/core/all.rb +5 -0
  25. data/lib/rspec/sleeping_king_studios/matchers/core/be_boolean.rb +11 -4
  26. data/lib/rspec/sleeping_king_studios/matchers/core/construct.rb +56 -32
  27. data/lib/rspec/sleeping_king_studios/matchers/core/have_property.rb +59 -29
  28. data/lib/rspec/sleeping_king_studios/matchers/core/have_reader.rb +31 -22
  29. data/lib/rspec/sleeping_king_studios/matchers/core/have_writer.rb +21 -55
  30. data/lib/rspec/sleeping_king_studios/matchers/core.rb +5 -3
  31. data/lib/rspec/sleeping_king_studios/matchers/shared/match_parameters.rb +1 -3
  32. data/lib/rspec/sleeping_king_studios/matchers/shared/match_property.rb +52 -0
  33. data/lib/rspec/sleeping_king_studios/matchers.rb +10 -3
  34. data/lib/rspec/sleeping_king_studios/version.rb +22 -1
  35. data/lib/rspec/sleeping_king_studios.rb +7 -1
  36. metadata +38 -16
  37. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/require.rb +0 -7
  38. data/lib/rspec/sleeping_king_studios/matchers/active_model/require.rb +0 -8
  39. data/lib/rspec/sleeping_king_studios/matchers/built_in/require.rb +0 -7
  40. data/lib/rspec/sleeping_king_studios/matchers/core/require.rb +0 -7
  41. data/lib/rspec/sleeping_king_studios/matchers/meta/fail_with_actual.rb +0 -107
  42. data/lib/rspec/sleeping_king_studios/matchers/meta/pass_with_actual.rb +0 -95
  43. data/lib/rspec/sleeping_king_studios/matchers/meta/require.rb +0 -7
  44. data/lib/rspec/sleeping_king_studios/matchers/meta.rb +0 -5
  45. data/lib/rspec/sleeping_king_studios/matchers/require.rb +0 -12
  46. data/lib/rspec/sleeping_king_studios/matchers/shared/require.rb +0 -7
  47. data/lib/rspec/sleeping_king_studios/require.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29c1c209fa47ee1227c9385fdb0381a81eda028f
4
- data.tar.gz: 8e7c6a833de4df42900de5e57fa48b1bc7ce4590
3
+ metadata.gz: 4f6b435b34abdf1b87b2496605d4472339e97b51
4
+ data.tar.gz: 9ab33137c4cdb76bdd1957e060814a5a8a6a23cd
5
5
  SHA512:
6
- metadata.gz: ea8a1a387419691c5ade0edb948b331415aa4b4e56bfbcf24cb51144d3f1c7f8b2a2a429b2d0d1cac7e8177357084336bba42eaf23a8a5e7d4ddc6677e3b20af
7
- data.tar.gz: 99ce1c09c14adbe4a14291a7bef9551172a84c694e856b13e028069ede03aef6a9eefb052a4c360b14ef0faff11aa93210df536cf160dac186b9d07498a3cb69
6
+ metadata.gz: 3fadfe034ff61756ef19b23eb4d4f15e7239b0e26a770cfa9711445d216e27efb487206b20848cae983732def47b3c45c2225778ddd9dc00023d2a742a5996ff
7
+ data.tar.gz: 6ea0170359b50b8b5a012085430ea5fa3cb92ee9fe563b38dcdc53ffdcee2ae7f0a9802c31d6f394a6d5b91759e4f5c15c90c225996eee865dd3ba6034348067
data/CHANGELOG.md CHANGED
@@ -2,28 +2,99 @@
2
2
 
3
3
  ## 2.0.0
4
4
 
5
- Update the entire library to support RSpec 3. Most of the updates are purely
6
- internal, but there are a few changes that are not backward compatible to be
7
- aware of.
5
+ Update the entire library to support RSpec 3. Most of the updates are purely internal, but there are a few changes that are not backward compatible to be aware of.
8
6
 
9
- ### Matchers
7
+ ### Ruby 1.9.3 Support
8
+
9
+ Support for Ruby 1.9.3 is officially dropped.
10
+
11
+ ### Concerns
12
+
13
+ Added module RSpec::SleepingKingStudios::Examples::SharedExampleGroup as a mixin for defining scoped shared example groups. Extend into a module to define shared example groups scoped to that module (and automatically included in example groups when the module is included), or extend into an example group to allow aliasing shared example groups with alternate or more expressive names.
14
+
15
+ ### Custom Examples
16
+
17
+ Added custom shared example groups for easier/more expressive tests.
18
+
19
+ #### Property Examples
20
+
21
+ Added 'has reader', 'has writer', and 'has property' examples as shorthand for defining property and attribute expectations.
22
+
23
+ #### RSpec Matcher Examples
24
+
25
+ Added custom examples for testing RSpec matchers. Replaces the (now removed) `pass_with_actual` and `fail_with_actual` matchers, which were fiddly and confusing (even for me) and couldn't handle all cases (such as failing on both `expect().to` and `expect().not_to`).
26
+
27
+ ### Custom Matchers
10
28
 
11
29
  All matchers have been updated to support the RSpec 3 matcher API.
12
30
 
13
- #### fail_with_actual Matcher
31
+ #### `construct` Matcher
32
+
33
+ Now has a fluent method for both `#argument` and `#arguments` to support the singular and plural use cases, similar to the built-in `respond_to` matcher.
34
+
35
+ expect(FooClass).to construct.with(1).argument
36
+ expect(BarClass).to construct.with(3).arguments
37
+
38
+ #### `fail_with_actual` Matcher
39
+
40
+ Removed. To test custom matchers, use the new shared examples (see Shared Examples, below).
41
+
42
+ #### `have_errors` Matcher
43
+
44
+ Adds the `#with` fluent method as an alias to `#with_messages`, as follows:
45
+
46
+ expect(model).to have_errors.on(:my_field).with("can't be blank")
47
+
48
+ In addition, the have_errors matcher will fail on both a positive expectation (`expect().to`) and a negative expectation (`expect().not_to` or `expect().to_not`) if the actual object does not respond to `#valid?`. The failure message has also been clarified for cases like `expect().not_to have_errors.on(attribute)`.
14
49
 
15
- Now correctly handles the #does_not_match? case for the new matcher API.
50
+ #### `have_property` Matcher
16
51
 
17
- #### respond\_to Matcher
52
+ Removed the functionality checking the value of `:property` after `:property=` has been invoked. The syntax for doing so was not expressive, and the feature was rarely used. To verify that invoking `:property=` will change `:property` to the desired value, set up the change expectation directly using a `#change` matcher.
18
53
 
19
- The #and fluent method has been removed, and the #a_block method for verifying
20
- the presence of a block argument has been renamed to #with_a_block.
54
+ Now supports composable matchers, as follows:
55
+
56
+ expect(object).to have_property(:my_method).with(an_instance_of(Fixnum))
57
+
58
+ Also added `#with_value` as an alias for `with`, and the error messages have been edited for clarity.
59
+
60
+ #### `have_reader` Matcher
61
+
62
+ Now supports composable matchers, as follows:
63
+
64
+ expect(object).to have_reader(:my_method).with(an_instance_of(String))
65
+
66
+ Also added `#with_value` as an alias for `with`, and the error messages have been edited for clarity.
67
+
68
+ #### `have_writer` Matcher
69
+
70
+ Removed the functionality checking the value of `:property` after `:property=` has been invoked. The syntax for doing so was not expressive, and the feature was rarely used. To verify that invoking `:property=` will change `:property` to the desired value, set up the change expectation directly using a `#change` matcher.
71
+
72
+ The error messages have also been edited for clarity.
73
+
74
+ #### `pass_with_actual` Matcher
75
+
76
+ Removed. To test custom matchers, use the new shared examples (see Shared Examples, below).
77
+
78
+ #### `respond_to` Matcher
79
+
80
+ The `#and` fluent method has been removed, and the `#a_block` method for verifying the presence of a block argument has been renamed to `#with_a_block`. In addition, by passing in `true` as the last argument, can check for the presence and arguments of protected or private methods, similar to the Ruby `Object#respond_to?` method.
21
81
 
22
82
  ### Mocks
23
83
 
24
- The #custom_double mock method has been completely removed. The recommended
25
- solution for that use case is `double('My Double').extend(MyModule)`, for some
26
- `MyModule` that implements the desired actual (non-stubbed) functionality.
84
+ The #custom_double mock method has been completely removed. The recommended solution for that use case is `double('My Double').extend(MyModule)`, for some `MyModule` that implements the desired actual (non-stubbed) functionality.
85
+
86
+ ### Shared Examples
87
+
88
+ Adds a new category of features, Shared Example groups, that can be included for easier or more expressive spec definitions.
89
+
90
+ #### Examples for Custom RSpec Matchers
91
+
92
+ Added four new shared examples to test custom matchers:
93
+
94
+ include_examples 'passes with a positive expectation'
95
+ include_examples 'passes with a negative expectation'
96
+ include_examples 'fails with a positive expectation'
97
+ include_examples 'fails with a negative expectation'
27
98
 
28
99
  ## 1.0.1
29
100
 
@@ -31,7 +102,7 @@ solution for that use case is `double('My Double').extend(MyModule)`, for some
31
102
 
32
103
  * The #construct and #respond_to matchers now support 2.1.0 required keyword
33
104
  arguments, of the form def foo(bar:, baz:). If the class constructor or
34
- method requires one or more keyword arguments, and one or more of those
105
+ method requires one or more keyword arguments, and one or more of those
35
106
  keywords are not provided when checking arguments using the #with
36
107
  method, the matcher will fail with the message "missing keywords" and a list
37
108
  of the keywords that were not provided as arguments to #with.
data/DEVELOPMENT.md ADDED
@@ -0,0 +1,16 @@
1
+ # Development Notes
2
+
3
+ ## Tasks
4
+
5
+ ### High Priority
6
+
7
+ ### Medium Priority
8
+
9
+ [RC1]
10
+ - Thorough documentation pass.
11
+ - Test against both RSpec 3.0 and 3.1 (multiple gemfiles? See ActiveModel::Collection for how it's done)
12
+
13
+ ### Low Priority
14
+
15
+ [RC1]
16
+ - Cucumber features for testing matchers, including returned text?
data/README.md CHANGED
@@ -1,15 +1,11 @@
1
1
  # RSpec::SleepingKingStudios [![Build Status](https://travis-ci.org/sleepingkingstudios/rspec-sleeping_king_studios.svg?branch=master)](https://travis-ci.org/sleepingkingstudios/rspec-sleeping_king_studios)
2
2
 
3
- A collection of matchers and extensions to ease TDD/BDD using RSpec. Extends
4
- built-in matchers with new functionality, such as support for Ruby 2.0+ keyword
5
- arguments, and adds new matchers for testing boolean-ness, object reader/writer
6
- properties, object constructor arguments, ActiveModel validations, and more.
3
+ A collection of matchers and extensions to ease TDD/BDD using RSpec. Extends built-in matchers with new functionality, such as support for Ruby 2.0+ keyword arguments, and adds new matchers for testing boolean-ness, object reader/writer properties, object constructor arguments, ActiveModel validations, and more. Also defines shared example groups for more expressive testing.
7
4
 
8
5
  ## Supported Ruby Versions
9
6
 
10
7
  Currently, the following versions of Ruby are officially supported:
11
8
 
12
- * 1.9.3
13
9
  * 2.0.0
14
10
  * 2.1.0
15
11
 
@@ -19,30 +15,70 @@ Currently, the following versions of Ruby are officially supported:
19
15
 
20
16
  ### A Note From The Developer
21
17
 
22
- Hi, I'm Rob Smith, the maintainer of this library. As a professional Ruby
23
- developer, I use these tools every day. If you find this project helpful in
24
- your own work, or if you have any questions, suggestions or critiques, please
25
- feel free to get in touch! I can be reached on GitHub (see above, and feel
26
- encouraged to submit bug reports or merge requests there) or via email at
27
- merlin@sleepingkingstudios.com. I look forward to hearing from you!
18
+ Hi, I'm Rob Smith, a Ruby Engineer and the developer of this library. I use these tools every day, but they're not just written for me. If you find this project helpful in your own work, or if you have any questions, suggestions or critiques, please feel free to get in touch! I can be reached on GitHub (see above, and feel encouraged to submit bug reports or merge requests there) or via email at `merlin@sleepingkingstudios.com`. I look forward to hearing from you!
28
19
 
29
- ## The Matchers
20
+ ## Configuration
21
+
22
+ RSpec::SleepingKingStudios now has configuration options available through `RSpec.configuration`. For example, to set the behavior of the matcher examples when a failure message expectation is undefined (see RSpec Matcher Examples, below), put the following in your `spec_helper` or other configuration file:
23
+
24
+ RSpec.configure do |config|
25
+ config.sleeping_king_studios do |config|
26
+ config.examples do |config|
27
+ config.handle_missing_failure_message_with = :ignore
28
+ end # config
29
+ end # config
30
+ end # config
31
+
32
+ ### Configuration Options
33
+
34
+ #### Handle Missing Failure Message With
35
+
36
+ This option is used with the RSpec matcher examples (see Examples, below), and determines the behavior when a matcher is expected to fail, but the corresponding failure message is not defined (via `let(:failure_message)` or `let(:failure_message_when_negated)`). The default option is `:pending`, which marks the generated example as skipped (and will show up as pending in the formatter). Other options include `:skip`, which marks the generated example as passing, and `:exception`, which marks the generated example as failing.
37
+
38
+ ## Concerns
39
+
40
+ RSpec::SleepingKingStudios defines a few concerns that can be included in or extended into modules or example groups for additional functionality.
41
+
42
+ ### Shared Example Groups
43
+
44
+ require 'rspec/sleeping_king_studios/examples/shared_example_group'
45
+
46
+ module MyCustomExamples
47
+ extend RSpec::SleepingKingStudios::Examples::SharedExampleGroup
48
+
49
+ shared_examples 'has custom behavior' do
50
+ # Define expectations here...
51
+ end # shared_examples
52
+ alias_shared_examples 'should have custom behavior', 'has custom behavior'
53
+ end # module
54
+
55
+ Utility functions for defining shared examples. If included in a module, any shared examples defined in that module are scoped to the module, rather than placed in a global scope. This allows you to define different shared examples with the same name in different contexts, similar to the current behavior when defining a shared example inside an example group. To use the defined examples, simply `include` the module in an example group. **Important Note:** Shared examples and aliases must be defined **before** including the module in an example group. Any shared examples or aliases defined afterword will not be available inside the example group.
56
+
57
+ ### `::alias_shared_examples`
58
+
59
+ Aliases a defined shared example group, allowing it to be accessed using a new name. The example group must be defined in the current context using `shared_examples`. The aliases must be defined before including the module into an example group, or they will not be available in the example group.
60
+
61
+ ### `::shared_examples`
62
+
63
+ Defines a shared example group within the context of the current module. Unlike a top-level example group defined using RSpec#shared_examples, these examples are not globally available, and must be mixed into an example group by including the module. The shared examples must be defined before including the module, or they will not be available in the example group.
64
+
65
+ ## Custom Matchers
30
66
 
31
67
  To enable a custom matcher, simply require the associated file. Matchers can be
32
68
  required individually or by category:
33
69
 
34
- require 'rspec/sleeping_king_studios'
70
+ require 'rspec/sleeping_king_studios/all'
35
71
  #=> requires all features, including matchers
36
72
 
37
- require 'rspec/sleeping_king_studios/matchers/core'
73
+ require 'rspec/sleeping_king_studios/matchers/core/all'
38
74
  #=> requires all of the core matchers
39
-
75
+
40
76
  require 'rspec/sleeping_king_studios/matchers/core/construct'
41
77
  #=> requires only the :construct matcher
42
78
 
43
79
  ### ActiveModel
44
80
 
45
- require 'rspec/sleeping_king_studios/matchers/active_model'
81
+ require 'rspec/sleeping_king_studios/matchers/active_model/all'
46
82
 
47
83
  These matchers validate ActiveModel functionality, such as validations.
48
84
 
@@ -56,21 +92,26 @@ individual fields to validate, or even specific messages for each attribute.
56
92
  **How To Use:**
57
93
 
58
94
  expect(instance).to have_errors
59
-
95
+
60
96
  expect(instance).to have_errors.on(:name)
61
-
97
+
62
98
  expect(instance).to have_errors.on(:name).with_message('not to be nil')
63
99
 
64
100
  **Chaining:**
65
101
 
66
102
  * **on:** [String, Symbol] Adds a field to validate; the matcher only passes if
67
103
  all validated fields have errors.
104
+ * **with:** [Array<String>] Adds one or more messages to the previously-defined
105
+ field validation. Raises ArgumentError if no field was previously set.
68
106
  * **with\_message:** [String] Adds a message to the previously-defined field
69
107
  validation. Raises ArgumentError if no field was previously set.
108
+ * **with\_messages:** [Array<String>] Adds one or more messages to the
109
+ previously-defined field validation. Raises ArgumentError if no field was
110
+ previously set.
70
111
 
71
112
  ### BuiltIn
72
113
 
73
- require 'rspec/sleeping_king_studios/matchers/built_in'
114
+ require 'rspec/sleeping_king_studios/matchers/built_in/all'
74
115
 
75
116
  These extend the built-in RSpec matchers with additional functionality.
76
117
 
@@ -104,41 +145,24 @@ now accepts an optional block as a shortcut for adding a proc expectation.
104
145
 
105
146
  require 'rspec/sleeping_king_studios/matchers/built_in/respond_to'
106
147
 
107
- Now has additional chaining functionality to validate the number of arguments
108
- accepted by the method, and whether the method accepts a block argument.
148
+ Now has additional chaining functionality to validate the number of arguments accepted by the method, the keyword arguments (if any) accepted by the method, and whether the method accepts a block argument.
109
149
 
110
150
  **How To Use:**
111
151
 
152
+ # With a variable number of arguments.
112
153
  expect(instance).to respond_to(:foo).with(2..3).arguments.with_a_block
113
154
 
114
- **Chaining:**
115
-
116
- * **with:** Expects one Integer or Range argument. If an Integer, verifies that
117
- the method accepts that number of arguments; if a Range, verifies that the
118
- method accepts both the minimum and maximum number of arguments.
119
- * **with\_a\_block:** No parameters. Verifies that the method requires a block
120
- argument of the form &my_argument. _Important note:_ A negative result does
121
- _not* mean the method cannot accept a block, merely that it does not require
122
- one. Also, does _not_ check whether the block is called or yielded.
123
-
124
- ##### Ruby 2.0+
125
-
126
- Has additional functionality to support Ruby 2.0 keyword arguments.
127
-
128
- **How To Use:**
129
- expect(instance).to respond_to(:foo).with(0, :bar, :baz)
155
+ # With keyword arguments.
156
+ expect(instance).to respond_to(:foo).with(0, :bar, :baz)
130
157
 
131
158
  **Chaining:**
132
159
 
133
- * **with:** Expects at most one Integer or Range argument, and zero or more
134
- Symbol arguments corresponding to optional keywords. Verifies that the method
135
- accepts that keyword, or has a variadic keyword of the form \*\*params. As
136
- of 2.1.0 and required keywords, verifies that all required keywords are
137
- provided.
160
+ * **with:** Expects at most one Integer or Range argument, and zero or more Symbol arguments corresponding to optional keywords. Verifies that the method accepts that keyword, or has a variadic keyword of the form `**params`. As of 2.1.0 and required keywords, verifies that all required keywords are provided.
161
+ * **with\_a\_block:** No parameters. Verifies that the method requires a block argument of the form `&my_argument`. _Important note:_ A negative result _does not_ mean the method cannot accept a block, merely that it does not require one. Also, _does not_ check whether the block is called or yielded.
138
162
 
139
163
  ### Core
140
164
 
141
- require 'rspec/sleeping_king_studios/matchers/core'
165
+ require 'rspec/sleeping_king_studios/matchers/core/all'
142
166
 
143
167
  These matchers check core functionality, such as object boolean-ness, the
144
168
  existence of properties, and so on.
@@ -187,28 +211,28 @@ Has additional functionality to support Ruby 2.0 keyword arguments.
187
211
  * **with:** Expects one Integer, Range, or nil argument, and zero or more
188
212
  Symbol arguments corresponding to optional keywords. Verifies that the
189
213
  class's constructor accepts that keyword, or has a variadic keyword of the
190
- form \*\*params. As of 2.1.0 and required keywords, verifies that all
214
+ form \*\*params. As of 2.1.0 and required keywords, verifies that all
191
215
  required keywords are provided.
192
216
 
193
217
  #### have\_property Matcher
194
218
 
195
219
  require 'rspec/sleeping_king_studios/matchers/core/have_property'
196
220
 
197
- Checks if the actual object responds to :property and :property=, and
198
- optionally if a value written to actual.property= can then be read by
199
- actual.property.
221
+ Checks if the actual object responds to :property and :property=, and optionally if the curernt value of actual.property is equal to a specified value.
200
222
 
201
223
  **How To Use:**
202
224
 
203
225
  expect(instance).to have_property(:foo).with("foo")
204
226
 
205
- **Parameters:** Property. Expects a string or symbol that is a valid
206
- identifier.
227
+ **Parameters:** Property. Expects a string or symbol that is a valid identifier.
207
228
 
208
229
  **Chaining:**
209
230
 
210
- * **with:** Expects one object, which is written to actual.property= and then
211
- read from actual.property.
231
+ * **with:** Expects one object, which is checked against the current value of actual.property if actual responds to :property. Can also be used with an RSpec matcher:
232
+
233
+ expect(instance).to have_property(:bar).with(an_instance_of(String))
234
+
235
+ * **with_value:** Alias for `#with`, above.
212
236
 
213
237
  #### have\_reader Matcher
214
238
 
@@ -221,37 +245,30 @@ current value of actual.property is equal to a specified value.
221
245
 
222
246
  expect(instance).to have_reader(:foo).with("foo")
223
247
 
224
- **Parameters:** Property. Expects a string or symbol that is a valid
225
- identifier.
248
+ **Parameters:** Property. Expects a string or symbol that is a valid identifier.
226
249
 
227
250
  **Chaining:**
228
251
 
229
- * **with:** Expects one object, which is checked against the current value of
230
- actual.property if actual responds to :property.
231
-
252
+ * **with:** Expects one object, which is checked against the current value of actual.property if actual responds to :property. Can also be used with an RSpec matcher:
253
+
254
+ expect(instance).to have_reader(:bar).with(an_instance_of(String))
255
+
256
+ * **with_value:** Alias for `#with`, above.
257
+
232
258
  #### have\_writer Matcher
233
259
 
234
260
  require 'rspec/sleeping_king_studios/matchers/core/have_writer'
235
261
 
236
- Checks if the actual object responds to :property=, and optionally if setting
237
- object.property = value sets object.property to value.
262
+ Checks if the actual object responds to :property=.
238
263
 
239
264
  **How To Use:**
240
265
 
241
- expect(instance).to have_writer(:foo=).with("foo")
266
+ expect(instance).to have_writer(:foo=)
242
267
 
243
268
  **Parameters:** Property. Expects a string or symbol that is a valid
244
269
  identifier. An equals sign '=' is automatically added if the identifier does
245
270
  not already terminate in '='.
246
271
 
247
- **Chaining:**
248
-
249
- * **with:** Expects one object. The matcher attempts to set the actual's value
250
- using actual.property=, then compare the value with actual.property.
251
-
252
- _Note:_ Currently, write-only properties cannot be checked using with().
253
- Attempting to do so will raise an exception.
254
-
255
272
  #### include\_matching Matcher
256
273
 
257
274
  require 'rspec/sleeping_king_studios/matchers/core/include_matching'
@@ -265,57 +282,143 @@ matches the given pattern.
265
282
 
266
283
  **Parameters:** Pattern. Expects a Regexp.
267
284
 
268
- ### Meta
285
+ ## Shared Examples
269
286
 
270
- require 'rspec/sleeping_king_studios/matchers/meta'
287
+ To use a custom example group, `require` the associated file and then `include`
288
+ the module in your example group:
271
289
 
272
- These meta-matchers are used to test other custom matchers.
290
+ require 'rspec/sleeping_king_studios/examples/some_examples'
273
291
 
274
- #### fail\_with\_actual Matcher
292
+ RSpec.describe MyCustomMatcher do
293
+ include RSpec::SleepingKingStudios::Examples::SomeExamples
275
294
 
276
- require 'rspec/sleeping_king_studios/matchers/meta/fail_with_actual'
295
+ # You can use the custom shared examples here.
296
+ include_examples 'some examples'
297
+ end # describe
277
298
 
278
- Checks if the given matcher will fail to match a specified actual object. Can
279
- take an optional string to check the expected failure message when the matcher
280
- is expected to pass, but does not.
299
+ Unless otherwise noted, these shared examples expect the example group to define either an explicit `#instance` method (using `let(:instance) {}`) or an implicit `subject`. Their behavior is **undefined** if neither `#instance` nor `subject` is defined.
281
300
 
282
- _Note:_ Do not use the not\_to syntax for this matcher; instead, use the
283
- pass\_with\_actual matcher, below.
301
+ ### Property Examples
284
302
 
285
- **How To Use:**
303
+ These examples are shorthand for defining a reader and/or writer expectation.
286
304
 
287
- expect(matcher).to fail_with_actual(actual).with_message(/expected to/)
288
-
289
- **Parameters:** Matcher. Expects an object that, at minimum, responds to
290
- :matches? and :failure\_message.
305
+ #### Has Property
291
306
 
292
- **Chaining:**
307
+ include_examples 'has property', :foo, 42
293
308
 
294
- * **with\_message:** Expects one String or Regexp argument, which is matched
295
- against the given matcher's failure\_message.
309
+ Delegates to the `#has_reader` and `#has_writer` matchers (see Core/Has Reader and Core/Has Writer, above) and passes if the actual object responds to the specified property and property writer methods. If a value is specified, the object must respond to the property and return the specified value. Alternatively, you can set a proc as the expected value, which can contain a comparison, an RSpec expectation, or a more complex expression:
296
310
 
297
- #### pass\_with\_actual Matcher
311
+ include_examples 'has property', :bar, ->() { an_instance_of(String) }
298
312
 
299
- require 'rspec/sleeping_king_studios/matchers/meta/pass_with_actual'
313
+ include_examples 'has property', :baz, ->(value) { value.count = 3 }
300
314
 
301
- Checks if the given matcher will match a specified actual object. Can take an
302
- optional string to check the expected failure message when the matcher is
303
- expected to fail, but does not.
315
+ #### Has Reader
304
316
 
305
- _Note:_ Do not use the not\_to syntax for this matcher; instead, use the
306
- fail\_with\_actual matcher, above.
317
+ include_examples 'has reader', :foo, 42
307
318
 
308
- **How To Use:**
319
+ Delegates to the `#has_reader` matcher (see Core/Has Reader, above) and passes if the actual object responds to the specified property. If a value is specified, the object must respond to the property and return the specified value. Alternatively, you can set a proc as the expected value, which can contain a comparison, an RSpec expectation, or a more complex expression:
309
320
 
310
- expect(matcher).to pass_with_actual(actual).with_message(/expected not to/)
311
-
312
- **Parameters:** Matcher. Expects an object that, at minimum, responds to
313
- :matches? and :failure\_message\_when\_negated.
321
+ include_examples 'has reader', :bar, ->() { an_instance_of(String) }
314
322
 
315
- **Chaining:**
323
+ include_examples 'has reader', :baz, ->(value) { value.count = 3 }
324
+
325
+ #### Has Writer
326
+
327
+ include_examples 'has writer', :foo=
328
+
329
+ Delegates to the `#has_writer` matcher (see Core/Has Writer, above) and passes if the actual object responds to the specified property writer.
330
+
331
+ ### RSpec Matcher Examples
332
+
333
+ These examples are used for validating custom RSpec matchers. They are used
334
+ internally by RSpec::SleepingKingStudios to verify the functionality of the
335
+ new and modified matchers.
336
+
337
+ require 'rspec/sleeping_king_studios/examples/rspec_matcher_examples'
338
+
339
+ RSpec.describe MyCustomMatcher do
340
+ include RSpec::SleepingKingStudios::Examples::RSpecMatcherExamples
341
+
342
+ # You can use the custom shared examples here.
343
+ end # describe
344
+
345
+ The `#instance` or `subject` for these examples should be an instance of a class matching the RSpec matcher API. For example, consider a matcher that checks if a number is a multiple of another number. This matcher would be used as follows:
346
+
347
+ expect(12).to be_a_multiple_of(3)
348
+ #=> true
349
+
350
+ expect(14).to be_a_multiple_of(3)
351
+ #=> false
352
+
353
+ Therefore, the `#instance` or `subject` should be defined as `BeAMultipleMatcher.new(3)`. If the custom matcher has additional fluent methods or options, these can be added to the instance as well, e.g. `expect(15).to be_a_multiple_of(3).and_of(5)` would be tested as `BeAMultipleMatcher.new(3).and_of(5)`.
354
+
355
+ In addition, all of these examples require a defined `#actual` method in the example group containing the object to be tested. The actual object is the object used in the expectation. In the above examples, the actual object is `12` in the first example, and `14` in the second. You can define the `#actual` method using `#let()`, e.g. `let(:actual) { Object.new }`.
356
+
357
+ Putting it all together:
358
+
359
+ require 'rspec/sleeping_king_studios/examples/rspec_matcher_examples'
360
+
361
+ RSpec.describe BeAMultipleOfMatcher do
362
+ include RSpec::SleepingKingStudios::Examples::RSpecMatcherExamples
363
+
364
+ let(:instance) { BeAMultipleOfMatcher.new(3) }
365
+
366
+ describe 'with a valid number' do
367
+ let(:actual) { 15 }
368
+
369
+ # Include examples here.
370
+
371
+ describe 'with a second factor' do
372
+ let(:instance) { BeAMultipleOfMatcher.new(3).and_of(5) }
373
+
374
+ # Include examples here.
375
+ end # describe
376
+ end # describe
377
+ end # describe
378
+
379
+ #### Passes With A Positive Expectation
380
+
381
+ include_examples 'passes with a positive expectation'
382
+
383
+ Verifies that the instance matcher will pass with a positive expectation (e.g. `expect().to`). Equivalent to verifying the result of the following:
384
+
385
+ expect(actual).to match_my_custom_matcher(*expected_values)
386
+ #=> passes
387
+
388
+ #### Passes With A Negative Expectation
389
+
390
+ include_examples 'passes with a negative expectation'
391
+
392
+ Verifies that the instance matcher will pass with a negative expectation (e.g. `expect().not_to`). Equivalent to verifying the result of the following:
393
+
394
+ expect(actual).not_to match_my_custom_matcher(*expected_values)
395
+ #=> passes
396
+
397
+ #### Fails With A Positive Expectation
398
+
399
+ include_examples 'fails with a positive expectation'
400
+
401
+ Verifies that the instance matcher will fail with a positive expectation (e.g. `expect().to`), and have the expected failure message. Equivalent to verifying the result of the following:
402
+
403
+ expect(actual).to match_my_custom_matcher(*expected_values)
404
+ #=> fails
405
+
406
+ In addition, verifies the `#failure_message` of the matcher by comparing it against a `#failure_message` method in the example group. This should be defined using `let(:failure_message) { 'expected to match' }`.
407
+
408
+ The behavior if the example group does not define `#failure_message` depends on the value of the `RSpec.configure.sleeping_king_studios.examples.handle_missing_failure_message_with` option (see Configuration, above). Accepted values are `:ignore`, `:pending` (default; marks the example as pending), and `:exception` (raises an exception).
409
+
410
+ #### Fails With A Negative Expectation
411
+
412
+ include_examples 'fails with a negative expectation'
413
+
414
+ Verifies that the instance matcher will fail with a negative expectation (e.g. `expect().not_to`), and have the expected failure message. Equivalent to verifying the result of the following:
415
+
416
+ expect(actual).not_to match_my_custom_matcher(*expected_values)
417
+ #=> fails
418
+
419
+ In addition, verifies the `#failure_message_when_negated` of the matcher by comparing it against a `#failure_message_when_negated` method in the example group. This should be defined using `let(:failure_message_when_negated) { 'expected not to match' }`.
316
420
 
317
- * **with\_message:** Expects one String or Regexp argument, which is matched
318
- against the given matcher's failure\_message\_when\_negated.
421
+ See Fails With A Positive Expectation, above, for behavior when the example group does not define `#failure_message_when_negated`.
319
422
 
320
423
  ## License
321
424
 
@@ -0,0 +1,4 @@
1
+ # lib/rspec/sleeping_king_studios/all.rb
2
+
3
+ require 'rspec/sleeping_king_studios/examples/all'
4
+ require 'rspec/sleeping_king_studios/matchers/all'
@@ -0,0 +1,42 @@
1
+ # lib/rspec/sleeping_king_studios/configuration.rb
2
+
3
+ require 'rspec/sleeping_king_studios'
4
+
5
+ module RSpec::SleepingKingStudios
6
+ class Configuration
7
+ class Examples
8
+ MISSING_FAILURE_MESSAGE_HANDLERS = %w(ignore pending exception).map(&:intern)
9
+
10
+ def handle_missing_failure_message_with
11
+ @handle_missing_failure_message_with ||= :pending
12
+ end # method missing_failure_message
13
+
14
+ def handle_missing_failure_message_with= value
15
+ unless MISSING_FAILURE_MESSAGE_HANDLERS.include?(value)
16
+ message = "unrecognized handler value -- must be in #{MISSING_FAILURE_MESSAGE_HANDLERS.join ', '}"
17
+ raise ArgumentError.new message
18
+ end # unless
19
+
20
+ @handle_missing_failure_message_with = value
21
+ end # message missing_failure_message=
22
+ end # class
23
+
24
+ def examples &block
25
+ (@examples ||= RSpec::SleepingKingStudios::Configuration::Examples.new).tap do |config|
26
+ if block_given?
27
+ config.instance_eval &block
28
+ end # if
29
+ end # tap
30
+ end # method examples
31
+ end # class
32
+ end # module
33
+
34
+ class RSpec::Core::Configuration
35
+ def sleeping_king_studios &block
36
+ (@sleeping_king_studios ||= RSpec::SleepingKingStudios::Configuration.new).tap do |config|
37
+ if block_given?
38
+ config.instance_eval &block
39
+ end # if
40
+ end # tap
41
+ end # method sleeping_king_studios
42
+ end # class
@@ -0,0 +1,5 @@
1
+ # lib/rspec/sleeping_king_studios/examples/all.rb
2
+
3
+ Dir[File.join File.dirname(__FILE__), '*_examples.rb'].each do |file|
4
+ require file
5
+ end # end each