Class: Phronomy::Workflow::Builder

Inherits:
Object
  • Object
show all
Defined in:
lib/phronomy/workflow.rb

Overview

DSL builder for Phronomy::Workflow.define. Collects state/event/transition declarations and produces a WorkflowRunner.

Constant Summary collapse

FINISH =
Phronomy::WorkflowRunner::FINISH

Instance Method Summary collapse

Constructor Details

#initialize(context_class) ⇒ Builder

Returns a new instance of Builder.



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/phronomy/workflow.rb', line 112

def initialize(context_class)
  @context_class = context_class
  @initial = nil
  # { node_name => callable }
  @states = {}
  # Array of { from:, to: } — auto-transitions after a state action
  @after_transitions = []
  # Array of { name:, from:, to:, guard: } — event-driven transitions
  @event_transitions = []
  # Set of wait state names
  @wait_state_names = []
end

Instance Method Details

#after(from, to:) ⇒ Object

Declares an automatic transition that fires after a state's action completes.

Parameters:

  • from (Symbol)

    source state name

  • to (Symbol)

    destination state name or :finish



151
152
153
154
# File 'lib/phronomy/workflow.rb', line 151

def after(from, to:)
  dest = (to == :__finish__) ? FINISH : to
  @after_transitions << {from: from, to: dest}
end

#buildObject

Builds and returns a Phronomy::Workflow backed by a WorkflowRunner.



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/phronomy/workflow.rb', line 171

def build
  nodes = @states.dup

  # After-transitions: { from => to }
  # Unconditional transitions that fire automatically after an action state completes.
  after_transitions = @after_transitions.each_with_object({}) do |t, h|
    h[t[:from]] = t[:to]
  end

  # Route transitions: { from => {event_name:, entries: [{guard:, to:}, ...]} }
  # Events declared from action states (not wait states) fire automatically
  # after the action completes. The event name is used to register the
  # state_machines event and may be any symbol (e.g. :route, :route_review).
  # Declaration order is preserved so guarded entries appear before fallbacks.
  route_transitions = {}

  # External events: { event_name => [{from:, to:, guard:}, ...] }
  # Events declared from wait states, triggered by human input (e.g. :approve).
  external_events = {}

  @event_transitions.each do |t|
    if @wait_state_names.include?(t[:from])
      # Source is a wait state → external event
      external_events[t[:name]] ||= []
      external_events[t[:name]] << {from: t[:from], to: t[:to], guard: t[:guard]}
    else
      # Source is an action state → routing event (auto-fires after action)
      # The event name is taken from the first declaration for each from-state.
      route_transitions[t[:from]] ||= {event_name: t[:name], entries: []}
      route_transitions[t[:from]][:entries] << {guard: t[:guard], to: t[:to]}
    end
  end

  runner = Phronomy::WorkflowRunner.new(
    state_class: @context_class,
    nodes: nodes,
    after_transitions: after_transitions,
    route_transitions: route_transitions,
    external_events: external_events,
    entry_point: @initial || nodes.keys.first,
    wait_state_names: @wait_state_names
  )

  Workflow.new(runner)
end

#event(name, from:, to:, guard: nil) ⇒ Object

Declares an event-driven transition. When +guard:+ is provided, the transition is taken only if the guard returns truthy for the current context. Multiple events with the same name and source are evaluated in declaration order; the first passing guard wins.

Parameters:

  • name (Symbol)

    event name

  • from (Symbol)

    source state where this event can be fired

  • to (Symbol)

    destination state or :finish

  • guard (Proc, nil) (defaults to: nil)

    optional guard — receives context, returns truthy/falsy



165
166
167
168
# File 'lib/phronomy/workflow.rb', line 165

def event(name, from:, to:, guard: nil)
  dest = (to == :__finish__) ? FINISH : to
  @event_transitions << {name: name, from: from, to: dest, guard: guard}
end

#initial(state_name) ⇒ Object

Declares the initial (entry) state. rubocop:disable Style/TrivialAccessors

Parameters:

  • state_name (Symbol)


128
129
130
# File 'lib/phronomy/workflow.rb', line 128

def initial(state_name)
  @initial = state_name
end

#state(name, action: nil) ⇒ Object

Declares an action state.

Parameters:

  • name (Symbol)

    state name

  • action (#call, nil) (defaults to: nil)

    callable invoked when entering the state. If nil, the state is treated as a no-op pass-through.



137
138
139
# File 'lib/phronomy/workflow.rb', line 137

def state(name, action: nil)
  @states[name] = action || ->(s) { s }
end

#wait_state(name) ⇒ Object

Declares a wait state that automatically halts execution when reached. No action is registered; the workflow pauses here until an event resumes it.

Parameters:

  • name (Symbol)

    wait state name (conventionally :awaiting_something)



144
145
146
# File 'lib/phronomy/workflow.rb', line 144

def wait_state(name)
  @wait_state_names << name
end