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, state_store: nil) ⇒ Builder

Returns a new instance of Builder.



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/phronomy/workflow.rb', line 168

def initialize(context_class, state_store: nil)
  @context_class = context_class
  @state_store = state_store
  @initial = nil
  # Ordered list of declared state names (action states only, not wait states).
  @declared_states = []
  # { state_name => [callable, ...] } — entry actions registered via entry()
  @entry_actions = {}
  # { state_name => [callable, ...] } — exit actions registered via exit()
  @exit_actions = {}
  # Array of { from:, to:, guard:, on: } — all transitions in declaration order
  @transitions = []
  # Set of wait state names
  @wait_state_names = []
  # { state_name => Numeric } — per-state action timeout in seconds
  @action_timeouts = {}
end

Instance Method Details

#buildObject

Builds and returns a Phronomy::Workflow backed by a WorkflowRunner. Performs build-time validation of the graph structure:

  • raises ArgumentError when no initial state is declared and no states have been defined
  • raises ArgumentError when a transition references an undeclared target state
  • warns when declared states are unreachable from the initial state

Raises:

  • (ArgumentError)

    on structural errors



329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/phronomy/workflow.rb', line 329

def build
  entry_actions = @entry_actions.dup
  exit_actions = @exit_actions.dup

  validate_graph!

  # Auto-fire transitions (no :on): fire automatically when action completes.
  # External events (with :on): triggered manually via send_event.
  auto_transitions = []
  external_events = {}

  @transitions.each do |t|
    if t[:on]
      external_events[t[:on]] ||= []
      external_events[t[:on]] << {from: t[:from], to: t[:to], guard: t[:guard]}
    else
      auto_transitions << {from: t[:from], to: t[:to], guard: t[:guard]}
    end
  end

  runner = Phronomy::WorkflowRunner.new(
    state_class: @context_class,
    entry_actions: entry_actions,
    exit_actions: exit_actions,
    declared_states: @declared_states.dup,
    auto_transitions: auto_transitions,
    external_events: external_events,
    entry_point: @initial || @declared_states.first,
    wait_state_names: @wait_state_names,
    state_store: @state_store,
    action_timeouts: @action_timeouts.dup
  )

  Workflow.new(runner)
end

#entry(name, callable) ⇒ Object

Declares an entry action for a state. The callable is invoked when the workflow enters +name+. It receives the current context. Two styles are supported:

  • Mutation-in-place: mutate context fields directly (+s.field = value+); the return value is ignored.
  • Immutable update: return a new context via +s.merge(field: value)+; the returned context replaces the current one. Multiple calls for the same state are allowed; callables fire in declaration order.

Parameters:

  • name (Symbol)

    state name

  • callable (#call)

    receives context; may return a new WorkflowContext



221
222
223
# File 'lib/phronomy/workflow.rb', line 221

def entry(name, callable)
  (@entry_actions[name] ||= []) << callable
end

#exit(name, callable) ⇒ Object

Declares an exit action for a state. The callable is invoked when the workflow leaves +name+. It receives the current context and should mutate it in place. Return value is ignored. Multiple calls for the same state are allowed; callables fire in declaration order.

Parameters:

  • name (Symbol)

    state name

  • callable (#call)

    receives context, mutates it in place



233
234
235
# File 'lib/phronomy/workflow.rb', line 233

def exit(name, callable)
  (@exit_actions[name] ||= []) << callable
end

#initial(state_name) ⇒ Object

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

Parameters:

  • state_name (Symbol)


190
191
192
# File 'lib/phronomy/workflow.rb', line 190

def initial(state_name)
  @initial = state_name
end

#state(name, action: nil, action_timeout: nil) ⇒ Object

Declares an action state.

Parameters:

  • name (Symbol)

    state name

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

    optional entry action shorthand. +state :generate, action: MY_PROC+ is equivalent to +state :generate; entry :generate, MY_PROC+.

  • action_timeout (Numeric, nil) (defaults to: nil)

    seconds before an async (Task-returning) entry action is cancelled and ActionTimeoutError is raised. Only applies when the action returns a Task or PendingOperation.



204
205
206
207
208
# File 'lib/phronomy/workflow.rb', line 204

def state(name, action: nil, action_timeout: nil)
  @declared_states << name
  @action_timeouts[name] = action_timeout if action_timeout
  entry(name, action) if action
end

#transition(from:, to:, guard: nil, on: nil) ⇒ Object

Declares a transition between states. Auto-fire transitions (no +on:+) fire automatically when an action state's action completes. External transitions (+on: :event_name+) are triggered manually via +send_event+. When +guard:+ is provided the transition is taken only if the guard returns truthy for the current context. Multiple transitions from the same source are evaluated in declaration order; the first passing guard wins.

Parameters:

  • from (Symbol)

    source state

  • to (Symbol)

    destination state or :finish

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

    optional guard — receives context, returns truthy/falsy

  • on (Symbol, nil) (defaults to: nil)

    named event for manual triggers (e.g. :approve)



257
258
259
260
# File 'lib/phronomy/workflow.rb', line 257

def transition(from:, to:, guard: nil, on: nil)
  dest = (to == :__finish__) ? FINISH : to
  @transitions << {from: from, to: dest, guard: guard, on: on}
end

#wait_state(name) ⇒ Object

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

Parameters:

  • name (Symbol)

    wait state name (conventionally :awaiting_something)



241
242
243
# File 'lib/phronomy/workflow.rb', line 241

def wait_state(name)
  @wait_state_names << name
end