standard_procedure_operations 0.3.0 → 0.3.5
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 +4 -4
- data/README.md +41 -1
- data/app/models/operations/task/background.rb +7 -1
- data/app/models/operations/task/state_management/decision_handler.rb +19 -3
- data/app/models/operations/task/state_management/wait_handler.rb +15 -6
- data/lib/operations/no_decision.rb +2 -0
- data/lib/operations/version.rb +1 -1
- data/lib/operations.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71a0ca8e718085505be26fcb316ed4a1e2f9338a12ea55901626696fe5e15269
|
4
|
+
data.tar.gz: 3b94981a2c8b8193bc01ee4f414db2c34161ac111c85a59f68eb3c88dd3b7aa6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 970184f8761aa729ceebf0cc5fa00a0c8c24a8ef9b1afaa3203b990d92c7c992441a51ef07579efcc93f4948f94d4da4b21c5df07df2adea700523cdb290d13d
|
7
|
+
data.tar.gz: 970e42aecaf9a622c259e27eb830a283ff1be70a4545ab01a4a42debe65ccf2cfcf68aa817a3778c2cfee503957cbf0c96de59e0ace254e2d773e1bb41d5c96e
|
data/README.md
CHANGED
@@ -116,6 +116,20 @@ end
|
|
116
116
|
```
|
117
117
|
(In theory the block used in the `fail_with` case can do anything within the [DataCarrier context](#data-and-results) - so you could set internal state or call methods on the containing task - but I've not tried this yet).
|
118
118
|
|
119
|
+
Alternatively, you can evaluate multiple conditions in your decision handler.
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
decision :is_the_weather_good? do
|
123
|
+
condition { weather_forecast.sunny? }
|
124
|
+
go_to :the_beach
|
125
|
+
condition { weather_forecast.rainy? }
|
126
|
+
go_to :grab_an_umbrella
|
127
|
+
condition { weather_forecast.snowing? }
|
128
|
+
go_to :build_a_snowman
|
129
|
+
end
|
130
|
+
```
|
131
|
+
If no conditions are matched then the task fails with a `NoDecision` exception.
|
132
|
+
|
119
133
|
You can specify the data that is required for a decision handler to run by specifying `inputs` and `optionals`:
|
120
134
|
```ruby
|
121
135
|
decision :authorised? do
|
@@ -158,7 +172,20 @@ end
|
|
158
172
|
Do not forget to call `go_to` from your action handler, otherwise the operation will just stop whilst still being marked as in progress. (TODO: don't let this happen).
|
159
173
|
|
160
174
|
### Waiting
|
161
|
-
Wait handlers only work within [background tasks](#background-operations-and-pauses).
|
175
|
+
Wait handlers are very similar to decision handlers but only work within [background tasks](#background-operations-and-pauses).
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
wait_until :weather_forecast_available? do
|
179
|
+
condition { weather_forecast.sunny? }
|
180
|
+
go_to :the_beach
|
181
|
+
condition { weather_forecast.rainy? }
|
182
|
+
go_to :grab_an_umbrella
|
183
|
+
condition { weather_forecast.snowing? }
|
184
|
+
go_to :build_a_snowman
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
If no conditions are met, then, unlike a decision handler, the task continues waiting in the same state.
|
162
189
|
|
163
190
|
### Results
|
164
191
|
A result handler marks the end of an operation, optionally returning some results. You need to copy your desired results from your [data](#data-and-results) to your results object. This is so only the information that matters to you is stored as the results.
|
@@ -431,6 +458,19 @@ class UserRegistration < Operations::Task
|
|
431
458
|
end
|
432
459
|
```
|
433
460
|
|
461
|
+
Instead of failing with an `Operations::Timeout` exception, you define an `on_timeout` handler for any special processing should the time-out occur.
|
462
|
+
|
463
|
+
```ruby
|
464
|
+
class WaitForSomething < Operations::Task
|
465
|
+
timeout 10.minutes
|
466
|
+
delay 1.minute
|
467
|
+
|
468
|
+
on_timeout do
|
469
|
+
Notifier.send_timeout_notification
|
470
|
+
end
|
471
|
+
end>
|
472
|
+
```
|
473
|
+
|
434
474
|
## Testing
|
435
475
|
Because operations are intended to model long, complex, flowcharts of decisions and actions, it can be a pain coming up with the combinations of inputs to test every path through the sequence.
|
436
476
|
|
@@ -10,17 +10,23 @@ module Operations::Task::Background
|
|
10
10
|
@execution_timeout = value
|
11
11
|
end
|
12
12
|
|
13
|
+
def on_timeout(&handler) = @on_timeout = handler
|
14
|
+
|
13
15
|
def background_delay = @background_delay ||= 1.second
|
14
16
|
|
15
17
|
def execution_timeout = @execution_timeout ||= 5.minutes
|
16
18
|
|
19
|
+
def timeout_handler = @on_timeout
|
20
|
+
|
17
21
|
def with_timeout(data) = data.merge(_execution_timeout: execution_timeout.from_now.utc)
|
18
22
|
end
|
19
23
|
|
20
24
|
private def background_delay = self.class.background_delay
|
21
25
|
private def execution_timeout = self.class.execution_timeout
|
26
|
+
private def timeout_handler = self.class.timeout_handler
|
22
27
|
private def timeout!
|
23
|
-
|
28
|
+
return unless timeout_expired?
|
29
|
+
timeout_handler.nil? ? raise(Operations::Timeout.new("Timeout expired", self)) : timeout_handler.call
|
24
30
|
end
|
25
31
|
private def timeout_expired? = data[:_execution_timeout].present? && data[:_execution_timeout] < Time.now.utc
|
26
32
|
end
|
@@ -3,13 +3,16 @@ class Operations::Task::StateManagement::DecisionHandler
|
|
3
3
|
|
4
4
|
def initialize name, &config
|
5
5
|
@name = name.to_sym
|
6
|
-
@
|
6
|
+
@conditions = []
|
7
|
+
@destinations = []
|
7
8
|
@true_state = nil
|
8
9
|
@false_state = nil
|
9
10
|
instance_eval(&config)
|
10
11
|
end
|
11
12
|
|
12
|
-
def condition(&condition) = @
|
13
|
+
def condition(&condition) = @conditions << condition
|
14
|
+
|
15
|
+
def go_to(destination) = @destinations << destination
|
13
16
|
|
14
17
|
def if_true(state = nil, &handler) = @true_state = state || handler
|
15
18
|
|
@@ -17,7 +20,20 @@ class Operations::Task::StateManagement::DecisionHandler
|
|
17
20
|
|
18
21
|
def call(task, data)
|
19
22
|
validate_inputs! data.to_h
|
20
|
-
|
23
|
+
has_true_false_handlers? ? handle_single_condition(task, data) : handle_multiple_conditions(task, data)
|
24
|
+
end
|
25
|
+
|
26
|
+
private def has_true_false_handlers? = !@true_state.nil? || !@false_state.nil?
|
27
|
+
|
28
|
+
private def handle_single_condition(task, data)
|
29
|
+
next_state = data.instance_eval(&@conditions.first) ? @true_state : @false_state
|
21
30
|
next_state.respond_to?(:call) ? data.instance_eval(&next_state) : data.go_to(next_state)
|
22
31
|
end
|
32
|
+
|
33
|
+
private def handle_multiple_conditions(task, data)
|
34
|
+
condition = @conditions.find { |condition| data.instance_eval(&condition) }
|
35
|
+
raise Operations::NoDecision.new("No conditions matched #{@name}") if condition.nil?
|
36
|
+
index = @conditions.index condition
|
37
|
+
data.go_to @destinations[index]
|
38
|
+
end
|
23
39
|
end
|
@@ -1,18 +1,27 @@
|
|
1
1
|
class Operations::Task::StateManagement::WaitHandler
|
2
2
|
def initialize name, &config
|
3
3
|
@name = name.to_sym
|
4
|
-
@
|
5
|
-
@
|
4
|
+
@conditions = []
|
5
|
+
@destinations = []
|
6
6
|
instance_eval(&config)
|
7
|
+
puts "Configured"
|
7
8
|
end
|
8
9
|
|
9
|
-
def condition(&condition) = @
|
10
|
+
def condition(&condition) = @conditions << condition
|
10
11
|
|
11
|
-
def go_to(state) = @
|
12
|
+
def go_to(state) = @destinations << state
|
12
13
|
|
13
14
|
def call(task, data)
|
14
15
|
raise Operations::CannotWaitInForeground.new("#{task.class} cannot wait in the foreground", task) unless task.background?
|
15
|
-
|
16
|
-
data.
|
16
|
+
puts "Searching"
|
17
|
+
condition = @conditions.find { |condition| data.instance_eval(&condition) }
|
18
|
+
if condition.nil?
|
19
|
+
puts "None"
|
20
|
+
data.go_to task.state
|
21
|
+
else
|
22
|
+
index = @conditions.index condition
|
23
|
+
puts "Found #{@destinations[index]}"
|
24
|
+
data.go_to @destinations[index]
|
25
|
+
end
|
17
26
|
end
|
18
27
|
end
|
data/lib/operations/version.rb
CHANGED
data/lib/operations.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: standard_procedure_operations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rahoul Baruah
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-03-04 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: rails
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/operations/failure.rb
|
55
55
|
- lib/operations/global_id_serialiser.rb
|
56
56
|
- lib/operations/matchers.rb
|
57
|
+
- lib/operations/no_decision.rb
|
57
58
|
- lib/operations/timeout.rb
|
58
59
|
- lib/operations/version.rb
|
59
60
|
- lib/standard_procedure_operations.rb
|