xsdvi 1.0.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +30 -0
  3. data/README.adoc +317 -0
  4. data/exe/xsdvi +6 -0
  5. data/lib/xsdvi/cli.rb +163 -0
  6. data/lib/xsdvi/svg/generator.rb +93 -0
  7. data/lib/xsdvi/svg/symbol.rb +234 -0
  8. data/lib/xsdvi/svg/symbols/all.rb +46 -0
  9. data/lib/xsdvi/svg/symbols/any.rb +59 -0
  10. data/lib/xsdvi/svg/symbols/any_attribute.rb +58 -0
  11. data/lib/xsdvi/svg/symbols/attribute.rb +64 -0
  12. data/lib/xsdvi/svg/symbols/choice.rb +46 -0
  13. data/lib/xsdvi/svg/symbols/element.rb +91 -0
  14. data/lib/xsdvi/svg/symbols/field.rb +42 -0
  15. data/lib/xsdvi/svg/symbols/key.rb +46 -0
  16. data/lib/xsdvi/svg/symbols/keyref.rb +49 -0
  17. data/lib/xsdvi/svg/symbols/loop.rb +35 -0
  18. data/lib/xsdvi/svg/symbols/schema.rb +42 -0
  19. data/lib/xsdvi/svg/symbols/selector.rb +42 -0
  20. data/lib/xsdvi/svg/symbols/sequence.rb +48 -0
  21. data/lib/xsdvi/svg/symbols/unique.rb +46 -0
  22. data/lib/xsdvi/tree/builder.rb +31 -0
  23. data/lib/xsdvi/tree/element.rb +62 -0
  24. data/lib/xsdvi/utils/resource_loader.rb +21 -0
  25. data/lib/xsdvi/utils/width_calculator.rb +23 -0
  26. data/lib/xsdvi/utils/writer.rb +29 -0
  27. data/lib/xsdvi/version.rb +5 -0
  28. data/lib/xsdvi/xsd_handler.rb +323 -0
  29. data/lib/xsdvi.rb +30 -0
  30. data/resources/svg/defined_symbols.svg +9 -0
  31. data/resources/svg/doctype.txt +1 -0
  32. data/resources/svg/menu_buttons.svg +7 -0
  33. data/resources/svg/script.js +265 -0
  34. data/resources/svg/style.css +29 -0
  35. data/resources/svg/style.html +3 -0
  36. data/resources/svg/style.xml +1 -0
  37. data/resources/svg/svg_end.txt +1 -0
  38. data/resources/svg/svg_start.txt +1 -0
  39. data/resources/svg/title.txt +1 -0
  40. data/resources/svg/xml_declaration.xml +1 -0
  41. metadata +113 -0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD keyref identity constraint
