rr 0.4.10 → 0.6.0

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.
Files changed (110) hide show
  1. data/CHANGES +14 -0
  2. data/README.rdoc +67 -13
  3. data/Rakefile +1 -1
  4. data/lib/rr.rb +29 -9
  5. data/lib/rr/adapters/rr_methods.rb +38 -158
  6. data/lib/rr/double.rb +46 -41
  7. data/lib/rr/double_definitions/child_double_definition_creator.rb +23 -0
  8. data/lib/rr/double_definitions/double_definition.rb +212 -0
  9. data/lib/rr/double_definitions/double_definition_creator.rb +153 -0
  10. data/lib/rr/double_definitions/double_definition_creator_proxy.rb +25 -0
  11. data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +15 -0
  12. data/lib/rr/double_definitions/strategies/implementation/proxy.rb +62 -0
  13. data/lib/rr/double_definitions/strategies/implementation/reimplementation.rb +14 -0
  14. data/lib/rr/double_definitions/strategies/scope/instance.rb +15 -0
  15. data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +43 -0
  16. data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +15 -0
  17. data/lib/rr/double_definitions/strategies/strategy.rb +70 -0
  18. data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +34 -0
  19. data/lib/rr/double_definitions/strategies/verification/mock.rb +44 -0
  20. data/lib/rr/double_definitions/strategies/verification/stub.rb +45 -0
  21. data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +15 -0
  22. data/lib/rr/double_injection.rb +21 -15
  23. data/lib/rr/expectations/argument_equality_expectation.rb +2 -1
  24. data/lib/rr/space.rb +23 -22
  25. data/lib/rr/wildcard_matchers/hash_including.rb +29 -0
  26. data/lib/rr/wildcard_matchers/satisfy.rb +26 -0
  27. data/spec/high_level_spec.rb +111 -64
  28. data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +1 -1
  29. data/spec/rr/adapters/rr_methods_creator_spec.rb +99 -315
  30. data/spec/rr/adapters/rr_methods_space_spec.rb +90 -109
  31. data/spec/rr/adapters/rr_methods_spec_helper.rb +1 -1
  32. data/spec/rr/adapters/rr_methods_times_matcher_spec.rb +1 -1
  33. data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +103 -0
  34. data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +83 -0
  35. data/spec/rr/double_definitions/double_definition_creator_spec.rb +495 -0
  36. data/spec/rr/double_definitions/double_definition_spec.rb +1116 -0
  37. data/spec/rr/double_injection/double_injection_bind_spec.rb +111 -0
  38. data/spec/rr/double_injection/double_injection_dispatching_spec.rb +245 -0
  39. data/spec/rr/{double → double_injection}/double_injection_has_original_method_spec.rb +9 -9
  40. data/spec/rr/double_injection/double_injection_reset_spec.rb +90 -0
  41. data/spec/rr/double_injection/double_injection_spec.rb +77 -0
  42. data/spec/rr/double_injection/double_injection_verify_spec.rb +29 -0
  43. data/spec/rr/double_spec.rb +156 -136
  44. data/spec/rr/errors/rr_error_spec.rb +1 -1
  45. data/spec/rr/expectations/any_argument_expectation_spec.rb +1 -1
  46. data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +6 -30
  47. data/spec/rr/expectations/argument_equality_expectation_spec.rb +35 -18
  48. data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +22 -41
  49. data/spec/rr/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
  50. data/spec/rr/expectations/hash_including_spec.rb +17 -0
  51. data/spec/rr/expectations/satisfy_argument_equality_expectation_spec.rb +59 -0
  52. data/spec/rr/expectations/satisfy_spec.rb +14 -0
  53. data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +30 -28
  54. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +55 -54
  55. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +49 -48
  56. data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +9 -7
  57. data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +77 -76
  58. data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +58 -57
  59. data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +59 -58
  60. data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +25 -24
  61. data/spec/rr/rspec/rspec_adapter_spec.rb +12 -11
  62. data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +10 -8
  63. data/spec/rr/rspec/rspec_usage_spec.rb +1 -1
  64. data/spec/rr/space/hash_with_object_id_key_spec.rb +1 -1
  65. data/spec/rr/space/space_spec.rb +330 -192
  66. data/spec/rr/test_unit/test_helper.rb +1 -2
  67. data/spec/rr/test_unit/test_unit_backtrace_test.rb +1 -2
  68. data/spec/rr/test_unit/test_unit_integration_test.rb +1 -2
  69. data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +1 -1
  70. data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +1 -1
  71. data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +1 -1
  72. data/spec/rr/times_called_matchers/integer_matcher_spec.rb +1 -1
  73. data/spec/rr/times_called_matchers/proc_matcher_spec.rb +1 -1
  74. data/spec/rr/times_called_matchers/range_matcher_spec.rb +1 -1
  75. data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +1 -1
  76. data/spec/rr/wildcard_matchers/anything_spec.rb +24 -0
  77. data/spec/rr/wildcard_matchers/boolean_spec.rb +36 -0
  78. data/spec/rr/wildcard_matchers/duck_type_spec.rb +52 -0
  79. data/spec/rr/wildcard_matchers/is_a_spec.rb +32 -0
  80. data/spec/rr/wildcard_matchers/numeric_spec.rb +32 -0
  81. data/spec/rr/wildcard_matchers/range_spec.rb +35 -0
  82. data/spec/rr/wildcard_matchers/regexp_spec.rb +43 -0
  83. data/spec/rr_spec.rb +28 -0
  84. data/spec/spec_helper.rb +84 -0
  85. metadata +43 -29
  86. data/lib/rr/double_creator.rb +0 -271
  87. data/lib/rr/double_definition.rb +0 -179
  88. data/lib/rr/double_definition_builder.rb +0 -44
  89. data/lib/rr/double_definition_creator.rb +0 -156
  90. data/lib/rr/double_definition_creator_proxy.rb +0 -20
  91. data/spec/rr/double/double_injection_bind_spec.rb +0 -105
  92. data/spec/rr/double/double_injection_dispatching_spec.rb +0 -228
  93. data/spec/rr/double/double_injection_reset_spec.rb +0 -86
  94. data/spec/rr/double/double_injection_spec.rb +0 -72
  95. data/spec/rr/double/double_injection_verify_spec.rb +0 -24
  96. data/spec/rr/double_definition_creator_proxy_spec.rb +0 -85
  97. data/spec/rr/double_definition_creator_spec.rb +0 -496
  98. data/spec/rr/double_definition_spec.rb +0 -815
  99. data/spec/rr/expectations/anything_spec.rb +0 -14
  100. data/spec/rr/expectations/boolean_spec.rb +0 -14
  101. data/spec/rr/expectations/duck_type_argument_equality_expectation_spec.rb +0 -71
  102. data/spec/rr/expectations/duck_type_spec.rb +0 -14
  103. data/spec/rr/expectations/is_a_argument_equality_expectation_spec.rb +0 -51
  104. data/spec/rr/expectations/is_a_spec.rb +0 -14
  105. data/spec/rr/expectations/numeric_argument_equality_expectation_spec.rb +0 -47
  106. data/spec/rr/expectations/numeric_spec.rb +0 -14
  107. data/spec/rr/expectations/range_argument_equality_expectation_spec.rb +0 -59
  108. data/spec/rr/expectations/range_spec.rb +0 -10
  109. data/spec/rr/expectations/regexp_argument_equality_expectation_spec.rb +0 -72
  110. data/spec/rr/expectations/regexp_spec.rb +0 -10
