delegate_matcher 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +23 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +87 -0
- data/LICENSE.txt +22 -0
- data/README.md +237 -0
- data/Rakefile +8 -0
- data/delegate_matcher.gemspec +29 -0
- data/lib/delegate_matcher/delegate_matcher.rb +281 -0
- data/lib/delegate_matcher/version.rb +3 -0
- data/lib/delegate_matcher.rb +2 -0
- data/spec/lib/active_support_delegation_spec.rb +53 -0
- data/spec/lib/delegate_matcher_spec.rb +472 -0
- data/spec/lib/forwardable_delegation_spec.rb +36 -0
- data/spec/spec_helper.rb +25 -0
- metadata +161 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0ec0997475eaaee1d410562d34021316d878821a
|
4
|
+
data.tar.gz: ec92634564aabfac3448516ba0cdfd16051df08b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 51ffc33cf2e980067e1647af487efc778ba776e5224e651d02a4d46edb6abdb7b071da44465847e8222eff8f77dd1aea1428837cd324c8c30e40821cc6cb2856
|
7
|
+
data.tar.gz: a5e1996cf241039408c03f2e3ffd69e132aeb563ecc9e684b5df2d889d30c586d4814be6f0a69711fc1bca6b736a8683d390d3611a100437c3217d45c2dc6f44
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Metrics/LineLength:
|
2
|
+
Max: 160
|
3
|
+
|
4
|
+
Metrics/CyclomaticComplexity:
|
5
|
+
Max: 10
|
6
|
+
|
7
|
+
Metrics/MethodLength:
|
8
|
+
Max: 15
|
9
|
+
|
10
|
+
Style/SingleSpaceBeforeFirstArg:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Style/ExtraSpacing:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
Style/Documentation:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Style/Semicolon:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Lint/Eval:
|
23
|
+
Enabled: false
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
delegate_matcher (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activesupport (4.2.3)
|
10
|
+
i18n (~> 0.7)
|
11
|
+
json (~> 1.7, >= 1.7.7)
|
12
|
+
minitest (~> 5.1)
|
13
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
14
|
+
tzinfo (~> 1.1)
|
15
|
+
ast (2.1.0)
|
16
|
+
astrolabe (1.3.1)
|
17
|
+
parser (~> 2.2)
|
18
|
+
coveralls (0.7.2)
|
19
|
+
multi_json (~> 1.3)
|
20
|
+
rest-client (= 1.6.7)
|
21
|
+
simplecov (>= 0.7)
|
22
|
+
term-ansicolor (= 1.2.2)
|
23
|
+
thor (= 0.18.1)
|
24
|
+
diff-lcs (1.2.5)
|
25
|
+
docile (1.1.5)
|
26
|
+
i18n (0.7.0)
|
27
|
+
json (1.8.3)
|
28
|
+
mime-types (2.4.3)
|
29
|
+
minitest (5.7.0)
|
30
|
+
multi_json (1.10.1)
|
31
|
+
parser (2.2.2.6)
|
32
|
+
ast (>= 1.1, < 3.0)
|
33
|
+
powerpack (0.1.1)
|
34
|
+
rainbow (2.0.0)
|
35
|
+
rest-client (1.6.7)
|
36
|
+
mime-types (>= 1.16)
|
37
|
+
rspec (3.3.0)
|
38
|
+
rspec-core (~> 3.3.0)
|
39
|
+
rspec-expectations (~> 3.3.0)
|
40
|
+
rspec-mocks (~> 3.3.0)
|
41
|
+
rspec-core (3.3.2)
|
42
|
+
rspec-support (~> 3.3.0)
|
43
|
+
rspec-expectations (3.3.1)
|
44
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
45
|
+
rspec-support (~> 3.3.0)
|
46
|
+
rspec-its (1.1.0)
|
47
|
+
rspec-core (>= 3.0.0)
|
48
|
+
rspec-expectations (>= 3.0.0)
|
49
|
+
rspec-mocks (3.3.2)
|
50
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
51
|
+
rspec-support (~> 3.3.0)
|
52
|
+
rspec-support (3.3.0)
|
53
|
+
rubocop (0.33.0)
|
54
|
+
astrolabe (~> 1.3)
|
55
|
+
parser (>= 2.2.2.5, < 3.0)
|
56
|
+
powerpack (~> 0.1)
|
57
|
+
rainbow (>= 1.99.1, < 3.0)
|
58
|
+
ruby-progressbar (~> 1.4)
|
59
|
+
ruby-progressbar (1.7.5)
|
60
|
+
simplecov (0.9.1)
|
61
|
+
docile (~> 1.1.0)
|
62
|
+
multi_json (~> 1.0)
|
63
|
+
simplecov-html (~> 0.8.0)
|
64
|
+
simplecov-html (0.8.0)
|
65
|
+
term-ansicolor (1.2.2)
|
66
|
+
tins (~> 0.8)
|
67
|
+
thor (0.18.1)
|
68
|
+
thread_safe (0.3.5)
|
69
|
+
tins (0.13.2)
|
70
|
+
tzinfo (1.2.2)
|
71
|
+
thread_safe (~> 0.1)
|
72
|
+
|
73
|
+
PLATFORMS
|
74
|
+
ruby
|
75
|
+
|
76
|
+
DEPENDENCIES
|
77
|
+
activesupport (~> 4.2)
|
78
|
+
bundler (~> 1.7)
|
79
|
+
coveralls (~> 0.7)
|
80
|
+
delegate_matcher!
|
81
|
+
rspec (~> 3.0)
|
82
|
+
rspec-its (~> 1.1)
|
83
|
+
rubocop (~> 0.30)
|
84
|
+
simplecov (~> 0.9)
|
85
|
+
|
86
|
+
BUNDLED WITH
|
87
|
+
1.10.6
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Declan Whelan
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
# Delegate Matcher
|
2
|
+
|
3
|
+
An RSpec matcher for validating delegation. This matcher works with delegation based on the [Forwardable](http://ruby-doc.org/stdlib-2.0.0/libdoc/forwardable/rdoc/Forwardable.html) module,
|
4
|
+
the [delegate](http://api.rubyonrails.org/classes/Module.html#method-i-delegate) method in the Active Support gem or with
|
5
|
+
simple custom delegation.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'delegate_matcher'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
$ bundle
|
19
|
+
```
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
```bash
|
24
|
+
$ gem install delegate_matcher
|
25
|
+
```
|
26
|
+
|
27
|
+
Then add the following to your ```spec_helper.rb``` file:
|
28
|
+
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'delegate_matcher'
|
32
|
+
```
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
This matcher allows you to validate delegation to:
|
37
|
+
* instance methods
|
38
|
+
* class methods
|
39
|
+
* instance variables
|
40
|
+
* class variables
|
41
|
+
* constants
|
42
|
+
* arbitrary objects
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
describe Post do
|
46
|
+
it { should delegate(:name).to(:author) } # name => author().name instance method
|
47
|
+
it { should delegate(:name).to(:class)) } # name => self.class.name class method
|
48
|
+
it { should delegate(:name).to(:@author) } # name => @author.name instance variable
|
49
|
+
it { should delegate(:name).to(:@@author) } # name => @@author.name class variable
|
50
|
+
it { should delegate(:first).to(:GENRES) } # first => GENRES.first constant
|
51
|
+
it { should delegate(:name).to(author) } # name => author.name object
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
### Delegate Method Name
|
56
|
+
|
57
|
+
If the name of the method being invoked on the delegate is different from the method being called you
|
58
|
+
can check this using the ```with_prefix``` method (based on Active Support ```delegate``` method) or the
|
59
|
+
```as``` method.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
describe Post do
|
63
|
+
it { should delegate(:name).to(author).with_prefix } # author_name => author.name
|
64
|
+
it { should delegate(:name).to(author).with_prefix(:writer) } # writer_name => author.name
|
65
|
+
it { should delegate(:writer).to(author).as(:name) } # writer => author.name
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
### Handling Nil Delegates
|
70
|
+
|
71
|
+
If you expect the delegate to return ```nil``` when the delegate is ```nil``` rather than raising an error
|
72
|
+
then you can check this using the ```allow_nil``` method.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
describe Post do
|
76
|
+
it { should delegate(:name).to(:author).allow_nil } # name => author && author.name
|
77
|
+
it { should delegate(:name).to(:author).allow_nil(true) } # name => author && author.name
|
78
|
+
it { should delegate(:name).to(:author).allow_nil(false) } # name => author.name
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Nil handling is only checked if ```allow_nil``` is specified.
|
83
|
+
|
84
|
+
Note that matcher will raise an error if you use this when checking delegation to a constant or an
|
85
|
+
object since the matcher cannot validate ```nil``` handling in these cases.
|
86
|
+
|
87
|
+
### Arguments
|
88
|
+
|
89
|
+
If the method being delegated takes arguments then you can supply them with the ```with``` method. The matcher
|
90
|
+
will ensure that the provided arguments are in turn passed to the delegate.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
describe Post do
|
94
|
+
it { should delegate(:name).with('Ms.')to(:author) } # name('Ms.') => author.name('Ms.')
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
Also, in some cases the delegator might make minor changes to the arguments. While this is arguably no
|
99
|
+
longer true delegation you can still check that arguments are correctly passed by using a second ```with```
|
100
|
+
method to specify the arguments expected by the delegate.
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
describe Post do
|
104
|
+
it { should delegate(:name).with('Ms.')to(author).with('Miss') } # name('Ms.') => author.name('Miss')
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
### Blocks
|
109
|
+
|
110
|
+
You can check that a block passed is in turn passed to the delegate via the ```with_block``` method.
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
describe Post do
|
114
|
+
it { should delegate(:name).to(author).with_a_block } # name(&block) => author.name(&block)
|
115
|
+
it { should delegate(:name).to(author).with_block } # name(&block) => author.name(&block) alias for with_a_block
|
116
|
+
|
117
|
+
it { should delegate(:name).to(author).without_a_block } # name(&block) => author.name
|
118
|
+
it { should delegate(:name).to(author).without_block } # name(&block) => author.name alias for without_a_block
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
By default, block delegated is only check if ```with_a_block``` or ```without_a_block``` is specified.
|
123
|
+
|
124
|
+
### Active Support
|
125
|
+
|
126
|
+
You can test delegation based on the [delegate](http://api.rubyonrails.org/classes/Module.html#method-i-delegate) method in the Active Support gem.
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
class Post
|
130
|
+
attr_accessor :author
|
131
|
+
|
132
|
+
class_variable_set(:@@authors, ['Ann Rand', 'Catherine Asaro'])
|
133
|
+
GENRES ||= ['Fiction', 'Science Fiction']
|
134
|
+
|
135
|
+
delegate :name, to: :author
|
136
|
+
delegate :name, to: :author, prefix: true
|
137
|
+
delegate :name, to: :author, prefix: :writer
|
138
|
+
delegate :name_with_nil_check, to: :author, allow_nil: true
|
139
|
+
delegate :name_with_arg, to: :author
|
140
|
+
delegate :name_with_block, to: :author
|
141
|
+
delegate :count, to: :@@authors
|
142
|
+
delegate :first, to: :GENRES
|
143
|
+
delegate :name, to: :class, prefix: true
|
144
|
+
end
|
145
|
+
|
146
|
+
class Author
|
147
|
+
def name
|
148
|
+
'Catherine Asaro'
|
149
|
+
end
|
150
|
+
|
151
|
+
def name_with_nil_check
|
152
|
+
name
|
153
|
+
end
|
154
|
+
|
155
|
+
def name_with_arg(arg)
|
156
|
+
"#{arg} #{name}"
|
157
|
+
end
|
158
|
+
|
159
|
+
def name_with_block(&block)
|
160
|
+
"#{block.call} #{name}"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe Post do
|
165
|
+
it { should delegate(:name).to(:author) }
|
166
|
+
it { should delegate(:name).to(:@author) }
|
167
|
+
it { should delegate(:name_with_nil_check).to(:author).allow_nil }
|
168
|
+
it { should delegate(:name).to(:author).with_prefix }
|
169
|
+
it { should delegate(:name).to(:author).with_prefix(:writer) }
|
170
|
+
|
171
|
+
it { should delegate(:name_with_arg).to(:author).with('Ms.') }
|
172
|
+
it { should delegate(:name_with_block).to(:author).with_block }
|
173
|
+
it { should delegate(:count).to(:@@authors) }
|
174
|
+
it { should delegate(:first).to(:GENRES) }
|
175
|
+
it { should delegate(:name).to(:class).with_prefix }
|
176
|
+
end
|
177
|
+
```
|
178
|
+
However, don't use the following features as they are not supported by the delegate method:
|
179
|
+
* delegation to objects
|
180
|
+
* different arguments passed to delegate
|
181
|
+
|
182
|
+
### Forwardable Module
|
183
|
+
|
184
|
+
You can test delegation based on the [Forwardable](http://ruby-doc.org/stdlib-2.0.0/libdoc/forwardable/rdoc/Forwardable.html) module.
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
class Post
|
188
|
+
extend Forwardable
|
189
|
+
|
190
|
+
attr_accessor :author
|
191
|
+
|
192
|
+
def_delegator :author, :name
|
193
|
+
def_delegator :author, :name, :writer
|
194
|
+
def_delegator :author, :name_with_arg
|
195
|
+
def_delegator :author, :name_with_block
|
196
|
+
end
|
197
|
+
|
198
|
+
class Author
|
199
|
+
def name
|
200
|
+
'Catherine Asaro'
|
201
|
+
end
|
202
|
+
|
203
|
+
def name_with_arg(arg)
|
204
|
+
"#{arg} #{name}"
|
205
|
+
end
|
206
|
+
|
207
|
+
def name_with_block(&block)
|
208
|
+
"#{block.call} #{name}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe Post do
|
213
|
+
it { should delegate(:name).to(:author) }
|
214
|
+
it { should delegate(:name).to(:@author) }
|
215
|
+
it { should delegate(:writer).to(:author).as(:name) }
|
216
|
+
it { should delegate(:name_with_arg).to(:author).with('Ms.') }
|
217
|
+
it { should delegate(:name_with_block).to(:author).with_block }
|
218
|
+
end
|
219
|
+
```
|
220
|
+
However, don't use the following features as they are not supported by the Forwardable module:
|
221
|
+
* allow_nil
|
222
|
+
* delegation to class variables
|
223
|
+
* delegation to constants
|
224
|
+
* delegation to objects
|
225
|
+
* different arguments passed to delegate
|
226
|
+
|
227
|
+
## Contributing
|
228
|
+
|
229
|
+
1. Fork it ( https://github.com/dwhelan/delegate_matcher/fork )
|
230
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
231
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
232
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
233
|
+
5. Create a new Pull Request
|
234
|
+
|
235
|
+
## Notes
|
236
|
+
|
237
|
+
This matcher was inspired by [Alan Winograd](https://github.com/awinograd) via the gist https://gist.github.com/awinograd/6158961
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'delegate_matcher/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |gem|
|
8
|
+
gem.name = 'delegate_matcher'
|
9
|
+
gem.version = DelegateMatcher::VERSION
|
10
|
+
gem.authors = ['Declan Whelan']
|
11
|
+
gem.email = ['declan@pleanintuit.com']
|
12
|
+
gem.summary = 'A matcher for testing ruby delegation.'
|
13
|
+
gem.description = 'A matcher for testing ruby delegation.'
|
14
|
+
gem.homepage = 'https://github.com/dwhelan/delegate_matcher'
|
15
|
+
gem.license = 'MIT'
|
16
|
+
|
17
|
+
gem.files = `git ls-files -z`.split("\x0")
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
20
|
+
gem.require_paths = ['lib']
|
21
|
+
|
22
|
+
gem.add_development_dependency 'activesupport', '~> 4.2'
|
23
|
+
gem.add_development_dependency 'bundler', '~> 1.7'
|
24
|
+
gem.add_development_dependency 'coveralls', '~> 0.7'
|
25
|
+
gem.add_development_dependency 'rspec', '~> 3.0'
|
26
|
+
gem.add_development_dependency 'rspec-its', '~> 1.1'
|
27
|
+
gem.add_development_dependency 'rubocop', '~> 0.30'
|
28
|
+
gem.add_development_dependency 'simplecov', '~> 0.9'
|
29
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
RSpec::Matchers.define(:delegate) do |method|
|
2
|
+
match do |delegator|
|
3
|
+
fail 'need to provide a "to"' unless delegate
|
4
|
+
|
5
|
+
@method = method
|
6
|
+
@delegator = delegator
|
7
|
+
|
8
|
+
allow_nil_ok? && delegate? && arguments_ok? && block_ok?
|
9
|
+
end
|
10
|
+
|
11
|
+
description do
|
12
|
+
"delegate #{delegator_description} to #{delegate_description}#{nil_description}#{block_description}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure_message
|
16
|
+
message = failure_message_details(false)
|
17
|
+
message.empty? ? super : message
|
18
|
+
end
|
19
|
+
|
20
|
+
def failure_message_when_negated
|
21
|
+
message = failure_message_details(true)
|
22
|
+
message.empty? ? super : message
|
23
|
+
end
|
24
|
+
|
25
|
+
chain(:to) { |delegate| @delegate = delegate }
|
26
|
+
chain(:as) { |delegate_method| @delegate_method = delegate_method }
|
27
|
+
chain(:allow_nil) { |allow_nil = true| @expected_nil_check = allow_nil }
|
28
|
+
chain(:with_prefix) { |prefix = nil| @prefix = prefix || delegate.to_s.sub(/@/, '') }
|
29
|
+
chain(:with) { |*args| @expected_args = args; @args ||= args }
|
30
|
+
chain(:with_a_block) { @expected_block = true }
|
31
|
+
chain(:without_a_block) { @expected_block = false }
|
32
|
+
|
33
|
+
alias_method :with_block, :with_a_block
|
34
|
+
alias_method :without_block, :without_a_block
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :method, :delegator, :delegate, :prefix, :args
|
39
|
+
attr_reader :expected_nil_check, :actual_nil_check
|
40
|
+
attr_reader :expected_args, :actual_args
|
41
|
+
attr_reader :expected_block, :actual_block
|
42
|
+
attr_reader :actual_return_value
|
43
|
+
|
44
|
+
def delegate?(test_delegate = delegate_double)
|
45
|
+
case
|
46
|
+
when delegate_is_a_class_variable?
|
47
|
+
delegate_to_class_variable(test_delegate)
|
48
|
+
when delegate_is_an_instance_variable?
|
49
|
+
delegate_to_instance_variable(test_delegate)
|
50
|
+
when delegate_is_a_constant?
|
51
|
+
delegate_to_constant
|
52
|
+
when delegate_is_a_method?
|
53
|
+
delegate_to_method(test_delegate)
|
54
|
+
else
|
55
|
+
delegate_to_object
|
56
|
+
end
|
57
|
+
|
58
|
+
return_value_ok?
|
59
|
+
end
|
60
|
+
|
61
|
+
def delegate_is_a_class_variable?
|
62
|
+
delegate.to_s.start_with?('@@')
|
63
|
+
end
|
64
|
+
|
65
|
+
def delegate_is_an_instance_variable?
|
66
|
+
delegate.to_s[0] == '@'
|
67
|
+
end
|
68
|
+
|
69
|
+
def delegate_is_a_constant?
|
70
|
+
(delegate.is_a?(String) || delegate.is_a?(Symbol)) && (delegate.to_s =~ /^[A-Z]/)
|
71
|
+
end
|
72
|
+
|
73
|
+
def delegate_is_a_method?
|
74
|
+
delegate.is_a?(String) || delegate.is_a?(Symbol)
|
75
|
+
end
|
76
|
+
|
77
|
+
def delegate_to_class_variable(test_delegate)
|
78
|
+
actual_delegate = delegator.class.class_variable_get(delegate)
|
79
|
+
delegator.class.class_variable_set(delegate, test_delegate)
|
80
|
+
call
|
81
|
+
ensure
|
82
|
+
delegator.class.class_variable_set(delegate, actual_delegate)
|
83
|
+
end
|
84
|
+
|
85
|
+
def delegate_to_instance_variable(test_delegate)
|
86
|
+
actual_delegate = delegator.instance_variable_get(delegate)
|
87
|
+
delegator.instance_variable_set(delegate, test_delegate)
|
88
|
+
call
|
89
|
+
ensure
|
90
|
+
delegator.instance_variable_set(delegate, actual_delegate)
|
91
|
+
end
|
92
|
+
|
93
|
+
def delegate_to_constant
|
94
|
+
ensure_allow_nil_is_not_specified_for('a constant')
|
95
|
+
stub_delegation(delegator.class.const_get(delegate))
|
96
|
+
call
|
97
|
+
end
|
98
|
+
|
99
|
+
def delegate_to_method(test_delegate)
|
100
|
+
ensure_delegate_method_is_valid
|
101
|
+
allow(delegator).to receive(delegate) { test_delegate }
|
102
|
+
call
|
103
|
+
end
|
104
|
+
|
105
|
+
def delegate_to_object
|
106
|
+
ensure_allow_nil_is_not_specified_for('an object')
|
107
|
+
stub_delegation(delegate)
|
108
|
+
call
|
109
|
+
end
|
110
|
+
|
111
|
+
def ensure_allow_nil_is_not_specified_for(target)
|
112
|
+
fail %(cannot verify "allow_nil" expectations when delegating to #{target}) unless expected_nil_check.nil?
|
113
|
+
end
|
114
|
+
|
115
|
+
def ensure_delegate_method_is_valid
|
116
|
+
fail "#{delegator} does not respond to #{delegate}" unless delegator.respond_to?(delegate, true)
|
117
|
+
fail "#{delegator}'s' #{delegate} method expects parameters" unless [0, -1].include?(delegator.method(delegate).arity)
|
118
|
+
end
|
119
|
+
|
120
|
+
def delegator_method
|
121
|
+
@delegator_method || (prefix ? :"#{prefix}_#{method}" : method)
|
122
|
+
end
|
123
|
+
|
124
|
+
def delegate_method
|
125
|
+
@delegate_method || method
|
126
|
+
end
|
127
|
+
|
128
|
+
def call
|
129
|
+
@actual_return_value = delegator.send(delegator_method, *args, &block)
|
130
|
+
end
|
131
|
+
|
132
|
+
def block
|
133
|
+
@block ||= proc {}
|
134
|
+
end
|
135
|
+
|
136
|
+
def delegate_double
|
137
|
+
double('delegate').tap { |delegate| stub_delegation(delegate) }
|
138
|
+
end
|
139
|
+
|
140
|
+
def stub_delegation(delegate)
|
141
|
+
@delegated = false
|
142
|
+
allow(delegate).to(receive(delegate_method)) do |*args, &block|
|
143
|
+
@actual_args = args
|
144
|
+
@actual_block = block
|
145
|
+
@delegated = true
|
146
|
+
expected_return_value
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def expected_return_value
|
151
|
+
self
|
152
|
+
end
|
153
|
+
|
154
|
+
def allow_nil_ok?
|
155
|
+
return true if expected_nil_check.nil?
|
156
|
+
return true unless delegate.is_a?(String) || delegate.is_a?(Symbol)
|
157
|
+
|
158
|
+
begin
|
159
|
+
actual_nil_check = true
|
160
|
+
delegate?(nil)
|
161
|
+
@return_value_when_delegate_nil = actual_return_value
|
162
|
+
rescue NoMethodError
|
163
|
+
actual_nil_check = false
|
164
|
+
end
|
165
|
+
|
166
|
+
expected_nil_check == actual_nil_check && @return_value_when_delegate_nil.nil?
|
167
|
+
end
|
168
|
+
|
169
|
+
def arguments_ok?
|
170
|
+
expected_args.nil? || actual_args.eql?(expected_args)
|
171
|
+
end
|
172
|
+
|
173
|
+
def block_ok?
|
174
|
+
case
|
175
|
+
when expected_block.nil?
|
176
|
+
true
|
177
|
+
when expected_block
|
178
|
+
actual_block == block
|
179
|
+
else
|
180
|
+
actual_block.nil?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def return_value_ok?
|
185
|
+
actual_return_value == expected_return_value
|
186
|
+
end
|
187
|
+
|
188
|
+
def delegator_description
|
189
|
+
"#{delegator_method}#{argument_description(args)}"
|
190
|
+
end
|
191
|
+
|
192
|
+
def delegate_description
|
193
|
+
case
|
194
|
+
when !args.eql?(expected_args)
|
195
|
+
"#{delegate}.#{delegate_method}#{argument_description(expected_args)}"
|
196
|
+
when delegate_method.eql?(delegator_method)
|
197
|
+
"#{delegate}"
|
198
|
+
else
|
199
|
+
"#{delegate}.#{delegate_method}"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def argument_description(args)
|
204
|
+
args ? "(#{args.map { |a| format('%p', a) }.join(', ')})" : ''
|
205
|
+
end
|
206
|
+
|
207
|
+
def nil_description
|
208
|
+
case
|
209
|
+
when expected_nil_check.nil?
|
210
|
+
''
|
211
|
+
when expected_nil_check
|
212
|
+
' with nil allowed'
|
213
|
+
else
|
214
|
+
' with nil not allowed'
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def block_description
|
219
|
+
case
|
220
|
+
when expected_block.nil?
|
221
|
+
''
|
222
|
+
when expected_block
|
223
|
+
' with a block'
|
224
|
+
else
|
225
|
+
' without a block'
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def failure_message_details(negated)
|
230
|
+
[
|
231
|
+
argument_failure_message(negated),
|
232
|
+
block_failure_message(negated),
|
233
|
+
return_value_failure_message(negated),
|
234
|
+
allow_nil_failure_message(negated)
|
235
|
+
].reject(&:empty?).join(' and ')
|
236
|
+
end
|
237
|
+
|
238
|
+
def argument_failure_message(negated)
|
239
|
+
case
|
240
|
+
when expected_args.nil? || negated ^ arguments_ok?
|
241
|
+
''
|
242
|
+
else
|
243
|
+
"was called with #{argument_description(actual_args)}"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def block_failure_message(negated)
|
248
|
+
case
|
249
|
+
when expected_block.nil? || (negated ^ block_ok?)
|
250
|
+
''
|
251
|
+
when negated
|
252
|
+
"a block was #{expected_block ? '' : 'not '}passed"
|
253
|
+
when expected_block
|
254
|
+
actual_block.nil? ? 'a block was not passed' : "a different block #{actual_block} was passed"
|
255
|
+
else
|
256
|
+
'a block was passed'
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def return_value_failure_message(_negated)
|
261
|
+
case
|
262
|
+
when !@delegated || return_value_ok?
|
263
|
+
''
|
264
|
+
else
|
265
|
+
format('a return value of %p was returned instead of the delegate return value', actual_return_value)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def allow_nil_failure_message(negated)
|
270
|
+
case
|
271
|
+
when expected_nil_check.nil? || negated ^ allow_nil_ok?
|
272
|
+
''
|
273
|
+
when !@return_value_when_delegate_nil.nil?
|
274
|
+
'did not return nil'
|
275
|
+
when negated
|
276
|
+
"#{delegate} was #{expected_nil_check ? '' : 'not '}allowed to be nil"
|
277
|
+
else
|
278
|
+
"#{delegate} was #{expected_nil_check ? 'not ' : ''}allowed to be nil"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|