rng 0.1.1 → 0.3.3

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 (192) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/docs.yml +63 -0
  3. data/.github/workflows/release.yml +8 -3
  4. data/.gitignore +11 -0
  5. data/.rubocop.yml +11 -6
  6. data/.rubocop_todo.yml +270 -0
  7. data/CHANGELOG.md +317 -0
  8. data/CLAUDE.md +139 -0
  9. data/CODE_OF_CONDUCT.md +132 -0
  10. data/Gemfile +11 -10
  11. data/README.adoc +1929 -0
  12. data/Rakefile +11 -3
  13. data/docs/Gemfile +8 -0
  14. data/docs/_config.yml +23 -0
  15. data/docs/getting-started/index.adoc +75 -0
  16. data/docs/guides/error-handling.adoc +137 -0
  17. data/docs/guides/external-references.adoc +128 -0
  18. data/docs/guides/index.adoc +24 -0
  19. data/docs/guides/parsing-rnc.adoc +141 -0
  20. data/docs/guides/parsing-rng-xml.adoc +81 -0
  21. data/docs/guides/rng-to-rnc.adoc +101 -0
  22. data/docs/guides/validation.adoc +85 -0
  23. data/docs/index.adoc +52 -0
  24. data/docs/reference/api.adoc +126 -0
  25. data/docs/reference/cli.adoc +182 -0
  26. data/docs/understanding/architecture.adoc +58 -0
  27. data/docs/understanding/rng-vs-rnc.adoc +118 -0
  28. data/exe/rng +5 -0
  29. data/lib/rng/any_name.rb +28 -0
  30. data/lib/rng/attribute.rb +61 -5
  31. data/lib/rng/choice.rb +60 -0
  32. data/lib/rng/cli.rb +607 -0
  33. data/lib/rng/data.rb +32 -0
  34. data/lib/rng/datatype_declaration.rb +26 -0
  35. data/lib/rng/define.rb +56 -5
  36. data/lib/rng/div.rb +36 -0
  37. data/lib/rng/documentation.rb +9 -0
  38. data/lib/rng/element.rb +66 -18
  39. data/lib/rng/empty.rb +23 -0
  40. data/lib/rng/except.rb +62 -0
  41. data/lib/rng/external_ref.rb +28 -0
  42. data/lib/rng/external_ref_resolver.rb +582 -0
  43. data/lib/rng/foreign_attribute.rb +26 -0
  44. data/lib/rng/foreign_element.rb +33 -0
  45. data/lib/rng/grammar.rb +38 -0
  46. data/lib/rng/group.rb +62 -0
  47. data/lib/rng/include.rb +23 -0
  48. data/lib/rng/include_processor.rb +461 -0
  49. data/lib/rng/interleave.rb +58 -0
  50. data/lib/rng/list.rb +56 -0
  51. data/lib/rng/mixed.rb +58 -0
  52. data/lib/rng/name.rb +28 -0
  53. data/lib/rng/namespace_declaration.rb +47 -0
  54. data/lib/rng/namespaces.rb +15 -0
  55. data/lib/rng/not_allowed.rb +23 -0
  56. data/lib/rng/ns_name.rb +31 -0
  57. data/lib/rng/one_or_more.rb +58 -0
  58. data/lib/rng/optional.rb +58 -0
  59. data/lib/rng/param.rb +30 -0
  60. data/lib/rng/parent_ref.rb +28 -0
  61. data/lib/rng/parse_rnc.rb +26 -0
  62. data/lib/rng/parse_tree_processor.rb +695 -0
  63. data/lib/rng/pattern.rb +24 -0
  64. data/lib/rng/ref.rb +28 -0
  65. data/lib/rng/rnc_builder.rb +927 -0
  66. data/lib/rng/rnc_parser.rb +672 -115
  67. data/lib/rng/rnc_to_rng_converter.rb +1408 -0
  68. data/lib/rng/schema_preamble.rb +73 -0
  69. data/lib/rng/schema_validator.rb +1622 -0
  70. data/lib/rng/start.rb +57 -6
  71. data/lib/rng/test_suite_parser.rb +168 -0
  72. data/lib/rng/text.rb +29 -0
  73. data/lib/rng/to_rnc.rb +24 -0
  74. data/lib/rng/value.rb +28 -0
  75. data/lib/rng/version.rb +1 -1
  76. data/lib/rng/zero_or_more.rb +58 -0
  77. data/lib/rng.rb +80 -5
  78. data/rng.gemspec +19 -19
  79. data/scripts/extract_spectest_resources.rb +96 -0
  80. data/spec/fixtures/compacttest.xml +2511 -0
  81. data/spec/fixtures/external/circular_a.rng +7 -0
  82. data/spec/fixtures/external/circular_b.rng +7 -0
  83. data/spec/fixtures/external/circular_main.rng +7 -0
  84. data/spec/fixtures/external/external_ref_lib.rng +7 -0
  85. data/spec/fixtures/external/external_ref_main.rng +7 -0
  86. data/spec/fixtures/external/include_lib.rng +7 -0
  87. data/spec/fixtures/external/include_main.rng +3 -0
  88. data/spec/fixtures/external/nested_chain.rng +6 -0
  89. data/spec/fixtures/external/nested_leaf.rng +7 -0
  90. data/spec/fixtures/external/nested_mid.rng +8 -0
  91. data/spec/fixtures/metanorma/3gpp.rnc +35 -0
  92. data/spec/fixtures/metanorma/3gpp.rng +105 -0
  93. data/spec/fixtures/metanorma/basicdoc.rnc +11 -0
  94. data/spec/fixtures/metanorma/bipm.rnc +148 -0
  95. data/spec/fixtures/metanorma/bipm.rng +376 -0
  96. data/spec/fixtures/metanorma/bsi.rnc +104 -0
  97. data/spec/fixtures/metanorma/bsi.rng +332 -0
  98. data/spec/fixtures/metanorma/csa.rnc +45 -0
  99. data/spec/fixtures/metanorma/csa.rng +131 -0
  100. data/spec/fixtures/metanorma/csd.rnc +43 -0
  101. data/spec/fixtures/metanorma/csd.rng +132 -0
  102. data/spec/fixtures/metanorma/gbstandard.rnc +99 -0
  103. data/spec/fixtures/metanorma/gbstandard.rng +316 -0
  104. data/spec/fixtures/metanorma/iec.rnc +49 -0
  105. data/spec/fixtures/metanorma/iec.rng +193 -0
  106. data/spec/fixtures/metanorma/ietf.rnc +275 -0
  107. data/spec/fixtures/metanorma/ietf.rng +925 -0
  108. data/spec/fixtures/metanorma/iho.rnc +58 -0
  109. data/spec/fixtures/metanorma/iho.rng +179 -0
  110. data/spec/fixtures/metanorma/isodoc.rnc +873 -0
  111. data/spec/fixtures/metanorma/isodoc.rng +2704 -0
  112. data/spec/fixtures/metanorma/isostandard-amd.rnc +43 -0
  113. data/spec/fixtures/metanorma/isostandard-amd.rng +108 -0
  114. data/spec/fixtures/metanorma/isostandard.rnc +166 -0
  115. data/spec/fixtures/metanorma/isostandard.rng +494 -0
  116. data/spec/fixtures/metanorma/itu.rnc +122 -0
  117. data/spec/fixtures/metanorma/itu.rng +377 -0
  118. data/spec/fixtures/metanorma/m3d.rnc +41 -0
  119. data/spec/fixtures/metanorma/m3d.rng +122 -0
  120. data/spec/fixtures/metanorma/mpfd.rnc +36 -0
  121. data/spec/fixtures/metanorma/mpfd.rng +95 -0
  122. data/spec/fixtures/metanorma/nist.rnc +77 -0
  123. data/spec/fixtures/metanorma/nist.rng +216 -0
  124. data/spec/fixtures/metanorma/ogc.rnc +51 -0
  125. data/spec/fixtures/metanorma/ogc.rng +151 -0
  126. data/spec/fixtures/metanorma/reqt.rnc +6 -0
  127. data/spec/fixtures/metanorma/rsd.rnc +36 -0
  128. data/spec/fixtures/metanorma/rsd.rng +95 -0
  129. data/spec/fixtures/metanorma/un.rnc +103 -0
  130. data/spec/fixtures/metanorma/un.rng +367 -0
  131. data/spec/fixtures/rnc/address_book.rnc +10 -0
  132. data/spec/fixtures/rnc/base.rnc +4 -0
  133. data/spec/fixtures/rnc/complex_example.rnc +61 -0
  134. data/spec/fixtures/rnc/grammar_with_trailing.rnc +8 -0
  135. data/spec/fixtures/rnc/main_include_trailing.rnc +3 -0
  136. data/spec/fixtures/rnc/main_with_include.rnc +5 -0
  137. data/spec/fixtures/rnc/test_augment.rnc +10 -0
  138. data/spec/fixtures/rnc/test_isodoc_simple.rnc +9 -0
  139. data/spec/fixtures/rnc/top_level_include.rnc +8 -0
  140. data/spec/fixtures/rng/address_book.rng +20 -0
  141. data/spec/fixtures/rng/relaxng.rng +335 -0
  142. data/spec/fixtures/rng/testSuite.rng +163 -0
  143. data/spec/fixtures/spectest.xml +6845 -0
  144. data/spec/fixtures/spectest_external/case_10_4.7/x +3 -0
  145. data/spec/fixtures/spectest_external/case_10_4.7/y +7 -0
  146. data/spec/fixtures/spectest_external/case_11_4.7/x +3 -0
  147. data/spec/fixtures/spectest_external/case_12_4.7/x +3 -0
  148. data/spec/fixtures/spectest_external/case_13_4.7/x +3 -0
  149. data/spec/fixtures/spectest_external/case_13_4.7/y +3 -0
  150. data/spec/fixtures/spectest_external/case_14_4.7/x +7 -0
  151. data/spec/fixtures/spectest_external/case_15_4.7/x +7 -0
  152. data/spec/fixtures/spectest_external/case_16_4.7/x +5 -0
  153. data/spec/fixtures/spectest_external/case_17_4.7/x +5 -0
  154. data/spec/fixtures/spectest_external/case_18_4.7/x +7 -0
  155. data/spec/fixtures/spectest_external/case_19_4.7/level1.rng +9 -0
  156. data/spec/fixtures/spectest_external/case_19_4.7/level2.rng +7 -0
  157. data/spec/fixtures/spectest_external/case_1_4.5/sub1/x +3 -0
  158. data/spec/fixtures/spectest_external/case_1_4.5/sub3/x +3 -0
  159. data/spec/fixtures/spectest_external/case_1_4.5/x +3 -0
  160. data/spec/fixtures/spectest_external/case_20_4.6/x +3 -0
  161. data/spec/fixtures/spectest_external/case_2_4.5/x +3 -0
  162. data/spec/fixtures/spectest_external/case_3_4.6/x +3 -0
  163. data/spec/fixtures/spectest_external/case_4_4.6/x +3 -0
  164. data/spec/fixtures/spectest_external/case_5_4.6/x +1 -0
  165. data/spec/fixtures/spectest_external/case_6_4.6/x +5 -0
  166. data/spec/fixtures/spectest_external/case_7_4.6/x +1 -0
  167. data/spec/fixtures/spectest_external/case_7_4.6/y +1 -0
  168. data/spec/fixtures/spectest_external/case_8_4.7/x +7 -0
  169. data/spec/fixtures/spectest_external/case_9_4.7/x +7 -0
  170. data/spec/fixtures/spectest_external/resources.json +149 -0
  171. data/spec/rng/advanced_rnc_spec.rb +101 -0
  172. data/spec/rng/compacttest_spec.rb +197 -0
  173. data/spec/rng/datatype_declaration_spec.rb +28 -0
  174. data/spec/rng/div_spec.rb +207 -0
  175. data/spec/rng/external_ref_resolver_spec.rb +122 -0
  176. data/spec/rng/metanorma_conversion_spec.rb +159 -0
  177. data/spec/rng/namespace_declaration_spec.rb +60 -0
  178. data/spec/rng/namespace_support_spec.rb +199 -0
  179. data/spec/rng/rnc_parser_spec.rb +501 -23
  180. data/spec/rng/rnc_roundtrip_spec.rb +135 -0
  181. data/spec/rng/rng_generation_spec.rb +288 -0
  182. data/spec/rng/roundtrip_spec.rb +342 -0
  183. data/spec/rng/schema_preamble_spec.rb +145 -0
  184. data/spec/rng/schema_spec.rb +125 -172
  185. data/spec/rng/spectest_spec.rb +273 -0
  186. data/spec/rng_spec.rb +2 -2
  187. data/spec/spec_helper.rb +7 -9
  188. metadata +188 -8
  189. data/lib/rng/builder.rb +0 -158
  190. data/lib/rng/rng_parser.rb +0 -107
  191. data/lib/rng/schema.rb +0 -18
  192. data/spec/rng/rng_parser_spec.rb +0 -102