@@ -19,7 +19,7 @@ module RR
19
19
  attr_reader :times_called, :double_injection, :definition
20
20
  include Space::Reader
21
21
 
22
- def initialize(double_injection, definition = DoubleDefinition.new)
22
+ def initialize(double_injection, definition)
23
23
  @double_injection = double_injection
24
24
  @definition = definition
25
25
  @times_called = 0
@@ -212,20 +212,6 @@ module RR
212
212
  definition.implemented_by implementation
213
213
  end
214
214
 
215
- # Double#proxy sets the implementation
216
- # of the Double to be the original method.
217
- # This is primarily used with proxy.
218
- #
219
- # obj = Object.new
220
- # def obj.foobar
221
- # yield(1)
222
- # end
223
- # mock(obj).method_name.proxy
224
- # obj.foobar {|arg| puts arg} # puts 1
225
- def proxy
226
- definition.proxy
227
- end
228
-
229
215
  # Double#call calls the Double's implementation. The return
230
216
  # value of the implementation is returned.
231
217
  #
@@ -235,46 +221,27 @@ module RR
235
221
  if verbose?
236
222
  puts Double.formatted_name(double_injection.method_name, args)
237
223
  end
238
- self.times_called_expectation.attempt if definition.times_matcher
224
+ times_called_expectation.attempt if definition.times_matcher
239
225
  space.verify_ordered_double(self) if ordered?
