Class: Diagrams::StateDiagram

Inherits:
Base
  • Object
show all
Defined in:
lib/diagrams/state_diagram.rb

Overview

Represents a State Diagram consisting of states and transitions between them.

Instance Attribute Summary collapse

Attributes inherited from Base

#checksum, #version

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#diff, from_hash, from_json, #to_h, #to_json

Constructor Details

#initialize(title: '', states: [], transitions: [], events: [], version: 1) ⇒ StateDiagram

Initializes a new StateDiagram.

Parameters:

  • title (String) (defaults to: '')

    Optional title for the diagram.

  • states (Array<Element::State>) (defaults to: [])

    An array of state objects.

  • transitions (Array<Element::Transition>) (defaults to: [])

    An array of transition objects.

  • events (Array<Element::Event>) (defaults to: [])

    An array of event objects (optional).

  • version (String, Integer, nil) (defaults to: 1)

    User-defined version identifier.



15
16
17
18
19
20
21
22
23
# File 'lib/diagrams/state_diagram.rb', line 15

def initialize(title: '', states: [], transitions: [], events: [], version: 1)
  super(version:)
  @title = title.is_a?(String) ? title : ''
  @states = Array(states)
  @transitions = Array(transitions)
  @events = Array(events) # Keep events for now
  validate_elements!
  update_checksum!
end

Instance Attribute Details

#eventsObject (readonly)

Returns the value of attribute events.



6
7
8
# File 'lib/diagrams/state_diagram.rb', line 6

def events
  @events
end

#statesObject (readonly)

Returns the value of attribute states.



6
7
8
# File 'lib/diagrams/state_diagram.rb', line 6

def states
  @states
end

#titleObject (readonly)

Returns the value of attribute title.



6
7
8
# File 'lib/diagrams/state_diagram.rb', line 6

def title
  @title
end

#transitionsObject (readonly)

Returns the value of attribute transitions.



6
7
8
# File 'lib/diagrams/state_diagram.rb', line 6

def transitions
  @transitions
end

Class Method Details

.from_h(data_hash, version:, checksum:) ⇒ StateDiagram

Class method to create a StateDiagram from a hash. Used by the deserialization factory in ‘Diagrams::Base`.

Parameters:

  • data_hash (Hash)

    Hash containing ‘:title`, `:states`, `:transitions`, `:events`.

  • version (String, Integer, nil)

    Diagram version.

  • checksum (String, nil)

    Expected checksum (optional, for verification).

Returns:



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/diagrams/state_diagram.rb', line 120

def self.from_h(data_hash, version:, checksum:)
  title = data_hash[:title] || data_hash['title'] || ''
  states_data = data_hash[:states] || data_hash['states'] || []
  transitions_data = data_hash[:transitions] || data_hash['transitions'] || []
  events_data = data_hash[:events] || data_hash['events'] || []

  states = states_data.map { |state_h| Diagrams::Elements::State.new(state_h.transform_keys(&:to_sym)) }
  transitions = transitions_data.map do |trans_h|
    Diagrams::Elements::Transition.new(trans_h.transform_keys(&:to_sym))
  end
  events = events_data.map { |event_h| Diagrams::Elements::Event.new(event_h.transform_keys(&:to_sym)) }

  diagram = new(title:, states:, transitions:, events:, version:)

  # Optional: Verify checksum if provided
  if checksum && diagram.checksum != checksum
    warn "Checksum mismatch for loaded StateDiagram (version: #{version}). Expected #{checksum}, got #{diagram.checksum}."
    # Or raise an error: raise "Checksum mismatch..."
  end

  diagram
end

Instance Method Details

#add_event(event) ⇒ Element::Event

Adds an event to the diagram.

Parameters:

  • event (Element::Event)

    The event object to add.

Returns:

  • (Element::Event)

    The added event.

Raises:

  • (ArgumentError)

    if an event with the same ID already exists.



64
65
66
67
68
69
70
71
# File 'lib/diagrams/state_diagram.rb', line 64

def add_event(event)
  raise ArgumentError, 'Event must be a Diagrams::Elements::Event' unless event.is_a?(Diagrams::Elements::Event)
  raise ArgumentError, "Event with ID '#{event.id}' already exists" if find_event(event.id)

  @events << event
  update_checksum!
  event
end

#add_state(state) ⇒ Element::State

Adds a state to the diagram.

Parameters:

  • state (Element::State)

    The state object to add.

Returns:

  • (Element::State)

    The added state.

Raises:

  • (ArgumentError)

    if a state with the same ID already exists.



30
31
32
33
34
35
36
37
# File 'lib/diagrams/state_diagram.rb', line 30

def add_state(state)
  raise ArgumentError, 'State must be a Diagrams::Elements::State' unless state.is_a?(Diagrams::Elements::State)
  raise ArgumentError, "State with ID '#{state.id}' already exists" if find_state(state.id)

  @states << state
  update_checksum!
  state
end

#add_transition(transition) ⇒ Element::Transition

Adds a transition to the diagram.

Parameters:

  • transition (Element::Transition)

    The transition object to add.

Returns:

  • (Element::Transition)

    The added transition.

Raises:

  • (ArgumentError)

    if the transition refers to non-existent state IDs.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/diagrams/state_diagram.rb', line 44

def add_transition(transition)
  unless transition.is_a?(Diagrams::Elements::Transition)
    raise ArgumentError,
          'Transition must be a Diagrams::Elements::Transition'
  end
  unless find_state(transition.source_state_id) && find_state(transition.target_state_id)
    raise ArgumentError,
          "Transition refers to non-existent state IDs ('#{transition.source_state_id}' or '#{transition.target_state_id}')"
  end

  @transitions << transition
  update_checksum!
  transition
end

#find_event(event_id) ⇒ Element::Event?

Finds an event by its ID.

Parameters:

  • event_id (String)

    The ID of the event to find.

Returns:

  • (Element::Event, nil)

    The found event or nil.



85
86
87
# File 'lib/diagrams/state_diagram.rb', line 85

def find_event(event_id)
  @events.find { |e| e.id == event_id }
end

#find_state(state_id) ⇒ Element::State?

Finds a state by its ID.

Parameters:

  • state_id (String)

    The ID of the state to find.

Returns:

  • (Element::State, nil)

    The found state or nil.



77
78
79
# File 'lib/diagrams/state_diagram.rb', line 77

def find_state(state_id)
  @states.find { |s| s.id == state_id }
end

#identifiable_elementsHash{Symbol => Array<Diagrams::Elements::State | Diagrams::Elements::Transition | Diagrams::Elements::Event>}

Returns a hash mapping element types to their collections for diffing.



105
106
107
108
109
110
111
# File 'lib/diagrams/state_diagram.rb', line 105

def identifiable_elements
  {
    states: @states,
    transitions: @transitions,
    events: @events
  }
end

#to_h_contentHash{Symbol => String | Array<Hash>}

Returns the specific content of the state diagram as a hash. Called by ‘Diagrams::Base#to_h`.

Returns:

  • (Hash{Symbol => String | Array<Hash>})


93
94
95
96
97
98
99
100
# File 'lib/diagrams/state_diagram.rb', line 93

def to_h_content
  {
    title: @title,
    states: @states.map(&:to_h),
    transitions: @transitions.map(&:to_h),
    events: @events.map(&:to_h)
  }
end