delegate_matcher 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|