jferris-rr 0.7.1.0.1239654108

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 (130) hide show
  1. data/CHANGES +196 -0
  2. data/README.rdoc +329 -0
  3. data/Rakefile +77 -0
  4. data/lib/rr.rb +84 -0
  5. data/lib/rr/adapters/rr_methods.rb +122 -0
  6. data/lib/rr/adapters/rspec.rb +58 -0
  7. data/lib/rr/adapters/test_unit.rb +29 -0
  8. data/lib/rr/double.rb +212 -0
  9. data/lib/rr/double_definitions/child_double_definition_creator.rb +27 -0
  10. data/lib/rr/double_definitions/double_definition.rb +346 -0
  11. data/lib/rr/double_definitions/double_definition_creator.rb +167 -0
  12. data/lib/rr/double_definitions/double_definition_creator_proxy.rb +37 -0
  13. data/lib/rr/double_definitions/strategies/implementation/implementation_strategy.rb +15 -0
  14. data/lib/rr/double_definitions/strategies/implementation/proxy.rb +62 -0
  15. data/lib/rr/double_definitions/strategies/implementation/reimplementation.rb +14 -0
  16. data/lib/rr/double_definitions/strategies/implementation/strongly_typed_reimplementation.rb +17 -0
  17. data/lib/rr/double_definitions/strategies/scope/instance.rb +15 -0
  18. data/lib/rr/double_definitions/strategies/scope/instance_of_class.rb +46 -0
  19. data/lib/rr/double_definitions/strategies/scope/scope_strategy.rb +15 -0
  20. data/lib/rr/double_definitions/strategies/strategy.rb +70 -0
  21. data/lib/rr/double_definitions/strategies/verification/dont_allow.rb +34 -0
  22. data/lib/rr/double_definitions/strategies/verification/mock.rb +44 -0
  23. data/lib/rr/double_definitions/strategies/verification/stub.rb +45 -0
  24. data/lib/rr/double_definitions/strategies/verification/verification_strategy.rb +15 -0
  25. data/lib/rr/double_injection.rb +143 -0
  26. data/lib/rr/double_matches.rb +51 -0
  27. data/lib/rr/errors/argument_equality_error.rb +6 -0
  28. data/lib/rr/errors/double_definition_error.rb +6 -0
  29. data/lib/rr/errors/double_not_found_error.rb +6 -0
  30. data/lib/rr/errors/double_order_error.rb +6 -0
  31. data/lib/rr/errors/rr_error.rb +20 -0
  32. data/lib/rr/errors/spy_verification_errors/double_injection_not_found_error.rb +8 -0
  33. data/lib/rr/errors/spy_verification_errors/invocation_count_error.rb +8 -0
  34. data/lib/rr/errors/spy_verification_errors/spy_verification_error.rb +8 -0
  35. data/lib/rr/errors/subject_does_not_implement_method_error.rb +6 -0
  36. data/lib/rr/errors/subject_has_different_arity_error.rb +6 -0
  37. data/lib/rr/errors/times_called_error.rb +6 -0
  38. data/lib/rr/expectations/any_argument_expectation.rb +21 -0
  39. data/lib/rr/expectations/argument_equality_expectation.rb +41 -0
  40. data/lib/rr/expectations/times_called_expectation.rb +57 -0
  41. data/lib/rr/hash_with_object_id_key.rb +41 -0
  42. data/lib/rr/recorded_calls.rb +103 -0
  43. data/lib/rr/space.rb +123 -0
  44. data/lib/rr/spy_verification.rb +48 -0
  45. data/lib/rr/spy_verification_proxy.rb +18 -0
  46. data/lib/rr/times_called_matchers/any_times_matcher.rb +18 -0
  47. data/lib/rr/times_called_matchers/at_least_matcher.rb +15 -0
  48. data/lib/rr/times_called_matchers/at_most_matcher.rb +23 -0
  49. data/lib/rr/times_called_matchers/integer_matcher.rb +19 -0
  50. data/lib/rr/times_called_matchers/non_terminal.rb +27 -0
  51. data/lib/rr/times_called_matchers/proc_matcher.rb +11 -0
  52. data/lib/rr/times_called_matchers/range_matcher.rb +21 -0
  53. data/lib/rr/times_called_matchers/terminal.rb +20 -0
  54. data/lib/rr/times_called_matchers/times_called_matcher.rb +44 -0
  55. data/lib/rr/wildcard_matchers/anything.rb +18 -0
  56. data/lib/rr/wildcard_matchers/boolean.rb +23 -0
  57. data/lib/rr/wildcard_matchers/duck_type.rb +32 -0
  58. data/lib/rr/wildcard_matchers/hash_including.rb +29 -0
  59. data/lib/rr/wildcard_matchers/is_a.rb +25 -0
  60. data/lib/rr/wildcard_matchers/numeric.rb +13 -0
  61. data/lib/rr/wildcard_matchers/range.rb +7 -0
  62. data/lib/rr/wildcard_matchers/regexp.rb +7 -0
  63. data/lib/rr/wildcard_matchers/satisfy.rb +26 -0
  64. data/spec/core_spec_suite.rb +19 -0
  65. data/spec/environment_fixture_setup.rb +6 -0
  66. data/spec/high_level_spec.rb +368 -0
  67. data/spec/rr/adapters/rr_methods_argument_matcher_spec.rb +67 -0
  68. data/spec/rr/adapters/rr_methods_creator_spec.rb +149 -0
  69. data/spec/rr/adapters/rr_methods_space_spec.rb +115 -0
  70. data/spec/rr/adapters/rr_methods_spec_helper.rb +11 -0
  71. data/spec/rr/adapters/rr_methods_times_matcher_spec.rb +17 -0
  72. data/spec/rr/double_definitions/child_double_definition_creator_spec.rb +112 -0
  73. data/spec/rr/double_definitions/double_definition_creator_proxy_spec.rb +155 -0
  74. data/spec/rr/double_definitions/double_definition_creator_spec.rb +502 -0
  75. data/spec/rr/double_definitions/double_definition_spec.rb +1159 -0
  76. data/spec/rr/double_injection/double_injection_bind_spec.rb +111 -0
  77. data/spec/rr/double_injection/double_injection_dispatching_spec.rb +244 -0
  78. data/spec/rr/double_injection/double_injection_has_original_method_spec.rb +55 -0
  79. data/spec/rr/double_injection/double_injection_reset_spec.rb +90 -0
  80. data/spec/rr/double_injection/double_injection_spec.rb +77 -0
  81. data/spec/rr/double_injection/double_injection_verify_spec.rb +29 -0
  82. data/spec/rr/double_spec.rb +352 -0
  83. data/spec/rr/errors/rr_error_spec.rb +67 -0
  84. data/spec/rr/expectations/any_argument_expectation_spec.rb +47 -0
  85. data/spec/rr/expectations/anything_argument_equality_expectation_spec.rb +14 -0
  86. data/spec/rr/expectations/argument_equality_expectation_spec.rb +135 -0
  87. data/spec/rr/expectations/boolean_argument_equality_expectation_spec.rb +34 -0
  88. data/spec/rr/expectations/hash_including_argument_equality_expectation_spec.rb +82 -0
  89. data/spec/rr/expectations/hash_including_spec.rb +17 -0
  90. data/spec/rr/expectations/satisfy_argument_equality_expectation_spec.rb +59 -0
  91. data/spec/rr/expectations/satisfy_spec.rb +14 -0
  92. data/spec/rr/expectations/times_called_expectation/times_called_expectation_any_times_spec.rb +46 -0
  93. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_least_spec.rb +69 -0
  94. data/spec/rr/expectations/times_called_expectation/times_called_expectation_at_most_spec.rb +71 -0
  95. data/spec/rr/expectations/times_called_expectation/times_called_expectation_helper.rb +23 -0
  96. data/spec/rr/expectations/times_called_expectation/times_called_expectation_integer_spec.rb +104 -0
  97. data/spec/rr/expectations/times_called_expectation/times_called_expectation_proc_spec.rb +81 -0
  98. data/spec/rr/expectations/times_called_expectation/times_called_expectation_range_spec.rb +83 -0
  99. data/spec/rr/expectations/times_called_expectation/times_called_expectation_spec.rb +38 -0
  100. data/spec/rr/rspec/invocation_matcher_spec.rb +279 -0
  101. data/spec/rr/rspec/rspec_adapter_spec.rb +66 -0
  102. data/spec/rr/rspec/rspec_backtrace_tweaking_spec.rb +31 -0
  103. data/spec/rr/rspec/rspec_backtrace_tweaking_spec_fixture.rb +11 -0
  104. data/spec/rr/rspec/rspec_usage_spec.rb +86 -0
  105. data/spec/rr/space/hash_with_object_id_key_spec.rb +88 -0
  106. data/spec/rr/space/space_spec.rb +542 -0
  107. data/spec/rr/test_unit/test_helper.rb +7 -0
  108. data/spec/rr/test_unit/test_unit_backtrace_test.rb +35 -0
  109. data/spec/rr/test_unit/test_unit_integration_test.rb +57 -0
  110. data/spec/rr/times_called_matchers/any_times_matcher_spec.rb +47 -0
  111. data/spec/rr/times_called_matchers/at_least_matcher_spec.rb +55 -0
  112. data/spec/rr/times_called_matchers/at_most_matcher_spec.rb +70 -0
  113. data/spec/rr/times_called_matchers/integer_matcher_spec.rb +70 -0
  114. data/spec/rr/times_called_matchers/proc_matcher_spec.rb +55 -0
  115. data/spec/rr/times_called_matchers/range_matcher_spec.rb +76 -0
  116. data/spec/rr/times_called_matchers/times_called_matcher_spec.rb +118 -0
  117. data/spec/rr/wildcard_matchers/anything_spec.rb +24 -0
  118. data/spec/rr/wildcard_matchers/boolean_spec.rb +36 -0
  119. data/spec/rr/wildcard_matchers/duck_type_spec.rb +52 -0
  120. data/spec/rr/wildcard_matchers/is_a_spec.rb +32 -0
  121. data/spec/rr/wildcard_matchers/numeric_spec.rb +32 -0
  122. data/spec/rr/wildcard_matchers/range_spec.rb +35 -0
  123. data/spec/rr/wildcard_matchers/regexp_spec.rb +43 -0
  124. data/spec/rr_spec.rb +28 -0
  125. data/spec/rspec_spec_suite.rb +16 -0
  126. data/spec/spec_helper.rb +107 -0
  127. data/spec/spec_suite.rb +27 -0
  128. data/spec/spy_verification_spec.rb +129 -0
  129. data/spec/test_unit_spec_suite.rb +21 -0
  130. metadata +187 -0
