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

Instance Method Details

#available_events(metadata: {}) ⇒ Object



25
26
27
28
29
30
31
32
33
# File 'lib/statecraft/introspection.rb', line 25

def available_events(metadata: {})
  normalized = Metadata.normalize()
  statecraft_graph.events.filter_map do |event_name, branches|
    edge = branches[statecraft_current_state]
    next unless edge

    event_name if statecraft_guards_pass?(edge, event_name, normalized)
  end
end

#available_transitions(metadata: {}) ⇒ Object



35
36
37
38
39
40
41
42
43
# File 'lib/statecraft/introspection.rb', line 35

def available_transitions(metadata: {})
  normalized = Metadata.normalize()
  statecraft_graph.edges.filter_map do |(from, _to), edge|
    next unless from == statecraft_current_state

    via = statecraft_passable_via(edge, normalized)
    Availability.new(to: edge.to, via: via) unless via.empty?
  end
end

#can_fire?(event_name, metadata: {}) ⇒ Boolean

Returns:

  • (Boolean)


14
15
16
17
18
19
20
21
22
23
# File 'lib/statecraft/introspection.rb', line 14

def can_fire?(event_name, metadata: {})
  graph = statecraft_graph
  branches = graph.events[event_name.to_sym]
  return false unless branches

  edge = branches[statecraft_current_state]
  return false unless edge

  statecraft_guards_pass?(edge, event_name.to_sym, Metadata.normalize())
end

#offerable_eventsObject

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.



52
53
54
55
56
57
58
59
# File 'lib/statecraft/introspection.rb', line 52

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 [].



64
65
66
67
68
69
70
71
72
# File 'lib/statecraft/introspection.rb', line 64

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

Returns:

  • (Boolean)


45
46
47
# File 'lib/statecraft/introspection.rb', line 45

def transitioned_to?(state_name)
  history.where(to_state: state_name.to_s).exists?
end