@@ -168,8 +168,27 @@ module Independent
168
168
# should delegate_method(:plan).to(:subscription).allow_nil
169
169
# end
170
170
#
171
- # @return [DelegateMethodMatcher]
171
+ # ##### with_private
172
+ #
173
+ # Use `with_private` if the delegation accounts for the fact that your
174
+ # delegation is private. (This is mostly intended as an analogue to
175
+ # the `private` option that Rails' `delegate` helper takes.)
176
+ #
177
+ # class Account
178
+ # delegate :plan, to: :subscription, private: true
179
+ # end
180
+ #
181
+ # # RSpec
182
+ # describe Account do
183
+ # it { should delegate_method(:plan).to(:subscription).with_private }
184
+ # end
185
+ #
186
+ # # Minitest
187
+ # class PageTest < Minitest::Test
188
+ # should delegate_method(:plan).to(:subscription).with_private
189
+ # end
172
190
#
191
+ # @return [DelegateMethodMatcher]
173
192
def delegate_method ( delegating_method )
174
193
DelegateMethodMatcher . new ( delegating_method ) . in_context ( self )
175
194
end
@@ -187,6 +206,7 @@ def initialize(delegating_method)
187
206
@delegate_object_reader_method = nil
188
207
@delegated_arguments = [ ]
189
208
@expects_to_allow_nil_delegate_object = false
209
+ @expects_private_delegation = false
190
210
end
191
211
192
212
def in_context ( context )
@@ -202,14 +222,19 @@ def matches?(subject)
202
222
subject_has_delegating_method? &&
203
223
subject_has_delegate_object_reader_method? &&
204
224
subject_delegates_to_delegate_object_correctly? &&
205
- subject_handles_nil_delegate_object?
225
+ subject_handles_nil_delegate_object? &&
226
+ subject_handles_private_delegation?
206
227
end
207
228
208
229
def description
209
230
string =
210
231
"delegate #{ formatted_delegating_method_name } to the " +
211
232
"#{ formatted_delegate_object_reader_method_name } object"
212
233
234
+ if expects_private_delegation?
235
+ string << ' privately'
236
+ end
237
+
213
238
if delegated_arguments . any?
214
239
string << " passing arguments #{ delegated_arguments . inspect } "
215
240
end
@@ -254,6 +279,11 @@ def allow_nil
254
279
self
255
280
end
256
281
282
+ def with_private
283
+ @expects_private_delegation = true
284
+ self
285
+ end
286
+
257
287
def build_delegating_method_prefix ( prefix )
258
288
case prefix
259
289
when true , nil then delegate_object_reader_method
@@ -264,14 +294,19 @@ def build_delegating_method_prefix(prefix)
264
294
def failure_message
265
295
message = "Expected #{ class_under_test } to #{ description } .\n \n "
266
296
267
- if failed_to_allow_nil_delegate_object?
297
+ if failed_to_allow_nil_delegate_object? || failed_to_handle_private_delegation?
268
298
message << formatted_delegating_method_name ( include_module : true )
269
299
message << ' did delegate to '
270
300
message << formatted_delegate_object_reader_method_name
301
+ end
302
+
303
+ if failed_to_allow_nil_delegate_object?
271
304
message << ' when it was non-nil, but it failed to account '
272
305
message << 'for when '
273
306
message << formatted_delegate_object_reader_method_name
274
307
message << ' *was* nil.'
308
+ elsif failed_to_handle_private_delegation?
309
+ message << ", but 'private: true' is missing."
275
310
else
276
311
message << 'Method calls sent to '
277
312
message << formatted_delegate_object_reader_method_name (
@@ -322,6 +357,10 @@ def expects_to_allow_nil_delegate_object?
322
357
@expects_to_allow_nil_delegate_object
323
358
end
324
359
360
+ def expects_private_delegation?
361
+ @expects_private_delegation
362
+ end
363
+
325
364
def formatted_delegate_method ( options = { } )
326
365
formatted_method_name_for ( delegate_method , options )
327
366
end
@@ -367,7 +406,11 @@ def delegate_object_received_call_with_delegated_arguments?
367
406
end
368
407
369
408
def subject_has_delegating_method?
370
- subject . respond_to? ( delegating_method )
409
+ if expects_private_delegation?
410
+ !subject . respond_to? ( delegating_method ) && subject . respond_to? ( delegating_method , true )
411
+ else
412
+ subject . respond_to? ( delegating_method )
413
+ end
371
414
end
372
415
373
416
def subject_has_delegate_object_reader_method?
@@ -381,7 +424,11 @@ def ensure_delegate_object_has_been_specified!
381
424
end
382
425
383
426
def subject_delegates_to_delegate_object_correctly?
384
- call_delegating_method_with_delegate_method_returning ( delegate_object )
427
+ if expects_private_delegation?
428
+ privately_call_delegating_method_with_delegate_method_returning ( delegate_object )
429
+ else
430
+ call_delegating_method_with_delegate_method_returning ( delegate_object )
431
+ end
385
432
386
433
if delegated_arguments . any?
387
434
delegate_object_received_call_with_delegated_arguments?
@@ -411,11 +458,37 @@ def subject_handles_nil_delegate_object?
411
458
end
412
459
end
413
460
461
+ def subject_handles_private_delegation?
462
+ @subject_handled_private_delegation =
463
+ if expects_private_delegation?
464
+ begin
465
+ call_delegating_method_with_delegate_method_returning ( delegate_object )
466
+ true
467
+ rescue Module ::DelegationError
468
+ false
469
+ rescue NoMethodError => e
470
+ if e . message =~
471
+ /private method `#{ delegating_method } ' called for/
472
+ true
473
+ else
474
+ raise e
475
+ end
476
+ end
477
+ else
478
+ true
479
+ end
480
+ end
481
+
414
482
def failed_to_allow_nil_delegate_object?
415
483
expects_to_allow_nil_delegate_object? &&
416
484
!@subject_handled_nil_delegate_object
417
485
end
418
486
487
+ def failed_to_handle_private_delegation?
488
+ expects_private_delegation? &&
489
+ !@subject_handled_private_delegation
490
+ end
491
+
419
492
def call_delegating_method_with_delegate_method_returning ( value )
420
493
register_subject_double_collection_to ( value )
421
494
@@ -424,6 +497,14 @@ def call_delegating_method_with_delegate_method_returning(value)
424
497
end
425
498
end
426
499
500
+ def privately_call_delegating_method_with_delegate_method_returning ( value )
501
+ register_subject_double_collection_to ( value )
502
+
503
+ Doublespeak . with_doubles_activated do
504
+ subject . __send__ ( delegating_method , *delegated_arguments )
505
+ end
506
+ end
507
+
427
508
def register_subject_double_collection_to ( returned_value )
428
509
double_collection =
429
510
Doublespeak . double_collection_for ( subject . singleton_class )
0 commit comments