data/lib/rng/builder.rb DELETED
@@ -1,158 +0,0 @@
1
- module Rng
2
- class Builder
3
- def build(schema, format:)
4
- case format
5
- when :rng
6
- build_rng(schema)
7
- when :rnc
8
- build_rnc(schema)
9
- else
10
- raise ArgumentError, "Unsupported format: #{format}"
11
- end
12
- end
13
-
14
- private
15
-
16
- def build_rng(schema)
17
- doc = Nokogiri::XML::Document.new
18
- doc.encoding = "UTF-8"
19
-
20
- if schema.is_a?(Rng::Schema)
21
- root = Nokogiri::XML::Node.new("grammar", doc)
22
- root["xmlns"] = "http://relaxng.org/ns/structure/1.0"
23
- doc.root = root
24
-
25
- start = Nokogiri::XML::Node.new("start", doc)
26
- root.add_child(start)
27
-
28
- if schema.start.ref
29
- ref = Nokogiri::XML::Node.new("ref", doc)
30
- ref["name"] = schema.start.ref
31
- start.add_child(ref)
32
- end
33
-
34
- schema.start.elements.each do |element|
35
- start.add_child(build_rng_element(element, doc))
36
- end
37
-
38
- schema.define&.each do |define|
39
- define_node = Nokogiri::XML::Node.new("define", doc)
40
- define_node["name"] = define.name
41
- define.elements.each do |element|
42
- define_node.add_child(build_rng_element(element, doc))
43
- end
44
- root.add_child(define_node)
45
- end
46
- elsif schema.is_a?(Rng::Element)
47
- el = build_rng_element(schema, doc)
48
- el["xmlns"] = "http://relaxng.org/ns/structure/1.0"
49
- doc.root = el
50
- end
51
-
52
- doc.to_xml
53
- end
54
-
55
- def build_rng_element(element, doc)
56
- if element.zero_or_more&.any?
57
- zero_or_more = Nokogiri::XML::Node.new("zeroOrMore", doc)
58
- el = Nokogiri::XML::Node.new("element", doc)
59
- el["name"] = element.name
60
- add_element_content(element, el, doc)
61
- zero_or_more.add_child(el)
62
- return zero_or_more
63
- elsif element.one_or_more&.any?
64
- one_or_more = Nokogiri::XML::Node.new("oneOrMore", doc)
65
- el = Nokogiri::XML::Node.new("element", doc)
66
- el["name"] = element.name
67
- add_element_content(element, el, doc)
68
- one_or_more.add_child(el)
69
- return one_or_more
70
- elsif element.optional&.any?
71
- optional = Nokogiri::XML::Node.new("optional", doc)
72
- el = Nokogiri::XML::Node.new("element", doc)
73
- el["name"] = element.name
74
- add_element_content(element, el, doc)
75
- optional.add_child(el)
76
- return optional
77
- else
78
- el = Nokogiri::XML::Node.new("element", doc)
79
- el["name"] = element.name
80
- add_element_content(element, el, doc)
81
- return el
82
- end
83
- end
84
-
85
- def add_element_content(element, el, doc)
86
- element.attributes&.each do |attr|
87
- attr_node = Nokogiri::XML::Node.new("attribute", doc)
88
- attr_node["name"] = attr.name
89
- if attr.type&.any?
90
- data = Nokogiri::XML::Node.new("data", doc)
91
- data["type"] = attr.type.first
92
- attr_node.add_child(data)
93
- else
94
- text = Nokogiri::XML::Node.new("text", doc)
95
- attr_node.add_child(text)
96
- end
97
- el.add_child(attr_node)
98
- end
99
-
100
- element.elements&.each do |child|
101
- el.add_child(build_rng_element(child, doc))
102
- end
103
-
104
- if element.text
105
- text = Nokogiri::XML::Node.new("text", doc)
106
- el.add_child(text)
107
- end
108
- end
109
-
110
- def build_rnc(schema)
111
- result = ""
112
- elements = schema.is_a?(Rng::Schema) ? schema.start.elements : [schema]
113
- elements.each do |element|
114
- result += build_rnc_element(element)
115
- end
116
- result
117
- end
118
-
119
- def build_rnc_element(element, indent = 0)
120
- return "" unless element # Handle nil elements
121
-
122
- result = " " * indent
123
- result += "element #{element.name} {\n"
124
-
125
- element.attributes&.each do |attr|
126
- result += " " * (indent + 1)
127
- result += "attribute #{attr.name} { text }"
128
- result += ",\n" unless element.attributes.last == attr && !element.elements&.any? && !element.text
129
- end
130
-
131
- element.elements&.each_with_index do |child, index|
132
- child_result = build_rnc_element(child, indent + 1)
133
- result += child_result
134
- result += "," unless index == element.elements.size - 1 && !element.text
135
- result += "\n"
136
- end
137
-
138
- if element.text
139
- result += " " * (indent + 1)
140
- result += "text"
141
- result += "\n"
142
- end
143
-
144
- result += " " * indent
145
- result += "}"
146
-
147
- if element.zero_or_more&.any?
148
- result += "*"
149
- elsif element.one_or_more&.any?
150
- result += "+"
151
- elsif element.optional&.any?
152
- result += "?"
153
- end
154
-
155
- result
156
- end
157
- end
158
- end
@@ -1,107 +0,0 @@
1
- require "nokogiri"
2
- require_relative "schema"
3
- require_relative "element"
4
-
5
- module Rng
6
- class RngParser
7
- RELAXNG_NS = "http://relaxng.org/ns/structure/1.0"
8
-
9
- def parse(input)
10
- doc = Nokogiri::XML(input)
11
- doc.remove_namespaces! # This simplifies namespace handling
12
-
13
- root = doc.root
14
- case root.name
15
- when "grammar"
16
- parse_grammar(doc)
17
- when "element"
18
- parse_element(doc)
19
- else
20
- raise Rng::Error, "Unexpected root element: #{root.name}"
21
- end
22
- end
23
-
24
- private
25
-
26
- def parse_grammar(doc)
27
- Schema.new(
28
- start: parse_start(doc.at_xpath("//start")),
29
- define: doc.xpath("//define").map { |define| parse_define(define) },
30
- )
31
- end
32
-
33
- def parse_start(node)
34
- return nil unless node
35
-
36
- Start.new(
37
- ref: node.at_xpath(".//ref")&.attr("name"),
38
- elements: node.xpath(".//element").map { |element| parse_element(element) },
39
- )
40
- end
41
-
42
- def parse_define(node)
43
- Define.new(
44
- name: node["name"],
45
- elements: node.xpath(".//element").map { |element| parse_element(element) },
46
- )
47
- end
48
-
49
- def parse_element(node)
50
- return nil unless node["name"]
51
-
52
- element = Element.new(
53
- name: node["name"],
54
- attributes: [],
55
- elements: [],
56
- text: false,
57
- )
58
-
59
- node.children.each do |child|
60
- parse_child(child, element)
61
- end
62
-
63
- element
64
- end
65
-
66
- def parse_child(node, element)
67
- case node.name
68
- when "attribute"
69
- element.attributes << parse_attribute(node)
70
- when "element"
71
- element.elements << parse_element(node)
72
- when "text"
73
- element.text = true
74
- when "zeroOrMore"
75
- parse_zero_or_more(node).each { |el| element.zero_or_more << el }
76
- when "oneOrMore"
77
- parse_one_or_more(node).each { |el| element.one_or_more << el }
78
- when "optional"
79
- parse_optional(node).each { |el| element.optional << el }
80
- end
81
- end
82
-
83
- def parse_attribute(node)
84
- data_node = node.at_xpath(".//data")
85
- Attribute.new(
86
- name: node["name"],
87
- type: data_node ? [data_node["type"]] : ["string"],
88
- )
89
- end
90
-
91
- def parse_zero_or_more(node)
92
- node.xpath("./element").map { |el| parse_element(el) }
93
- end
94
-
95
- def parse_one_or_more(node)
96
- node.xpath("./element").map { |el| parse_element(el) }
97
- end
98
-
99
- def parse_optional(node)
100
- node.xpath("./element").map { |el| parse_element(el) }
101
- end
102
-
103
- def parse_choice(node)
104
- node.xpath(".//choice/element").map { |el| parse_element(el) }
105
- end
106
- end
107
- end
data/lib/rng/schema.rb DELETED
@@ -1,18 +0,0 @@
1
- require "lutaml/model"
2
- require_relative "start"
3
- require_relative "define"
4
-
5
- module Rng
6
- class Schema < Lutaml::Model::Serializable
7
- attribute :start, Start
8
- attribute :define, Define, collection: true
9
-
10
- xml do
11
- root "grammar"
12
- namespace "http://relaxng.org/ns/structure/1.0"
13
-
14
- map_element "start", to: :start
15
- map_element "define", to: :define
16
- end
17
- end
18
- end
@@ -1,102 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe Rng::RngParser do
4
- let(:parser) { described_class.new }
5
-
6
- describe "#parse" do
7
- context "with a simple RNG schema" do
8
- let(:input) do
9
- <<~RNG
10
- <grammar xmlns="http://relaxng.org/ns/structure/1.0">
11
- <start>
12
- <element name="addressBook">
13
- <zeroOrMore>
14
- <element name="card">
15
- <element name="name">
16
- <text/>
17
- </element>
18
- <element name="email">
19
- <text/>
20
- </element>
21
- </element>
22
- </zeroOrMore>
23
- </element>
24
- </start>
25
- </grammar>
26
- RNG
27
- end
28
-
29
- it "correctly parses the schema" do
30
- result = parser.parse(input)
31
- expect(result).to be_a(Rng::Schema)
32
- expect(result.start.elements.first.name).to eq("addressBook")
33
- expect(result.start.elements.first.zero_or_more.first.name).to eq("card")
34
- expect(result.start.elements.first.zero_or_more.first.elements.map(&:name)).to eq(["name", "email"])
35
- end
36
- end
37
-
38
- context "with a complex RNG schema" do
39
- let(:input) do
40
- <<~RNG
41
- <grammar xmlns="http://relaxng.org/ns/structure/1.0">
42
- <start>
43
- <ref name="addressBook"/>
44
- </start>
45
- <define name="addressBook">
46
- <element name="addressBook">
47
- <zeroOrMore>
48
- <element name="card">
49
- <element name="name">
50
- <text/>
51
- </element>
52
- <element name="email">
53
- <text/>
54
- </element>
55
- <optional>
56
- <element name="note">
57
- <text/>
58
- </element>
59
- </optional>
60
- </element>
61
- </zeroOrMore>
62
- </element>
63
- </define>
64
- </grammar>
65
- RNG
66
- end
67
-
68
- it "correctly parses the schema" do
69
- result = parser.parse(input)
70
- expect(result).to be_a(Rng::Schema)
71
- expect(result.start.ref).to eq("addressBook")
72
- expect(result.define.first.name).to eq("addressBook")
73
- expect(result.define.first.elements.first.name).to eq("addressBook")
74
- end
75
- end
76
-
77
- context "with attributes" do
78
- let(:input) do
79
- <<~RNG
80
- <grammar xmlns="http://relaxng.org/ns/structure/1.0">
81
- <start>
82
- <element name="person">
83
- <attribute name="id">
84
- <data type="ID"/>
85
- </attribute>
86
- <element name="name">
87
- <text/>
88
- </element>
89
- </element>
90
- </start>
91
- </grammar>
92
- RNG
93
- end
94
-
95
- it "correctly parses attributes" do
96
- result = parser.parse(input)
97
- expect(result.start.elements.first.attributes.first.name).to eq("id")
98
- expect(result.start.elements.first.attributes.first.type).to eq(["ID"])
99
- end
100
- end
101
- end
102
- end