Class: Hecks::Bluebook::DSL::ProcessManagerBuilder
- Inherits:
-
Object
- Object
- Hecks::Bluebook::DSL::ProcessManagerBuilder
- Includes:
- WordGate
- Defined in:
- lib/hecks/bluebook/dsl/process_manager_builder.rb
Defined Under Namespace
Classes: HandlerBuilder, InvalidProcessManager
Constant Summary collapse
- GRAMMAR_CONTEXT =
"ProcessManager"
Constants included from WordGate
Class Method Summary collapse
Instance Method Summary collapse
- #build ⇒ Object
-
#initialize(name) ⇒ ProcessManagerBuilder
constructor
A new instance of ProcessManagerBuilder.
-
#transition_impl(mapping, &block) ⇒ Object
ONE STATE-MACHINE VOCABULARY (S7, ADR 0025 — "events and reactions"): the SAME word
Lifecycle#transitionalready carries, one level over — `transition "AccountDebited" => "awaiting_credit", from: "requested" do ...
Constructor Details
#initialize(name) ⇒ ProcessManagerBuilder
Returns a new instance of ProcessManagerBuilder.
12 13 14 15 |
# File 'lib/hecks/bluebook/dsl/process_manager_builder.rb', line 12 def initialize(name) @name = name @handlers = [] end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class Hecks::Bluebook::DSL::WordGate
Class Method Details
.build(name, &block) ⇒ Object
106 107 108 109 110 |
# File 'lib/hecks/bluebook/dsl/process_manager_builder.rb', line 106 def self.build(name, &block) builder = new(name) builder.instance_eval(&block) if block builder.build end |
Instance Method Details
#build ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/hecks/bluebook/dsl/process_manager_builder.rb', line 93 def build validate! ProcessManager.new( name: @name, correlates_by: @correlates_by, starts_on: @starts_on, ends_on: @ends_on, states: derived_states, handlers: @handlers ) end |
#transition_impl(mapping, &block) ⇒ Object
ONE STATE-MACHINE VOCABULARY (S7, ADR 0025 — "events and
reactions"): the SAME word Lifecycle#transition already
carries, one level over — transition "AccountDebited" => "awaiting_credit", from: "requested" do ... end replaces on "AccountDebited", transition: { "requested" => "awaiting_ credit" } do ... end. Same bare rocket-pair argument shape
(not a NAMED transition: kwarg wrapping a second Hash), same
from: — including the array form Lifecycle's own commands
could already take and a process manager's own events could
not — and the states a procedure runs on are DERIVED from the
transitions that name them, the same way Behaviour::Lifecycle #states already derives an aggregate's ; state "x" lines
duplicated exactly what the transition list already said,
and could drift from it (validate!'s own "undeclared state"
check existed only because they could).
starts_on/ends_on are NOT unified into this — verified
against the real corpus rather than assumed: Settlement's own
ends_on "TransferSettled" names an event NONE of its own
transitions ever handle (Transfer.Settle's own emission, a
full step downstream of the transition that dispatches it),
so "the terminal state's own event" is not a fact the
transition graph carries — deriving it would either be wrong
for this exact corpus member or need a second new word to
cover the case, which is not less vocabulary than keeping the
one that already says it correctly.
EXPANDS IMMEDIATELY, unlike Lifecycle#transition (which
defers to Behaviour::Lifecycle#expand, called at emission
time) — ProcessManager's own IR constructor takes states:/
handlers: exactly as it always has, so the runtime
(Behaviour::ProcessManager, SagaInterpreter, saga
persistence/rehydration) needs no change at all: what changed
is how the DECLARATION reaches that same shape, not the shape
a real run ever sees or persists.
RENAMED FROM transition — item #13's full metaprogrammed
dispatch (slice 4c). Not bootstrap-reachable (checked
directly — no core/attached chapter declares a ProcessManager
of its own).
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/hecks/bluebook/dsl/process_manager_builder.rb', line 61 def transition_impl(mapping, &block) mapping = mapping.dup from = mapping.delete(:from) # ALWAYS REQUIRED, unlike `Lifecycle#transition`'s own `from:` # — an aggregate's unconstrained transition is admitted from # ANY current state (`Behaviour::Lifecycle#applies_from?` # returns true for a nil `from`), a reading `SagaInterpreter# # advance_saga`'s own admission check does not share: it tests # `instance[:state] == handler.from_state` by plain equality, # nothing softer. Leaving that check unchanged (this slice's # own scope decision — see the class-level comment on why the # runtime stays untouched) means an unconstrained PM # transition would build cleanly and then match no instance # ever, silently — refused here instead, at the one point that # can still see the mistake. if from.nil? raise InvalidProcessManager, "#{@name}'s transition #{mapping.inspect} names no from: — a process manager's own " \ "admission checks a saga instance's CURRENT state exactly, so a transition with no " \ "from: would match no instance ever, silently" end handler = HandlerBuilder.new handler.instance_eval(&block) if block mapping.each do |event_type, target| state_transition = StateTransition.new(target: target, from: from) (event_type.to_s, state_transition, handler.dispatches).each { |row| @handlers << row } end end |