240
226
  yields!(block)
241
227
  return_value = call_implementation(double_injection, *args, &block)
242
- return return_value unless definition.after_call_value
243
- definition.after_call_value.call(return_value)
228
+ definition.after_call_proc ? extract_subject_from_return_value(definition.after_call_proc.call(return_value)) : return_value
244
229
  end
245
230
 
246
231
  def yields!(block)
247
232
  if definition.yields_value
248
- unless block
233
+ if block
234
+ block.call(*definition.yields_value)
235
+ else
249
236
  raise ArgumentError, "A Block must be passed into the method call when using yields"
250
237
  end
251
- block.call(*definition.yields_value)
252
238
  end
253
239
  end
254
240
  protected :yields!
255
241
 
256
242
  def call_implementation(double_injection, *args, &block)
257
- return nil unless implementation
258
-
259
- if implementation === DoubleDefinition::ORIGINAL_METHOD
260
- if double_injection.object_has_original_method?
261
- return double_injection.call_original_method(*args, &block)
262
- else
263
- return double_injection.object.__send__(
264
- :method_missing,
265
- method_name,
266
- *args,
267
- &block
268
- )
269
- end
270
- end
271
-
272
- if implementation.is_a?(Method)
273
- return implementation.call(*args, &block)
274
- else
275
- args << block if block
276
- return implementation.call(*args)
277
- end
243
+ return_value = do_call_implementation_and_get_return_value(double_injection, *args, &block)
244
+ extract_subject_from_return_value(return_value)
278
245
  end
279
246
  protected :call_implementation
280
247
 
@@ -351,5 +318,43 @@ module RR
351
318
  def formatted_name
352
319
  self.class.formatted_name(method_name, expected_arguments)
353
320
  end
321
+
322
+ protected
323
+ def do_call_implementation_and_get_return_value(double_injection, *args, &block)
324
+ if definition.implementation_is_original_method?
325
+ if double_injection.object_has_original_method?
326
+ double_injection.call_original_method(*args, &block)
327
+ else
328
+ double_injection.subject.__send__(
329
+ :method_missing,
330
+ method_name,
331
+ *args,
332
+ &block
333
+ )
334
+ end
335
+ else
336
+ if implementation
337
+ if implementation.is_a?(Method)
338
+ implementation.call(*args, &block)
339
+ else
340
+ args << block if block
341
+ implementation.call(*args)
342
+ end
343
+ else
344
+ nil
345
+ end
346
+ end
347
+ end
348
+
349
+ def extract_subject_from_return_value(return_value)
350
+ case return_value
351
+ when DoubleDefinitions::DoubleDefinition
352
+ return_value.subject
353
+ when DoubleDefinitions::DoubleDefinitionCreatorProxy
354
+ return_value.__creator__.subject
355
+ else
356
+ return_value
357
+ end
358
+ end
354
359
  end
355
360
  end
