sirena 0.1.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 +7 -0
- data/.github/workflows/build_deploy.yml +59 -0
- data/.github/workflows/links.yml +85 -0
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +27 -0
- data/.gitignore +68 -0
- data/.rspec +3 -0
- data/.rubocop.yml +14 -0
- data/.rubocop_todo.yml +70 -0
- data/ARCHITECTURE.md +744 -0
- data/Gemfile +12 -0
- data/LICENSE +25 -0
- data/README.adoc +357 -0
- data/Rakefile +11 -0
- data/docs/.gitignore +1 -0
- data/docs/Gemfile +13 -0
- data/docs/_config.yml +182 -0
- data/docs/_diagram_types/architecture-diagram.adoc +314 -0
- data/docs/_diagram_types/block-diagram.adoc +345 -0
- data/docs/_diagram_types/c4-diagram.adoc +559 -0
- data/docs/_diagram_types/class-diagram.adoc +816 -0
- data/docs/_diagram_types/er-diagram.adoc +719 -0
- data/docs/_diagram_types/error-diagram.adoc +114 -0
- data/docs/_diagram_types/examples/flowchart-examples.adoc +29 -0
- data/docs/_diagram_types/flowchart.adoc +488 -0
- data/docs/_diagram_types/gantt-chart.adoc +502 -0
- data/docs/_diagram_types/git-graph.adoc +600 -0
- data/docs/_diagram_types/index.adoc +192 -0
- data/docs/_diagram_types/info-diagram.adoc +103 -0
- data/docs/_diagram_types/kanban-diagram.adoc +262 -0
- data/docs/_diagram_types/mindmap.adoc +603 -0
- data/docs/_diagram_types/packet-diagram.adoc +378 -0
- data/docs/_diagram_types/pie-chart.adoc +335 -0
- data/docs/_diagram_types/quadrant-chart.adoc +406 -0
- data/docs/_diagram_types/radar-chart.adoc +528 -0
- data/docs/_diagram_types/requirement-diagram.adoc +416 -0
- data/docs/_diagram_types/sankey-diagram.adoc +357 -0
- data/docs/_diagram_types/sequence-diagram.adoc +664 -0
- data/docs/_diagram_types/state-diagram.adoc +658 -0
- data/docs/_diagram_types/timeline.adoc +352 -0
- data/docs/_diagram_types/treemap-diagram.adoc +462 -0
- data/docs/_diagram_types/user-journey.adoc +602 -0
- data/docs/_features/index.adoc +129 -0
- data/docs/_guides/cli-reference.adoc +203 -0
- data/docs/_guides/index.adoc +56 -0
- data/docs/_guides/installation.adoc +100 -0
- data/docs/_guides/quick-start.adoc +132 -0
- data/docs/_pages/comparison.adoc +441 -0
- data/docs/_pages/compatibility.adoc +300 -0
- data/docs/_pages/index.adoc +39 -0
- data/docs/_references/index.adoc +103 -0
- data/docs/_tutorials/index.adoc +57 -0
- data/docs/index.adoc +166 -0
- data/docs/lychee.toml +54 -0
- data/examples/.gitignore +10 -0
- data/examples/README.adoc +196 -0
- data/examples/README.md +64 -0
- data/examples/architecture/01-basic-services.mmd +9 -0
- data/examples/architecture/01-basic-services.svg +37 -0
- data/examples/architecture/02-service-groups.mmd +16 -0
- data/examples/architecture/02-service-groups.svg +55 -0
- data/examples/architecture/README.adoc +79 -0
- data/examples/block/01-basic-blocks.mmd +13 -0
- data/examples/block/01-basic-blocks.svg +44 -0
- data/examples/block/02-block-shapes.mmd +13 -0
- data/examples/block/02-block-shapes.svg +47 -0
- data/examples/block/README.adoc +85 -0
- data/examples/c4/01-context-diagram.mmd +10 -0
- data/examples/c4/01-context-diagram.svg +45 -0
- data/examples/c4/02-container-diagram.mmd +24 -0
- data/examples/c4/02-container-diagram.svg +105 -0
- data/examples/c4/README.adoc +92 -0
- data/examples/class_diagram/01-basic-classes.mmd +61 -0
- data/examples/class_diagram/01-basic-classes.svg +117 -0
- data/examples/class_diagram/02-relationships.mmd +61 -0
- data/examples/class_diagram/02-relationships.svg +129 -0
- data/examples/class_diagram/README.adoc +93 -0
- data/examples/er_diagram/01-basic-entities.mmd +64 -0
- data/examples/er_diagram/01-basic-entities.svg +5 -0
- data/examples/er_diagram/02-cardinality.mmd +57 -0
- data/examples/er_diagram/02-cardinality.svg +125 -0
- data/examples/er_diagram/README.adoc +88 -0
- data/examples/error/01-basic-error.mmd +1 -0
- data/examples/error/01-basic-error.svg +13 -0
- data/examples/error/02-error-display.mmd +1 -0
- data/examples/error/02-error-display.svg +13 -0
- data/examples/error/README.adoc +71 -0
- data/examples/error_message_example.svg +13 -0
- data/examples/flowchart/00-original.mmd +13 -0
- data/examples/flowchart/00-original.svg +5 -0
- data/examples/flowchart/01-basic-flow.mmd +7 -0
- data/examples/flowchart/01-basic-flow.svg +52 -0
- data/examples/flowchart/01-basic-flow.yml +13 -0
- data/examples/flowchart/02*.svg +87 -0
- data/examples/flowchart/02-node-shapes.mmd +9 -0
- data/examples/flowchart/02-node-shapes.svg +33 -0
- data/examples/flowchart/03-edge-types.mmd +7 -0
- data/examples/flowchart/03-edge-types.svg +53 -0
- data/examples/flowchart/04-subgraphs.mmd +9 -0
- data/examples/flowchart/04-subgraphs.svg +33 -0
- data/examples/flowchart/05-styling.mmd +9 -0
- data/examples/flowchart/05-styling.svg +33 -0
- data/examples/flowchart/06-complex-flow.mmd +8 -0
- data/examples/flowchart/06-complex-flow.svg +59 -0
- data/examples/flowchart/README.adoc +167 -0
- data/examples/gantt/01-simple-timeline.* +14 -0
- data/examples/gantt/01-simple-timeline.mmd +6 -0
- data/examples/gantt/01-simple-timeline.svg +26 -0
- data/examples/gantt/02-task-dependencies.mmd +6 -0
- data/examples/gantt/02-task-dependencies.svg +26 -0
- data/examples/gantt/README.adoc +86 -0
- data/examples/git_graph/01-linear-history.mmd +12 -0
- data/examples/git_graph/01-linear-history.svg +26 -0
- data/examples/git_graph/02-branching.mmd +12 -0
- data/examples/git_graph/02-branching.svg +26 -0
- data/examples/git_graph/README.adoc +73 -0
- data/examples/info/02-showinfo.mmd +1 -0
- data/examples/info/02-showinfo.svg +10 -0
- data/examples/info/README.adoc +58 -0
- data/examples/info_showinfo_example.svg +10 -0
- data/examples/kanban/01-simple-board.mmd +8 -0
- data/examples/kanban/01-simple-board.svg +43 -0
- data/examples/kanban/02-workflow.mmd +8 -0
- data/examples/kanban/02-workflow.svg +43 -0
- data/examples/kanban/README.adoc +79 -0
- data/examples/mindmap/01-simple-tree.mmd +19 -0
- data/examples/mindmap/01-simple-tree.svg +61 -0
- data/examples/mindmap/02-knowledge-map.mmd +19 -0
- data/examples/mindmap/02-knowledge-map.svg +61 -0
- data/examples/mindmap/README.adoc +77 -0
- data/examples/packet/01-basic-packet.* +17 -0
- data/examples/packet/01-basic-packet.mmd +4 -0
- data/examples/packet/01-basic-packet.svg +82 -0
- data/examples/packet/README.adoc +58 -0
- data/examples/pie/01-simple-chart.mmd +5 -0
- data/examples/pie/01-simple-chart.svg +17 -0
- data/examples/pie/02-labeled-slices.mmd +6 -0
- data/examples/pie/02-labeled-slices.svg +19 -0
- data/examples/pie/README.adoc +75 -0
- data/examples/quadrant/01-basic-quadrant.mmd +13 -0
- data/examples/quadrant/01-basic-quadrant.svg +33 -0
- data/examples/quadrant/02-positioned-items.mmd +14 -0
- data/examples/quadrant/02-positioned-items.svg +35 -0
- data/examples/quadrant/README.adoc +84 -0
- data/examples/radar/01-simple-radar.* +5 -0
- data/examples/radar/01-simple-radar.mmd +3 -0
- data/examples/radar/01-simple-radar.svg +25 -0
- data/examples/radar/02-multiple-curves.mmd +4 -0
- data/examples/radar/02-multiple-curves.svg +43 -0
- data/examples/radar/README.adoc +75 -0
- data/examples/requirement/01-basic-requirements.mmd +23 -0
- data/examples/requirement/01-basic-requirements.svg +49 -0
- data/examples/requirement/02-risk-levels.mmd +23 -0
- data/examples/requirement/02-risk-levels.svg +49 -0
- data/examples/requirement/README.adoc +85 -0
- data/examples/sankey/01-simple-flow.mmd +7 -0
- data/examples/sankey/01-simple-flow.svg +34 -0
- data/examples/sankey/02-multi-stage.mmd +11 -0
- data/examples/sankey/02-multi-stage.svg +44 -0
- data/examples/sankey/README.adoc +74 -0
- data/examples/sequence/01-basic-sequence.mmd +27 -0
- data/examples/sequence/01-basic-sequence.svg +5 -0
- data/examples/sequence/02-activations.mmd +17 -0
- data/examples/sequence/02-activations.svg +78 -0
- data/examples/sequence/README.adoc +86 -0
- data/examples/state_diagram/01-simple-states.mmd +29 -0
- data/examples/state_diagram/01-simple-states.svg +5 -0
- data/examples/state_diagram/02-composite.mmd +19 -0
- data/examples/state_diagram/02-composite.svg +81 -0
- data/examples/state_diagram/README.adoc +90 -0
- data/examples/timeline/01-simple-timeline.mmd +11 -0
- data/examples/timeline/01-simple-timeline.svg +36 -0
- data/examples/timeline/02-periods.mmd +15 -0
- data/examples/timeline/02-periods.svg +47 -0
- data/examples/timeline/README.adoc +78 -0
- data/examples/treemap/01-basic-treemap.mmd +12 -0
- data/examples/treemap/01-basic-treemap.svg +59 -0
- data/examples/treemap/README.adoc +59 -0
- data/examples/user_journey/01-simple-journey.mmd +23 -0
- data/examples/user_journey/01-simple-journey.svg +5 -0
- data/examples/user_journey/02-multi-actor.mmd +18 -0
- data/examples/user_journey/02-multi-actor.svg +129 -0
- data/examples/user_journey/README.adoc +81 -0
- data/examples/xychart/01-line-chart.mmd +5 -0
- data/examples/xychart/01-line-chart.svg +43 -0
- data/examples/xychart/02-bar-chart.mmd +7 -0
- data/examples/xychart/02-bar-chart.svg +48 -0
- data/examples/xychart/README.adoc +80 -0
- data/exe/sirena +7 -0
- data/lib/sirena/cli.rb +138 -0
- data/lib/sirena/commands/batch.rb +117 -0
- data/lib/sirena/commands/render.rb +80 -0
- data/lib/sirena/commands/types.rb +29 -0
- data/lib/sirena/commands/version.rb +24 -0
- data/lib/sirena/diagram/architecture.rb +46 -0
- data/lib/sirena/diagram/base.rb +61 -0
- data/lib/sirena/diagram/block.rb +81 -0
- data/lib/sirena/diagram/c4.rb +328 -0
- data/lib/sirena/diagram/class_diagram.rb +385 -0
- data/lib/sirena/diagram/er_diagram.rb +238 -0
- data/lib/sirena/diagram/error.rb +38 -0
- data/lib/sirena/diagram/flowchart.rb +160 -0
- data/lib/sirena/diagram/gantt.rb +71 -0
- data/lib/sirena/diagram/git_graph.rb +36 -0
- data/lib/sirena/diagram/info.rb +38 -0
- data/lib/sirena/diagram/kanban.rb +178 -0
- data/lib/sirena/diagram/mindmap.rb +54 -0
- data/lib/sirena/diagram/packet.rb +79 -0
- data/lib/sirena/diagram/pie.rb +115 -0
- data/lib/sirena/diagram/quadrant.rb +138 -0
- data/lib/sirena/diagram/radar.rb +52 -0
- data/lib/sirena/diagram/requirement.rb +133 -0
- data/lib/sirena/diagram/sankey.rb +217 -0
- data/lib/sirena/diagram/sequence.rb +242 -0
- data/lib/sirena/diagram/state_diagram.rb +237 -0
- data/lib/sirena/diagram/timeline.rb +171 -0
- data/lib/sirena/diagram/treemap.rb +84 -0
- data/lib/sirena/diagram/user_journey.rb +149 -0
- data/lib/sirena/diagram/xy_chart.rb +76 -0
- data/lib/sirena/diagram.rb +8 -0
- data/lib/sirena/diagram_registry.rb +101 -0
- data/lib/sirena/engine.rb +292 -0
- data/lib/sirena/parser/architecture.rb +41 -0
- data/lib/sirena/parser/base.rb +41 -0
- data/lib/sirena/parser/block.rb +72 -0
- data/lib/sirena/parser/c4.rb +53 -0
- data/lib/sirena/parser/class_diagram.rb +63 -0
- data/lib/sirena/parser/er_diagram.rb +40 -0
- data/lib/sirena/parser/error.rb +49 -0
- data/lib/sirena/parser/flowchart.rb +71 -0
- data/lib/sirena/parser/gantt.rb +60 -0
- data/lib/sirena/parser/git_graph.rb +95 -0
- data/lib/sirena/parser/grammars/architecture.rb +145 -0
- data/lib/sirena/parser/grammars/block.rb +190 -0
- data/lib/sirena/parser/grammars/c4.rb +226 -0
- data/lib/sirena/parser/grammars/class_diagram.rb +284 -0
- data/lib/sirena/parser/grammars/common.rb +84 -0
- data/lib/sirena/parser/grammars/er_diagram.rb +114 -0
- data/lib/sirena/parser/grammars/error.rb +40 -0
- data/lib/sirena/parser/grammars/flowchart.rb +298 -0
- data/lib/sirena/parser/grammars/gantt.rb +252 -0
- data/lib/sirena/parser/grammars/git_graph.rb +167 -0
- data/lib/sirena/parser/grammars/info.rb +58 -0
- data/lib/sirena/parser/grammars/kanban.rb +83 -0
- data/lib/sirena/parser/grammars/mindmap.rb +115 -0
- data/lib/sirena/parser/grammars/packet.rb +73 -0
- data/lib/sirena/parser/grammars/pie.rb +128 -0
- data/lib/sirena/parser/grammars/quadrant.rb +199 -0
- data/lib/sirena/parser/grammars/radar.rb +150 -0
- data/lib/sirena/parser/grammars/requirement.rb +188 -0
- data/lib/sirena/parser/grammars/sankey.rb +104 -0
- data/lib/sirena/parser/grammars/sequence.rb +247 -0
- data/lib/sirena/parser/grammars/state_diagram.rb +172 -0
- data/lib/sirena/parser/grammars/timeline.rb +142 -0
- data/lib/sirena/parser/grammars/treemap.rb +120 -0
- data/lib/sirena/parser/grammars/xy_chart.rb +120 -0
- data/lib/sirena/parser/info.rb +49 -0
- data/lib/sirena/parser/kanban.rb +97 -0
- data/lib/sirena/parser/mindmap.rb +106 -0
- data/lib/sirena/parser/packet.rb +76 -0
- data/lib/sirena/parser/pie.rb +49 -0
- data/lib/sirena/parser/quadrant.rb +57 -0
- data/lib/sirena/parser/radar.rb +104 -0
- data/lib/sirena/parser/requirement.rb +70 -0
- data/lib/sirena/parser/sankey.rb +64 -0
- data/lib/sirena/parser/sequence.rb +51 -0
- data/lib/sirena/parser/state_diagram.rb +69 -0
- data/lib/sirena/parser/timeline.rb +57 -0
- data/lib/sirena/parser/transforms/architecture.rb +97 -0
- data/lib/sirena/parser/transforms/block.rb +254 -0
- data/lib/sirena/parser/transforms/c4.rb +347 -0
- data/lib/sirena/parser/transforms/class_diagram.rb +352 -0
- data/lib/sirena/parser/transforms/er_diagram.rb +169 -0
- data/lib/sirena/parser/transforms/error.rb +58 -0
- data/lib/sirena/parser/transforms/flowchart.rb +293 -0
- data/lib/sirena/parser/transforms/gantt.rb +215 -0
- data/lib/sirena/parser/transforms/git_graph.rb +160 -0
- data/lib/sirena/parser/transforms/info.rb +58 -0
- data/lib/sirena/parser/transforms/kanban.rb +176 -0
- data/lib/sirena/parser/transforms/mindmap.rb +227 -0
- data/lib/sirena/parser/transforms/packet.rb +63 -0
- data/lib/sirena/parser/transforms/pie.rb +143 -0
- data/lib/sirena/parser/transforms/quadrant.rb +177 -0
- data/lib/sirena/parser/transforms/radar.rb +126 -0
- data/lib/sirena/parser/transforms/requirement.rb +272 -0
- data/lib/sirena/parser/transforms/sankey.rb +122 -0
- data/lib/sirena/parser/transforms/sequence.rb +342 -0
- data/lib/sirena/parser/transforms/state_diagram.rb +292 -0
- data/lib/sirena/parser/transforms/timeline.rb +177 -0
- data/lib/sirena/parser/transforms/treemap.rb +81 -0
- data/lib/sirena/parser/transforms/xy_chart.rb +132 -0
- data/lib/sirena/parser/treemap.rb +98 -0
- data/lib/sirena/parser/user_journey.rb +120 -0
- data/lib/sirena/parser/xy_chart.rb +114 -0
- data/lib/sirena/parser.rb +8 -0
- data/lib/sirena/renderer/architecture.rb +251 -0
- data/lib/sirena/renderer/base.rb +251 -0
- data/lib/sirena/renderer/block.rb +286 -0
- data/lib/sirena/renderer/c4.rb +490 -0
- data/lib/sirena/renderer/class_diagram.rb +499 -0
- data/lib/sirena/renderer/er_diagram.rb +417 -0
- data/lib/sirena/renderer/error.rb +131 -0
- data/lib/sirena/renderer/flowchart.rb +301 -0
- data/lib/sirena/renderer/gantt.rb +331 -0
- data/lib/sirena/renderer/git_graph.rb +368 -0
- data/lib/sirena/renderer/info.rb +93 -0
- data/lib/sirena/renderer/kanban.rb +295 -0
- data/lib/sirena/renderer/mindmap.rb +396 -0
- data/lib/sirena/renderer/packet.rb +239 -0
- data/lib/sirena/renderer/pie.rb +235 -0
- data/lib/sirena/renderer/quadrant.rb +292 -0
- data/lib/sirena/renderer/radar.rb +323 -0
- data/lib/sirena/renderer/requirement.rb +371 -0
- data/lib/sirena/renderer/sankey.rb +255 -0
- data/lib/sirena/renderer/sequence.rb +424 -0
- data/lib/sirena/renderer/state_diagram.rb +328 -0
- data/lib/sirena/renderer/timeline.rb +304 -0
- data/lib/sirena/renderer/treemap.rb +152 -0
- data/lib/sirena/renderer/user_journey.rb +331 -0
- data/lib/sirena/renderer/xy_chart.rb +452 -0
- data/lib/sirena/renderer.rb +8 -0
- data/lib/sirena/svg/circle.rb +41 -0
- data/lib/sirena/svg/document.rb +103 -0
- data/lib/sirena/svg/element.rb +65 -0
- data/lib/sirena/svg/ellipse.rb +33 -0
- data/lib/sirena/svg/group.rb +71 -0
- data/lib/sirena/svg/line.rb +49 -0
- data/lib/sirena/svg/path.rb +76 -0
- data/lib/sirena/svg/polygon.rb +43 -0
- data/lib/sirena/svg/polyline.rb +35 -0
- data/lib/sirena/svg/rect.rb +57 -0
- data/lib/sirena/svg/style.rb +44 -0
- data/lib/sirena/svg/text.rb +72 -0
- data/lib/sirena/svg.rb +19 -0
- data/lib/sirena/text_measurement.rb +71 -0
- data/lib/sirena/theme/builtin/dark.yml +70 -0
- data/lib/sirena/theme/builtin/default.yml +80 -0
- data/lib/sirena/theme/builtin/high_contrast.yml +70 -0
- data/lib/sirena/theme/builtin/light.yml +70 -0
- data/lib/sirena/theme/color_palette.rb +48 -0
- data/lib/sirena/theme/effect_styles.rb +28 -0
- data/lib/sirena/theme/registry.rb +41 -0
- data/lib/sirena/theme/shape_styles.rb +28 -0
- data/lib/sirena/theme/spacing_config.rb +24 -0
- data/lib/sirena/theme/typography.rb +30 -0
- data/lib/sirena/theme.rb +69 -0
- data/lib/sirena/transform/architecture.rb +273 -0
- data/lib/sirena/transform/base.rb +199 -0
- data/lib/sirena/transform/block.rb +215 -0
- data/lib/sirena/transform/c4.rb +288 -0
- data/lib/sirena/transform/class_diagram.rb +296 -0
- data/lib/sirena/transform/er_diagram.rb +204 -0
- data/lib/sirena/transform/error.rb +39 -0
- data/lib/sirena/transform/flowchart.rb +161 -0
- data/lib/sirena/transform/gantt.rb +253 -0
- data/lib/sirena/transform/git_graph.rb +283 -0
- data/lib/sirena/transform/info.rb +39 -0
- data/lib/sirena/transform/kanban.rb +180 -0
- data/lib/sirena/transform/mindmap.rb +251 -0
- data/lib/sirena/transform/packet.rb +185 -0
- data/lib/sirena/transform/pie.rb +62 -0
- data/lib/sirena/transform/quadrant.rb +167 -0
- data/lib/sirena/transform/radar.rb +227 -0
- data/lib/sirena/transform/requirement.rb +233 -0
- data/lib/sirena/transform/sankey.rb +212 -0
- data/lib/sirena/transform/sequence.rb +143 -0
- data/lib/sirena/transform/state_diagram.rb +228 -0
- data/lib/sirena/transform/timeline.rb +139 -0
- data/lib/sirena/transform/treemap.rb +120 -0
- data/lib/sirena/transform/user_journey.rb +207 -0
- data/lib/sirena/transform/xy_chart.rb +273 -0
- data/lib/sirena/transform.rb +8 -0
- data/lib/sirena/version.rb +5 -0
- data/lib/sirena.rb +328 -0
- data/lib/tasks/benchmark.rake +532 -0
- data/lib/tasks/examples.rake +468 -0
- data/lib/tasks/generate_mermaid_fixtures.rake +363 -0
- data/lib/tasks/mermaid_fixtures.rake +46 -0
- data/scripts/extract_mermaid_tests.rb +493 -0
- data/scripts/rename_to_sirena.rb +73 -0
- data/sirena.gemspec +47 -0
- metadata +529 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'lutaml/model'
|
|
4
|
+
require_relative 'base'
|
|
5
|
+
|
|
6
|
+
module Sirena
|
|
7
|
+
module Diagram
|
|
8
|
+
# Represents a flowchart node.
|
|
9
|
+
#
|
|
10
|
+
# A node has an identifier, label text, and a shape type that
|
|
11
|
+
# determines how it should be rendered visually.
|
|
12
|
+
class FlowchartNode < Lutaml::Model::Serializable
|
|
13
|
+
# Unique identifier for the node
|
|
14
|
+
attribute :id, :string
|
|
15
|
+
|
|
16
|
+
# Display text/label for the node
|
|
17
|
+
attribute :label, :string
|
|
18
|
+
|
|
19
|
+
# Shape type: :rect, :rounded, :stadium, :subroutine, :cylindrical,
|
|
20
|
+
# :circle, :asymmetric, :rhombus, :hexagon, :parallelogram,
|
|
21
|
+
# :parallelogram_alt, :trapezoid, :trapezoid_alt, :double_circle
|
|
22
|
+
attribute :shape, :string
|
|
23
|
+
|
|
24
|
+
# Optional classes/styles
|
|
25
|
+
attribute :classes, :string
|
|
26
|
+
|
|
27
|
+
# Initialize with default shape
|
|
28
|
+
def initialize(*args)
|
|
29
|
+
super
|
|
30
|
+
self.shape ||= 'rect'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Validates the node has required attributes.
|
|
34
|
+
#
|
|
35
|
+
# @return [Boolean] true if node is valid
|
|
36
|
+
def valid?
|
|
37
|
+
!id.nil? && !id.empty? && !label.nil?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Represents a flowchart edge (connection between nodes).
|
|
42
|
+
#
|
|
43
|
+
# An edge connects a source node to a target node, with optional
|
|
44
|
+
# label text and arrow styling.
|
|
45
|
+
class FlowchartEdge < Lutaml::Model::Serializable
|
|
46
|
+
# Source node identifier
|
|
47
|
+
attribute :source_id, :string
|
|
48
|
+
|
|
49
|
+
# Target node identifier
|
|
50
|
+
attribute :target_id, :string
|
|
51
|
+
|
|
52
|
+
# Optional edge label
|
|
53
|
+
attribute :label, :string
|
|
54
|
+
|
|
55
|
+
# Arrow type: :arrow, :dotted_arrow, :thick_arrow, :line,
|
|
56
|
+
# :dotted_line, :thick_line
|
|
57
|
+
attribute :arrow_type, :string
|
|
58
|
+
|
|
59
|
+
# Initialize with default arrow type
|
|
60
|
+
def initialize(*args)
|
|
61
|
+
super
|
|
62
|
+
self.arrow_type ||= 'arrow'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Validates the edge has required attributes.
|
|
66
|
+
#
|
|
67
|
+
# @return [Boolean] true if edge is valid
|
|
68
|
+
def valid?
|
|
69
|
+
!source_id.nil? && !source_id.empty? &&
|
|
70
|
+
!target_id.nil? && !target_id.empty?
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Flowchart diagram model.
|
|
75
|
+
#
|
|
76
|
+
# Represents a complete flowchart with nodes and edges. Flowcharts
|
|
77
|
+
# support various node shapes and edge types to create flow diagrams,
|
|
78
|
+
# decision trees, and process flows.
|
|
79
|
+
#
|
|
80
|
+
# @example Creating a simple flowchart
|
|
81
|
+
# flowchart = Flowchart.new(direction: 'TD')
|
|
82
|
+
# flowchart.nodes << FlowchartNode.new(
|
|
83
|
+
# id: 'A',
|
|
84
|
+
# label: 'Start',
|
|
85
|
+
# shape: 'stadium'
|
|
86
|
+
# )
|
|
87
|
+
# flowchart.nodes << FlowchartNode.new(
|
|
88
|
+
# id: 'B',
|
|
89
|
+
# label: 'Process',
|
|
90
|
+
# shape: 'rect'
|
|
91
|
+
# )
|
|
92
|
+
# flowchart.edges << FlowchartEdge.new(
|
|
93
|
+
# source_id: 'A',
|
|
94
|
+
# target_id: 'B',
|
|
95
|
+
# arrow_type: 'arrow'
|
|
96
|
+
# )
|
|
97
|
+
class Flowchart < Base
|
|
98
|
+
# Collection of nodes in the flowchart
|
|
99
|
+
attribute :nodes, FlowchartNode, collection: true, default: -> { [] }
|
|
100
|
+
|
|
101
|
+
# Collection of edges connecting nodes
|
|
102
|
+
attribute :edges, FlowchartEdge, collection: true, default: -> { [] }
|
|
103
|
+
|
|
104
|
+
# Returns the diagram type identifier.
|
|
105
|
+
#
|
|
106
|
+
# @return [Symbol] :flowchart
|
|
107
|
+
def diagram_type
|
|
108
|
+
:flowchart
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Validates the flowchart structure.
|
|
112
|
+
#
|
|
113
|
+
# A flowchart is valid if:
|
|
114
|
+
# - It has at least one node
|
|
115
|
+
# - All nodes are valid
|
|
116
|
+
# - All edges are valid
|
|
117
|
+
# - All edge references point to existing nodes
|
|
118
|
+
#
|
|
119
|
+
# @return [Boolean] true if flowchart is valid
|
|
120
|
+
def valid?
|
|
121
|
+
return false if nodes.nil? || nodes.empty?
|
|
122
|
+
return false unless nodes.all?(&:valid?)
|
|
123
|
+
return false unless edges.nil? || edges.all?(&:valid?)
|
|
124
|
+
|
|
125
|
+
# Validate edge references
|
|
126
|
+
node_ids = nodes.map(&:id)
|
|
127
|
+
edges&.each do |edge|
|
|
128
|
+
return false unless node_ids.include?(edge.source_id)
|
|
129
|
+
return false unless node_ids.include?(edge.target_id)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Finds a node by its identifier.
|
|
136
|
+
#
|
|
137
|
+
# @param id [String] the node identifier to find
|
|
138
|
+
# @return [FlowchartNode, nil] the node or nil if not found
|
|
139
|
+
def find_node(id)
|
|
140
|
+
nodes.find { |n| n.id == id }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Finds all edges originating from a specific node.
|
|
144
|
+
#
|
|
145
|
+
# @param node_id [String] the source node identifier
|
|
146
|
+
# @return [Array<FlowchartEdge>] edges from the node
|
|
147
|
+
def edges_from(node_id)
|
|
148
|
+
edges.select { |e| e.source_id == node_id }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Finds all edges targeting a specific node.
|
|
152
|
+
#
|
|
153
|
+
# @param node_id [String] the target node identifier
|
|
154
|
+
# @return [Array<FlowchartEdge>] edges to the node
|
|
155
|
+
def edges_to(node_id)
|
|
156
|
+
edges.select { |e| e.target_id == node_id }
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Sirena
|
|
6
|
+
module Diagram
|
|
7
|
+
# Gantt chart task
|
|
8
|
+
class GanttTask < Lutaml::Model::Serializable
|
|
9
|
+
attribute :description, :string
|
|
10
|
+
attribute :id, :string
|
|
11
|
+
attribute :start_date, :string
|
|
12
|
+
attribute :end_date, :string
|
|
13
|
+
attribute :duration, :string
|
|
14
|
+
attribute :after_task, :string
|
|
15
|
+
attribute :until_task, :string
|
|
16
|
+
attribute :tags, :string, collection: true
|
|
17
|
+
attribute :click_href, :string
|
|
18
|
+
attribute :click_callback, :string
|
|
19
|
+
|
|
20
|
+
def initialize
|
|
21
|
+
super
|
|
22
|
+
@tags ||= []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def done?
|
|
26
|
+
tags.include?("done")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def active?
|
|
30
|
+
tags.include?("active")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def critical?
|
|
34
|
+
tags.include?("crit")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def milestone?
|
|
38
|
+
tags.include?("milestone")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Gantt chart section grouping
|
|
43
|
+
class GanttSection < Lutaml::Model::Serializable
|
|
44
|
+
attribute :name, :string
|
|
45
|
+
attribute :tasks, GanttTask, collection: true
|
|
46
|
+
|
|
47
|
+
def initialize(name = nil)
|
|
48
|
+
super()
|
|
49
|
+
@name = name
|
|
50
|
+
@tasks ||= []
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Gantt chart diagram model
|
|
55
|
+
class GanttChart < Lutaml::Model::Serializable
|
|
56
|
+
attribute :title, :string
|
|
57
|
+
attribute :date_format, :string, default: -> { "YYYY-MM-DD" }
|
|
58
|
+
attribute :axis_format, :string
|
|
59
|
+
attribute :tick_interval, :string
|
|
60
|
+
attribute :excludes, :string, collection: true
|
|
61
|
+
attribute :today_marker, :string
|
|
62
|
+
attribute :sections, GanttSection, collection: true
|
|
63
|
+
|
|
64
|
+
def initialize
|
|
65
|
+
super
|
|
66
|
+
@sections ||= []
|
|
67
|
+
@excludes ||= []
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Sirena
|
|
6
|
+
module Diagram
|
|
7
|
+
# Represents a Git Graph diagram
|
|
8
|
+
class GitGraph < Base
|
|
9
|
+
# Represents a commit in the git graph
|
|
10
|
+
class Commit < Lutaml::Model::Serializable
|
|
11
|
+
attribute :id, :string
|
|
12
|
+
attribute :message, :string
|
|
13
|
+
attribute :type, :string, default: -> { "NORMAL" }
|
|
14
|
+
attribute :tag, :string
|
|
15
|
+
attribute :branch_name, :string
|
|
16
|
+
attribute :parent_ids, :string, collection: true, default: -> { [] }
|
|
17
|
+
attribute :is_merge, :boolean, default: -> { false }
|
|
18
|
+
attribute :merge_branch, :string
|
|
19
|
+
attribute :is_cherry_pick, :boolean, default: -> { false }
|
|
20
|
+
attribute :cherry_pick_parent, :string
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Represents a branch in the git graph
|
|
24
|
+
class Branch < Lutaml::Model::Serializable
|
|
25
|
+
attribute :name, :string
|
|
26
|
+
attribute :order, :integer
|
|
27
|
+
attribute :parent_branch, :string
|
|
28
|
+
attribute :created_at_commit, :string
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
attribute :orientation, :string, default: -> { "LR" }
|
|
32
|
+
attribute :commits, Commit, collection: true, default: -> { [] }
|
|
33
|
+
attribute :branches, Branch, collection: true, default: -> { [] }
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'lutaml/model'
|
|
4
|
+
require_relative 'base'
|
|
5
|
+
|
|
6
|
+
module Sirena
|
|
7
|
+
module Diagram
|
|
8
|
+
# Info diagram model.
|
|
9
|
+
#
|
|
10
|
+
# Represents a simple informational diagram that displays a message
|
|
11
|
+
# or status information. Info diagrams are typically used to show
|
|
12
|
+
# system information, help text, or status messages.
|
|
13
|
+
#
|
|
14
|
+
# @example Creating an info diagram
|
|
15
|
+
# info = Info.new
|
|
16
|
+
# info.show_info = true
|
|
17
|
+
class Info < Base
|
|
18
|
+
# Whether to show additional info
|
|
19
|
+
attribute :show_info, :boolean, default: -> { false }
|
|
20
|
+
|
|
21
|
+
# Returns the diagram type identifier.
|
|
22
|
+
#
|
|
23
|
+
# @return [Symbol] :info
|
|
24
|
+
def diagram_type
|
|
25
|
+
:info
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Validates the info diagram structure.
|
|
29
|
+
#
|
|
30
|
+
# Info diagrams are always valid as they have no required content.
|
|
31
|
+
#
|
|
32
|
+
# @return [Boolean] true
|
|
33
|
+
def valid?
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
require_relative "base"
|
|
5
|
+
|
|
6
|
+
module Sirena
|
|
7
|
+
module Diagram
|
|
8
|
+
# Represents a card in a Kanban column.
|
|
9
|
+
#
|
|
10
|
+
# A card has an id, text content, and optional metadata like
|
|
11
|
+
# assigned user, ticket number, icon, priority, etc.
|
|
12
|
+
class KanbanCard < Lutaml::Model::Serializable
|
|
13
|
+
# Card identifier
|
|
14
|
+
attribute :id, :string
|
|
15
|
+
|
|
16
|
+
# Card text content
|
|
17
|
+
attribute :text, :string
|
|
18
|
+
|
|
19
|
+
# Optional metadata
|
|
20
|
+
attribute :assigned, :string
|
|
21
|
+
attribute :ticket, :string
|
|
22
|
+
attribute :icon, :string
|
|
23
|
+
attribute :label, :string
|
|
24
|
+
attribute :priority, :string
|
|
25
|
+
|
|
26
|
+
# Validates the card has required fields.
|
|
27
|
+
#
|
|
28
|
+
# @return [Boolean] true if card is valid
|
|
29
|
+
def valid?
|
|
30
|
+
!id.nil? && !id.empty? && !text.nil? && !text.empty?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns all metadata as a hash.
|
|
34
|
+
#
|
|
35
|
+
# @return [Hash] metadata hash
|
|
36
|
+
def metadata
|
|
37
|
+
{
|
|
38
|
+
assigned: assigned,
|
|
39
|
+
ticket: ticket,
|
|
40
|
+
icon: icon,
|
|
41
|
+
label: label,
|
|
42
|
+
priority: priority
|
|
43
|
+
}.compact
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Checks if card has any metadata.
|
|
47
|
+
#
|
|
48
|
+
# @return [Boolean] true if card has metadata
|
|
49
|
+
def has_metadata?
|
|
50
|
+
!metadata.empty?
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Represents a column in a Kanban board.
|
|
55
|
+
#
|
|
56
|
+
# A column has an id, title, and contains multiple cards.
|
|
57
|
+
class KanbanColumn < Lutaml::Model::Serializable
|
|
58
|
+
# Column identifier
|
|
59
|
+
attribute :id, :string
|
|
60
|
+
|
|
61
|
+
# Column title/name
|
|
62
|
+
attribute :title, :string
|
|
63
|
+
|
|
64
|
+
# Collection of cards in this column
|
|
65
|
+
attribute :cards, KanbanCard, collection: true, default: -> { [] }
|
|
66
|
+
|
|
67
|
+
# Validates the column has required fields.
|
|
68
|
+
#
|
|
69
|
+
# @return [Boolean] true if column is valid
|
|
70
|
+
def valid?
|
|
71
|
+
!id.nil? && !id.empty? &&
|
|
72
|
+
!title.nil? && !title.empty? &&
|
|
73
|
+
cards.all?(&:valid?)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Adds a card to this column.
|
|
77
|
+
#
|
|
78
|
+
# @param card [KanbanCard] the card to add
|
|
79
|
+
# @return [void]
|
|
80
|
+
def add_card(card)
|
|
81
|
+
cards << card
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Kanban board diagram model.
|
|
86
|
+
#
|
|
87
|
+
# Represents a complete Kanban board with columns and cards
|
|
88
|
+
# for workflow visualization.
|
|
89
|
+
#
|
|
90
|
+
# @example Creating a simple kanban board
|
|
91
|
+
# diagram = Kanban.new
|
|
92
|
+
# column = KanbanColumn.new.tap do |c|
|
|
93
|
+
# c.id = "todo"
|
|
94
|
+
# c.title = "Todo"
|
|
95
|
+
# end
|
|
96
|
+
# card = KanbanCard.new.tap do |c|
|
|
97
|
+
# c.id = "docs"
|
|
98
|
+
# c.text = "Create Documentation"
|
|
99
|
+
# c.priority = "High"
|
|
100
|
+
# end
|
|
101
|
+
# column.add_card(card)
|
|
102
|
+
# diagram.add_column(column)
|
|
103
|
+
class Kanban < Base
|
|
104
|
+
# Collection of columns in the board
|
|
105
|
+
attribute :columns, KanbanColumn, collection: true,
|
|
106
|
+
default: -> { [] }
|
|
107
|
+
|
|
108
|
+
# Returns the diagram type identifier.
|
|
109
|
+
#
|
|
110
|
+
# @return [Symbol] :kanban
|
|
111
|
+
def diagram_type
|
|
112
|
+
:kanban
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Validates the kanban board structure.
|
|
116
|
+
#
|
|
117
|
+
# A kanban is valid if:
|
|
118
|
+
# - It has at least one column
|
|
119
|
+
# - All columns are valid
|
|
120
|
+
# - All cards within columns are valid
|
|
121
|
+
#
|
|
122
|
+
# @return [Boolean] true if kanban board is valid
|
|
123
|
+
def valid?
|
|
124
|
+
return false if columns.nil? || columns.empty?
|
|
125
|
+
return false unless columns.all?(&:valid?)
|
|
126
|
+
|
|
127
|
+
true
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Adds a column to the board.
|
|
131
|
+
#
|
|
132
|
+
# @param column [KanbanColumn] the column to add
|
|
133
|
+
# @return [void]
|
|
134
|
+
def add_column(column)
|
|
135
|
+
columns << column
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Returns all cards across all columns.
|
|
139
|
+
#
|
|
140
|
+
# @return [Array<KanbanCard>] all cards in the board
|
|
141
|
+
def all_cards
|
|
142
|
+
columns.flat_map(&:cards)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Finds a column by id.
|
|
146
|
+
#
|
|
147
|
+
# @param id [String] the column id
|
|
148
|
+
# @return [KanbanColumn, nil] the column or nil if not found
|
|
149
|
+
def find_column(id)
|
|
150
|
+
columns.find { |c| c.id == id }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Finds cards by assigned user.
|
|
154
|
+
#
|
|
155
|
+
# @param user [String] the assigned user
|
|
156
|
+
# @return [Array<KanbanCard>] cards assigned to the user
|
|
157
|
+
def cards_by_assigned(user)
|
|
158
|
+
all_cards.select { |c| c.assigned == user }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Finds cards by priority.
|
|
162
|
+
#
|
|
163
|
+
# @param priority [String] the priority level
|
|
164
|
+
# @return [Array<KanbanCard>] cards with the given priority
|
|
165
|
+
def cards_by_priority(priority)
|
|
166
|
+
all_cards.select { |c| c.priority == priority }
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Finds cards by ticket.
|
|
170
|
+
#
|
|
171
|
+
# @param ticket [String] the ticket number
|
|
172
|
+
# @return [Array<KanbanCard>] cards with the given ticket
|
|
173
|
+
def cards_by_ticket(ticket)
|
|
174
|
+
all_cards.select { |c| c.ticket == ticket }
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module Sirena
|
|
6
|
+
module Diagram
|
|
7
|
+
# Represents a Mindmap diagram
|
|
8
|
+
class Mindmap < Base
|
|
9
|
+
# Represents a node in the mindmap
|
|
10
|
+
class MindmapNode < Lutaml::Model::Serializable
|
|
11
|
+
attribute :id, :string
|
|
12
|
+
attribute :content, :string
|
|
13
|
+
attribute :level, :integer, default: -> { 0 }
|
|
14
|
+
attribute :shape, :string, default: -> { "default" }
|
|
15
|
+
attribute :icon, :string
|
|
16
|
+
attribute :classes, :string, collection: true, default: -> { [] }
|
|
17
|
+
attribute :children, MindmapNode, collection: true, default: -> { [] }
|
|
18
|
+
attribute :parent, MindmapNode
|
|
19
|
+
|
|
20
|
+
# Shape constants
|
|
21
|
+
SHAPES = {
|
|
22
|
+
circle: "circle", # ((text))
|
|
23
|
+
cloud: "cloud", # )text(
|
|
24
|
+
bang: "bang", # ))text((
|
|
25
|
+
hexagon: "hexagon", # {{text}}
|
|
26
|
+
square: "square", # [text]
|
|
27
|
+
default: "default" # plain text (rounded rectangle)
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
def add_child(child)
|
|
31
|
+
child.parent = self
|
|
32
|
+
child.level = level + 1
|
|
33
|
+
children << child
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def root?
|
|
37
|
+
level == 0
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def leaf?
|
|
41
|
+
children.empty?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
attribute :root, MindmapNode
|
|
46
|
+
attribute :nodes, MindmapNode, collection: true, default: -> { [] }
|
|
47
|
+
|
|
48
|
+
def add_node(node)
|
|
49
|
+
nodes << node
|
|
50
|
+
@root = node if node.root?
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sirena
|
|
4
|
+
module Diagram
|
|
5
|
+
# Represents a packet diagram showing network packet structures
|
|
6
|
+
class PacketDiagram < Base
|
|
7
|
+
attr_accessor :title, :fields
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
super
|
|
11
|
+
@fields = []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def type
|
|
15
|
+
:packet
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Add a field to the packet
|
|
19
|
+
def add_field(field)
|
|
20
|
+
@fields << field
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Get the maximum bit position used in the packet
|
|
24
|
+
def max_bit_position
|
|
25
|
+
return 0 if @fields.empty?
|
|
26
|
+
|
|
27
|
+
@fields.map(&:bit_end).max
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Calculate the number of rows needed (assuming 32-bit width)
|
|
31
|
+
def row_count(bits_per_row = 32)
|
|
32
|
+
return 1 if @fields.empty?
|
|
33
|
+
|
|
34
|
+
((max_bit_position + 1).to_f / bits_per_row).ceil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Represents a field in a packet diagram
|
|
39
|
+
class PacketField
|
|
40
|
+
attr_accessor :bit_start, :bit_end, :label
|
|
41
|
+
|
|
42
|
+
def initialize(bit_start, bit_end, label)
|
|
43
|
+
@bit_start = bit_start.to_i
|
|
44
|
+
@bit_end = bit_end.to_i
|
|
45
|
+
@label = label
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Get the size of the field in bits
|
|
49
|
+
def size
|
|
50
|
+
@bit_end - @bit_start + 1
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Get the row this field starts in (for 32-bit rows)
|
|
54
|
+
def start_row(bits_per_row = 32)
|
|
55
|
+
@bit_start / bits_per_row
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Get the row this field ends in (for 32-bit rows)
|
|
59
|
+
def end_row(bits_per_row = 32)
|
|
60
|
+
@bit_end / bits_per_row
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Check if this field spans multiple rows
|
|
64
|
+
def spans_rows?(bits_per_row = 32)
|
|
65
|
+
start_row(bits_per_row) != end_row(bits_per_row)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Get the bit position within a row (0-31 for 32-bit rows)
|
|
69
|
+
def start_bit_in_row(bits_per_row = 32)
|
|
70
|
+
@bit_start % bits_per_row
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Get the ending bit position within a row
|
|
74
|
+
def end_bit_in_row(bits_per_row = 32)
|
|
75
|
+
@bit_end % bits_per_row
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|