metanorma-standoc 1.3.29 → 1.4.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/lib/asciidoctor/standoc/base.rb +2 -25
  4. data/lib/asciidoctor/standoc/biblio.rng +13 -3
  5. data/lib/asciidoctor/standoc/blocks.rb +20 -17
  6. data/lib/asciidoctor/standoc/cleanup.rb +2 -0
  7. data/lib/asciidoctor/standoc/cleanup_block.rb +2 -2
  8. data/lib/asciidoctor/standoc/cleanup_section.rb +8 -125
  9. data/lib/asciidoctor/standoc/cleanup_terms.rb +134 -0
  10. data/lib/asciidoctor/standoc/datamodel/attributes_table_preprocessor.rb +57 -0
  11. data/lib/asciidoctor/standoc/datamodel/diagram_preprocessor.rb +102 -0
  12. data/lib/asciidoctor/standoc/datamodel/plantuml_renderer.rb +408 -0
  13. data/lib/asciidoctor/standoc/inline.rb +10 -5
  14. data/lib/asciidoctor/standoc/isodoc.rng +17 -1
  15. data/lib/asciidoctor/standoc/macros.rb +13 -8
  16. data/lib/asciidoctor/standoc/macros_yaml2text.rb +19 -13
  17. data/lib/asciidoctor/standoc/ref.rb +13 -56
  18. data/lib/asciidoctor/standoc/ref_sect.rb +124 -0
  19. data/lib/asciidoctor/standoc/section.rb +2 -46
  20. data/lib/asciidoctor/standoc/views/datamodel/model_representation.adoc.erb +30 -0
  21. data/lib/asciidoctor/standoc/views/datamodel/plantuml_representation.adoc.erb +20 -0
  22. data/lib/metanorma/standoc/version.rb +1 -1
  23. data/metanorma-standoc.gemspec +1 -1
  24. data/spec/asciidoctor-standoc/cleanup_spec.rb +51 -0
  25. data/spec/asciidoctor-standoc/datamodel/attributes_table_preprocessor_spec.rb +76 -0
  26. data/spec/asciidoctor-standoc/datamodel/diagram_preprocessor_spec.rb +72 -0
  27. data/spec/asciidoctor-standoc/inline_spec.rb +5 -1
  28. data/spec/asciidoctor-standoc/macros_spec.rb +50 -0
  29. data/spec/asciidoctor-standoc/macros_yaml2text_spec.rb +2 -1
  30. data/spec/asciidoctor-standoc/refs_spec.rb +0 -4
  31. data/spec/examples/datamodel/address_class_profile.adoc +4 -0
  32. data/spec/examples/datamodel/address_component_profile.adoc +4 -0
  33. data/spec/examples/datamodel/common_models_diagram.adoc +4 -0
  34. data/spec/examples/datamodel/models/models/AddressClassProfile.yml +90 -0
  35. data/spec/examples/datamodel/models/models/AddressComponentProfile.yml +63 -0
  36. data/spec/examples/datamodel/models/models/AddressComponentSpecification.yml +15 -0
  37. data/spec/examples/datamodel/models/models/AddressProfile.yml +36 -0
  38. data/spec/examples/datamodel/models/models/AttributeProfile.yml +32 -0
  39. data/spec/examples/datamodel/models/models/InterchangeAddressClassProfile.yml +79 -0
  40. data/spec/examples/datamodel/models/models/Localization copy.yml +23 -0
  41. data/spec/examples/datamodel/models/models/Localization.yml +23 -0
  42. data/spec/examples/datamodel/models/models/ProfileCompliantAddress.yml +36 -0
  43. data/spec/examples/datamodel/models/models/ProfileCompliantAddressComponent.yml +15 -0
  44. data/spec/examples/datamodel/models/models/Signature copy.yml +20 -0
  45. data/spec/examples/datamodel/models/models/Signature.yml +20 -0
  46. data/spec/examples/datamodel/models/models/TextDirectionCode copy.yml +16 -0
  47. data/spec/examples/datamodel/models/models/TextDirectionCode.yml +16 -0
  48. data/spec/examples/datamodel/models/models/Validity.yml +14 -0
  49. data/spec/examples/datamodel/models/models/iso19160-1/Address.yml +22 -0
  50. data/spec/examples/datamodel/models/models/iso19160-1/AddressComponent.yml +2 -0
  51. data/spec/examples/datamodel/models/style.uml.inc +37 -0
  52. data/spec/examples/datamodel/models/views/CommonModels.yml +9 -0
  53. data/spec/examples/datamodel/models/views/TopDown.yml +62 -0
  54. data/spec/examples/datamodel/top_down_diagram.adoc +4 -0
  55. data/spec/fixtures/macros_datamodel/address_class_profile.xml +149 -0
  56. data/spec/fixtures/macros_datamodel/address_component_profile.xml +71 -0
  57. data/spec/fixtures/macros_datamodel/common_models_diagram.xml +7 -0
  58. data/spec/fixtures/macros_datamodel/top_down_diagram.xml +7 -0
  59. data/spec/spec_helper.rb +13 -2
  60. data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +66 -66
  61. data/spec/vcr_cassettes/isobib_get_123.yml +36 -36
  62. data/spec/vcr_cassettes/isobib_get_123_2001.yml +16 -16
  63. data/spec/vcr_cassettes/isobib_get_124.yml +17 -17
  64. data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +8 -8
  65. data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +41 -38
  66. metadata +41 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e964fb25b29d5ecbe775bf397a17f9cf264fa3709e8756be7a9025bcf043250f