@@ -0,0 +1,23 @@
1
+ module RR
2
+ module DoubleDefinitions
3
+ class ChildDoubleDefinitionCreator < DoubleDefinitionCreator # :nodoc
4
+ attr_reader :parent_double_definition
5
+ def initialize(parent_double_definition)
6
+ @parent_double_definition = parent_double_definition
7
+ super()
8
+ end
9
+
10
+ def instance_of(*args)
11
+ raise NoMethodError
12
+ end
13
+
14
+ protected
15
+ def add_strategy(subject, method_name, definition_eval_block, &block)
16
+ super do
17
+ block.call
18
+ parent_double_definition.implemented_by(lambda {subject})
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,212 @@
1
+ module RR
2
+ module DoubleDefinitions
3
+ class DoubleDefinition #:nodoc:
4
+ class << self
5
+ def register_strategy_class(strategy_class, method_name)
6
+ class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
7
+ def #{method_name}(subject=DoubleDefinitionCreator::NO_SUBJECT, method_name=nil, &definition_eval_block)
8
+ ChildDoubleDefinitionCreator.new(self).#{method_name}(subject, method_name, &definition_eval_block)
9
+ end
10
+ CLASS
11
+
12
+ class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
13
+ def #{method_name}!(method_name=nil, &definition_eval_block)
14
+ ChildDoubleDefinitionCreator.new(self).#{method_name}!(method_name, &definition_eval_block)
15
+ end
16
+ CLASS
17
+ end
18
+ end
19
+
20
+ ORIGINAL_METHOD = Object.new
21
+ attr_accessor(
22
+ :argument_expectation,
23
+ :times_matcher,
24
+ :implementation,
25
+ :after_call_proc,
26
+ :yields_value,
27
+ :double,
28
+ :double_definition_creator,
29
+ :subject
30
+ )
31
+
32
+ include Space::Reader
33
+
34
+ def initialize(double_definition_creator, subject)
35
+ @implementation = nil
36
+ @argument_expectation = nil
37
+ @times_matcher = nil
38
+ @after_call_proc = nil
39
+ @yields_value = nil
40
+ @double_definition_creator = double_definition_creator
41
+ @subject = subject
42
+ end
43
+
44
+ module DefinitionConstructionMethods
45
+ def with(*args, &return_value_block)
46
+ @argument_expectation = Expectations::ArgumentEqualityExpectation.new(*args)
47
+ install_method_callback return_value_block
48
+ self
49
+ end
50
+
51
+ def with_any_args(&return_value_block)
52
+ @argument_expectation = Expectations::AnyArgumentExpectation.new
53
+ install_method_callback return_value_block
54
+ self
55
+ end
56
+
57
+ def with_no_args(&return_value_block)
58
+ @argument_expectation = Expectations::ArgumentEqualityExpectation.new()
59
+ install_method_callback return_value_block
60
+ self
61
+ end
62
+
63
+ def never
64
+ @times_matcher = TimesCalledMatchers::IntegerMatcher.new(0)
65
+ self
66
+ end
67
+
68
+ def once(&return_value_block)
69
+ @times_matcher = TimesCalledMatchers::IntegerMatcher.new(1)
70
+ install_method_callback return_value_block
71
+ self
72
+ end
73
+
74
+ def twice(&return_value_block)
75
+ @times_matcher = TimesCalledMatchers::IntegerMatcher.new(2)
76
+ install_method_callback return_value_block
77
+ self
78
+ end
79
+
80
+ def at_least(number, &return_value_block)
81
+ @times_matcher = TimesCalledMatchers::AtLeastMatcher.new(number)
82
+ install_method_callback return_value_block
83
+ self
84
+ end
85
+
86
+ def at_most(number, &return_value_block)
87
+ @times_matcher = TimesCalledMatchers::AtMostMatcher.new(number)
88
+ install_method_callback return_value_block
89
+ self
90
+ end
91
+
92
+ def any_number_of_times(&return_value_block)
93
+ @times_matcher = TimesCalledMatchers::AnyTimesMatcher.new
94
+ install_method_callback return_value_block
95
+ self
96
+ end
97
+
98
+ def times(matcher_value, &return_value_block)
99
+ @times_matcher = TimesCalledMatchers::TimesCalledMatcher.create(matcher_value)
100
+ install_method_callback return_value_block
101
+ self
102
+ end
103
+
104
+ def ordered(&return_value_block)
105
+ raise(
106
+ Errors::DoubleDefinitionError,
107
+ "Double Definitions must have a dedicated Double to be ordered. " <<
108
+ "For example, using instance_of does not allow ordered to be used. " <<
109
+ "proxy the class's #new method instead."
110
+ ) unless @double
111
+ @ordered = true
112
+ space.register_ordered_double(@double)
113
+ install_method_callback return_value_block
114
+ DoubleDefinitionCreatorProxy.new(double_definition_creator)
115
+ end
116
+ alias_method :then, :ordered
117
+
118
+ def yields(*args, &return_value_block)
119
+ @yields_value = args
120
+ install_method_callback return_value_block
121
+ self
122
+ end
123
+
124
+ def after_call(&after_call_proc)
125
+ raise ArgumentError, "after_call expects a block" unless after_call_proc
126
+ @after_call_proc = after_call_proc
127
+ self
128
+ end
129
+
130
+ def verbose(&after_call_proc)
131
+ @verbose = true
132
+ @after_call_proc = after_call_proc
133
+ self
134
+ end
135
+
136
+ def returns(*args, &implementation)
137
+ value = args.first
138
+ if !args.empty? && implementation
139
+ raise ArgumentError, "returns cannot accept both an argument and a block"
140
+ end
141
+ if implementation
142
+ implemented_by implementation
143
+ else
144
+ implemented_by lambda {value}
145
+ end
146
+ self
147
+ end
148
+
149
+ def implemented_by_original_method
150
+ implemented_by ORIGINAL_METHOD
151
+ self
152
+ end
153
+
154
+ def implemented_by(implementation)
155
+ @implementation = implementation
156
+ self
157
+ end
158
+
159
+ protected
160
+ def install_method_callback(block)
161
+ return unless block
162
+ if implementation_is_original_method?
163
+ after_call(&block)
164
+ else
165
+ returns(&block)
166
+ end
167
+ end
168
+ end
169
+ include DefinitionConstructionMethods
170
+
171
+ module StateQueryMethods
172
+ def ordered?
173
+ @ordered
174
+ end
175
+
176
+ def verbose?
177
+ @verbose ? true : false
178
+ end
179
+
180
+ def exact_match?(*arguments)
181
+ raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @argument_expectation
182
+ @argument_expectation.exact_match?(*arguments)
183
+ end
184
+
185
+ def wildcard_match?(*arguments)
186
+ raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @argument_expectation
187
+ @argument_expectation.wildcard_match?(*arguments)
188
+ end
189
+
190
+ def terminal?
191
+ raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @times_matcher
192
+ @times_matcher.terminal?
193
+ end
194
+
195
+ def expected_arguments
196
+ return [] unless argument_expectation
197
+ argument_expectation.expected_arguments
198
+ end
199
+
200
+ def implementation_is_original_method?
201
+ implementation_strategy.is_a?(Strategies::Implementation::Proxy)
202
+ end
203
+
204
+ protected
205
+ def implementation_strategy
206
+ double_definition_creator.implementation_strategy
207
+ end
208
+ end
209
+ include StateQueryMethods
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,153 @@
1
+ module RR
2
+ module DoubleDefinitions
3
+ class DoubleDefinitionCreator # :nodoc
4
+ class << self
5
+ def register_verification_strategy_class(strategy_class, method_name)
6
+ class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
7
+ def #{method_name}(subject=NO_SUBJECT, method_name=nil, &definition_eval_block)
8
+ add_strategy(subject, method_name, definition_eval_block) do
9
+ self.verification_strategy = #{strategy_class.name}.new(self)
10
+ end
11
+ end
12
+ CLASS
13
+
14
+ class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
15
+ def #{method_name}!(method_name=nil, &definition_eval_block)
16
+ #{method_name}(Object.new, method_name, &definition_eval_block)
17
+ end
18
+ CLASS
19
+ end
20
+
21
+ def register_implementation_strategy_class(strategy_class, method_name)
22
+ class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
23
+ def #{method_name}(subject=NO_SUBJECT, method_name=nil, &definition_eval_block)
24
+ add_strategy(subject, method_name, definition_eval_block) do
25
+ self.implementation_strategy = #{strategy_class.name}.new(self)
26
+ end
27
+ end
28
+ CLASS
29
+
30
+ class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
31
+ def #{method_name}!(method_name=nil, &definition_eval_block)
32
+ #{method_name}(Object.new, method_name, &definition_eval_block)
33
+ end
34
+ CLASS
35
+ end
36
+
37
+ def register_scope_strategy_class(strategy_class, method_name)
38
+ class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
39
+ def #{method_name}(subject=NO_SUBJECT, method_name=nil, &definition_eval_block)
40
+ add_strategy(subject, method_name, definition_eval_block) do
41
+ self.scope_strategy = #{strategy_class.name}.new(self)
42
+ end
43
+ end
44
+ CLASS
45
+
46
+ class_eval((<<-CLASS), __FILE__, __LINE__ + 1)
47
+ def #{method_name}!(method_name=nil, &definition_eval_block)
48
+ #{method_name}(Object.new, method_name, &definition_eval_block)
49
+ end
50
+ CLASS
51
+ end
52
+ end
53
+
54
+ attr_reader :subject, :method_name, :args, :handler, :definition, :verification_strategy, :implementation_strategy, :scope_strategy
55
+ NO_SUBJECT = Object.new
56
+
57
+ include Space::Reader
58
+
59
+ def initialize
60
+ @verification_strategy = nil
61
+ @implementation_strategy = Strategies::Implementation::Reimplementation.new(self)
62
+ @scope_strategy = Strategies::Scope::Instance.new(self)
63
+ end
64
+
65
+ module StrategySetupMethods
66
+ def no_subject?
67
+ subject.__id__ === NO_SUBJECT.__id__
68
+ end
69
+
70
+ protected
71
+ def add_strategy(subject, method_name, definition_eval_block)
72
+ if method_name && definition_eval_block
73
+ raise ArgumentError, "Cannot pass in a method name and a block"
74
+ end
75
+ @subject = subject
76
+ yield
77
+ if no_subject?
78
+ self
79
+ elsif method_name
80
+ create(method_name)
81
+ else
82
+ DoubleDefinitionCreatorProxy.new(self, &definition_eval_block)
83
+ end
84
+ end
85
+
86
+ def verification_strategy=(verification_strategy)
87
+ verify_no_verification_strategy
88
+ verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
89
+ @verification_strategy = verification_strategy
90
+ verification_strategy
91
+ end
92
+
93
+ def implementation_strategy=(implementation_strategy)
94
+ verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
95
+ @implementation_strategy = implementation_strategy
96
+ end
97
+
98
+ def scope_strategy=(scope_strategy)
99
+ verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
100
+ @scope_strategy = scope_strategy
101
+ end
102
+
103
+ def verify_no_verification_strategy
104
+ strategy_already_defined_error if verification_strategy
105
+ end
106
+
107
+ def strategy_already_defined_error
108
+ raise(
109
+ Errors::DoubleDefinitionError,
110
+ "This Double already has a #{verification_strategy.name} strategy"
111
+ )
112
+ end
113
+
114
+ def verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
115
+ proxy_when_dont_allow_error if
116
+ verification_strategy.is_a?(Strategies::Verification::DontAllow) &&
117
+ implementation_strategy.is_a?(Strategies::Implementation::Proxy)
118
+ end
119
+
120
+ def proxy_when_dont_allow_error
121
+ raise(
122
+ Errors::DoubleDefinitionError,
123
+ "Doubles cannot be proxied when using dont_allow strategy"
124
+ )
125
+ end
126
+
127
+ def no_strategy_error
128
+ raise(
129
+ Errors::DoubleDefinitionError,
130
+ "This Double has no strategy"
131
+ )
132
+ end
133
+ end
134
+ include StrategySetupMethods
135
+
136
+ module StrategyExecutionMethods
137
+ def create(method_name, *args, &handler)
138
+ raise DoubleDefinitionCreatorError if no_subject?
139
+ @method_name, @args, @handler = method_name, args, handler
140
+ @definition = DoubleDefinition.new(self, subject)
141
+ verification_strategy ? verification_strategy.call(definition, method_name, args, handler) : no_strategy_error
142
+ implementation_strategy.call(definition, method_name, args, handler)
143
+ scope_strategy.call(definition, method_name, args, handler)
144
+ definition
145
+ end
146
+ end
147
+ include StrategyExecutionMethods
148
+
149
+ class DoubleDefinitionCreatorError < Errors::RRError
150
+ end
151
+ end
152
+ end
153
+ end