Module: Statecraft::Introspection
- Defined in:
- lib/statecraft/introspection.rb
Overview
The record-facing questions: "would the guards pass if I fired this transition with these metadata right now". Normalization and freeze are identical to the pipeline's, so a guard that mutates metadata fails the same way in a check as in a transition, and the answer never diverges from what fire! would actually do. Every answer is a snapshot: CAS may still reject the transition later.
Defined Under Namespace
Classes: Availability, Refusal
Instance Method Summary collapse
- #available_events(metadata: Metadata::OMITTED) ⇒ Object
- #available_transitions(metadata: Metadata::OMITTED) ⇒ Object
- #can_fire?(event_name, metadata: Metadata::OMITTED) ⇒ Boolean
-
#offerable_events ⇒ Object
The offering: which events the graph AND this record allow from here — the record layer alone, so an input-reading guard never hides the form its input arrives through.
-
#refusals_for(event_name) ⇒ Object
The structured "why not": every record-layer guard refusing the event right now.
- #transitioned_to?(state_name) ⇒ Boolean
Instance Method Details
#available_events(metadata: Metadata::OMITTED) ⇒ Object
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/statecraft/introspection.rb', line 27 def available_events(metadata: Metadata::OMITTED) consulted = statecraft_graph.events.filter_map do |event_name, branches| edge = branches[statecraft_current_state] [edge, event_name] if edge end normalized = (, consulted, question: "available_events") consulted.filter_map do |edge, event_name| event_name if statecraft_guards_pass?(edge, event_name, normalized) end end |
#available_transitions(metadata: Metadata::OMITTED) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/statecraft/introspection.rb', line 38 def available_transitions(metadata: Metadata::OMITTED) outgoing = statecraft_graph.edges.filter_map do |(from, _to), edge| edge if from == statecraft_current_state end consulted = outgoing.flat_map do |edge| pairs = edge.event_names.map { |event_name| [edge, event_name] } statecraft_direct_legal?(edge) ? pairs + [[edge, nil]] : pairs end normalized = (, consulted, question: "available_transitions") outgoing.filter_map do |edge| via = statecraft_passable_via(edge, normalized) Availability.new(to: edge.to, via: via) unless via.empty? end end |
#can_fire?(event_name, metadata: Metadata::OMITTED) ⇒ Boolean
14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/statecraft/introspection.rb', line 14 def can_fire?(event_name, metadata: Metadata::OMITTED) graph = statecraft_graph branches = graph.events[event_name.to_sym] return false unless branches edge = branches[statecraft_current_state] return false unless edge normalized = (, [[edge, event_name.to_sym]], question: "can_fire?(#{event_name.inspect})") statecraft_guards_pass?(edge, event_name.to_sym, normalized) end |
#offerable_events ⇒ Object
The offering: which events the graph AND this record allow from here — the record layer alone, so an input-reading guard never hides the form its input arrives through. A snapshot, like every question here.
60 61 62 63 64 65 66 67 |
# File 'lib/statecraft/introspection.rb', line 60 def offerable_events statecraft_graph.events.filter_map do |event_name, branches| edge = branches[statecraft_current_state] next unless edge event_name if statecraft_record_refusals(edge, event_name).empty? end end |
#refusals_for(event_name) ⇒ Object
The structured "why not": every record-layer guard refusing the event right now. Guard handlers by name, no words — the words belong to the presentation. An unknown event or a missing branch answers [].
72 73 74 75 76 77 78 79 80 |
# File 'lib/statecraft/introspection.rb', line 72 def refusals_for(event_name) branches = statecraft_graph.events[event_name.to_sym] return [].freeze unless branches edge = branches[statecraft_current_state] return [].freeze unless edge statecraft_record_refusals(edge, event_name.to_sym) end |
#transitioned_to?(state_name) ⇒ Boolean
53 54 55 |
# File 'lib/statecraft/introspection.rb', line 53 def transitioned_to?(state_name) history.where(to_state: state_name.to_s).exists? end |