4
- data.tar.gz: d6085180737f332f6aa657eb129bf72f02ca0466b60e22276ddda03cd2cbd788
3
+ metadata.gz: 1e86d9135fffb1f112db82f9d052632aa36f134a76b03ff48e65dcb841c7cbb4
4
+ data.tar.gz: ea05dff988ebaf6b51c029d99cbadd195300c3c524acd301157a335257436c01
5
5
  SHA512:
6
- metadata.gz: baccf6cbbb3c32defcac92b95911e83f10f44338a2bb631a8c6ee86a7b00833583d27161b18ad45b2d80aeec8dcbe3dd349a39b4cfa08670f6cdbe1c8492323c
7
- data.tar.gz: 347739395332e6d3ac88ea0ec5bec557fa0d06dee7f7f2bbafa198e245131dd313c3f229f63bb3afc92c99eb4cd0cec8fc2a9f969e0cbf42a76271e45955e8eb
6
+ metadata.gz: beead161e217dba5841732200aa8cb897900ea90b1a449f092fe63ffe40ca59a6b904b098affd1a475723ac4663ba5dadd09fdab48b661376c4fe659360c79a4
7
+ data.tar.gz: 43b697f04165938864eab22a1d4d49613adef7ae1703995a5541018fe438f09ff21dd43e37e25ebeab9a0d514b50f64b64d2a8a47c8836b924d4578b9f076d19
data/.gitignore CHANGED
@@ -9,3 +9,4 @@ spec/examples/rice.doc
9
9
  spec/examples/rice.html
10
10
  spec/examples/rice.xml
11
11
  spec/examples/rice_files/
12
+ Gemfile.lock
@@ -15,6 +15,8 @@ module Asciidoctor
15
15
  XML_NAMESPACE = "https://www.metanorma.org/ns/standoc".freeze
16
16
 
17
17
  Asciidoctor::Extensions.register do
18
+ preprocessor Asciidoctor::Standoc::Datamodel::AttributesTablePreprocessor
19
+ preprocessor Asciidoctor::Standoc::Datamodel::DiagramPreprocessor
18
20
  preprocessor Asciidoctor::Standoc::Yaml2TextPreprocessor
19
21
  inline_macro Asciidoctor::Standoc::AltTermInlineMacro
20
22
  inline_macro Asciidoctor::Standoc::DeprecatedTermInlineMacro
@@ -125,31 +127,6 @@ module Asciidoctor
125
127
  i18n_init(lang, script)
126
128
  end
127
129
 