@@ -0,0 +1,27 @@
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 root_subject
11
+ parent_double_definition.root_subject
12
+ end
13
+
14
+ def instance_of(*args)
15
+ raise NoMethodError
16
+ end
17
+
18
+ protected
19
+ def add_strategy(subject, method_name, definition_eval_block, &block)
20
+ super do
21
+ block.call
22
+ parent_double_definition.implemented_by(lambda {subject})
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,346 @@
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
+ attr_reader :argument_expectation
45
+
46
+ def root_subject
47
+ double_definition_creator.root_subject
48
+ end
49
+
50
+ module ArgumentDefinitionConstructionMethods
51
+ # Double#with sets the expectation that the Double will receive
52
+ # the passed in arguments.
53
+ #
54
+ # Passing in a block sets the return value.
55
+ #
56
+ # mock(subject).method_name.with(1, 2) {:return_value}
57
+ def with(*args, &return_value_block)
58
+ @argument_expectation = Expectations::ArgumentEqualityExpectation.new(*args)
59
+ install_method_callback return_value_block
60
+ self
61
+ end
62
+
63
+ # Double#with_any_args sets the expectation that the Double can receive
64
+ # any arguments.
65
+ #
66
+ # Passing in a block sets the return value.
67
+ #
68
+ # mock(subject).method_name.with_any_args {:return_value}
69
+ def with_any_args(&return_value_block)
70
+ @argument_expectation = Expectations::AnyArgumentExpectation.new
71
+ install_method_callback return_value_block
72
+ self
73
+ end
74
+
75
+ # Double#with_no_args sets the expectation that the Double will receive
76
+ # no arguments.
77
+ #
78
+ # Passing in a block sets the return value.
79
+ #
80
+ # mock(subject).method_name.with_no_args {:return_value}
81
+ def with_no_args(&return_value_block)
82
+ @argument_expectation = Expectations::ArgumentEqualityExpectation.new()
83
+ install_method_callback return_value_block
84
+ self
85
+ end
86
+ end
87
+ include ArgumentDefinitionConstructionMethods
88
+
89
+ module TimesDefinitionConstructionMethods
90
+ # Double#never sets the expectation that the Double will never be
91
+ # called.
92
+ #
93
+ # This method does not accept a block because it will never be called.
94
+ #
95
+ # mock(subject).method_name.never
96
+ def never
97
+ @times_matcher = TimesCalledMatchers::IntegerMatcher.new(0)
98
+ self
99
+ end
100
+
101
+ # Double#once sets the expectation that the Double will be called
102
+ # 1 time.
103
+ #
104
+ # Passing in a block sets the return value.
105
+ #
106
+ # mock(subject).method_name.once {:return_value}
107
+ def once(&return_value_block)
108
+ @times_matcher = TimesCalledMatchers::IntegerMatcher.new(1)
109
+ install_method_callback return_value_block
110
+ self
111
+ end
112
+
113
+ # Double#twice sets the expectation that the Double will be called
114
+ # 2 times.
115
+ #
116
+ # Passing in a block sets the return value.
117
+ #
118
+ # mock(subject).method_name.twice {:return_value}
119
+ def twice(&return_value_block)
120
+ @times_matcher = TimesCalledMatchers::IntegerMatcher.new(2)
121
+ install_method_callback return_value_block
122
+ self
123
+ end
124
+
125
+ # Double#at_least sets the expectation that the Double
126
+ # will be called at least n times.
127
+ # It works by creating a TimesCalledExpectation.
128
+ #
129
+ # Passing in a block sets the return value.
130
+ #
131
+ # mock(subject).method_name.at_least(4) {:return_value}
132
+ def at_least(number, &return_value_block)
133
+ @times_matcher = TimesCalledMatchers::AtLeastMatcher.new(number)
134
+ install_method_callback return_value_block
135
+ self
136
+ end
137
+
138
+ # Double#at_most allows sets the expectation that the Double
139
+ # will be called at most n times.
140
+ # It works by creating a TimesCalledExpectation.
141
+ #
142
+ # Passing in a block sets the return value.
143
+ #
144
+ # mock(subject).method_name.at_most(4) {:return_value}
145
+ def at_most(number, &return_value_block)
146
+ @times_matcher = TimesCalledMatchers::AtMostMatcher.new(number)
147
+ install_method_callback return_value_block
148
+ self
149
+ end
150
+
151
+ # Double#any_number_of_times sets an that the Double will be called
152
+ # any number of times. This effectively removes the times called expectation
153
+ # from the Doublen
154
+ #
155
+ # Passing in a block sets the return value.
156
+ #
157
+ # mock(subject).method_name.any_number_of_times
158
+ def any_number_of_times(&return_value_block)
159
+ @times_matcher = TimesCalledMatchers::AnyTimesMatcher.new
160
+ install_method_callback return_value_block
161
+ self
162
+ end
163
+
164
+ # Double#times creates an TimesCalledExpectation of the passed
165
+ # in number.
166
+ #
167
+ # Passing in a block sets the return value.
168
+ #
169
+ # mock(subject).method_name.times(4) {:return_value}
170
+ def times(matcher_value, &return_value_block)
171
+ @times_matcher = TimesCalledMatchers::TimesCalledMatcher.create(matcher_value)
172
+ install_method_callback return_value_block
173
+ self
174
+ end
175
+ end
176
+ include TimesDefinitionConstructionMethods
177
+
178
+ module DefinitionConstructionMethods
179
+ # Double#ordered sets the Double to have an ordered
180
+ # expectation.
181
+ #
182
+ # Passing in a block sets the return value.
183
+ #
184
+ # mock(subject).method_name.ordered {return_value}
185
+ def ordered(&return_value_block)
186
+ raise(
187
+ Errors::DoubleDefinitionError,
188
+ "Double Definitions must have a dedicated Double to be ordered. " <<
189
+ "For example, using instance_of does not allow ordered to be used. " <<
190
+ "proxy the class's #new method instead."
191
+ ) unless @double
192
+ @ordered = true
193
+ space.register_ordered_double(@double)
194
+ install_method_callback return_value_block
195
+ DoubleDefinitionCreatorProxy.new(double_definition_creator)
196
+ end
197
+ alias_method :then, :ordered
198
+
199
+ # Double#yields sets the Double to invoke a passed in block when
200
+ # the Double is called.
201
+ # An Expection will be raised if no block is passed in when the
202
+ # Double is called.
203
+ #
204
+ # Passing in a block sets the return value.
205
+ #
206
+ # mock(subject).method_name.yields(yield_arg1, yield_arg2) {return_value}
207
+ # subject.method_name {|yield_arg1, yield_arg2|}
208
+ def yields(*args, &return_value_block)
209
+ @yields_value = args
210
+ install_method_callback return_value_block
211
+ self
212
+ end
213
+
214
+ # Double#after_call creates a callback that occurs after call
215
+ # is called. The passed in block receives the return value of
216
+ # the Double being called.
217
+ # An Expection will be raised if no block is passed in.
218
+ #
219
+ # mock(subject).method_name {return_value}.after_call {|return_value|}
220
+ # subject.method_name # return_value
221
+ #
222
+ # This feature is built into proxies.
223
+ # mock.proxy(User).find('1') {|user| mock(user).valid? {false}}
224
+ def after_call(&after_call_proc)
225
+ raise ArgumentError, "after_call expects a block" unless after_call_proc
226
+ @after_call_proc = after_call_proc
227
+ self
228
+ end
229
+
230
+ # Double#verbose sets the Double to print out each method call it receives.
231
+ #
232
+ # Passing in a block sets the return value
233
+ def verbose(&after_call_proc)
234
+ @verbose = true
235
+ @after_call_proc = after_call_proc
236
+ self
237
+ end
238
+
239
+ # Double#returns accepts an argument value or a block.
240
+ # It will raise an ArgumentError if both are passed in.
241
+ #
242
+ # Passing in a block causes Double to return the return value of
243
+ # the passed in block.
244
+ #
245
+ # Passing in an argument causes Double to return the argument.
246
+ def returns(*args, &implementation)
247
+ value = args.first
248
+ if !args.empty? && implementation
249
+ raise ArgumentError, "returns cannot accept both an argument and a block"
250
+ end
251
+ if implementation
252
+ implemented_by implementation
253
+ else
254
+ implemented_by lambda {value}
255
+ end
256
+ self
257
+ end
258
+
259
+ def implemented_by_original_method
260
+ implemented_by ORIGINAL_METHOD
261
+ self
262
+ end
263
+
264
+ # Double#implemented_by sets the implementation of the Double.
265
+ # This method takes a Proc or a Method. Passing in a Method allows
266
+ # the Double to accept blocks.
267
+ #
268
+ # obj = Object.new
269
+ # def obj.foobar
270
+ # yield(1)
271
+ # end
272
+ # mock(obj).method_name.implemented_by(obj.method(:foobar))
273
+ def implemented_by(implementation)
274
+ @implementation = implementation
275
+ self
276
+ end
277
+
278
+ def verify_method_signature
279
+ @verify_method_signature = true
280
+ self
281
+ end
282
+ alias_method :strong, :verify_method_signature
283
+
284
+ protected
285
+ def install_method_callback(block)
286
+ return unless block
287
+ if implementation_is_original_method?
288
+ after_call(&block)
289
+ else
290
+ returns(&block)
291
+ end
292
+ end
293
+ end
294
+ include DefinitionConstructionMethods
295
+
296
+ module StateQueryMethods
297
+ # Double#ordered? returns true when the Double is ordered.
298
+ #
299
+ # mock(subject).method_name.ordered?
300
+ def ordered?
301
+ @ordered
302
+ end
303
+
304
+ # Double#verbose? returns true when verbose has been called on it. It returns
305
+ # true when the double is set to print each method call it receives.
306
+ def verbose?
307
+ @verbose ? true : false
308
+ end
309
+
310
+ def exact_match?(*arguments)
311
+ raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @argument_expectation
312
+ @argument_expectation.exact_match?(*arguments)
313
+ end
314
+
315
+ def wildcard_match?(*arguments)
316
+ raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @argument_expectation
317
+ @argument_expectation.wildcard_match?(*arguments)
318
+ end
319
+
320
+ def terminal?
321
+ raise(Errors::DoubleDefinitionError, "#argument_expectation must be defined on #{inspect}") unless @times_matcher
322
+ @times_matcher.terminal?
323
+ end
324
+
325
+ def expected_arguments
326
+ argument_expectation ? argument_expectation.expected_arguments : []
327
+ end
328
+
329
+ def implementation_is_original_method?
330
+ implementation_strategy.is_a?(Strategies::Implementation::Proxy)
331
+ end
332
+
333
+ def verify_method_signature?
334
+ !!@verify_method_signature
335
+ end
336
+ alias_method :strong?, :verify_method_signature?
337
+
338
+ protected
339
+ def implementation_strategy
340
+ double_definition_creator.implementation_strategy
341
+ end
342
+ end
343
+ include StateQueryMethods
344
+ end
345
+ end
346
+ end
@@ -0,0 +1,167 @@
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,
55
+ :method_name,
56
+ :args, :handler,
57
+ :definition,
58
+ :verification_strategy,
59
+ :implementation_strategy,
60
+ :scope_strategy
61
+ NO_SUBJECT = Object.new
62
+
63
+ include Space::Reader
64
+
65
+ def initialize
66
+ @verification_strategy = nil
67
+ @implementation_strategy = Strategies::Implementation::Reimplementation.new(self)
68
+ @scope_strategy = Strategies::Scope::Instance.new(self)
69
+ end
70
+
71
+ def root_subject
72
+ subject
73
+ end
74
+
75
+ def method_name
76
+ @verification_strategy.method_name
77
+ end
78
+
79
+ module StrategySetupMethods
80
+ def no_subject?
81
+ subject.__id__ === NO_SUBJECT.__id__
82
+ end
83
+
84
+ protected
85
+ def add_strategy(subject, method_name, definition_eval_block)
86
+ if method_name && definition_eval_block
87
+ raise ArgumentError, "Cannot pass in a method name and a block"
88
+ end
89
+ @subject = subject
90
+ yield
91
+ if no_subject?
92
+ self
93
+ elsif method_name
94
+ create(method_name)
95
+ else
96
+ DoubleDefinitionCreatorProxy.new(self, &definition_eval_block)
97
+ end
98
+ end
99
+
100
+ def verification_strategy=(verification_strategy)
101
+ verify_no_verification_strategy
102
+ verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
103
+ @verification_strategy = verification_strategy
104
+ verification_strategy
105
+ end
106
+
107
+ def implementation_strategy=(implementation_strategy)
108
+ verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
109
+ @implementation_strategy = implementation_strategy
110
+ end
111
+
112
+ def scope_strategy=(scope_strategy)
113
+ verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
114
+ @scope_strategy = scope_strategy
115
+ end
116
+
117
+ def verify_no_verification_strategy
118
+ strategy_already_defined_error if verification_strategy
119
+ end
120
+
121
+ def strategy_already_defined_error
122
+ raise(
123
+ Errors::DoubleDefinitionError,
124
+ "This Double already has a #{verification_strategy.name} strategy"
125
+ )
126
+ end
127
+
128
+ def verify_not_proxy_and_dont_allow(verification_strategy, implementation_strategy)
129
+ proxy_when_dont_allow_error if
130
+ verification_strategy.is_a?(Strategies::Verification::DontAllow) &&
131
+ implementation_strategy.is_a?(Strategies::Implementation::Proxy)
132
+ end
133
+
134
+ def proxy_when_dont_allow_error
135
+ raise(
136
+ Errors::DoubleDefinitionError,
137
+ "Doubles cannot be proxied when using dont_allow strategy"
138
+ )
139
+ end
140
+
141
+ def no_strategy_error
142
+ raise(
143
+ Errors::DoubleDefinitionError,
144
+ "This Double has no strategy"
145
+ )
146
+ end
147
+ end
148
+ include StrategySetupMethods
149
+
150
+ module StrategyExecutionMethods
151
+ def create(method_name, *args, &handler)
152
+ raise DoubleDefinitionCreatorError if no_subject?
153
+ @method_name, @args, @handler = method_name, args, handler
154
+ @definition = DoubleDefinition.new(self, subject)
155
+ verification_strategy ? verification_strategy.call(definition, method_name, args, handler) : no_strategy_error
156
+ implementation_strategy.call(definition, method_name, args, handler)
157
+ scope_strategy.call(definition, method_name, args, handler)
158
+ definition
159
+ end
160
+ end
161
+ include StrategyExecutionMethods
162
+
163
+ class DoubleDefinitionCreatorError < Errors::RRError
164
+ end
165
+ end
166
+ end
167
+ end