state_machines-mermaid 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/state_machines/mermaid/renderer.rb +48 -30
- data/lib/state_machines/mermaid/version.rb +1 -1
- data/test/mermaid_renderer_test.rb +45 -8
- metadata +9 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0d80eff2b0ed1c6b458aba82d93fd4e423281ad88d4e6c32b60057e17e2be418
|
|
4
|
+
data.tar.gz: fbd58452672027b070cd34e0be625477a1acccc553e1f0d4396496446c418824
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f0d020c31b57e63e05e880d57c855df53b7fa07b60957f20e494ce314144d6215ab339fe5d06b8ba5f09aeb000f6e025ed7b1826c5954bd3018a391cdf55f398
|
|
7
|
+
data.tar.gz: 267911f506950eb0fc12792eb60722c3c2aba6f287850e8d249e33a6dba9011eb138df373e0c81308851ef9cc1905b4b8702fcda7d24e938826ddfbb2aa2bdb0
|
|
@@ -14,6 +14,7 @@ module StateMachines
|
|
|
14
14
|
@last_state_metadata = nil
|
|
15
15
|
@last_transition_metadata = nil
|
|
16
16
|
@last_transition_metadata_map = nil
|
|
17
|
+
@last_state_id_map = nil
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
# The new simplified approach - leverages the diagram gem's semantic structure
|
|
@@ -75,10 +76,15 @@ module StateMachines
|
|
|
75
76
|
return diagram.to_mermaid unless @last_transition_metadata
|
|
76
77
|
|
|
77
78
|
lines = ["stateDiagram-v2"]
|
|
79
|
+
state_id_map = mermaid_state_id_map(diagram)
|
|
78
80
|
|
|
79
81
|
diagram.states.each do |state|
|
|
80
|
-
fragment = state.
|
|
82
|
+
fragment = render_state_fragment(state, state_id_map.fetch(state.id))
|
|
81
83
|
lines << " #{fragment}" if fragment && !fragment.empty?
|
|
84
|
+
|
|
85
|
+
metadata = @last_state_metadata[state.id] || {}
|
|
86
|
+
lines << " [*] --> #{state_id_map.fetch(state.id)}" if metadata[:type] == 'initial'
|
|
87
|
+
lines << " #{state_id_map.fetch(state.id)} --> [*]" if metadata[:type] == 'final'
|
|
82
88
|
end
|
|
83
89
|
|
|
84
90
|
diagram.transitions.each do |transition|
|
|
@@ -126,16 +132,11 @@ module StateMachines
|
|
|
126
132
|
def build_condition_tokens(conditions)
|
|
127
133
|
return [] unless conditions.is_a?(Hash)
|
|
128
134
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
end
|
|
134
|
-
Array(conditions[:unless]).each do |token|
|
|
135
|
-
next if token.nil? || token.to_s.empty?
|
|
136
|
-
tokens << "unless #{token}"
|
|
135
|
+
%i[if unless if_state unless_state if_all_states unless_all_states if_any_state unless_any_state].flat_map do |kind|
|
|
136
|
+
Array(conditions[kind]).filter_map do |token|
|
|
137
|
+
"#{kind} #{token}" unless token.nil? || token.to_s.empty?
|
|
138
|
+
end
|
|
137
139
|
end
|
|
138
|
-
tokens
|
|
139
140
|
end
|
|
140
141
|
|
|
141
142
|
def build_callback_tokens(callbacks)
|
|
@@ -153,39 +154,56 @@ module StateMachines
|
|
|
153
154
|
|
|
154
155
|
def format_callback_reference(callback)
|
|
155
156
|
case callback
|
|
156
|
-
when Symbol, String
|
|
157
|
-
callback.to_s
|
|
158
157
|
when Proc, Method
|
|
159
|
-
|
|
160
|
-
file, line = callback.source_location
|
|
161
|
-
filename = File.basename(file) if file
|
|
162
|
-
"lambda@#{filename}:#{line}"
|
|
163
|
-
else
|
|
164
|
-
'lambda'
|
|
165
|
-
end
|
|
158
|
+
StateMachines::Diagram::Builder.callable_label(callback)
|
|
166
159
|
else
|
|
167
160
|
callback.to_s
|
|
168
161
|
end
|
|
169
162
|
end
|
|
170
163
|
|
|
171
164
|
def format_node_id(node_id)
|
|
172
|
-
|
|
165
|
+
return '[*]' if node_id == '*'
|
|
166
|
+
|
|
167
|
+
@last_state_id_map.fetch(node_id, node_id)
|
|
173
168
|
end
|
|
174
169
|
|
|
175
|
-
def
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
line.include?(state_name) || line.start_with?("stateDiagram")
|
|
170
|
+
def mermaid_state_id_map(diagram)
|
|
171
|
+
@last_state_id_map ||= diagram.states.each_with_object({}) do |state, map|
|
|
172
|
+
map[state.id] = safe_state_id(state.id)
|
|
179
173
|
end
|
|
180
|
-
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def safe_state_id(state_id)
|
|
177
|
+
value = state_id.to_s
|
|
178
|
+
return value if value.match?(/\A[A-Za-z_][A-Za-z0-9_]*\z/)
|
|
179
|
+
|
|
180
|
+
"state_#{value.bytes.map { |byte| byte.to_s(16).rjust(2, '0') }.join}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def render_state_fragment(state, rendered_id)
|
|
184
|
+
label = state.label || state.id
|
|
185
|
+
return "#{rendered_id} : #{label}" if rendered_id == state.id
|
|
186
|
+
|
|
187
|
+
"state #{mermaid_string(label)} as #{rendered_id}"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def mermaid_string(value)
|
|
191
|
+
%Q{"#{value.to_s.gsub('"', '\\\"')}"}
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def filter_mermaid_for_state(mermaid_syntax, state_name)
|
|
195
|
+
filter_mermaid_lines(mermaid_syntax, state_name)
|
|
181
196
|
end
|
|
182
197
|
|
|
183
198
|
def filter_mermaid_for_event(mermaid_syntax, event_name)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
199
|
+
filter_mermaid_lines(mermaid_syntax, event_name)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Keeps only the diagram header and the lines mentioning the given term
|
|
203
|
+
def filter_mermaid_lines(mermaid_syntax, term)
|
|
204
|
+
mermaid_syntax.split("\n").select do |line|
|
|
205
|
+
line.include?(term) || line.start_with?("stateDiagram")
|
|
206
|
+
end.join("\n")
|
|
189
207
|
end
|
|
190
208
|
end
|
|
191
209
|
end
|
|
@@ -46,12 +46,23 @@ class MermaidRendererTest < Minitest::Test
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def test_final_states
|
|
49
|
+
klass = Class.new do
|
|
50
|
+
attr_accessor :state
|
|
51
|
+
|
|
52
|
+
state_machine :state, initial: :idle do
|
|
53
|
+
event :finish do
|
|
54
|
+
transition idle: :done
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
49
59
|
io = StringIO.new
|
|
50
|
-
StateMachines::Mermaid::Renderer.draw_machine(
|
|
60
|
+
StateMachines::Mermaid::Renderer.draw_machine(klass.state_machine(:state), io: io)
|
|
51
61
|
|
|
52
62
|
output = io.string
|
|
53
|
-
|
|
54
|
-
assert_includes output, "
|
|
63
|
+
assert_includes output, "done : done"
|
|
64
|
+
assert_includes output, "[*] --> idle"
|
|
65
|
+
assert_includes output, "done --> [*]"
|
|
55
66
|
end
|
|
56
67
|
|
|
57
68
|
def test_multiple_from_states
|
|
@@ -143,11 +154,10 @@ class MermaidRendererTest < Minitest::Test
|
|
|
143
154
|
StateMachines::Mermaid::Renderer.draw_machine(klass.state_machine(:status), io: io)
|
|
144
155
|
|
|
145
156
|
output = io.string
|
|
146
|
-
|
|
147
|
-
assert_includes output, "
|
|
148
|
-
assert_includes output, "
|
|
149
|
-
assert_includes output,
|
|
150
|
-
assert_includes output, "waiting-for-input --> processing/data"
|
|
157
|
+
assert_includes output, 'state "waiting-for-input" as state_77616974696e672d666f722d696e707574'
|
|
158
|
+
assert_includes output, 'state "processing/data" as state_70726f63657373696e672f64617461'
|
|
159
|
+
assert_includes output, 'state "error!" as state_6572726f7221'
|
|
160
|
+
assert_includes output, 'state_77616974696e672d666f722d696e707574 --> state_70726f63657373696e672f64617461'
|
|
151
161
|
end
|
|
152
162
|
|
|
153
163
|
def test_dragon_age_progression
|
|
@@ -190,6 +200,33 @@ class MermaidRendererTest < Minitest::Test
|
|
|
190
200
|
assert output.include?("-->"), "Should have transitions"
|
|
191
201
|
end
|
|
192
202
|
|
|
203
|
+
def test_renders_coordinated_state_guards
|
|
204
|
+
klass = Class.new do
|
|
205
|
+
attr_accessor :state, :gate
|
|
206
|
+
|
|
207
|
+
state_machine :gate, initial: :locked do
|
|
208
|
+
event :unlock do
|
|
209
|
+
transition locked: :unlocked
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
state_machine :state, initial: :idle do
|
|
214
|
+
event :run do
|
|
215
|
+
transition idle: :running, if_state: { gate: :unlocked }
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
io = StringIO.new
|
|
221
|
+
StateMachines::Mermaid::Renderer.draw_machine(
|
|
222
|
+
klass.state_machine(:state),
|
|
223
|
+
io: io,
|
|
224
|
+
show_conditions: true
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
assert_includes io.string, '[if_state gate=unlocked]'
|
|
228
|
+
end
|
|
229
|
+
|
|
193
230
|
def test_all_character_types_render_properly
|
|
194
231
|
[@dragon, @mage, @troll, @regiment].each do |character|
|
|
195
232
|
character.class.state_machines.each do |name, machine|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: state_machines-mermaid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Abdelkader Boudih
|
|
@@ -29,14 +29,14 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.
|
|
32
|
+
version: 0.2.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.
|
|
39
|
+
version: 0.2.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: mermaid
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -83,16 +83,16 @@ dependencies:
|
|
|
83
83
|
name: minitest
|
|
84
84
|
requirement: !ruby/object:Gem::Requirement
|
|
85
85
|
requirements:
|
|
86
|
-
- - "
|
|
86
|
+
- - "~>"
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
|
-
version:
|
|
88
|
+
version: '6.0'
|
|
89
89
|
type: :development
|
|
90
90
|
prerelease: false
|
|
91
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
|
-
- - "
|
|
93
|
+
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
|
-
version:
|
|
95
|
+
version: '6.0'
|
|
96
96
|
- !ruby/object:Gem::Dependency
|
|
97
97
|
name: minitest-reporters
|
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -140,14 +140,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
140
140
|
requirements:
|
|
141
141
|
- - ">="
|
|
142
142
|
- !ruby/object:Gem::Version
|
|
143
|
-
version:
|
|
143
|
+
version: '4.0'
|
|
144
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
145
|
requirements:
|
|
146
146
|
- - ">="
|
|
147
147
|
- !ruby/object:Gem::Version
|
|
148
148
|
version: '0'
|
|
149
149
|
requirements: []
|
|
150
|
-
rubygems_version:
|
|
150
|
+
rubygems_version: 4.0.20
|
|
151
151
|
specification_version: 4
|
|
152
152
|
summary: Mermaid renderer for state machines
|
|
153
153
|
test_files:
|