128
- def init_bib_caches(node)
129
- return if @no_isobib
130
- global = !@no_isobib_cache && !node.attr("local-cache-only")
131
- local = node.attr("local-cache") || node.attr("local-cache-only")
132
- local = nil if @no_isobib_cache
133
- @bibdb = Relaton::DbCache.init_bib_caches(
134
- local_cache: local,
135
- flush_caches: node.attr("flush-caches"),
136
- global_cache: global)
137
- end
138
-
139
- def init_iev_caches(node)
140
- unless (@no_isobib_cache || @no_isobib)
141
- node.attr("local-cache-only") or
142
- @iev_globalname = global_ievcache_name
143
- @iev_localname = local_ievcache_name(node.attr("local-cache") ||
144
- node.attr("local-cache-only"))
145
- if node.attr("flush-caches")
146
- FileUtils.rm_f @iev_globalname unless @iev_globalname.nil?
147
- FileUtils.rm_f @iev_localname unless @iev_localname.nil?
148
- end
149
- end
150
- #@iev = Iev::Db.new(globalname, localname) unless @no_isobib
151
- end
152
-
153
130
  def default_fonts(node)
154
131
  b = node.attr("body-font") ||
155
132
  (node.attr("script") == "Hans" ? '"SimSun",serif' :
@@ -661,9 +661,9 @@
661
661
  <optional>
662
662
  <ref name="status"/>
663
663
  </optional>
664
- <optional>
664
+ <zeroOrMore>
665
665
  <ref name="copyright"/>
666
- </optional>
666
+ </zeroOrMore>
667
667
  <zeroOrMore>
668
668
  <ref name="docrelation"/>
669
669
  </zeroOrMore>
@@ -1021,7 +1021,17 @@
1021
1021
  <optional>
1022
1022
  <ref name="to"/>
1023
1023
  </optional>
1024
- <ref name="owner"/>
1024
+ <oneOrMore>
1025
+ <ref name="owner"/>
1026
+ </oneOrMore>
1027
+ <optional>
1028
+ <ref name="copyright_scope"/>
1029
+ </optional>
1030
+ </element>
1031
+ </define>
1032
+ <define name="copyright_scope">
1033
+ <element name="scope">
1034
+ <text/>
1025
1035
  </element>
1026
1036
  </define>
1027
1037
  <define name="from">
@@ -21,15 +21,21 @@ module Asciidoctor
21
21
  subsequence: node.attr("subsequence") )
22
22
  end
23
23
 
24
+ def termnote_attr(node)
25
+ attr_code(id_attr(node).merge(
26
+ "keep-separate": node.attr("keep-separate")))
27
+ end
28
+
24
29
  def note_attr(node)
25
- attr_code(id_attr(node).merge("keep-separate": node.attr("keep-separate")))
30
+ attr_code(id_attr(node).merge(
31
+ "keep-separate": node.attr("keep-separate"),
32
+ beforeclauses: node.attr("beforeclauses") == "true" ? "true" : nil))
26
33
  end
27
34
 
28
35
  # We append each contained block to its parent
29
36
  def open(node)
30
37
  role = node.role || node.attr("style")
31
- Utils::reqt_subpart(role) and
32
- return requirement_subpart(node)
38
+ Utils::reqt_subpart(role) and return requirement_subpart(node)
33
39
  result = []
34
40
  node.blocks.each do |b|
35
41
  result << send(b.context, b)
@@ -53,18 +59,16 @@ module Asciidoctor
53
59
 
54
60
  # NOTE: html escaping is performed by Nokogiri
55
61
  def stem(node)
56
- stem_content = node.lines.join("\n")
57
62
  noko do |xml|
58
63
  xml.formula **formula_attr(node) do |s|
59
- stem_parse(stem_content, s, node.style.to_sym)
64
+ stem_parse(node.lines.join("\n"), s, node.style.to_sym)
60
65
  end
61
66
  end
62
67
  end
63
68
 
64
69
  def sidebar_attrs(node)
65
70
  todo_attrs(node).merge(attr_code(
66
- from: node.attr("from"),
67
- to: node.attr("to") || node.attr("from") ))
71
+ from: node.attr("from"), to: node.attr("to") || node.attr("from") ))
68
72
  end
