Class: Serviced::Flow
- Inherits:
-
Object
- Object
- Serviced::Flow
- Includes:
- ResultHelpers
- Defined in:
- lib/serviced/flow.rb
Overview
Composes several steps into a single callable pipeline.
A step is anything that responds to call(context) and returns a
Result: usually a Service subclass, but a lambda or
any callable works too. Steps run in order, each receiving an immutable
context hash. The first failing step halts the flow and its failure is
returned. When every step succeeds, whatever hash each step returned as its
success value is merged into the context, and the final context is returned
as the success value.
class RegisterPatient < Serviced::Flow
transactional # wrap every step in one database transaction
step CreatePatient # returns success(patient: patient)
step CreateChart # reads :patient from the context
step SendWelcome
end
result = RegisterPatient.call(name: "Ada", age: 36)
result.value # => merged context hash of everything the steps produced
A flow can also be built inline:
RegisterPatient = Serviced::Flow.define(transaction: true) do
step CreatePatient
step CreateChart
end
Class Method Summary collapse
-
.call(context = {}) ⇒ Serviced::Result
Runs the flow.
-
.define(transaction: false, &block) ⇒ Class
Builds an anonymous flow subclass from a block.
-
.step(callable) ⇒ Object
Registers a step.
-
.steps ⇒ Array<#call>
The steps registered on this flow.
-
.transactional ⇒ Object
Marks the flow as transactional: all steps run inside a single transaction that rolls back if any step fails or raises.
-
.transactional? ⇒ Boolean
Whether the flow runs inside a transaction.
Instance Method Summary collapse
- #call ⇒ Serviced::Result
-
#initialize(context = {}) ⇒ Flow
constructor
A new instance of Flow.
Constructor Details
#initialize(context = {}) ⇒ Flow
Returns a new instance of Flow.
88 89 90 |
# File 'lib/serviced/flow.rb', line 88 def initialize(context = {}) @context = normalize(context).freeze end |
Class Method Details
.call(context = {}) ⇒ Serviced::Result
Runs the flow.
74 75 76 |
# File 'lib/serviced/flow.rb', line 74 def call(context = {}) new(context).call end |
.define(transaction: false, &block) ⇒ Class
Builds an anonymous flow subclass from a block.
64 65 66 67 68 69 |
# File 'lib/serviced/flow.rb', line 64 def define(transaction: false, &block) Class.new(self) do transactional if transaction class_eval(&block) if block end end |
.step(callable) ⇒ Object
Registers a step. Steps run in the order they are declared.
46 47 48 |
# File 'lib/serviced/flow.rb', line 46 def step(callable) steps << callable end |
.steps ⇒ Array<#call>
Returns the steps registered on this flow.
39 40 41 |
# File 'lib/serviced/flow.rb', line 39 def steps @steps ||= [] end |
.transactional ⇒ Object
Marks the flow as transactional: all steps run inside a single transaction that rolls back if any step fails or raises.
52 53 54 |
# File 'lib/serviced/flow.rb', line 52 def transactional @transactional = true end |
.transactional? ⇒ Boolean
Returns whether the flow runs inside a transaction.
57 58 59 |
# File 'lib/serviced/flow.rb', line 57 def transactional? @transactional end |
Instance Method Details
#call ⇒ Serviced::Result
93 94 95 |
# File 'lib/serviced/flow.rb', line 93 def call self.class.transactional? ? within_transaction { run_steps } : run_steps end |