switchyard 7.0.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.
- checksums.yaml +7 -0
- data/.github/workflows/project-build.yml +71 -0
- data/.gitignore +24 -0
- data/.rspec +3 -0
- data/.rubocop.yml +101 -0
- data/.solargraph.yml +11 -0
- data/Appraisals +7 -0
- data/CHANGELOG.md +303 -0
- data/CODE_OF_CONDUCT.md +22 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +1663 -0
- data/Rakefile +12 -0
- data/VERSION +1 -0
- data/audit/bench.rb +99 -0
- data/audit/verify_findings.rb +172 -0
- data/gemfiles/dry_inflector_0_2_1.gemfile +5 -0
- data/gemfiles/i18n_1_8_11.gemfile +5 -0
- data/lib/switchyard/action.rb +145 -0
- data/lib/switchyard/configuration.rb +36 -0
- data/lib/switchyard/context/key_verifier.rb +124 -0
- data/lib/switchyard/context.rb +208 -0
- data/lib/switchyard/deprecations.rb +26 -0
- data/lib/switchyard/errors.rb +9 -0
- data/lib/switchyard/functional/enum.rb +286 -0
- data/lib/switchyard/functional/maybe.rb +21 -0
- data/lib/switchyard/functional/monad.rb +77 -0
- data/lib/switchyard/functional/null.rb +88 -0
- data/lib/switchyard/functional/option.rb +100 -0
- data/lib/switchyard/functional/result.rb +129 -0
- data/lib/switchyard/functional/sequencer.rb +144 -0
- data/lib/switchyard/i18n/localization_adapter.rb +50 -0
- data/lib/switchyard/localization_adapter.rb +39 -0
- data/lib/switchyard/localization_map.rb +9 -0
- data/lib/switchyard/organizer/execute.rb +16 -0
- data/lib/switchyard/organizer/iterate.rb +30 -0
- data/lib/switchyard/organizer/reduce_case.rb +50 -0
- data/lib/switchyard/organizer/reduce_if.rb +19 -0
- data/lib/switchyard/organizer/reduce_if_else.rb +23 -0
- data/lib/switchyard/organizer/reduce_until.rb +22 -0
- data/lib/switchyard/organizer/reduce_while.rb +31 -0
- data/lib/switchyard/organizer/scoped_reducable.rb +15 -0
- data/lib/switchyard/organizer/with_callback.rb +28 -0
- data/lib/switchyard/organizer/with_reducer.rb +81 -0
- data/lib/switchyard/organizer/with_reducer_factory.rb +20 -0
- data/lib/switchyard/organizer/with_reducer_log_decorator.rb +111 -0
- data/lib/switchyard/organizer.rb +129 -0
- data/lib/switchyard/testing/context_factory.rb +48 -0
- data/lib/switchyard/testing.rb +3 -0
- data/lib/switchyard/version.rb +5 -0
- data/lib/switchyard.rb +36 -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 +87 -0
- data/spec/acceptance/around_each_spec.rb +19 -0
- data/spec/acceptance/before_actions_spec.rb +115 -0
- data/spec/acceptance/custom_log_from_organizer_spec.rb +61 -0
- data/spec/acceptance/deprecation_warnings_spec.rb +82 -0
- data/spec/acceptance/fail_spec.rb +52 -0
- data/spec/acceptance/log_from_organizer_spec.rb +154 -0
- data/spec/acceptance/message_localization_spec.rb +119 -0
- data/spec/acceptance/organizer/add_aliases_spec.rb +28 -0
- data/spec/acceptance/organizer/add_to_context_spec.rb +54 -0
- data/spec/acceptance/organizer/around_each_with_reduce_if_spec.rb +42 -0
- data/spec/acceptance/organizer/context_failure_and_skipping_spec.rb +90 -0
- data/spec/acceptance/organizer/execute_spec.rb +67 -0
- data/spec/acceptance/organizer/iterate_spec.rb +44 -0
- data/spec/acceptance/organizer/reduce_case_spec.rb +65 -0
- data/spec/acceptance/organizer/reduce_if_else_spec.rb +60 -0
- data/spec/acceptance/organizer/reduce_if_spec.rb +89 -0
- data/spec/acceptance/organizer/reduce_until_spec.rb +49 -0
- data/spec/acceptance/organizer/reduce_while_spec.rb +96 -0
- data/spec/acceptance/organizer/with_callback_spec.rb +113 -0
- data/spec/acceptance/organizer_entry_point_spec.rb +35 -0
- data/spec/acceptance/rollback_spec.rb +183 -0
- data/spec/acceptance/skip_all_remaining_spec.rb +139 -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 +97 -0
- data/spec/action_optional_expected_keys_spec.rb +107 -0
- data/spec/action_promised_keys_spec.rb +126 -0
- data/spec/action_spec.rb +97 -0
- data/spec/context/inspect_spec.rb +52 -0
- data/spec/context_spec.rb +301 -0
- data/spec/examples/amount_spec.rb +77 -0
- data/spec/examples/controller_spec.rb +63 -0
- data/spec/examples/validate_address_spec.rb +38 -0
- data/spec/i18n_localization_adapter_spec.rb +83 -0
- data/spec/lib/deterministic/class_mixin_spec.rb +24 -0
- data/spec/lib/deterministic/currify_spec.rb +90 -0
- data/spec/lib/deterministic/monad_axioms.rb +46 -0
- data/spec/lib/deterministic/monad_spec.rb +47 -0
- data/spec/lib/deterministic/null_spec.rb +65 -0
- data/spec/lib/deterministic/option_spec.rb +140 -0
- data/spec/lib/deterministic/result/failure_spec.rb +65 -0
- data/spec/lib/deterministic/result/result_map_spec.rb +155 -0
- data/spec/lib/deterministic/result/result_shared.rb +25 -0
- data/spec/lib/deterministic/result/success_spec.rb +41 -0
- data/spec/lib/deterministic/result_spec.rb +63 -0
- data/spec/lib/deterministic/sequencer_spec.rb +506 -0
- data/spec/lib/edge_cases_spec.rb +156 -0
- data/spec/lib/enum_spec.rb +114 -0
- data/spec/lib/native_pattern_matching_spec.rb +74 -0
- data/spec/localization_adapter_spec.rb +66 -0
- data/spec/organizer/with_reducer_spec.rb +56 -0
- data/spec/organizer_key_aliases_spec.rb +29 -0
- data/spec/organizer_spec.rb +115 -0
- data/spec/readme_spec.rb +45 -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 +55 -0
- data/spec/sample/provides_free_shipping_action_spec.rb +25 -0
- data/spec/sample/tax/calculates_order_tax_action.rb +10 -0
- data/spec/sample/tax/calculates_tax.rb +11 -0
- data/spec/sample/tax/looks_up_tax_percentage_action.rb +28 -0
- data/spec/sample/tax/provides_free_shipping_action.rb +11 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support.rb +1 -0
- data/spec/test_doubles.rb +656 -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 +76 -0
- data/switchyard.gemspec +35 -0
- metadata +351 -0
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
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 98
|
|
13
|
+
SimpleCov.minimum_coverage_by_file 90
|
|
14
|
+
|
|
15
|
+
require "simplecov-cobertura"
|
|
16
|
+
SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# i18n non e' piu una dipendenza runtime della gem: viene caricata qui
|
|
20
|
+
# per testare l'adapter I18n e la selezione automatica in Configuration
|
|
21
|
+
require "i18n"
|
|
22
|
+
require "switchyard"
|
|
23
|
+
require "switchyard/testing"
|
|
24
|
+
require "switchyard/functional/null"
|
|
25
|
+
require "support"
|
|
26
|
+
require "test_doubles"
|
|
27
|
+
require "stringio"
|
|
28
|
+
|
|
29
|
+
# Le API deprecate (Maybe/Null, operatori esotici) restano testate:
|
|
30
|
+
# i warning vengono silenziati globalmente e riattivati solo nelle
|
|
31
|
+
# spec che li verificano
|
|
32
|
+
Switchyard::Deprecations.silenced = true
|
data/spec/support.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
# A collection of Action and Organizer dummies used in specs
|
|
2
|
+
|
|
3
|
+
module TestDoubles
|
|
4
|
+
class RollbackAction
|
|
5
|
+
extend Switchyard::Action
|
|
6
|
+
|
|
7
|
+
executed(&:fail_with_rollback!)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class RaiseErrorAction
|
|
11
|
+
extend Switchyard::Action
|
|
12
|
+
|
|
13
|
+
executed do |_ctx|
|
|
14
|
+
raise 'A problem has occured.'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class RaiseAnotherErrorAction
|
|
19
|
+
extend Switchyard::Action
|
|
20
|
+
|
|
21
|
+
executed do |_ctx|
|
|
22
|
+
raise 'More problems'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class SkipAllAction
|
|
27
|
+
extend Switchyard::Action
|
|
28
|
+
|
|
29
|
+
executed(&:skip_remaining!)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class FailureAction
|
|
33
|
+
extend Switchyard::Action
|
|
34
|
+
|
|
35
|
+
executed(&:fail!)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class AddTwoOrganizer
|
|
39
|
+
extend Switchyard::Organizer
|
|
40
|
+
|
|
41
|
+
def self.call(context)
|
|
42
|
+
with(context).reduce([AddsOneAction, AddsOneAction])
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class AroundEachNullHandler
|
|
47
|
+
def self.call(_action)
|
|
48
|
+
yield
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class TestLogger
|
|
53
|
+
attr_accessor :logs
|
|
54
|
+
|
|
55
|
+
def initialize
|
|
56
|
+
@logs = []
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class AroundEachLoggerHandler
|
|
61
|
+
def self.call(context)
|
|
62
|
+
before_number = context[:number]
|
|
63
|
+
result = yield
|
|
64
|
+
|
|
65
|
+
context[:logger].logs << {
|
|
66
|
+
:action => context.current_action,
|
|
67
|
+
:before => before_number,
|
|
68
|
+
:after => result[:number]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
result
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class AroundEachOrganizer
|
|
76
|
+
extend Switchyard::Organizer
|
|
77
|
+
|
|
78
|
+
def self.call(action_arguments)
|
|
79
|
+
with(action_arguments)
|
|
80
|
+
.around_each(AroundEachLoggerHandler)
|
|
81
|
+
.reduce([AddsTwoActionWithFetch])
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class AddsTwoActionWithFetch
|
|
86
|
+
extend Switchyard::Action
|
|
87
|
+
|
|
88
|
+
executed do |context|
|
|
89
|
+
number = context.fetch(:number, 0)
|
|
90
|
+
context[:number] = number + 2
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
class AnAction
|
|
95
|
+
extend Switchyard::Action
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class AnotherAction
|
|
99
|
+
extend Switchyard::Action
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class AnOrganizer
|
|
103
|
+
extend Switchyard::Organizer
|
|
104
|
+
|
|
105
|
+
def self.call(action_arguments)
|
|
106
|
+
with(action_arguments).reduce([AnAction, AnotherAction])
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def self.do_something_with_no_actions(action_arguments)
|
|
110
|
+
with(action_arguments).reduce
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.do_something_with_no_starting_context
|
|
114
|
+
reduce([AnAction, AnotherAction])
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
class NotExplicitlyReturningContextOrganizer
|
|
119
|
+
extend Switchyard::Organizer
|
|
120
|
+
|
|
121
|
+
def self.call(context)
|
|
122
|
+
context[:foo] = [1, 2, 3]
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class NestingOrganizer
|
|
127
|
+
extend Switchyard::Organizer
|
|
128
|
+
|
|
129
|
+
def self.call(context)
|
|
130
|
+
with(context).reduce(actions)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def self.actions
|
|
134
|
+
[NotExplicitlyReturningContextOrganizer, NestedAction]
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class NestedAction
|
|
139
|
+
extend Switchyard::Action
|
|
140
|
+
|
|
141
|
+
expects :foo
|
|
142
|
+
|
|
143
|
+
executed do |context|
|
|
144
|
+
context[:bar] = context.foo
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
class MakesTeaWithMilkAction
|
|
149
|
+
extend Switchyard::Action
|
|
150
|
+
|
|
151
|
+
expects :tea, :milk
|
|
152
|
+
promises :milk_tea
|
|
153
|
+
|
|
154
|
+
executed do |context|
|
|
155
|
+
context.milk_tea = "#{context.tea} - #{context.milk}"
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
class MultipleExpectsAction
|
|
160
|
+
extend Switchyard::Action
|
|
161
|
+
|
|
162
|
+
expects :tea
|
|
163
|
+
expects :milk, :chocolate
|
|
164
|
+
promises :milk_tea
|
|
165
|
+
|
|
166
|
+
executed do |context|
|
|
167
|
+
context.milk_tea = "#{context.tea} - #{context.milk} " \
|
|
168
|
+
"- with #{context.chocolate}"
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
class MakesCappuccinoAction
|
|
173
|
+
extend Switchyard::Action
|
|
174
|
+
|
|
175
|
+
expects :coffee, :milk
|
|
176
|
+
promises :cappuccino
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
class MakesLatteAction
|
|
180
|
+
extend Switchyard::Action
|
|
181
|
+
|
|
182
|
+
expects :coffee, :milk
|
|
183
|
+
promises :latte
|
|
184
|
+
|
|
185
|
+
executed do |context|
|
|
186
|
+
context.fail!("Can't make a latte from a milk that's very hot!") if context.milk == :very_hot
|
|
187
|
+
|
|
188
|
+
if context.milk == :super_hot
|
|
189
|
+
error_message = "Can't make a latte from a milk that's super hot!"
|
|
190
|
+
context.fail_with_rollback!(error_message)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
context[:latte] = "#{context.coffee} - with lots of #{context.milk}"
|
|
194
|
+
|
|
195
|
+
if context.milk == "5%"
|
|
196
|
+
msg = "Can't make a latte with a fatty milk like that!"
|
|
197
|
+
context.skip_remaining!(msg)
|
|
198
|
+
next context
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
class MultiplePromisesAction
|
|
204
|
+
extend Switchyard::Action
|
|
205
|
+
|
|
206
|
+
expects :coffee, :milk
|
|
207
|
+
promises :cappuccino
|
|
208
|
+
promises :latte
|
|
209
|
+
|
|
210
|
+
executed do |context|
|
|
211
|
+
context.cappuccino = "Cappucino needs #{context.coffee} and a little milk"
|
|
212
|
+
context.latte = "Latte needs #{context.coffee} and a lot of milk"
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
class MakesTeaAndCappuccino
|
|
217
|
+
extend Switchyard::Organizer
|
|
218
|
+
|
|
219
|
+
def self.call(tea, milk, coffee)
|
|
220
|
+
with(:tea => tea, :milk => milk, :coffee => coffee)
|
|
221
|
+
.reduce(TestDoubles::MakesTeaWithMilkAction,
|
|
222
|
+
TestDoubles::MakesLatteAction)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
class MakesCappuccinoAddsTwo
|
|
227
|
+
extend Switchyard::Organizer
|
|
228
|
+
|
|
229
|
+
def self.call(milk, coffee)
|
|
230
|
+
with(:milk => milk, :coffee => coffee)
|
|
231
|
+
.reduce(TestDoubles::AddsTwoActionWithFetch,
|
|
232
|
+
TestDoubles::MakesLatteAction)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
class MakesCappuccinoAddsTwoAndFails
|
|
237
|
+
extend Switchyard::Organizer
|
|
238
|
+
|
|
239
|
+
def self.call(coffee, this_hot = :very_hot)
|
|
240
|
+
with(:milk => this_hot, :coffee => coffee)
|
|
241
|
+
.reduce(TestDoubles::MakesLatteAction,
|
|
242
|
+
TestDoubles::AddsTwoActionWithFetch)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
class MakesCappuccinoSkipsAddsTwo
|
|
247
|
+
extend Switchyard::Organizer
|
|
248
|
+
|
|
249
|
+
def self.call(coffee)
|
|
250
|
+
with(:milk => "5%", :coffee => coffee)
|
|
251
|
+
.reduce(TestDoubles::MakesLatteAction,
|
|
252
|
+
TestDoubles::AddsTwoActionWithFetch)
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
class AdditionOrganizer
|
|
257
|
+
extend Switchyard::Organizer
|
|
258
|
+
|
|
259
|
+
def self.call(number)
|
|
260
|
+
with(:number => number).reduce(actions)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def self.actions
|
|
264
|
+
[
|
|
265
|
+
AddsOneAction,
|
|
266
|
+
AddsTwoAction,
|
|
267
|
+
AddsThreeAction
|
|
268
|
+
]
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
class ExtraArgumentAdditionOrganizer
|
|
273
|
+
extend Switchyard::Organizer
|
|
274
|
+
|
|
275
|
+
def self.call(number, another_number)
|
|
276
|
+
with(:number => number + another_number).reduce(actions)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def self.actions
|
|
280
|
+
[
|
|
281
|
+
AddsOneAction,
|
|
282
|
+
AddsTwoAction,
|
|
283
|
+
AddsThreeAction
|
|
284
|
+
]
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
class AddsOne
|
|
289
|
+
extend Switchyard::Organizer
|
|
290
|
+
|
|
291
|
+
def call(ctx)
|
|
292
|
+
with(ctx).reduce(actions)
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def self.actions
|
|
296
|
+
[AddsOneAction]
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
class AddsOneAction
|
|
301
|
+
extend Switchyard::Action
|
|
302
|
+
|
|
303
|
+
expects :number
|
|
304
|
+
promises :number
|
|
305
|
+
|
|
306
|
+
executed do |context|
|
|
307
|
+
context.number += 1
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
class AddsTwoAction
|
|
312
|
+
extend Switchyard::Action
|
|
313
|
+
|
|
314
|
+
expects :number
|
|
315
|
+
|
|
316
|
+
executed do |context|
|
|
317
|
+
context.number += 2
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
class AddsThreeAction
|
|
322
|
+
extend Switchyard::Action
|
|
323
|
+
|
|
324
|
+
expects :number
|
|
325
|
+
|
|
326
|
+
executed do |context|
|
|
327
|
+
context.number += 3
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
class IterateOrganizer
|
|
332
|
+
extend Switchyard::Organizer
|
|
333
|
+
|
|
334
|
+
def self.call(ctx)
|
|
335
|
+
with(ctx).reduce(actions)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def self.actions
|
|
339
|
+
[
|
|
340
|
+
AddsOneIteratesAction,
|
|
341
|
+
iterate(:numbers, [
|
|
342
|
+
AddsTwoAction,
|
|
343
|
+
AddsThreeAction
|
|
344
|
+
])
|
|
345
|
+
]
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
class AddsOneIteratesAction
|
|
350
|
+
extend Switchyard::Action
|
|
351
|
+
|
|
352
|
+
expects :numbers
|
|
353
|
+
promises :numbers
|
|
354
|
+
|
|
355
|
+
executed do |context|
|
|
356
|
+
context.numbers = context.numbers.map { |n| n + 1 }
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
class CallbackOrganizer
|
|
361
|
+
extend Switchyard::Organizer
|
|
362
|
+
|
|
363
|
+
def self.call(ctx)
|
|
364
|
+
with(ctx).reduce(actions)
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def self.actions
|
|
368
|
+
[
|
|
369
|
+
AddsOneAction,
|
|
370
|
+
with_callback(AddTenCallbackAction, [
|
|
371
|
+
AddsTwoAction,
|
|
372
|
+
AddsThreeAction
|
|
373
|
+
])
|
|
374
|
+
]
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
class AddTenCallbackAction
|
|
379
|
+
extend Switchyard::Action
|
|
380
|
+
|
|
381
|
+
expects :number, :callback
|
|
382
|
+
|
|
383
|
+
executed do |context|
|
|
384
|
+
context.number += 10
|
|
385
|
+
context.number =
|
|
386
|
+
context.callback.call(context).fetch(:number)
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
class ReduceUntilOrganizer
|
|
391
|
+
extend Switchyard::Organizer
|
|
392
|
+
|
|
393
|
+
def self.call(ctx)
|
|
394
|
+
with(ctx).reduce(actions)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def self.actions
|
|
398
|
+
[
|
|
399
|
+
AddsOneAction,
|
|
400
|
+
reduce_until(->(ctx) { ctx.number > 3 }, [
|
|
401
|
+
AddsTwoAction,
|
|
402
|
+
AddsThreeAction
|
|
403
|
+
])
|
|
404
|
+
]
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
class ReduceIfOrganizer
|
|
409
|
+
extend Switchyard::Organizer
|
|
410
|
+
|
|
411
|
+
def self.call(ctx)
|
|
412
|
+
with(ctx).reduce(actions)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def self.actions
|
|
416
|
+
[
|
|
417
|
+
AddsOneAction,
|
|
418
|
+
reduce_if(->(ctx) { ctx.number > 1 }, [
|
|
419
|
+
AddsTwoAction,
|
|
420
|
+
AddsThreeAction
|
|
421
|
+
])
|
|
422
|
+
]
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
class MakesTeaExpectingReservedKey
|
|
427
|
+
extend Switchyard::Action
|
|
428
|
+
|
|
429
|
+
expects :tea, :message
|
|
430
|
+
|
|
431
|
+
executed do |context|
|
|
432
|
+
context.product = context.number + 3
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
class MakesTeaExpectingMultipleReservedKeys
|
|
437
|
+
extend Switchyard::Action
|
|
438
|
+
|
|
439
|
+
expects :tea, :message, :error_code, :current_action
|
|
440
|
+
|
|
441
|
+
executed do |context|
|
|
442
|
+
context.product = context.number + 3
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
class MakesTeaPromisingReservedKey
|
|
447
|
+
extend Switchyard::Action
|
|
448
|
+
|
|
449
|
+
expects :tea
|
|
450
|
+
promises :product, :message
|
|
451
|
+
|
|
452
|
+
executed do |context|
|
|
453
|
+
context.product = context.number + 3
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
class MakesTeaPromisingMultipleReservedKeys
|
|
458
|
+
extend Switchyard::Action
|
|
459
|
+
|
|
460
|
+
expects :tea
|
|
461
|
+
promises :product, :message, :error_code, :current_action
|
|
462
|
+
|
|
463
|
+
executed do |context|
|
|
464
|
+
context.product = context.number + 3
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
class MakesTeaPromisingKeyButRaisesException
|
|
469
|
+
extend Switchyard::Action
|
|
470
|
+
|
|
471
|
+
promises :product
|
|
472
|
+
|
|
473
|
+
executed do |context|
|
|
474
|
+
context.product = make_product
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def self.make_product
|
|
478
|
+
raise "Fail"
|
|
479
|
+
end
|
|
480
|
+
private_class_method :make_product
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
class PromisesPromisedKeyAction
|
|
484
|
+
extend Switchyard::Action
|
|
485
|
+
|
|
486
|
+
promises :promised_key
|
|
487
|
+
|
|
488
|
+
executed do |ctx|
|
|
489
|
+
ctx.promised_key = "promised_key"
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
class ExpectsExpectedKeyAction
|
|
494
|
+
extend Switchyard::Action
|
|
495
|
+
|
|
496
|
+
expects :expected_key
|
|
497
|
+
promises :final_key
|
|
498
|
+
|
|
499
|
+
executed do |ctx|
|
|
500
|
+
ctx.final_key = ctx.expected_key
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
class NullAction
|
|
505
|
+
extend Switchyard::Action
|
|
506
|
+
|
|
507
|
+
# rubocop:disable Lint/EmptyBlock
|
|
508
|
+
executed { |_ctx| }
|
|
509
|
+
# rubocop:enable Lint/EmptyBlock
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
class TestIterate
|
|
513
|
+
extend Switchyard::Organizer
|
|
514
|
+
|
|
515
|
+
def self.call(context)
|
|
516
|
+
with(context)
|
|
517
|
+
.reduce([iterate(:counters,
|
|
518
|
+
[TestDoubles::AddsOneAction])])
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
def self.call_single(context)
|
|
522
|
+
with(context)
|
|
523
|
+
.reduce([iterate(:counters,
|
|
524
|
+
TestDoubles::AddsOneAction)])
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
class TestWithCallback
|
|
529
|
+
extend Switchyard::Organizer
|
|
530
|
+
|
|
531
|
+
def self.call(context = {})
|
|
532
|
+
with(context).reduce(actions)
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
def self.actions
|
|
536
|
+
[
|
|
537
|
+
SetUpContextAction,
|
|
538
|
+
with_callback(IterateCollectionAction,
|
|
539
|
+
[IncrementCountAction,
|
|
540
|
+
AddToTotalAction])
|
|
541
|
+
]
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
class SetUpContextAction
|
|
546
|
+
extend Switchyard::Action
|
|
547
|
+
|
|
548
|
+
promises :numbers, :counter, :total
|
|
549
|
+
|
|
550
|
+
executed do |ctx|
|
|
551
|
+
ctx.numbers = [1, 2, 3]
|
|
552
|
+
ctx.counter = 0
|
|
553
|
+
ctx.total = 0
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
class IterateCollectionAction
|
|
558
|
+
extend Switchyard::Action
|
|
559
|
+
|
|
560
|
+
expects :numbers, :callback
|
|
561
|
+
promises :number
|
|
562
|
+
|
|
563
|
+
executed do |ctx|
|
|
564
|
+
ctx.numbers.each do |number|
|
|
565
|
+
ctx.number = number
|
|
566
|
+
ctx.callback.call(ctx)
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
class IncrementCountAction
|
|
572
|
+
extend Switchyard::Action
|
|
573
|
+
|
|
574
|
+
expects :counter
|
|
575
|
+
|
|
576
|
+
executed do |ctx|
|
|
577
|
+
ctx.counter = ctx.counter + 1
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
class AddToTotalAction
|
|
582
|
+
extend Switchyard::Action
|
|
583
|
+
|
|
584
|
+
expects :number, :total
|
|
585
|
+
|
|
586
|
+
executed do |ctx|
|
|
587
|
+
ctx.total += ctx.number
|
|
588
|
+
end
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
class CapitalizeMessage
|
|
592
|
+
extend Switchyard::Action
|
|
593
|
+
|
|
594
|
+
expects :a_message
|
|
595
|
+
promises :final_message
|
|
596
|
+
|
|
597
|
+
executed do |ctx|
|
|
598
|
+
ctx.final_message = ctx.a_message.upcase
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
class AddsNumbersWithOptionalDefaults
|
|
603
|
+
extend Switchyard::Action
|
|
604
|
+
|
|
605
|
+
expects :first_number
|
|
606
|
+
expects :second_number, :default => ->(ctx) { ctx[:first_number] + 7 }
|
|
607
|
+
expects :third_number, :default => 10
|
|
608
|
+
promises :total
|
|
609
|
+
|
|
610
|
+
executed do |ctx|
|
|
611
|
+
ctx.total = ctx.first_number + ctx.second_number + ctx.third_number
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
class OrganizerWithActionsUsingDefaults
|
|
616
|
+
extend Switchyard::Organizer
|
|
617
|
+
|
|
618
|
+
def self.call
|
|
619
|
+
with(:first_number => 1, :number => 1).reduce(actions)
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
def self.actions
|
|
623
|
+
[
|
|
624
|
+
AddsNumbersWithOptionalDefaults,
|
|
625
|
+
AddToTotalAction
|
|
626
|
+
]
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
class AnOrganizerThatAddsToContext
|
|
631
|
+
extend Switchyard::Organizer
|
|
632
|
+
|
|
633
|
+
def self.call
|
|
634
|
+
with.reduce(actions)
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
def self.actions
|
|
638
|
+
[add_to_context(
|
|
639
|
+
:strongest_avenger => :thor,
|
|
640
|
+
:last_jedi => "Rey"
|
|
641
|
+
)]
|
|
642
|
+
end
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
class AnOrganizerThatAddsAliases
|
|
646
|
+
extend Switchyard::Organizer
|
|
647
|
+
|
|
648
|
+
def self.call
|
|
649
|
+
with(:foo => :bar).reduce(actions)
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
def self.actions
|
|
653
|
+
[add_aliases(:foo => :baz)]
|
|
654
|
+
end
|
|
655
|
+
end
|
|
656
|
+
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
|
+
Switchyard::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
|
+
Switchyard::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
|
+
Switchyard::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
|