functional-light-service 0.2.4
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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/.rubocop.yml +72 -0
- data/.travis.yml +22 -0
- data/Appraisals +3 -0
- data/CHANGELOG.md +37 -0
- data/CODE_OF_CONDUCT.md +22 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +1424 -0
- data/Rakefile +12 -0
- data/VERSION +1 -0
- data/functional-light-service.gemspec +26 -0
- data/gemfiles/activesupport_5.gemfile +8 -0
- data/gemfiles/activesupport_5.gemfile.lock +82 -0
- data/lib/functional-light-service/action.rb +102 -0
- data/lib/functional-light-service/configuration.rb +24 -0
- data/lib/functional-light-service/context/key_verifier.rb +118 -0
- data/lib/functional-light-service/context.rb +165 -0
- data/lib/functional-light-service/errors.rb +6 -0
- data/lib/functional-light-service/functional/enum.rb +254 -0
- data/lib/functional-light-service/functional/maybe.rb +14 -0
- data/lib/functional-light-service/functional/monad.rb +66 -0
- data/lib/functional-light-service/functional/null.rb +74 -0
- data/lib/functional-light-service/functional/option.rb +99 -0
- data/lib/functional-light-service/functional/result.rb +122 -0
- data/lib/functional-light-service/localization_adapter.rb +44 -0
- data/lib/functional-light-service/organizer/execute.rb +14 -0
- data/lib/functional-light-service/organizer/iterate.rb +22 -0
- data/lib/functional-light-service/organizer/reduce_if.rb +17 -0
- data/lib/functional-light-service/organizer/reduce_until.rb +20 -0
- data/lib/functional-light-service/organizer/scoped_reducable.rb +13 -0
- data/lib/functional-light-service/organizer/verify_call_method_exists.rb +28 -0
- data/lib/functional-light-service/organizer/with_callback.rb +26 -0
- data/lib/functional-light-service/organizer/with_reducer.rb +71 -0
- data/lib/functional-light-service/organizer/with_reducer_factory.rb +18 -0
- data/lib/functional-light-service/organizer/with_reducer_log_decorator.rb +105 -0
- data/lib/functional-light-service/organizer.rb +105 -0
- data/lib/functional-light-service/testing/context_factory.rb +40 -0
- data/lib/functional-light-service/testing.rb +1 -0
- data/lib/functional-light-service/version.rb +3 -0
- data/lib/functional-light-service.rb +29 -0
- data/resources/fail_actions.png +0 -0
- data/resources/light-service.png +0 -0
- data/resources/organizer_and_actions.png +0 -0
- data/resources/skip_actions.png +0 -0
- data/spec/acceptance/add_numbers_spec.rb +11 -0
- data/spec/acceptance/after_actions_spec.rb +71 -0
- data/spec/acceptance/around_each_spec.rb +19 -0
- data/spec/acceptance/before_actions_spec.rb +98 -0
- data/spec/acceptance/custom_log_from_organizer_spec.rb +60 -0
- data/spec/acceptance/fail_spec.rb +24 -0
- data/spec/acceptance/include_warning_spec.rb +29 -0
- data/spec/acceptance/log_from_organizer_spec.rb +154 -0
- data/spec/acceptance/message_localization_spec.rb +118 -0
- data/spec/acceptance/not_having_call_method_warning_spec.rb +39 -0
- data/spec/acceptance/organizer/around_each_with_reduce_if_spec.rb +42 -0
- data/spec/acceptance/organizer/context_failure_and_skipping_spec.rb +65 -0
- data/spec/acceptance/organizer/execute_spec.rb +46 -0
- data/spec/acceptance/organizer/iterate_spec.rb +37 -0
- data/spec/acceptance/organizer/reduce_if_spec.rb +51 -0
- data/spec/acceptance/organizer/reduce_until_spec.rb +43 -0
- data/spec/acceptance/organizer/with_callback_spec.rb +110 -0
- data/spec/acceptance/rollback_spec.rb +132 -0
- data/spec/acceptance/skip_all_warning_spec.rb +20 -0
- data/spec/acceptance/testing/context_factory_spec.rb +54 -0
- data/spec/action_expected_keys_spec.rb +63 -0
- data/spec/action_expects_and_promises_spec.rb +93 -0
- data/spec/action_promised_keys_spec.rb +122 -0
- data/spec/action_spec.rb +89 -0
- data/spec/context/inspect_spec.rb +57 -0
- data/spec/context_spec.rb +197 -0
- data/spec/examples/amount_spec.rb +77 -0
- data/spec/examples/controller_spec.rb +63 -0
- data/spec/examples/validate_address_spec.rb +37 -0
- data/spec/lib/deterministic/class_mixin_spec.rb +24 -0
- data/spec/lib/deterministic/currify_spec.rb +88 -0
- data/spec/lib/deterministic/monad_axioms.rb +44 -0
- data/spec/lib/deterministic/monad_spec.rb +45 -0
- data/spec/lib/deterministic/null_spec.rb +58 -0
- data/spec/lib/deterministic/option_spec.rb +133 -0
- data/spec/lib/deterministic/result/failure_spec.rb +65 -0
- data/spec/lib/deterministic/result/result_map_spec.rb +154 -0
- data/spec/lib/deterministic/result/result_shared.rb +24 -0
- data/spec/lib/deterministic/result/success_spec.rb +41 -0
- data/spec/lib/deterministic/result_spec.rb +63 -0
- data/spec/lib/enum_spec.rb +112 -0
- data/spec/localization_adapter_spec.rb +83 -0
- data/spec/organizer/with_reducer_spec.rb +56 -0
- data/spec/organizer_key_aliases_spec.rb +29 -0
- data/spec/organizer_spec.rb +93 -0
- data/spec/readme_spec.rb +47 -0
- data/spec/sample/calculates_order_tax_action_spec.rb +16 -0
- data/spec/sample/calculates_tax_spec.rb +30 -0
- data/spec/sample/looks_up_tax_percentage_action_spec.rb +53 -0
- data/spec/sample/provides_free_shipping_action_spec.rb +25 -0
- data/spec/sample/tax/calculates_order_tax_action.rb +9 -0
- data/spec/sample/tax/calculates_tax.rb +11 -0
- data/spec/sample/tax/looks_up_tax_percentage_action.rb +27 -0
- data/spec/sample/tax/provides_free_shipping_action.rb +10 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support.rb +1 -0
- data/spec/test_doubles.rb +552 -0
- data/spec/testing/context_factory/iterate_spec.rb +39 -0
- data/spec/testing/context_factory/reduce_if_spec.rb +40 -0
- data/spec/testing/context_factory/reduce_until_spec.rb +40 -0
- data/spec/testing/context_factory/with_callback_spec.rb +38 -0
- data/spec/testing/context_factory_spec.rb +55 -0
- metadata +285 -0
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
|
2
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__))
|
|
3
|
+
|
|
4
|
+
if ENV['RUN_COVERAGE_REPORT']
|
|
5
|
+
require 'simplecov'
|
|
6
|
+
|
|
7
|
+
SimpleCov.start do
|
|
8
|
+
add_filter 'vendor/'
|
|
9
|
+
add_filter %r{^/spec/}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
SimpleCov.minimum_coverage_by_file 90
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
require 'functional-light-service'
|
|
16
|
+
require 'functional-light-service/testing'
|
|
17
|
+
require "functional-light-service/functional/null"
|
|
18
|
+
require 'ostruct'
|
|
19
|
+
require 'pry'
|
|
20
|
+
require 'support'
|
|
21
|
+
require 'test_doubles'
|
|
22
|
+
require 'stringio'
|
|
23
|
+
|
|
24
|
+
I18n.enforce_available_locales = true
|
data/spec/support.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
# A collection of Action and Organizer dummies used in specs
|
|
2
|
+
|
|
3
|
+
module TestDoubles
|
|
4
|
+
class RollbackAction
|
|
5
|
+
extend FunctionalLightService::Action
|
|
6
|
+
executed(&:fail_with_rollback!)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class RaiseErrorAction
|
|
10
|
+
extend FunctionalLightService::Action
|
|
11
|
+
executed do |_ctx|
|
|
12
|
+
raise 'A problem has occured.'
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class RaiseAnotherErrorAction
|
|
17
|
+
extend FunctionalLightService::Action
|
|
18
|
+
executed do |_ctx|
|
|
19
|
+
raise 'More problems'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class SkipAllAction
|
|
24
|
+
extend FunctionalLightService::Action
|
|
25
|
+
executed(&:skip_remaining!)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class FailureAction
|
|
29
|
+
extend FunctionalLightService::Action
|
|
30
|
+
executed(&:fail!)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class AddTwoOrganizer
|
|
34
|
+
extend FunctionalLightService::Organizer
|
|
35
|
+
def self.call(context)
|
|
36
|
+
with(context).reduce([AddsOneAction, AddsOneAction])
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class AroundEachNullHandler
|
|
41
|
+
def self.call(_action)
|
|
42
|
+
yield
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class TestLogger
|
|
47
|
+
attr_accessor :logs
|
|
48
|
+
def initialize
|
|
49
|
+
@logs = []
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class AroundEachLoggerHandler
|
|
54
|
+
def self.call(context)
|
|
55
|
+
before_number = context[:number]
|
|
56
|
+
result = yield
|
|
57
|
+
|
|
58
|
+
context[:logger].logs << {
|
|
59
|
+
:action => context.current_action,
|
|
60
|
+
:before => before_number,
|
|
61
|
+
:after => result[:number]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
result
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class AroundEachOrganizer
|
|
69
|
+
extend FunctionalLightService::Organizer
|
|
70
|
+
def self.call(action_arguments)
|
|
71
|
+
with(action_arguments)
|
|
72
|
+
.around_each(AroundEachLoggerHandler)
|
|
73
|
+
.reduce([AddsTwoActionWithFetch])
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class AddsTwoActionWithFetch
|
|
78
|
+
extend FunctionalLightService::Action
|
|
79
|
+
|
|
80
|
+
executed do |context|
|
|
81
|
+
number = context.fetch(:number, 0)
|
|
82
|
+
context[:number] = number + 2
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class AnAction; end
|
|
87
|
+
class AnotherAction; end
|
|
88
|
+
|
|
89
|
+
class AnOrganizer
|
|
90
|
+
extend FunctionalLightService::Organizer
|
|
91
|
+
|
|
92
|
+
def self.call(action_arguments)
|
|
93
|
+
with(action_arguments).reduce([AnAction, AnotherAction])
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def self.do_something_with_no_actions(action_arguments)
|
|
97
|
+
with(action_arguments).reduce
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def self.do_something_with_no_starting_context
|
|
101
|
+
reduce([AnAction, AnotherAction])
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class NotExplicitlyReturningContextOrganizer
|
|
106
|
+
extend FunctionalLightService::Organizer
|
|
107
|
+
|
|
108
|
+
def self.call(context)
|
|
109
|
+
context[:foo] = [1, 2, 3]
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
class NestingOrganizer
|
|
114
|
+
extend FunctionalLightService::Organizer
|
|
115
|
+
|
|
116
|
+
def self.call(context)
|
|
117
|
+
with(context).reduce(actions)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.actions
|
|
121
|
+
[NotExplicitlyReturningContextOrganizer, NestedAction]
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
class NestedAction
|
|
126
|
+
extend FunctionalLightService::Action
|
|
127
|
+
|
|
128
|
+
expects :foo
|
|
129
|
+
|
|
130
|
+
executed do |context|
|
|
131
|
+
context[:bar] = context.foo
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
class MakesTeaWithMilkAction
|
|
136
|
+
extend FunctionalLightService::Action
|
|
137
|
+
expects :tea, :milk
|
|
138
|
+
promises :milk_tea
|
|
139
|
+
|
|
140
|
+
executed do |context|
|
|
141
|
+
context.milk_tea = "#{context.tea} - #{context.milk}"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
class MultipleExpectsAction
|
|
146
|
+
extend FunctionalLightService::Action
|
|
147
|
+
expects :tea
|
|
148
|
+
expects :milk, :chocolate
|
|
149
|
+
promises :milk_tea
|
|
150
|
+
|
|
151
|
+
executed do |context|
|
|
152
|
+
context.milk_tea = "#{context.tea} - #{context.milk}"\
|
|
153
|
+
" - with #{context.chocolate}"
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
class MakesCappuccinoAction
|
|
158
|
+
extend FunctionalLightService::Action
|
|
159
|
+
expects :coffee, :milk
|
|
160
|
+
promises :cappuccino
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
class MakesLatteAction
|
|
164
|
+
extend FunctionalLightService::Action
|
|
165
|
+
expects :coffee, :milk
|
|
166
|
+
promises :latte
|
|
167
|
+
|
|
168
|
+
executed do |context|
|
|
169
|
+
context[:latte] = "#{context.coffee} - with lots of #{context.milk}"
|
|
170
|
+
case context.milk
|
|
171
|
+
when :very_hot then
|
|
172
|
+
context.fail!("Can't make a latte from a milk that's very hot!")
|
|
173
|
+
when :super_hot then
|
|
174
|
+
context.fail_with_rollback!("Can't make a latte from a milk that's super hot!")
|
|
175
|
+
when "5%" then
|
|
176
|
+
context.skip_remaining!("Can't make a latte with a fatty milk like that!")
|
|
177
|
+
next context
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
class MultiplePromisesAction
|
|
183
|
+
extend FunctionalLightService::Action
|
|
184
|
+
expects :coffee, :milk
|
|
185
|
+
promises :cappuccino
|
|
186
|
+
promises :latte
|
|
187
|
+
|
|
188
|
+
executed do |context|
|
|
189
|
+
context.cappuccino = "Cappucino needs #{context.coffee} and a little milk"
|
|
190
|
+
context.latte = "Latte needs #{context.coffee} and a lot of milk"
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
class MakesTeaAndCappuccino
|
|
195
|
+
extend FunctionalLightService::Organizer
|
|
196
|
+
|
|
197
|
+
def self.call(tea, milk, coffee)
|
|
198
|
+
with(:tea => tea, :milk => milk, :coffee => coffee)
|
|
199
|
+
.reduce(TestDoubles::MakesTeaWithMilkAction,
|
|
200
|
+
TestDoubles::MakesLatteAction)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
class MakesCappuccinoAddsTwo
|
|
205
|
+
extend FunctionalLightService::Organizer
|
|
206
|
+
|
|
207
|
+
def self.call(milk, coffee)
|
|
208
|
+
with(:milk => milk, :coffee => coffee)
|
|
209
|
+
.reduce(TestDoubles::AddsTwoActionWithFetch,
|
|
210
|
+
TestDoubles::MakesLatteAction)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
class MakesCappuccinoAddsTwoAndFails
|
|
215
|
+
extend FunctionalLightService::Organizer
|
|
216
|
+
|
|
217
|
+
def self.call(coffee, this_hot = :very_hot)
|
|
218
|
+
with(:milk => this_hot, :coffee => coffee)
|
|
219
|
+
.reduce(TestDoubles::MakesLatteAction,
|
|
220
|
+
TestDoubles::AddsTwoActionWithFetch)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
class MakesCappuccinoSkipsAddsTwo
|
|
225
|
+
extend FunctionalLightService::Organizer
|
|
226
|
+
|
|
227
|
+
def self.call(coffee)
|
|
228
|
+
with(:milk => "5%", :coffee => coffee)
|
|
229
|
+
.reduce(TestDoubles::MakesLatteAction,
|
|
230
|
+
TestDoubles::AddsTwoActionWithFetch)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
class AdditionOrganizer
|
|
235
|
+
extend FunctionalLightService::Organizer
|
|
236
|
+
|
|
237
|
+
def self.call(number)
|
|
238
|
+
with(:number => number).reduce(actions)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def self.actions
|
|
242
|
+
[
|
|
243
|
+
AddsOneAction,
|
|
244
|
+
AddsTwoAction,
|
|
245
|
+
AddsThreeAction
|
|
246
|
+
]
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
class ExtraArgumentAdditionOrganizer
|
|
251
|
+
extend FunctionalLightService::Organizer
|
|
252
|
+
|
|
253
|
+
def self.call(number, another_number)
|
|
254
|
+
with(:number => number + another_number).reduce(actions)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def self.actions
|
|
258
|
+
[
|
|
259
|
+
AddsOneAction,
|
|
260
|
+
AddsTwoAction,
|
|
261
|
+
AddsThreeAction
|
|
262
|
+
]
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
class AddsOne
|
|
267
|
+
extend FunctionalLightService::Organizer
|
|
268
|
+
|
|
269
|
+
def call(ctx)
|
|
270
|
+
with(ctx).reduce(actions)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def self.actions
|
|
274
|
+
[AddsOneAction]
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
class AddsOneAction
|
|
279
|
+
extend FunctionalLightService::Action
|
|
280
|
+
expects :number
|
|
281
|
+
promises :number
|
|
282
|
+
|
|
283
|
+
executed do |context|
|
|
284
|
+
context.number += 1
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
class AddsTwoAction
|
|
289
|
+
extend FunctionalLightService::Action
|
|
290
|
+
expects :number
|
|
291
|
+
|
|
292
|
+
executed do |context|
|
|
293
|
+
context.number += 2
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
class AddsThreeAction
|
|
298
|
+
extend FunctionalLightService::Action
|
|
299
|
+
expects :number
|
|
300
|
+
|
|
301
|
+
executed do |context|
|
|
302
|
+
context.number += 3
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
class IterateOrganizer
|
|
307
|
+
extend FunctionalLightService::Organizer
|
|
308
|
+
|
|
309
|
+
def self.call(ctx)
|
|
310
|
+
with(ctx).reduce(actions)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def self.actions
|
|
314
|
+
[
|
|
315
|
+
AddsOneIteratesAction,
|
|
316
|
+
iterate(:numbers, [
|
|
317
|
+
AddsTwoAction,
|
|
318
|
+
AddsThreeAction
|
|
319
|
+
])
|
|
320
|
+
]
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
class AddsOneIteratesAction
|
|
325
|
+
extend FunctionalLightService::Action
|
|
326
|
+
expects :numbers
|
|
327
|
+
promises :numbers
|
|
328
|
+
|
|
329
|
+
executed do |context|
|
|
330
|
+
context.numbers = context.numbers.map { |n| n + 1 }
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
class CallbackOrganizer
|
|
335
|
+
extend FunctionalLightService::Organizer
|
|
336
|
+
|
|
337
|
+
def self.call(ctx)
|
|
338
|
+
with(ctx).reduce(actions)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def self.actions
|
|
342
|
+
[
|
|
343
|
+
AddsOneAction,
|
|
344
|
+
with_callback(AddTenCallbackAction, [
|
|
345
|
+
AddsTwoAction,
|
|
346
|
+
AddsThreeAction
|
|
347
|
+
])
|
|
348
|
+
]
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
class AddTenCallbackAction
|
|
353
|
+
extend FunctionalLightService::Action
|
|
354
|
+
expects :number, :callback
|
|
355
|
+
|
|
356
|
+
executed do |context|
|
|
357
|
+
context.number += 10
|
|
358
|
+
context.number =
|
|
359
|
+
context.callback.call(context).fetch(:number)
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
class ReduceUntilOrganizer
|
|
364
|
+
extend FunctionalLightService::Organizer
|
|
365
|
+
|
|
366
|
+
def self.call(ctx)
|
|
367
|
+
with(ctx).reduce(actions)
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def self.actions
|
|
371
|
+
[
|
|
372
|
+
AddsOneAction,
|
|
373
|
+
reduce_until(->(ctx) { ctx.number > 3 }, [
|
|
374
|
+
AddsTwoAction,
|
|
375
|
+
AddsThreeAction
|
|
376
|
+
])
|
|
377
|
+
]
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
class ReduceIfOrganizer
|
|
382
|
+
extend FunctionalLightService::Organizer
|
|
383
|
+
|
|
384
|
+
def self.call(ctx)
|
|
385
|
+
with(ctx).reduce(actions)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def self.actions
|
|
389
|
+
[
|
|
390
|
+
AddsOneAction,
|
|
391
|
+
reduce_if(->(ctx) { ctx.number > 1 }, [
|
|
392
|
+
AddsTwoAction,
|
|
393
|
+
AddsThreeAction
|
|
394
|
+
])
|
|
395
|
+
]
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
class MakesTeaExpectingReservedKey
|
|
400
|
+
extend FunctionalLightService::Action
|
|
401
|
+
expects :tea, :message
|
|
402
|
+
|
|
403
|
+
executed do |context|
|
|
404
|
+
context.product = context.number + 3
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
class MakesTeaExpectingMultipleReservedKeys
|
|
409
|
+
extend FunctionalLightService::Action
|
|
410
|
+
expects :tea, :message, :error_code, :current_action
|
|
411
|
+
|
|
412
|
+
executed do |context|
|
|
413
|
+
context.product = context.number + 3
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
class MakesTeaPromisingReservedKey
|
|
418
|
+
extend FunctionalLightService::Action
|
|
419
|
+
expects :tea
|
|
420
|
+
promises :product, :message
|
|
421
|
+
|
|
422
|
+
executed do |context|
|
|
423
|
+
context.product = context.number + 3
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
class MakesTeaPromisingMultipleReservedKeys
|
|
428
|
+
extend FunctionalLightService::Action
|
|
429
|
+
expects :tea
|
|
430
|
+
promises :product, :message, :error_code, :current_action
|
|
431
|
+
|
|
432
|
+
executed do |context|
|
|
433
|
+
context.product = context.number + 3
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
class MakesTeaPromisingKeyButRaisesException
|
|
438
|
+
extend FunctionalLightService::Action
|
|
439
|
+
promises :product
|
|
440
|
+
|
|
441
|
+
executed do |context|
|
|
442
|
+
context.product = make_product
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def self.make_product
|
|
446
|
+
raise "Fail"
|
|
447
|
+
end
|
|
448
|
+
private_class_method :make_product
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
class PromisesPromisedKeyAction
|
|
452
|
+
extend FunctionalLightService::Action
|
|
453
|
+
|
|
454
|
+
promises :promised_key
|
|
455
|
+
|
|
456
|
+
executed do |ctx|
|
|
457
|
+
ctx.promised_key = "promised_key"
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
class ExpectsExpectedKeyAction
|
|
462
|
+
extend FunctionalLightService::Action
|
|
463
|
+
|
|
464
|
+
expects :expected_key
|
|
465
|
+
promises :final_key
|
|
466
|
+
|
|
467
|
+
executed do |ctx|
|
|
468
|
+
ctx.final_key = ctx.expected_key
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
class NullAction
|
|
473
|
+
extend FunctionalLightService::Action
|
|
474
|
+
|
|
475
|
+
executed { |_ctx| }
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
class TestIterate
|
|
479
|
+
extend FunctionalLightService::Organizer
|
|
480
|
+
|
|
481
|
+
def self.call(context)
|
|
482
|
+
with(context)
|
|
483
|
+
.reduce([iterate(:counters,
|
|
484
|
+
[TestDoubles::AddsOneAction])])
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
def self.call_single(context)
|
|
488
|
+
with(context)
|
|
489
|
+
.reduce([iterate(:counters,
|
|
490
|
+
TestDoubles::AddsOneAction)])
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
class TestWithCallback
|
|
495
|
+
extend FunctionalLightService::Organizer
|
|
496
|
+
|
|
497
|
+
def self.call(context = {})
|
|
498
|
+
with(context).reduce(actions)
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def self.actions
|
|
502
|
+
[
|
|
503
|
+
SetUpContextAction,
|
|
504
|
+
with_callback(IterateCollectionAction,
|
|
505
|
+
[IncrementCountAction,
|
|
506
|
+
AddToTotalAction])
|
|
507
|
+
]
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
class SetUpContextAction
|
|
512
|
+
extend FunctionalLightService::Action
|
|
513
|
+
promises :numbers, :counter, :total
|
|
514
|
+
|
|
515
|
+
executed do |ctx|
|
|
516
|
+
ctx.numbers = [1, 2, 3]
|
|
517
|
+
ctx.counter = 0
|
|
518
|
+
ctx.total = 0
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
class IterateCollectionAction
|
|
523
|
+
extend FunctionalLightService::Action
|
|
524
|
+
expects :numbers, :callback
|
|
525
|
+
promises :number
|
|
526
|
+
|
|
527
|
+
executed do |ctx|
|
|
528
|
+
ctx.numbers.each do |number|
|
|
529
|
+
ctx.number = number
|
|
530
|
+
ctx.callback.call(ctx)
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
class IncrementCountAction
|
|
536
|
+
extend FunctionalLightService::Action
|
|
537
|
+
expects :counter
|
|
538
|
+
|
|
539
|
+
executed do |ctx|
|
|
540
|
+
ctx.counter = ctx.counter + 1
|
|
541
|
+
end
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
class AddToTotalAction
|
|
545
|
+
extend FunctionalLightService::Action
|
|
546
|
+
expects :number, :total
|
|
547
|
+
|
|
548
|
+
executed do |ctx|
|
|
549
|
+
ctx.total += ctx.number
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'test_doubles'
|
|
3
|
+
|
|
4
|
+
RSpec.describe 'ContextFactory - used with IterateOrganizer' do
|
|
5
|
+
let(:organizer) { TestDoubles::IterateOrganizer }
|
|
6
|
+
|
|
7
|
+
context 'when called with outside iterate steps' do
|
|
8
|
+
it 'creates a context up-to the action defined before the iteration' do
|
|
9
|
+
ctx =
|
|
10
|
+
FunctionalLightService::Testing::ContextFactory
|
|
11
|
+
.make_from(organizer)
|
|
12
|
+
.for(TestDoubles::AddsOneIteratesAction)
|
|
13
|
+
.with(:numbers => [1, 2])
|
|
14
|
+
|
|
15
|
+
expect(ctx[:numbers]).to eq([1, 2])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'creates a context up-to iteration with empty context steps' do
|
|
19
|
+
ctx =
|
|
20
|
+
FunctionalLightService::Testing::ContextFactory
|
|
21
|
+
.make_from(organizer)
|
|
22
|
+
.for(TestDoubles::AddsTwoAction)
|
|
23
|
+
.with(:numbers => [1, 2])
|
|
24
|
+
|
|
25
|
+
expect(ctx.numbers).to eq([2, 3])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'creates a context only to the first step of the iteration' do
|
|
29
|
+
ctx =
|
|
30
|
+
FunctionalLightService::Testing::ContextFactory
|
|
31
|
+
.make_from(organizer)
|
|
32
|
+
.for(TestDoubles::AddsThreeAction)
|
|
33
|
+
.with(:numbers => [1, 2])
|
|
34
|
+
|
|
35
|
+
expect(ctx.numbers).to eq([2, 3])
|
|
36
|
+
expect(ctx.number).to eq(4)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'test_doubles'
|
|
3
|
+
|
|
4
|
+
RSpec.describe 'ContextFactory - used with ReduceIfOrganizer' do
|
|
5
|
+
let(:organizer) { TestDoubles::ReduceIfOrganizer }
|
|
6
|
+
|
|
7
|
+
context 'when called with a truthy argument action' do
|
|
8
|
+
it 'executes a context up-to the callback action' do
|
|
9
|
+
ctx =
|
|
10
|
+
FunctionalLightService::Testing::ContextFactory
|
|
11
|
+
.make_from(organizer)
|
|
12
|
+
.for(TestDoubles::AddsThreeAction)
|
|
13
|
+
.with(:number => 1)
|
|
14
|
+
|
|
15
|
+
expect(ctx.number).to eq(4)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'creates a context up-to action with empty context steps' do
|
|
19
|
+
ctx =
|
|
20
|
+
FunctionalLightService::Testing::ContextFactory
|
|
21
|
+
.make_from(organizer)
|
|
22
|
+
.for(TestDoubles::AddsTwoAction)
|
|
23
|
+
.with(:number => 1)
|
|
24
|
+
|
|
25
|
+
expect(ctx.number).to eq(2)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'when called with a false argument action' do
|
|
30
|
+
it 'does not execute the steps' do
|
|
31
|
+
ctx =
|
|
32
|
+
FunctionalLightService::Testing::ContextFactory
|
|
33
|
+
.make_from(organizer)
|
|
34
|
+
.for(TestDoubles::AddsThreeAction)
|
|
35
|
+
.with(:number => 0)
|
|
36
|
+
|
|
37
|
+
expect(ctx.number).to eq(1)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'test_doubles'
|
|
3
|
+
|
|
4
|
+
RSpec.describe 'ContextFactory - used with ReduceUntilOrganizer' do
|
|
5
|
+
let(:organizer) { TestDoubles::ReduceUntilOrganizer }
|
|
6
|
+
|
|
7
|
+
context 'when called with truthy block' do
|
|
8
|
+
it 'creates a context up-to the action defined before the iteration' do
|
|
9
|
+
ctx =
|
|
10
|
+
FunctionalLightService::Testing::ContextFactory
|
|
11
|
+
.make_from(organizer)
|
|
12
|
+
.for(TestDoubles::AddsTwoAction)
|
|
13
|
+
.with(:number => 1)
|
|
14
|
+
|
|
15
|
+
expect(ctx[:number]).to eq(2)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'creates a context only to the first step of the loop' do
|
|
19
|
+
ctx =
|
|
20
|
+
FunctionalLightService::Testing::ContextFactory
|
|
21
|
+
.make_from(organizer)
|
|
22
|
+
.for(TestDoubles::AddsThreeAction)
|
|
23
|
+
.with(:number => 1)
|
|
24
|
+
|
|
25
|
+
expect(ctx.number).to eq(4)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'when called with falsey block' do
|
|
30
|
+
it 'creates a context up-to the first step' do
|
|
31
|
+
ctx =
|
|
32
|
+
FunctionalLightService::Testing::ContextFactory
|
|
33
|
+
.make_from(organizer)
|
|
34
|
+
.for(TestDoubles::AddsThreeAction)
|
|
35
|
+
.with(:number => 7)
|
|
36
|
+
|
|
37
|
+
expect(ctx[:number]).to eq(10)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|