9
+ class Keyref < Symbol
10
+ attr_accessor :name, :namespace, :refer
11
+
12
+ def initialize
13
+ super
14
+ @name = nil
15
+ @namespace = nil
16
+ @refer = nil
17
+ end
18
+
19
+ def draw
20
+ process_description
21
+ draw_g_start
22
+ print("<rect class='shadow' x='3' y='3' width='#{width}' " \
23
+ "height='#{height}' rx='9'/>")
24
+ print("<rect class='boxkeyref' x='0' y='0' width='#{width}' " \
25
+ "height='#{height}' rx='9'/>")
26
+ print("<text class='visible' x='5' y='13'>#{namespace}</text>") if namespace
27
+ print("<text class='strong' x='5' y='27'>keyref: #{name}</text>") if name
28
+ print("<text class='visible' x='5' y='41'>refer: #{refer}</text>") if refer
29
+ draw_description(41)
30
+ draw_connection
31
+ draw_use
32
+ draw_g_end
33
+ end
34
+
35
+ def calculate_width
36
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
37
+ calc.new_width(15, name, 8)
38
+ calc.new_width(15, namespace)
39
+ calc.new_width(15, refer, 7)
40
+ calc.width
41
+ end
42
+
43
+ def calculate_height
44
+ MAX_HEIGHT
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for recursive loop references
9
+ class Loop < Symbol
10
+ def draw
11
+ draw_g_start
12
+ print("<rect class='boxloop' x='0' y='12' width='#{width}' " \
13
+ "height='#{height}' rx='9'/>")
14
+ print("<polygon class='filled' points='#{(width / 2) + 3},8 " \
15
+ "#{(width / 2) - 2},12 #{(width / 2) + 3},17'/>")
16
+ print("<polygon class='filled' points='#{width - 5},24 " \
17
+ "#{width},19 #{width + 5},24'/>")
18
+ print("<text x='10' y='27'>LOOP</text>")
19
+ draw_connection
20
+ draw_g_end
21
+ end
22
+
23
+ def calculate_width
24
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
25
+ calc.new_width(25, 4)
26
+ calc.width
27
+ end
28
+
29
+ def calculate_height
30
+ MIN_HEIGHT
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD schema root
9
+ class Schema < Symbol
10
+ def prepare_box
11
+ # Schema root positioning
12
+ @x_position = 20
13
+ @y_position = 50
14
+ @width = calculate_width
15
+ @height = calculate_height
16
+
17
+ # Set highest to 50 so children start at 50
18
+ # Must use Symbol.highest_y_position, not self.class
19
+ Symbol.highest_y_position = 50
20
+ end
21
+
22
+ def draw
23
+ draw_g_start
24
+ print("<rect class='boxschema' x='0' y='12' width='#{width}' height='#{height}'/>")
25
+ print("<text x='5' y='27'><tspan class='big'>/ </tspan>schema</text>")
26
+ draw_use
27
+ draw_g_end
28
+ end
29
+
30
+ def calculate_width
31
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
32
+ calc.new_width(15, 8)
33
+ calc.width
34
+ end
35
+
36
+ def calculate_height
37
+ MIN_HEIGHT
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD selector
9
+ class Selector < Symbol
10
+ attr_accessor :xpath
11
+
12
+ def initialize
13
+ super
14
+ @xpath = nil
15
+ end
16
+
17
+ def draw
18
+ draw_g_start
19
+ print("<rect class='shadow' x='3' y='3' width='#{width}' " \
20
+ "height='#{height}' rx='9'/>")
21
+ print("<rect class='boxselector' x='0' y='0' width='#{width}' " \
22
+ "height='#{height}' rx='9'/>")
23
+ print("<text class='strong' x='5' y='13'>selector</text>")
24
+ print("<text class='visible' x='5' y='27'>#{xpath}</text>") if xpath
25
+ draw_connection
26
+ draw_g_end
27
+ end
28
+
29
+ def calculate_width
30
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
31
+ calc.new_width(15, 8)
32
+ calc.new_width(15, xpath)
33
+ calc.width
34
+ end
35
+
36
+ def calculate_height
37
+ MID_HEIGHT
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD sequence compositor
9
+ class Sequence < Symbol
10
+ attr_accessor :cardinality
11
+
12
+ def initialize
13
+ super
14
+ @cardinality = nil
15
+ end
16
+
17
+ def draw
18
+ process_description
19
+ draw_g_start
20
+ print("<rect class='boxcompositor' x='0' y='8' width='#{width}' " \
21
+ "height='#{height}' rx='9'/>")
22
+ print("<circle cx='#{(width / 2) + 12}' cy='14' r='2'/>")
23
+ print("<circle cx='#{(width / 2) + 12}' cy='23' r='2'/>")
24
+ print("<circle cx='#{(width / 2) + 12}' cy='32' r='2'/>")
25
+ print("<text class='small' x='#{width / 2}' y='17'>1</text>")
26
+ print("<text class='small' x='#{width / 2}' y='26'>2</text>")
27
+ print("<text class='small' x='#{width / 2}' y='35'>3</text>")
28
+ print("<line x1='#{(width / 2) + 12}' y1='14' x2='#{(width / 2) + 12}' y2='32'/>")
29
+ print("<text x='5' y='52'>#{cardinality}</text>") if cardinality
30
+ draw_description(52)
31
+ draw_connection
32
+ draw_use
33
+ draw_g_end
34
+ end
35
+
36
+ def calculate_width
37
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
38
+ calc.new_width(15, cardinality)
39
+ calc.width
40
+ end
41
+
42
+ def calculate_height
43
+ MID_HEIGHT
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../symbol"
4
+
5
+ module Xsdvi
6
+ module SVG
7
+ module Symbols
8
+ # Symbol for XSD unique identity constraint
9
+ class Unique < Symbol
10
+ attr_accessor :name, :namespace
11
+
12
+ def initialize
13
+ super
14
+ @name = nil
15
+ @namespace = nil
16
+ end
17
+
18
+ def draw
19
+ process_description
20
+ draw_g_start
21
+ print("<rect class='shadow' x='3' y='3' width='#{width}' " \
22
+ "height='#{height}' rx='9'/>")
23
+ print("<rect class='boxunique' x='0' y='0' width='#{width}' " \
24
+ "height='#{height}' rx='9'/>")
25
+ print("<text class='visible' x='5' y='13'>#{namespace}</text>") if namespace
26
+ print("<text class='strong' x='5' y='27'>unique: #{name}</text>") if name
27
+ draw_description(27)
28
+ draw_connection
29
+ draw_use
30
+ draw_g_end
31
+ end
32
+
33
+ def calculate_width
34
+ calc = Utils::WidthCalculator.new(MIN_WIDTH)
35
+ calc.new_width(15, name, 8)
36
+ calc.new_width(15, namespace)
37
+ calc.width
38
+ end
39
+
40
+ def calculate_height
41
+ MID_HEIGHT
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xsdvi
4
+ module Tree
5
+ # Builds a tree structure
6
+ class Builder
7
+ attr_accessor :root
8
+ attr_reader :parent
9
+
10
+ def initialize
11
+ @parent = nil
12
+ @root = nil
13
+ end
14
+
15
+ def append_child(child)
16
+ parent.add_child(child)
17
+ child.parent = parent
18
+ @parent = child
19
+ end
20
+
21
+ def level_up
22
+ @parent = parent.parent
23
+ end
24
+
25
+ def set_root(new_root)
26
+ @parent = new_root
27
+ @root = new_root
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xsdvi
4
+ module Tree
5
+ # Represents a node in the tree structure
6
+ class Element
7
+ attr_accessor :parent
8
+ attr_reader :children
9
+
10
+ def initialize
11
+ @parent = nil
12
+ @children = []
13
+ end
14
+
15
+ def index
16
+ return 1 unless parent?
17
+
18
+ parent.children.index(self) + 1
19
+ end
20
+
21
+ def parent?
22
+ !parent.nil?
23
+ end
24
+
25
+ def last_child
26
+ children.last
27
+ end
28
+
29
+ def last_child?
30
+ return true unless parent?
31
+
32
+ parent.children.last == self
33
+ end
34
+
35
+ def first_child?
36
+ return true unless parent?
37
+
38
+ parent.children.first == self
39
+ end
40
+
41
+ def add_child(child)
42
+ children << child
43
+ end
44
+
45
+ def children?
46
+ !children.empty?
47
+ end
48
+
49
+ def code
50
+ buffer = []
51
+ element = self
52
+ while element.parent?
53
+ buffer.unshift(element.index)
54
+ buffer.unshift("_")
55
+ element = element.parent
56
+ end
57
+ buffer.unshift("_1")
58
+ buffer.join
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xsdvi
4
+ module Utils
5
+ # Helper class for loading resource files
6
+ class ResourceLoader
7
+ def read_resource_file(resource_file)
8
+ resource_path = File.join(
9
+ File.dirname(__FILE__),
10
+ "../../..",
11
+ "resources",
12
+ resource_file,
13
+ )
14
+ File.read(resource_path)
15
+ rescue Errno::ENOENT => e
16
+ warn "Resource file not found: #{resource_path}"
17
+ raise e
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xsdvi
4
+ module Utils
5
+ # Calculates width for SVG elements based on text content
6
+ class WidthCalculator
7
+ attr_reader :width
8
+
9
+ def initialize(min_width)
10
+ @width = min_width
11
+ end
12
+
13
+ def new_width(char_width, text, additional = 0)
14
+ return unless text
15
+
16
+ text_length = text.is_a?(String) ? text.length : text
17
+ calculated_width = char_width + (text_length * 6) + additional
18
+
19
+ @width = calculated_width if calculated_width > @width
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xsdvi
4
+ module Utils
5
+ # Helper class for writing output files
6
+ class Writer
7
+ DEFAULT_CHARSET = "UTF-8"
8
+
9
+ attr_reader :writer
10
+
11
+ def initialize(uri = nil, charset_name = DEFAULT_CHARSET)
12
+ new_writer(uri, charset_name) if uri
13
+ end
14
+
15
+ def close
16
+ writer&.close
17
+ end
18
+
19
+ def append(content)
20
+ writer&.write(content)
21
+ writer
22
+ end
23
+
24
+ def new_writer(uri, charset_name = DEFAULT_CHARSET)
25
+ @writer = File.open(uri, "w:#{charset_name}")
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Xsdvi
4
+ VERSION = "1.0.0"
5
+ end