rspec-sleeping_king_studios 2.2.4 → 2.3.0.rc.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -1
- data/DEVELOPMENT.md +20 -30
- data/README.md +201 -10
- data/lib/rspec/sleeping_king_studios/concerns/example_constants.rb +94 -0
- data/lib/rspec/sleeping_king_studios/concerns/shared_example_group.rb +3 -1
- data/lib/rspec/sleeping_king_studios/concerns/toolbelt.rb +25 -0
- data/lib/rspec/sleeping_king_studios/concerns/wrap_env.rb +46 -0
- data/lib/rspec/sleeping_king_studios/examples/property_examples/class_properties.rb +66 -0
- data/lib/rspec/sleeping_king_studios/examples/property_examples/constants.rb +51 -0
- data/lib/rspec/sleeping_king_studios/examples/property_examples/predicates.rb +28 -0
- data/lib/rspec/sleeping_king_studios/examples/property_examples/private_properties.rb +64 -0
- data/lib/rspec/sleeping_king_studios/examples/property_examples/properties.rb +78 -0
- data/lib/rspec/sleeping_king_studios/examples/property_examples.rb +12 -117
- data/lib/rspec/sleeping_king_studios/matchers/core/have_property.rb +5 -2
- data/lib/rspec/sleeping_king_studios/matchers/core/have_property_matcher.rb +19 -10
- data/lib/rspec/sleeping_king_studios/matchers/core/have_reader.rb +5 -2
- data/lib/rspec/sleeping_king_studios/matchers/core/have_reader_matcher.rb +17 -8
- data/lib/rspec/sleeping_king_studios/matchers/core/have_writer.rb +5 -2
- data/lib/rspec/sleeping_king_studios/matchers/core/have_writer_matcher.rb +14 -7
- data/lib/rspec/sleeping_king_studios/matchers/shared/match_property.rb +6 -6
- data/lib/rspec/sleeping_king_studios/version.rb +4 -4
- metadata +44 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a9d2f85f2b455f1996f711b0d606f5b1ca1c299
|
4
|
+
data.tar.gz: 21a4f0209ed50bc16090b2de208540a10e28dfd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fefccdff728588bd83fca3941faffc70330531edcfd8a9c9507c5b2cec59340d0492feeeb17d857729974d132e3d2687283f5957da799577226b5979c091e19b
|
7
|
+
data.tar.gz: 47d1c296a0acc07d2b8a24fd5e3f1cceea18fa8ce5f7e7da51e9c510b2f3b06f36199ed3b89628ce8a1f53cb0f8e62137c0ded9f1b79d51ced492779d12662eb
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 2.3.0
|
4
|
+
|
5
|
+
### Concerns
|
6
|
+
|
7
|
+
Added ExampleConstants concern to define named, example-scoped constants and classes.
|
8
|
+
|
9
|
+
Added Toolbelt concern to automatically expose SleepingKingStudios::Tools methods in examples and example groups.
|
10
|
+
|
11
|
+
Added WrapEnv concern to cleanly control environment variables per example or within example blocks.
|
12
|
+
|
13
|
+
### Examples
|
14
|
+
|
15
|
+
Added shared examples for expecting class readers, writers, and properties.
|
16
|
+
|
17
|
+
Added shared examples for expecting private readers, writers, and properties.
|
18
|
+
|
19
|
+
Added aliased examples for "has constant", "has immutable constant".
|
20
|
+
|
21
|
+
### Matchers
|
22
|
+
|
23
|
+
Added :allow_private option to HaveReaderMatcher, HaveWriterMatcher, and HavePropertyMatcher.
|
24
|
+
|
3
25
|
## 2.2.4
|
4
26
|
|
5
27
|
Reverted support for RSpec 3.0 to 3.2.
|
@@ -173,7 +195,7 @@ Removed the functionality checking the value of `:property` after `:property=` h
|
|
173
195
|
|
174
196
|
Now supports composable matchers, as follows:
|
175
197
|
|
176
|
-
expect(object).to have_property(:my_method).with(an_instance_of(
|
198
|
+
expect(object).to have_property(:my_method).with(an_instance_of(Integer))
|
177
199
|
|
178
200
|
Also added `#with_value` as an alias for `with`, and the error messages have been edited for clarity.
|
179
201
|
|
data/DEVELOPMENT.md
CHANGED
@@ -2,65 +2,55 @@
|
|
2
2
|
|
3
3
|
## Version 2.3
|
4
4
|
|
5
|
-
|
5
|
+
## Version 2.3.1
|
6
|
+
|
7
|
+
### Features - Syntactic Sugar
|
6
8
|
|
7
9
|
- Alias `have_reader`, etc as `define_reader`.
|
8
10
|
- Also alias shared examples.
|
9
11
|
- Alias `have_constant` as `define_constant`.
|
10
12
|
- Alias #immutable as #frozen.
|
11
13
|
- Also alias shared examples.
|
12
|
-
- Add 'should have class reader/writer/property' shared examples.
|
13
|
-
- Add 'should have private reader/writer/property' shared examples.
|
14
|
-
- Implement RespondToMatcher#with_at_least(N).arguments, equivalent to with(N).arguments.and_unlimited_arguments.
|
15
14
|
|
16
15
|
## Future Tasks
|
17
16
|
|
18
17
|
- Resolve Aruba deprecation warnings.
|
19
|
-
- Run each file individually as CI step.
|
20
18
|
|
21
19
|
### Bug Fixes
|
22
20
|
|
23
21
|
- false negative on #alias_method?
|
22
|
+
- need reproduction steps!
|
24
23
|
- compare via Method#source_location equality and Method#original_name is expected?
|
25
24
|
|
26
|
-
### Features
|
27
|
-
|
28
|
-
- Implement ::stub_env, #stub_env: |
|
29
|
-
|
30
|
-
describe 'something' do
|
31
|
-
# Changes the value using an around(:example) block.
|
32
|
-
stub_env('FIRST_KEY', 'value')
|
33
|
-
|
34
|
-
# Block syntax.
|
35
|
-
stub_env('SECOND_KEY') { calculated_value }
|
36
|
-
|
37
|
-
it 'should something' do
|
38
|
-
# Temporarily changes the value, calls the block, and resets the value.
|
39
|
-
stub_env('THIRD_KEY', 'value') do
|
40
|
-
|
41
|
-
end # stub_env
|
42
|
-
end # it
|
43
|
-
end # describe
|
25
|
+
### Features - Functionality
|
44
26
|
|
45
|
-
-
|
46
|
-
|
47
|
-
example_class 'Example::Class::Name' do |klass| ... end
|
48
|
-
|
49
|
-
example_module 'Example::Module::Name' do |mod| ... end
|
27
|
+
- Add spy+matcher for expect(my_object, :my_method).to have_changed ?
|
50
28
|
|
51
|
-
|
29
|
+
### Features - Quality of Life
|
52
30
|
|
31
|
+
- Implement RespondToMatcher#with_optional_keywords, #with_required_keywords.
|
53
32
|
- Implement be_immutable matcher.
|
54
33
|
- Enhance RSpec matcher examples to display the #failure_message on a failed "should pass/fail with" example.
|
55
34
|
- let?(:name) { } # Defines a memoized helper, but only if one is not already defined.
|
56
|
-
|
35
|
+
|
36
|
+
### Features - Syntactic Sugar
|
37
|
+
|
38
|
+
- Implement RespondToMatcher#with_at_least(N).arguments, equivalent to with(N).arguments.and_unlimited_arguments.
|
57
39
|
|
58
40
|
### Maintenance
|
59
41
|
|
42
|
+
- Update all Concerns to be #include-d, not #extend-ed.
|
43
|
+
- Update SharedExampleGroup concern to use Ruby paradigms:
|
44
|
+
- overload #include_examples
|
45
|
+
- use proper method-based lookup, inheritance, etc
|
46
|
+
- less fragility than hooking into existing RSpec internals
|
60
47
|
- Revisit failure messages for #respond_to, #be_constructible - see #received/#have_received for example?
|
61
48
|
- Revisit how matchers are documented, particularly in README.md
|
62
49
|
- Use matcher class name instead of macro names?
|
63
50
|
- Clarify documentation of parameters - YARD-like?
|
51
|
+
- Integration specs for shared example groups
|
52
|
+
- Run in external process, parse output for expected values (similar to Aruba)
|
53
|
+
- Allows testing of failing example groups
|
64
54
|
- Pare down Cucumber features for matchers - repurpose as documentation/examples only.
|
65
55
|
- Break down into smaller (bite-sized?) individual examples.
|
66
56
|
- RuboCop - use RSpec rule file as starting point?
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ A collection of matchers and extensions to ease TDD/BDD using RSpec. Extends bui
|
|
4
4
|
|
5
5
|
## Support
|
6
6
|
|
7
|
-
RSpec::SleepingKingStudios is tested against RSpec 3.
|
7
|
+
RSpec::SleepingKingStudios is tested against RSpec 3.3 through 3.6.
|
8
8
|
|
9
9
|
Currently, the following versions of Ruby are officially supported:
|
10
10
|
|
@@ -14,7 +14,7 @@ Currently, the following versions of Ruby are officially supported:
|
|
14
14
|
|
15
15
|
For Ruby 2.0 support, use version 2.1 or earlier: `gem "rspec-sleeping_king_studios", "~> 2.1.1"`.
|
16
16
|
|
17
|
-
For RSpec 3.0 to 3.2 support, use version 2.2 or earlier: `gem "rspec-sleeping_king_studios", "~> 2.2.
|
17
|
+
For RSpec 3.0 to 3.2 support, use version 2.2 or earlier: `gem "rspec-sleeping_king_studios", "~> 2.2.2"`.
|
18
18
|
|
19
19
|
If you require a previous version of Ruby or RSpec, the 1.0 branch supports Ruby 1.9.3 and RSpec 2: `gem "rspec-sleeping_king_studios", "~> 1.0.1"`. However, changes from 2.0 and higher will not be backported.
|
20
20
|
|
@@ -98,12 +98,55 @@ This option is used with the HavePredicateMatcher (see `#have_predicate`, below)
|
|
98
98
|
|
99
99
|
RSpec::SleepingKingStudios defines a few concerns that can be included in or extended into modules or example groups for additional functionality.
|
100
100
|
|
101
|
+
### Example Constants
|
102
|
+
|
103
|
+
require 'rspec/sleeping_king_studios/concerns/example_constants'
|
104
|
+
|
105
|
+
RSpec.describe 'constants' do
|
106
|
+
extend RSpec::SleepingKingStudios::Concerns::ExampleConstants
|
107
|
+
|
108
|
+
example_constant 'THE_ANSWER', 42
|
109
|
+
|
110
|
+
example_class 'Spec::Examples::Question' do |klass|
|
111
|
+
klass.send :define_method, :answer, THE_ANSWER
|
112
|
+
end # example_class
|
113
|
+
|
114
|
+
let(:described_class) { Spec::Examples::Question }
|
115
|
+
let(:instance) { described_class.new }
|
116
|
+
|
117
|
+
it { expect(described_class.name).to be == 'Spec::Examples::Question' }
|
118
|
+
|
119
|
+
it { expect(instance.answer).to be THE_ANSWER }
|
120
|
+
end # describe
|
121
|
+
|
122
|
+
Provides a programmatic way to define temporary constants and classes scoped to the current example.
|
123
|
+
|
124
|
+
#### `::example_constant`
|
125
|
+
|
126
|
+
`param constant_name [String, Symbol]` The name of the constant. Can be a qualified name separated by :: (e.g. `'Spec::Examples::Question'`), in which case any missing modules will be temporarily set as well.
|
127
|
+
|
128
|
+
`param constant_value` Defaults to nil. If the constant value is not set and a block is given, the block will be executed in the context of the example (so previously-set constants will be available, as well as example features such as the values of `let` blocks) and the value of the constant will be set to the result of the block call.
|
129
|
+
|
130
|
+
`option force [Boolean]` Defaults to false. If the constant is already defined, trying to set the constant value will raise an error unless the force option is set to true.
|
131
|
+
|
132
|
+
Sets the value of the named constant to the specified value within the context of the current example.
|
133
|
+
|
134
|
+
#### `::example_class`
|
135
|
+
|
136
|
+
`param constant_name [String, Symbol]` The name of the constant. Can be a qualified name separated by :: (e.g. `'Spec::Examples::Question'`), in which case any missing modules will be temporarily set as well.
|
137
|
+
|
138
|
+
`option base_class [Class]` Defaults to Object. The base class of the generated class.
|
139
|
+
|
140
|
+
`yield klass [Class]` If a block is given, it is executed in the context of the generated class and yielded the class.
|
141
|
+
|
142
|
+
Creates a new class with the specified base class and sets the value of the named constant to the created class within the context of the current example.
|
143
|
+
|
101
144
|
### Focus Examples
|
102
145
|
|
103
146
|
require 'rspec/sleeping_king_studios/concerns/focus_examples'
|
104
147
|
|
105
148
|
RSpec.describe String do
|
106
|
-
extend RSpec::SleepingKingStudios::Concerns::
|
149
|
+
extend RSpec::SleepingKingStudios::Concerns::FocusExamples
|
107
150
|
|
108
151
|
shared_examples 'should be a greeting' do
|
109
152
|
it { expect(salutation).to be =~ /greeting/i }
|
@@ -160,6 +203,74 @@ Utility functions for defining shared examples. If included in a module, any sha
|
|
160
203
|
|
161
204
|
(also `::shared_context`) 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.
|
162
205
|
|
206
|
+
### Toolbelt
|
207
|
+
|
208
|
+
require 'rspec/sleeping_king_studios/concerns/toolbelt'
|
209
|
+
|
210
|
+
RSpec.describe "a String" do
|
211
|
+
include RSpec::SleepingKingStudios::Concerns::Toolbelt
|
212
|
+
|
213
|
+
shared_examples 'should process' do |string|
|
214
|
+
singular = tools.string.singularize(string)
|
215
|
+
plural = tools.string.pluralize(string)
|
216
|
+
|
217
|
+
it "should singularize #{string} to #{singular}" do
|
218
|
+
expect(tools.singularize string).to be_a String
|
219
|
+
end # it
|
220
|
+
|
221
|
+
it "should pluralize #{string} to #{plural}" do
|
222
|
+
expect(tools.pluralize string).to be_a String
|
223
|
+
end # it
|
224
|
+
end # shared_examples
|
225
|
+
|
226
|
+
include_examples 'should pluralize', 'light'
|
227
|
+
end # describe
|
228
|
+
|
229
|
+
A helper module for exposing SleepingKingStudios::Tools methods in examples and example groups.
|
230
|
+
|
231
|
+
### Wrap Environment
|
232
|
+
|
233
|
+
require 'rspec/sleeping_king_studios/concerns/wrap_env'
|
234
|
+
|
235
|
+
RSpec.describe 'environment' do
|
236
|
+
include RSpec::SleepingKingStudios::Concerns::WrapEnv
|
237
|
+
|
238
|
+
it { expect(ENV['VAR_NAME']).to be nil }
|
239
|
+
|
240
|
+
context 'when the variable is set in the example group' do
|
241
|
+
wrap_env 'VAR_NAME', 'custom_value'
|
242
|
+
|
243
|
+
it { expect(ENV['VAR_NAME']).to be == 'custom_value' }
|
244
|
+
end # context
|
245
|
+
|
246
|
+
context 'when the variable is set in the example group with a block' do
|
247
|
+
let(:calculated_value) { 'calculated_value' }
|
248
|
+
|
249
|
+
wrap_env('VAR_NAME') { calculated_value }
|
250
|
+
|
251
|
+
it { expect(ENV['VAR_NAME']).to be == calculated_value }
|
252
|
+
end # context
|
253
|
+
|
254
|
+
context 'when the variable is set inside an example' do
|
255
|
+
it 'should set the variable' do
|
256
|
+
expect(ENV['VAR_NAME']).to be nil
|
257
|
+
|
258
|
+
begin
|
259
|
+
wrap_env('VAR_NAME', 'new_value') do
|
260
|
+
expect(ENV['VAR_NAME']).to be == 'new_value'
|
261
|
+
|
262
|
+
raise RuntimeError, 'must handle errors and reset the var'
|
263
|
+
end # wrap_env
|
264
|
+
rescue RuntimeError
|
265
|
+
end # begin-rescue
|
266
|
+
|
267
|
+
expect(ENV['VAR_NAME']).to be nil
|
268
|
+
end # it
|
269
|
+
end # context
|
270
|
+
end # describe
|
271
|
+
|
272
|
+
Provides helper methods for temporarily overwriting values in the environment, which are safely and automatically reset after the example or block.
|
273
|
+
|
163
274
|
### Wrap Examples
|
164
275
|
|
165
276
|
require 'rspec/sleeping_king_studios/concerns/wrap_examples'
|
@@ -446,7 +557,13 @@ Checks if the actual object responds to `#property` and `#property=`, and option
|
|
446
557
|
|
447
558
|
expect(instance).to have_property(:foo).with("foo")
|
448
559
|
|
449
|
-
|
560
|
+
expect(instance).to have_property(:foo, :allow_private => true).with("foo")
|
561
|
+
|
562
|
+
**Parameters:**
|
563
|
+
|
564
|
+
`param property [String, Symbol]` The name of the property.
|
565
|
+
|
566
|
+
`option allow_private [Boolean]` Defaults to false. If true, the matcher will also match a private or protected reader or writer method.
|
450
567
|
|
451
568
|
**Chaining:**
|
452
569
|
|
@@ -458,19 +575,23 @@ Checks if the actual object responds to `#property` and `#property=`, and option
|
|
458
575
|
|
459
576
|
require 'rspec/sleeping_king_studios/matchers/core/have_reader'
|
460
577
|
|
461
|
-
Checks if the actual object responds to `#property
|
578
|
+
Checks if the actual object responds to `#property` with 0 arguments, and optionally if the current value of `actual.property()` is equal to a specified value.
|
462
579
|
|
463
580
|
**How To Use:**
|
464
581
|
|
465
582
|
expect(instance).to have_reader(:foo).with("foo")
|
466
583
|
|
467
|
-
|
584
|
+
expect(instance).to have_reader(:foo, :allow_private => true).with("foo")
|
468
585
|
|
469
|
-
**
|
586
|
+
**Parameters:**
|
470
587
|
|
471
|
-
|
588
|
+
`param property [String, Symbol]` The name of the reader method.
|
589
|
+
|
590
|
+
`option allow_private [Boolean]` Defaults to false. If true, the matcher will also match a private or protected method.
|
591
|
+
|
592
|
+
**Chaining:**
|
472
593
|
|
473
|
-
|
594
|
+
* **`#with`:** (also `#with_value`) 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: `expect(instance).to have_reader(:bar).with(an_instance_of(String))`
|
474
595
|
|
475
596
|
#### `#have_writer` Matcher
|
476
597
|
|
@@ -482,7 +603,13 @@ Checks if the actual object responds to `#property=`.
|
|
482
603
|
|
483
604
|
expect(instance).to have_writer(:foo=)
|
484
605
|
|
485
|
-
|
606
|
+
expect(instance).to have_writer(:foo=, :allow_private => true)
|
607
|
+
|
608
|
+
**Parameters:**
|
609
|
+
|
610
|
+
`param property [String, Symbol]` The name of the writer method. An equals sign '=' is automatically added if the identifier does not already terminate in '='.
|
611
|
+
|
612
|
+
`option allow_private [Boolean]` Defaults to false. If true, the matcher will also match a private or protected method.
|
486
613
|
|
487
614
|
## Shared Examples
|
488
615
|
|
@@ -512,6 +639,32 @@ These examples are shorthand for defining a property expectation.
|
|
512
639
|
# You can use the custom shared examples here.
|
513
640
|
end # describe
|
514
641
|
|
642
|
+
#### Should Have Class Property
|
643
|
+
|
644
|
+
include_examples 'should have class property', :foo, 42
|
645
|
+
|
646
|
+
Delegates to the `#have_property` matcher (see Core/#have\_property, above) and passes if `described_class` responds to the specified reader and writer methods. If a value is specified, the described class 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:
|
647
|
+
|
648
|
+
include_examples 'should have class property', :bar, ->() { an_instance_of(String) }
|
649
|
+
|
650
|
+
include_examples 'should have class property', :baz, ->(value) { value.count = 3 }
|
651
|
+
|
652
|
+
#### Should Have Class Reader
|
653
|
+
|
654
|
+
include_examples 'should have class reader', :foo, 42
|
655
|
+
|
656
|
+
Delegates to the `#have_reader` matcher (see Core/#have_reader, above) and passes if `described_class` responds to the specified property reader. If a value is specified, the described class 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:
|
657
|
+
|
658
|
+
include_examples 'should have class reader', :bar, ->() { an_instance_of(String) }
|
659
|
+
|
660
|
+
include_examples 'should have class reader', :baz, ->(value) { value.count = 3 }
|
661
|
+
|
662
|
+
#### Should Have Class Writer
|
663
|
+
|
664
|
+
include_examples 'should have class writer', :foo=
|
665
|
+
|
666
|
+
Delegates to the `#have_writer` matcher (see Core/#have_writer, above) and passes if `described_class` responds to the specified property writer.
|
667
|
+
|
515
668
|
#### Should Have Constant
|
516
669
|
|
517
670
|
include_examples 'should have constant', :FOO, 42
|
@@ -550,6 +703,20 @@ Delegates to the `#have_property` matcher (see Core/#have\_property, above) and
|
|
550
703
|
|
551
704
|
include_examples 'should have property', :baz, ->(value) { value.count = 3 }
|
552
705
|
|
706
|
+
You can also set the :allow_private option to allow the examples to match a private reader and/or writer method:
|
707
|
+
|
708
|
+
include_examples 'should have property', :foo, :allow_private => true
|
709
|
+
|
710
|
+
include_examples 'should have property', :foo, 42, :allow_private => true
|
711
|
+
|
712
|
+
#### Should Have Private Property
|
713
|
+
|
714
|
+
include_examples 'should have private property', :foo
|
715
|
+
|
716
|
+
include_examples 'should have private property', :foo, 42
|
717
|
+
|
718
|
+
Passes if the actual object has the specified private or protected property reader and writer, and fails if the actual object does not have the specified reader and writer or if the specified reader or writer is a public method. If a value is specified, the value of the private reader must match the specified value.
|
719
|
+
|
553
720
|
#### Should Have Reader
|
554
721
|
|
555
722
|
include_examples 'should have reader', :foo, 42
|
@@ -560,24 +727,48 @@ Delegates to the `#have_reader` matcher (see Core/#have_reader, above) and passe
|
|
560
727
|
|
561
728
|
include_examples 'should have reader', :baz, ->(value) { value.count = 3 }
|
562
729
|
|
730
|
+
You can also set the :allow_private option to allow the examples to match a private reader method:
|
731
|
+
|
732
|
+
include_examples 'should have reader', :foo, :allow_private => true
|
733
|
+
|
734
|
+
include_examples 'should have reader', :foo, 42, :allow_private => true
|
735
|
+
|
563
736
|
#### Should Not Have Reader
|
564
737
|
|
565
738
|
include_examples 'should not have reader', :foo
|
566
739
|
|
567
740
|
Delegates to the `#have_reader` matcher (see Core/#have_reader, above) and passes if the actual object does not respond to to the specified property reader.
|
568
741
|
|
742
|
+
#### Should Have Private Reader
|
743
|
+
|
744
|
+
include_examples 'should have private reader', :foo
|
745
|
+
|
746
|
+
include_examples 'should have private reader', :foo, 42
|
747
|
+
|
748
|
+
Passes if the actual object has the specified private or protected property reader, and fails if the actual object does not have the specified reader or if the specified reader is a public method. If a value is specified, the value of the private reader must match the specified value.
|
749
|
+
|
569
750
|
#### Should Have Writer
|
570
751
|
|
571
752
|
include_examples 'should have writer', :foo=
|
572
753
|
|
573
754
|
Delegates to the `#have_writer` matcher (see Core/#have_writer, above) and passes if the actual object responds to the specified property writer.
|
574
755
|
|
756
|
+
You can also set the :allow_private option to allow the examples to match a private writer method:
|
757
|
+
|
758
|
+
include_examples 'should have writer', :foo=, :allow_private => true
|
759
|
+
|
575
760
|
#### Should Not Have Writer
|
576
761
|
|
577
762
|
include_examples 'should not have writer', :foo=
|
578
763
|
|
579
764
|
Delegates to the `#have_writer` matcher (see Core/#have_writer, above) and passes if the actual object does not respond to to the specified property writer.
|
580
765
|
|
766
|
+
#### Should Have Private Writer
|
767
|
+
|
768
|
+
include_examples 'should have private writer', :foo=
|
769
|
+
|
770
|
+
Passes if the actual object has the specified private or protected property writer, and fails if the actual object does not have the specified writer or if the specified writer is a public method.
|
771
|
+
|
581
772
|
### RSpec Matcher Examples
|
582
773
|
|
583
774
|
These examples are used for validating custom RSpec matchers. They are used
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# lib/rspec/sleeping_king_studios/concerns/example_constants.rb
|
2
|
+
|
3
|
+
require 'rspec/sleeping_king_studios/concerns'
|
4
|
+
|
5
|
+
module RSpec::SleepingKingStudios::Concerns
|
6
|
+
module ExampleConstants
|
7
|
+
DEFAULT_VALUE = Object.new.freeze
|
8
|
+
private_constant :DEFAULT_VALUE
|
9
|
+
|
10
|
+
def self.assign_constant namespace, constant_name, constant_value
|
11
|
+
prior_value = DEFAULT_VALUE
|
12
|
+
|
13
|
+
if namespace.const_defined?(constant_name)
|
14
|
+
prior_value = namespace.const_get(constant_name)
|
15
|
+
end # if
|
16
|
+
|
17
|
+
namespace.const_set(constant_name, constant_value)
|
18
|
+
|
19
|
+
yield
|
20
|
+
ensure
|
21
|
+
if prior_value == DEFAULT_VALUE
|
22
|
+
namespace.send :remove_const, constant_name
|
23
|
+
else
|
24
|
+
namespace.const_set(constant_name, prior_value)
|
25
|
+
end # if-else
|
26
|
+
end # class method assign_constant
|
27
|
+
|
28
|
+
def self.guard_existing_constant! namespace, constant_name
|
29
|
+
return unless namespace.const_defined?(constant_name)
|
30
|
+
|
31
|
+
message =
|
32
|
+
"constant #{constant_name} is already defined with value "\
|
33
|
+
"#{namespace.const_get(constant_name).inspect}"
|
34
|
+
|
35
|
+
raise NameError, message
|
36
|
+
end # class method guard_existing_constant!
|
37
|
+
|
38
|
+
def self.resolve_namespace module_names
|
39
|
+
last_defined = nil
|
40
|
+
|
41
|
+
resolved =
|
42
|
+
module_names.reduce(Object) do |ns, module_name|
|
43
|
+
next ns.const_get(module_name) if ns.const_defined?(module_name)
|
44
|
+
|
45
|
+
last_defined ||= { :namespace => ns, :module_name => module_name }
|
46
|
+
|
47
|
+
ns.const_set(module_name, Module.new)
|
48
|
+
end # reduce
|
49
|
+
|
50
|
+
yield resolved
|
51
|
+
ensure
|
52
|
+
if last_defined
|
53
|
+
last_defined[:namespace].send(:remove_const, last_defined[:module_name])
|
54
|
+
end # if
|
55
|
+
end # class method resolve_namespace
|
56
|
+
|
57
|
+
def example_class class_name, base_class: Object, &block
|
58
|
+
example_constant(class_name) do
|
59
|
+
base_class = Object.const_get(base_class) if base_class.is_a?(String)
|
60
|
+
klass = Class.new(base_class)
|
61
|
+
|
62
|
+
klass.define_singleton_method(:name) { class_name }
|
63
|
+
klass.singleton_class.send(:alias_method, :inspect, :name)
|
64
|
+
klass.singleton_class.send(:alias_method, :to_s, :name)
|
65
|
+
|
66
|
+
klass.instance_exec(klass, &block) if block_given?
|
67
|
+
|
68
|
+
klass
|
69
|
+
end # example_constant
|
70
|
+
end # method example_class
|
71
|
+
|
72
|
+
def example_constant qualified_name, constant_value = DEFAULT_VALUE, force: false, &block
|
73
|
+
around(:example) do |example|
|
74
|
+
resolved_value =
|
75
|
+
if constant_value == DEFAULT_VALUE
|
76
|
+
block ? example.instance_exec(&block) : nil
|
77
|
+
else
|
78
|
+
constant_value
|
79
|
+
end # if
|
80
|
+
|
81
|
+
module_names = qualified_name.to_s.split('::')
|
82
|
+
constant_name = module_names.pop
|
83
|
+
|
84
|
+
ExampleConstants.resolve_namespace(module_names) do |namespace|
|
85
|
+
ExampleConstants.guard_existing_constant!(namespace, constant_name) unless force
|
86
|
+
|
87
|
+
ExampleConstants.assign_constant(namespace, constant_name, resolved_value) do
|
88
|
+
example.call
|
89
|
+
end # assign_constant
|
90
|
+
end # resolve_namespace
|
91
|
+
end # before example
|
92
|
+
end # method example_constant
|
93
|
+
end # module
|
94
|
+
end # module
|
@@ -8,7 +8,7 @@ module RSpec::SleepingKingStudios::Concerns
|
|
8
8
|
#
|
9
9
|
# @example
|
10
10
|
# module MySharedExamples
|
11
|
-
# extend
|
11
|
+
# extend RSpec::SleepingKingStudios::Concerns::SharedExampleGroup
|
12
12
|
#
|
13
13
|
# shared_examples 'my examples' do
|
14
14
|
# # Define shared examples here.
|
@@ -48,6 +48,8 @@ module RSpec::SleepingKingStudios::Concerns
|
|
48
48
|
#
|
49
49
|
# Hook to merge defined example groups when included in another module.
|
50
50
|
def included other
|
51
|
+
super
|
52
|
+
|
51
53
|
merge_shared_example_groups other
|
52
54
|
end # method included
|
53
55
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# lib/rspec/sleeping_king_studios/concerns/toolbelt.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools/toolbox/mixin'
|
4
|
+
|
5
|
+
require 'rspec/sleeping_king_studios/concerns'
|
6
|
+
|
7
|
+
module RSpec::SleepingKingStudios::Concerns
|
8
|
+
# Defines ::tools and #tools methods for example groups and examples, exposing
|
9
|
+
# an instance of SleepingKingStudios::Tools::Toolbelt.
|
10
|
+
module Toolbelt
|
11
|
+
extend SleepingKingStudios::Tools::Toolbox::Mixin
|
12
|
+
|
13
|
+
# Class methods to define when including
|
14
|
+
# RSpec::SleepingKingStudios::Concerns::Toolbelt in a class.
|
15
|
+
module ClassMethods
|
16
|
+
def tools
|
17
|
+
@tools ||= SleepingKingStudios::Tools::Toolbelt.instance
|
18
|
+
end # class method tools
|
19
|
+
end # module
|
20
|
+
|
21
|
+
def tools
|
22
|
+
@tools ||= self.class.tools
|
23
|
+
end # method tools
|
24
|
+
end # module
|
25
|
+
end # module
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# lib/rspec/sleeping_king_studios/concerns/wrap_env.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools/toolbox/mixin'
|
4
|
+
|
5
|
+
require 'rspec/sleeping_king_studios/concerns'
|
6
|
+
|
7
|
+
module RSpec::SleepingKingStudios::Concerns
|
8
|
+
# Methods for temporarily overwriting values in the environment, which are
|
9
|
+
# safely and automatically reset after the block or example.
|
10
|
+
module WrapEnv
|
11
|
+
extend SleepingKingStudios::Tools::Toolbox::Mixin
|
12
|
+
|
13
|
+
# Class methods to define when including
|
14
|
+
# RSpec::SleepingKingStudios::Concerns::WrapEnv in a class.
|
15
|
+
module ClassMethods
|
16
|
+
def wrap_env key, value = nil, &block
|
17
|
+
around(:example) do |wrapped_example|
|
18
|
+
begin
|
19
|
+
if block_given?
|
20
|
+
example = wrapped_example.example
|
21
|
+
value = example.instance_exec(&block)
|
22
|
+
end # if
|
23
|
+
|
24
|
+
prior_value = ENV[key]
|
25
|
+
ENV[key] = value
|
26
|
+
|
27
|
+
wrapped_example.call
|
28
|
+
ensure
|
29
|
+
ENV[key] = prior_value
|
30
|
+
end # begin-ensure
|
31
|
+
end # around example
|
32
|
+
end # class method wrap_env
|
33
|
+
alias_method :stub_env, :wrap_env
|
34
|
+
end # module
|
35
|
+
|
36
|
+
def wrap_env key, value
|
37
|
+
prior_value = ENV[key]
|
38
|
+
ENV[key] = value
|
39
|
+
|
40
|
+
yield
|
41
|
+
ensure
|
42
|
+
ENV[key] = prior_value
|
43
|
+
end # method wrap_env
|
44
|
+
alias_method :stub_env, :wrap_env
|
45
|
+
end # module
|
46
|
+
end # module
|