69
73
 
70
74
  def sidebar(node)
@@ -95,7 +99,7 @@ module Asciidoctor
95
99
 
96
100
  def termnote(n)
97
101
  noko do |xml|
98
- xml.termnote **note_attr(n) do |ex|
102
+ xml.termnote **termnote_attr(n) do |ex|
99
103
  wrap_in_para(n, ex)
100
104
  end
101
105
  end.join("\n")
@@ -111,12 +115,11 @@ module Asciidoctor
111
115
 
112
116
  def admonition_attrs(node)
113
117
  name = node.attr("name")
114
- if type = node.attr("type")
115
- ["danger", "safety precautions"].each do |t|
116
- name = t if type.casecmp(t).zero?
117
- end
118
+ a = node.attr("type") and ["danger", "safety precautions"].each do |t|
119
+ name = t if a.casecmp(t).zero?
118
120
  end
119
- attr_code(id: Utils::anchor_or_uuid(node), type: name)
121
+ attr_code(id: Utils::anchor_or_uuid(node), type: name,
122
+ beforeclauses: node.attr("beforeclauses") == "true" ? "true" : nil)
120
123
  end
121
124
 
122
125
  def admonition(node)
@@ -149,6 +152,8 @@ module Asciidoctor
149
152
  end
150
153
 
151
154
  def pseudocode_example(node)
155
+ # prevent A's and other subs inappropriate for pseudocode
156
+ node.blocks.each { |b| b.remove_sub(:replacements) }
152
157
  noko do |xml|
153
158
  xml.figure **id_unnum_attr(node).merge(class: "pseudocode") do |ex|
154
159
  figure_title(node, ex)
@@ -189,8 +194,7 @@ module Asciidoctor
189
194
  end
190
195
 
191
196
  def para_attrs(node)
192
- attr_code(align: node.attr("align"),
193
- id: Utils::anchor_or_uuid(node))
197
+ attr_code(align: node.attr("align"), id: Utils::anchor_or_uuid(node))
194
198
  end
195
199
 
196
200
  def paragraph(node)
@@ -213,9 +217,8 @@ module Asciidoctor
213
217
  s << m[:text]
214
218
  end
215
219
  end
216
- if node.attr("attribution")
220
+ node.attr("attribution") and
217
221
  out.author { |a| a << node.attr("attribution") }
218
- end
219
222
  end
220
223
 
221
224
  def quote(node)
@@ -7,6 +7,7 @@ require_relative "./cleanup_footnotes.rb"
7
7
  require_relative "./cleanup_ref.rb"
8
8
  require_relative "./cleanup_boilerplate.rb"
9
9
  require_relative "./cleanup_section.rb"
10
+ require_relative "./cleanup_terms.rb"
10
11
  require_relative "./cleanup_inline.rb"
11
12
  require "relaton_iev"
12
13
 
@@ -39,6 +40,7 @@ module Asciidoctor
39
40
  figure_cleanup(xmldoc)
40
41
  ref_cleanup(xmldoc)
41
42
  note_cleanup(xmldoc)
43
+ clausebefore_cleanup(xmldoc)
42
44
  ref_dl_cleanup(xmldoc)
43
45
  normref_cleanup(xmldoc)
44
46
  biblio_cleanup(xmldoc)
@@ -147,7 +147,7 @@ module Asciidoctor
147
147
 
148
148
  def requirement_inherit(x)
149
149
  x.xpath("//requirement | //recommendation | //permission").each do |r|
150
- ins = r.at("./classification") ||
150
+ ins = r.at("./classification") ||
151
151
  r.at("./description | ./measurementtarget | ./specification | "\
152
152
  "./verification | ./import | ./description | ./requirement | "\
153
153
  "./recommendation | ./permission")
@@ -158,7 +158,7 @@ module Asciidoctor
158
158
  def requirement_descriptions(x)
159
159
  x.xpath("//requirement | //recommendation | //permission").each do |r|
160
160
  r.children.each do |e|
