delegate_matcher 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,3 @@
1
+ /.idea/
2
+ /coverage/
3
+ /pkg/
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
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
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,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: [:spec, :rubocop, :build]
@@ -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