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.
- data/CHANGES +14 -0
- data/README.rdoc +67 -13
- data/Rakefile +1 -1
- data/lib/rr.rb +29 -9
- data/lib/rr/adapters/rr_methods.rb +38 -158
- data/lib/rr/double.rb +46 -41
- data/lib/rr/double_definitions/child_double_definition_creator.rb +23 -0
- data/lib/rr/double_definitions/double_definition.rb +212 -0
- data/lib/rr/double_definitions/double_definition_creator.rb +153 -0
- data/lib/rr/double_definitions/double_definition_creator_proxy.rb +25 -0
- data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +15 -0
- data/lib/rr/double_definitions/strategies/implementation/proxy.rb +62 -0
- data/lib/rr/double_definitions/strategies/implementation/reimplementation.rb +14 -0
- data/lib/rr/double_definitions/strategies/scope/instance.rb +15 -0
- data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +43 -0
- data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +15 -0
- data/lib/rr/double_definitions/strategies/strategy.rb +70 -0
- data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +34 -0
- data/lib/rr/double_definitions/strategies/verification/mock.rb +44 -0
- data/lib/rr/double_definitions/strategies/verification/stub.rb +45 -0
- data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +15 -0
- data/lib/rr/double_injection.rb +21 -15
- data/lib/rr/expectations/argument_equality_expectation.rb +2 -1
- data/lib/rr/space.rb +23 -22
- data/lib/rr/wildcard_matchers/hash_including.rb +29 -0
- data/lib/rr/wildcard_matchers/satisfy.rb +26 -0
- data/spec/high_level_spec.rb +111 -64
- data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +1 -1
- data/spec/rr/adapters/rr_methods_creator_spec.rb +99 -315
- data/spec/rr/adapters/rr_methods_space_spec.rb +90 -109
- data/spec/rr/adapters/rr_methods_spec_helper.rb +1 -1
- data/spec/rr/adapters/rr_methods_times_matcher_spec.rb +1 -1
- data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +103 -0
- data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +83 -0
- data/spec/rr/double_definitions/double_definition_creator_spec.rb +495 -0
- data/spec/rr/double_definitions/double_definition_spec.rb +1116 -0
- data/spec/rr/double_injection/double_injection_bind_spec.rb +111 -0
- data/spec/rr/double_injection/double_injection_dispatching_spec.rb +245 -0
- data/spec/rr/{double → double_injection}/double_injection_has_original_method_spec.rb +9 -9
- data/spec/rr/double_injection/double_injection_reset_spec.rb +90 -0
- data/spec/rr/double_injection/double_injection_spec.rb +77 -0
- data/spec/rr/double_injection/double_injection_verify_spec.rb +29 -0
- data/spec/rr/double_spec.rb +156 -136
- data/spec/rr/errors/rr_error_spec.rb +1 -1
- data/spec/rr/expectations/any_argument_expectation_spec.rb +1 -1
- data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +6 -30
- data/spec/rr/expectations/argument_equality_expectation_spec.rb +35 -18
- data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +22 -41
- data/spec/rr/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
- data/spec/rr/expectations/hash_including_spec.rb +17 -0
- data/spec/rr/expectations/satisfy_argument_equality_expectation_spec.rb +59 -0
- data/spec/rr/expectations/satisfy_spec.rb +14 -0
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +30 -28
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +55 -54
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +49 -48
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +9 -7
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +77 -76
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +58 -57
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +59 -58
- data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +25 -24
- data/spec/rr/rspec/rspec_adapter_spec.rb +12 -11
- data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +10 -8
- data/spec/rr/rspec/rspec_usage_spec.rb +1 -1
- data/spec/rr/space/hash_with_object_id_key_spec.rb +1 -1
- data/spec/rr/space/space_spec.rb +330 -192
- data/spec/rr/test_unit/test_helper.rb +1 -2
- data/spec/rr/test_unit/test_unit_backtrace_test.rb +1 -2
- data/spec/rr/test_unit/test_unit_integration_test.rb +1 -2
- data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +1 -1
- data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +1 -1
- data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +1 -1
- data/spec/rr/times_called_matchers/integer_matcher_spec.rb +1 -1
- data/spec/rr/times_called_matchers/proc_matcher_spec.rb +1 -1
- data/spec/rr/times_called_matchers/range_matcher_spec.rb +1 -1
- data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +1 -1
- data/spec/rr/wildcard_matchers/anything_spec.rb +24 -0
- data/spec/rr/wildcard_matchers/boolean_spec.rb +36 -0
- data/spec/rr/wildcard_matchers/duck_type_spec.rb +52 -0
- data/spec/rr/wildcard_matchers/is_a_spec.rb +32 -0
- data/spec/rr/wildcard_matchers/numeric_spec.rb +32 -0
- data/spec/rr/wildcard_matchers/range_spec.rb +35 -0
- data/spec/rr/wildcard_matchers/regexp_spec.rb +43 -0
- data/spec/rr_spec.rb +28 -0
- data/spec/spec_helper.rb +84 -0
- metadata +43 -29
- data/lib/rr/double_creator.rb +0 -271
- data/lib/rr/double_definition.rb +0 -179
- data/lib/rr/double_definition_builder.rb +0 -44
- data/lib/rr/double_definition_creator.rb +0 -156
- data/lib/rr/double_definition_creator_proxy.rb +0 -20
- data/spec/rr/double/double_injection_bind_spec.rb +0 -105
- data/spec/rr/double/double_injection_dispatching_spec.rb +0 -228
- data/spec/rr/double/double_injection_reset_spec.rb +0 -86
- data/spec/rr/double/double_injection_spec.rb +0 -72
- data/spec/rr/double/double_injection_verify_spec.rb +0 -24
- data/spec/rr/double_definition_creator_proxy_spec.rb +0 -85
- data/spec/rr/double_definition_creator_spec.rb +0 -496
- data/spec/rr/double_definition_spec.rb +0 -815
- data/spec/rr/expectations/anything_spec.rb +0 -14
- data/spec/rr/expectations/boolean_spec.rb +0 -14
- data/spec/rr/expectations/duck_type_argument_equality_expectation_spec.rb +0 -71
- data/spec/rr/expectations/duck_type_spec.rb +0 -14
- data/spec/rr/expectations/is_a_argument_equality_expectation_spec.rb +0 -51
- data/spec/rr/expectations/is_a_spec.rb +0 -14
- data/spec/rr/expectations/numeric_argument_equality_expectation_spec.rb +0 -47
- data/spec/rr/expectations/numeric_spec.rb +0 -14
- data/spec/rr/expectations/range_argument_equality_expectation_spec.rb +0 -59
- data/spec/rr/expectations/range_spec.rb +0 -10
- data/spec/rr/expectations/regexp_argument_equality_expectation_spec.rb +0 -72
- data/spec/rr/expectations/regexp_spec.rb +0 -10
data/lib/rr/double.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|