Class: Signoff::Definition
- Inherits:
-
Object
- Object
- Signoff::Definition
- Defined in:
- lib/signoff/definition.rb
Overview
Immutable-once-validated description of a model’s workflow: its states, the allowed forward transitions, the reject state, authorization guards and lifecycle callbacks. Built by Signoff::DSL and stored on the model class as signoff_definition.
Instance Attribute Summary collapse
-
#after_callbacks ⇒ Object
readonly
Returns the value of attribute after_callbacks.
-
#authorizations ⇒ Object
readonly
Returns the value of attribute authorizations.
-
#before_callbacks ⇒ Object
readonly
Returns the value of attribute before_callbacks.
-
#initial_state ⇒ Object
— queries ———————————————————.
-
#reject_state ⇒ Object
Returns the value of attribute reject_state.
-
#state_column ⇒ Object
readonly
Returns the value of attribute state_column.
-
#states ⇒ Object
readonly
Returns the value of attribute states.
-
#transitions ⇒ Object
readonly
Returns the value of attribute transitions.
Instance Method Summary collapse
- #add_authorization(from, guard) ⇒ Object
-
#add_state(name) ⇒ Object
— builders (called by the DSL) ————————————.
- #add_transition(from, to) ⇒ Object
-
#approval_terminal_states ⇒ Object
Terminal states that represent successful completion (everything that is terminal except the reject state).
-
#forward_targets(state) ⇒ Object
Targets reachable from
statevia a declared forward transition. - #guard_for(state) ⇒ Object
-
#initialize(state_column: :approval_state) ⇒ Definition
constructor
A new instance of Definition.
-
#next_state(from, to: nil) ⇒ Object
Resolve the next state when advancing forward from
from. -
#terminal_states ⇒ Object
States with no outgoing forward transition.
-
#validate! ⇒ Object
— validation ——————————————————.
Constructor Details
#initialize(state_column: :approval_state) ⇒ Definition
Returns a new instance of Definition.
13 14 15 16 17 18 19 20 21 22 |
# File 'lib/signoff/definition.rb', line 13 def initialize(state_column: :approval_state) @states = [] @transitions = {} # from(Symbol) => [to(Symbol), ...] @authorizations = {} # from(Symbol) => callable guard @before_callbacks = [] @after_callbacks = [] @initial_state = nil @reject_state = nil @state_column = state_column.to_sym end |
Instance Attribute Details
#after_callbacks ⇒ Object (readonly)
Returns the value of attribute after_callbacks.
9 10 11 |
# File 'lib/signoff/definition.rb', line 9 def after_callbacks @after_callbacks end |
#authorizations ⇒ Object (readonly)
Returns the value of attribute authorizations.
9 10 11 |
# File 'lib/signoff/definition.rb', line 9 def @authorizations end |
#before_callbacks ⇒ Object (readonly)
Returns the value of attribute before_callbacks.
9 10 11 |
# File 'lib/signoff/definition.rb', line 9 def before_callbacks @before_callbacks end |
#initial_state ⇒ Object
— queries ———————————————————
54 55 56 |
# File 'lib/signoff/definition.rb', line 54 def initial_state @initial_state || @states.first end |
#reject_state ⇒ Object
Returns the value of attribute reject_state.
50 51 52 |
# File 'lib/signoff/definition.rb', line 50 def reject_state @reject_state end |
#state_column ⇒ Object (readonly)
Returns the value of attribute state_column.
9 10 11 |
# File 'lib/signoff/definition.rb', line 9 def state_column @state_column end |
#states ⇒ Object (readonly)
Returns the value of attribute states.
9 10 11 |
# File 'lib/signoff/definition.rb', line 9 def states @states end |
#transitions ⇒ Object (readonly)
Returns the value of attribute transitions.
9 10 11 |
# File 'lib/signoff/definition.rb', line 9 def transitions @transitions end |
Instance Method Details
#add_authorization(from, guard) ⇒ Object
42 43 44 |
# File 'lib/signoff/definition.rb', line 42 def (from, guard) @authorizations[from.to_sym] = guard end |
#add_state(name) ⇒ Object
— builders (called by the DSL) ————————————
26 27 28 29 30 31 |
# File 'lib/signoff/definition.rb', line 26 def add_state(name) name = name.to_sym raise DefinitionError, "duplicate state #{name.inspect}" if @states.include?(name) @states << name end |
#add_transition(from, to) ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/signoff/definition.rb', line 33 def add_transition(from, to) from = from.to_sym Array(to).each do |target| target = target.to_sym @transitions[from] ||= [] @transitions[from] << target unless @transitions[from].include?(target) end end |
#approval_terminal_states ⇒ Object
Terminal states that represent successful completion (everything that is terminal except the reject state).
70 71 72 |
# File 'lib/signoff/definition.rb', line 70 def approval_terminal_states terminal_states - [reject_state].compact end |
#forward_targets(state) ⇒ Object
Targets reachable from state via a declared forward transition.
59 60 61 |
# File 'lib/signoff/definition.rb', line 59 def forward_targets(state) @transitions[state.to_sym] || [] end |
#guard_for(state) ⇒ Object
74 75 76 |
# File 'lib/signoff/definition.rb', line 74 def guard_for(state) @authorizations[state.to_sym] end |
#next_state(from, to: nil) ⇒ Object
Resolve the next state when advancing forward from from. to may be supplied to disambiguate when several forward transitions exist.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/signoff/definition.rb', line 80 def next_state(from, to: nil) from = from.to_sym targets = forward_targets(from) if to to = to.to_sym return to if targets.include?(to) raise InvalidTransitionError, "no transition declared from #{from.inspect} to #{to.inspect}" end case targets.size when 0 raise InvalidTransitionError, "no forward transition declared from #{from.inspect}" when 1 targets.first else raise InvalidTransitionError, "ambiguous transition from #{from.inspect}; pass to: " \ "(one of #{targets.inspect})" end end |
#terminal_states ⇒ Object
States with no outgoing forward transition.
64 65 66 |
# File 'lib/signoff/definition.rb', line 64 def terminal_states @states.reject { |s| forward_targets(s).any? } end |
#validate! ⇒ Object
— validation ——————————————————
107 108 109 110 111 112 113 114 115 |
# File 'lib/signoff/definition.rb', line 107 def validate! raise DefinitionError, "no states have been defined" if @states.empty? validate_initial_state! validate_transitions! validate_reject_state! self end |