161
- unless e.element? && (Utils::reqt_subpart(e.name) ||
161
+ unless e.element? && (Utils::reqt_subpart(e.name) ||
162
162
  %w(requirement recommendation permission).include?(e.name))
163
163
  t = Nokogiri::XML::Element.new("description", x)
164
164
  e.before(t)
@@ -138,133 +138,16 @@ module Asciidoctor
138
138
  end
139
139
  end
140
140
 
141
- def termdef_stem_cleanup(xmldoc)
142
- xmldoc.xpath("//term/p/stem").each do |a|
143
- if a.parent.elements.size == 1 # para contains just a stem expression
144
- t = Nokogiri::XML::Element.new("admitted", xmldoc)
145
- parent = a.parent
146
- t.children = a.remove
147
- parent.replace(t)
148
- end
149
- end
150
- end
151
-
152
- def termdomain_cleanup(xmldoc)
153
- xmldoc.xpath("//p/domain").each do |a|
154
- prev = a.parent.previous
155
- prev.next = a.remove
156
- end
157
- end
158
-
159
- def termdomain1_cleanup(xmldoc)
160
- xmldoc.xpath("//domain").each do |d|
161
- defn = d.at("../definition") and
162
- defn.previous = d.remove
163
- end
164
- end
165
-
166
- def termdefinition_cleanup(xmldoc)
167
- xmldoc.xpath("//term").each do |d|
168
- first_child = d.at("./p | ./figure | ./formula") || next
169
- t = Nokogiri::XML::Element.new("definition", xmldoc)
170
- first_child.replace(t)
171
- t << first_child.remove
172
- d.xpath("./p | ./figure | ./formula").each { |n| t << n.remove }
173
- end
174
- end
175
-
176
- def termdef_unnest_cleanup(xmldoc)
177
- # release termdef tags from surrounding paras
178
- nodes = xmldoc.xpath("//p/admitted | //p/deprecates")
179
- while !nodes.empty?
180
- nodes[0].parent.replace(nodes[0].parent.children)
181
- nodes = xmldoc.xpath("//p/admitted | //p/deprecates")
182
- end
183
- end
184
-
185
- def termdef_boilerplate_cleanup(xmldoc)
186
- xmldoc.xpath("//terms/p | //terms/ul").each(&:remove)
187
- end
188
-
189
- def termdef_subclause_cleanup(xmldoc)
190
- xmldoc.xpath("//terms[terms]").each { |t| t.name = "clause" }
191
- end
192
-
193
- def termdocsource_cleanup(xmldoc)
194
- f = xmldoc.at("//preface | //sections")
195
- xmldoc.xpath("//termdocsource").each do |s|
196
- f.previous = s.remove
141
+ def clausebefore_cleanup(xmldoc)
142
+ return unless xmldoc.at("//sections")
143
+ unless ins = xmldoc.at("//sections").children.first
144
+ xmldoc.at("//sections") << " "
145
+ ins = xmldoc.at("//sections").children.first
197
146
  end
198
- end
199
-
200
- def term_children_cleanup(xmldoc)
201
- xmldoc.xpath("//term").each do |t|
202
- t.xpath("./termnote").each { |n| t << n.remove }
203
- t.xpath("./termexample").each { |n| t << n.remove }
204
- t.xpath("./termsource").each { |n| t << n.remove }
205
- end
206
- end
207
-
208
- def termdef_from_termbase(xmldoc)
209
- xmldoc.xpath("//term").each do |x|
210
- if c = x.at("./origin/termref") and !x.at("./definition")
211
- x.at("./origin").previous = fetch_termbase(c["base"], c.text)
212
- end
213
- end
214
- end
215
-
216
- def termdef_cleanup(xmldoc)
217
- termdef_from_termbase(xmldoc)
218
- termdef_unnest_cleanup(xmldoc)
219
- termdef_stem_cleanup(xmldoc)
220
- termdomain_cleanup(xmldoc)
221
- termdefinition_cleanup(xmldoc)
222
- termdomain1_cleanup(xmldoc)
223
- termdef_boilerplate_cleanup(xmldoc)
224
- termdef_subclause_cleanup(xmldoc)
225
- term_children_cleanup(xmldoc)
226
- termdocsource_cleanup(xmldoc)
227
- end
228
-
229
- # Indices sort after letter but before any following
230
- # letter (x, x_m, x_1, xa); we use colon to force that sort order.
231
- # Numbers sort *after* letters; we use thorn to force that sort order.
232
- def symbol_key(x)
233
- key = x.dup
234
- key.traverse do |n|
235
- next unless n.name == "math"
236
- n.replace(grkletters(MathML2AsciiMath.m2a(n.to_xml)))
237
- end
238
- ret = Nokogiri::XML(key.to_xml)
239
- HTMLEntities.new.decode(ret.text).
240
- gsub(/[\[\]\{\}<>\(\)]/, "").strip.
241
- gsub(/[[:punct]]|[_^]/, ":\\0").gsub(/`/, "").
242
- gsub(/[0-9]+/, "þ\\0")
243
- end
244
-
245
- def grkletters(x)
246
- x.gsub(/\b(alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\b/i, "&\\1;")
247
- end
248
-
249
- def extract_symbols_list(dl)
250
- dl_out = []
251
- dl.xpath("./dt | ./dd").each do |dtd|
252
- if dtd.name == "dt"
253
- dl_out << { dt: dtd.remove, key: symbol_key(dtd) }
254
- else
255
- dl_out.last[:dd] = dtd.remove
256
- end
257
- end
258
- dl_out
259
- end
260
-
261
- def symbols_cleanup(docxml)
262
- docxml.xpath("//definitions/dl").each do |dl|
263
- dl_out = extract_symbols_list(dl)
264
- dl_out.sort! { |a, b| a[:key] <=> b[:key] || a[:dt] <=> b[:dt] }
265
- dl.children = dl_out.map { |d| d[:dt].to_s + d[:dd].to_s }.join("\n")
147
+ xmldoc.xpath("//*[@beforeclauses = 'true']").each do |x|
148
+ x.delete("beforeclauses")
149
+ ins.previous = x.remove
266
150
  end
267
- docxml
268
151
  end
269
152
  end
270
153
  end
@@ -0,0 +1,134 @@
1
+ module Asciidoctor
2
+ module Standoc
3
+ module Cleanup
4
+ def termdef_stem_cleanup(xmldoc)
5
+ xmldoc.xpath("//term/p/stem").each do |a|
6
+ if a.parent.elements.size == 1 # para contains just a stem expression
7
+ t = Nokogiri::XML::Element.new("admitted", xmldoc)
8
+ parent = a.parent
9
+ t.children = a.remove
10
+ parent.replace(t)
11
+ end
12
+ end
13
+ end
14
+
15
+ def termdomain_cleanup(xmldoc)
16
+ xmldoc.xpath("//p/domain").each do |a|
17
+ prev = a.parent.previous
18
+ prev.next = a.remove
19
+ end
20
+ end
21
+
22
+ def termdomain1_cleanup(xmldoc)
23
+ xmldoc.xpath("//domain").each do |d|
24
+ defn = d.at("../definition") and
25
+ defn.previous = d.remove
26
+ end
27
+ end
28
+
29
+ def termdefinition_cleanup(xmldoc)
30
+ xmldoc.xpath("//term").each do |d|
31
+ first_child = d.at("./p | ./figure | ./formula") || next
32
+ t = Nokogiri::XML::Element.new("definition", xmldoc)
33
+ first_child.replace(t)
34
+ t << first_child.remove
35
+ d.xpath("./p | ./figure | ./formula").each { |n| t << n.remove }
36
+ end
37
+ end
38
+
39
+ def termdef_unnest_cleanup(xmldoc)
40
+ # release termdef tags from surrounding paras
41
+ nodes = xmldoc.xpath("//p/admitted | //p/deprecates")
42
+ while !nodes.empty?
43
+ nodes[0].parent.replace(nodes[0].parent.children)
44
+ nodes = xmldoc.xpath("//p/admitted | //p/deprecates")
45
+ end
46
+ end
47
+
48
+ def termdef_boilerplate_cleanup(xmldoc)
49
+ xmldoc.xpath("//terms/p | //terms/ul").each(&:remove)
50
+ end
51
+
52
+ def termdef_subclause_cleanup(xmldoc)
53
+ xmldoc.xpath("//terms[terms]").each { |t| t.name = "clause" }
54
+ end
55
+
56
+ def termdocsource_cleanup(xmldoc)
57
+ f = xmldoc.at("//preface | //sections")
58
+ xmldoc.xpath("//termdocsource").each do |s|
59
+ f.previous = s.remove
60
+ end
61
+ end
62
+
63
+ def term_children_cleanup(xmldoc)
64
+ xmldoc.xpath("//term").each do |t|
65
+ t.xpath("./termnote").each { |n| t << n.remove }
66
+ t.xpath("./termexample").each { |n| t << n.remove }
67
+ t.xpath("./termsource").each { |n| t << n.remove }
68
+ end
69
+ end
70
+
71
+ def termdef_from_termbase(xmldoc)
72
+ xmldoc.xpath("//term").each do |x|
73
+ if c = x.at("./origin/termref") and !x.at("./definition")
74
+ x.at("./origin").previous = fetch_termbase(c["base"], c.text)
75
+ end
76
+ end
77
+ end
78
+
79
+ def termdef_cleanup(xmldoc)
80
+ termdef_from_termbase(xmldoc)
81
+ termdef_unnest_cleanup(xmldoc)
82
+ termdef_stem_cleanup(xmldoc)
83
+ termdomain_cleanup(xmldoc)
84
+ termdefinition_cleanup(xmldoc)
85
+ termdomain1_cleanup(xmldoc)
86
+ termdef_boilerplate_cleanup(xmldoc)
87
+ termdef_subclause_cleanup(xmldoc)
88
+ term_children_cleanup(xmldoc)
89
+ termdocsource_cleanup(xmldoc)
90
+ end
91
+
92
+ # Indices sort after letter but before any following
93
+ # letter (x, x_m, x_1, xa); we use colon to force that sort order.
94
+ # Numbers sort *after* letters; we use thorn to force that sort order.
95
+ def symbol_key(x)
96
+ key = x.dup
97
+ key.traverse do |n|
98
+ next unless n.name == "math"
99
+ n.replace(grkletters(MathML2AsciiMath.m2a(n.to_xml)))
100
+ end
101
+ ret = Nokogiri::XML(key.to_xml)
102
+ HTMLEntities.new.decode(ret.text).
103
+ gsub(/[\[\]\{\}<>\(\)]/, "").strip.
104
+ gsub(/[[:punct]]|[_^]/, ":\\0").gsub(/`/, "").
105
+ gsub(/[0-9]+/, "þ\\0")
106
+ end
107
+
108
+ def grkletters(x)
109
+ x.gsub(/\b(alpha|beta|gamma|delta|epsilon|zeta|eta|theta|iota|kappa|lambda|mu|nu|xi|omicron|pi|rho|sigma|tau|upsilon|phi|chi|psi|omega)\b/i, "&\\1;")
110
+ end
111
+
112
+ def extract_symbols_list(dl)
113
+ dl_out = []
114
+ dl.xpath("./dt | ./dd").each do |dtd|
115
+ if dtd.name == "dt"
116
+ dl_out << { dt: dtd.remove, key: symbol_key(dtd) }
117
+ else
118
+ dl_out.last[:dd] = dtd.remove
119
+ end
120
+ end
121
+ dl_out
122
+ end
123
+
124
+ def symbols_cleanup(docxml)
125
+ docxml.xpath("//definitions/dl").each do |dl|
126
+ dl_out = extract_symbols_list(dl)
127
+ dl_out.sort! { |a, b| a[:key] <=> b[:key] || a[:dt] <=> b[:dt] }
128
+ dl.children = dl_out.map { |d| d[:dt].to_s + d[:dd].to_s }.join("\n")
129
+ end
130
+ docxml
131
+ end
132
+ end
133
+ end
134
+ end