metanorma-standoc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +4 -0
  3. data/.gitignore +11 -0
  4. data/.hound.yml +3 -0
  5. data/.oss-guides.rubocop.yml +1077 -0
  6. data/.rubocop.ribose.yml +66 -0
  7. data/.rubocop.tb.yml +650 -0
  8. data/.rubocop.yml +15 -0
  9. data/.travis.yml +21 -0
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/Gemfile +7 -0
  12. data/LICENSE +25 -0
  13. data/Makefile +39 -0
  14. data/README.adoc +9 -0
  15. data/Rakefile +6 -0
  16. data/bin/rspec +18 -0
  17. data/docs/customisation.adoc +178 -0
  18. data/docs/guidance.adoc +436 -0
  19. data/docs/htmloutput.adoc +115 -0
  20. data/docs/quickstart.adoc +375 -0
  21. data/lib/asciidoctor/standoc/base.rb +198 -0
  22. data/lib/asciidoctor/standoc/biblio.rng +836 -0
  23. data/lib/asciidoctor/standoc/blocks.rb +190 -0
  24. data/lib/asciidoctor/standoc/cleanup.rb +247 -0
  25. data/lib/asciidoctor/standoc/cleanup_block.rb +193 -0
  26. data/lib/asciidoctor/standoc/cleanup_footnotes.rb +78 -0
  27. data/lib/asciidoctor/standoc/cleanup_ref.rb +125 -0
  28. data/lib/asciidoctor/standoc/converter.rb +55 -0
  29. data/lib/asciidoctor/standoc/front.rb +121 -0
  30. data/lib/asciidoctor/standoc/inline.rb +134 -0
  31. data/lib/asciidoctor/standoc/isodoc.rng +1059 -0
  32. data/lib/asciidoctor/standoc/lists.rb +87 -0
  33. data/lib/asciidoctor/standoc/macros.rb +95 -0
  34. data/lib/asciidoctor/standoc/ref.rb +187 -0
  35. data/lib/asciidoctor/standoc/section.rb +159 -0
  36. data/lib/asciidoctor/standoc/table.rb +61 -0
  37. data/lib/asciidoctor/standoc/utils.rb +121 -0
  38. data/lib/asciidoctor/standoc/validate.rb +65 -0
  39. data/lib/asciidoctor/standoc/validate_section.rb +42 -0
  40. data/lib/asciidoctor/standoc/version.rb +5 -0
  41. data/lib/metanorma-standoc.rb +9 -0
  42. data/lib/metanorma/standoc.rb +7 -0
  43. data/lib/metanorma/standoc/processor.rb +40 -0
  44. data/metanorma-standoc.gemspec +47 -0
  45. data/spec/asciidoctor-standoc/base_spec.rb +271 -0
  46. data/spec/asciidoctor-standoc/blocks_spec.rb +469 -0
  47. data/spec/asciidoctor-standoc/cleanup_spec.rb +760 -0
  48. data/spec/asciidoctor-standoc/inline_spec.rb +162 -0
  49. data/spec/asciidoctor-standoc/isobib_cache_spec.rb +332 -0
  50. data/spec/asciidoctor-standoc/lists_spec.rb +190 -0
  51. data/spec/asciidoctor-standoc/macros_spec.rb +111 -0
  52. data/spec/asciidoctor-standoc/refs_spec.rb +606 -0
  53. data/spec/asciidoctor-standoc/section_spec.rb +310 -0
  54. data/spec/asciidoctor-standoc/table_spec.rb +307 -0
  55. data/spec/asciidoctor-standoc/validate_spec.rb +133 -0
  56. data/spec/assets/header.html +7 -0
  57. data/spec/assets/html.css +2 -0
  58. data/spec/assets/htmlcover.html +4 -0
  59. data/spec/assets/htmlintro.html +5 -0
  60. data/spec/assets/i18n.yaml +2 -0
  61. data/spec/assets/iso.headless.html +33 -0
  62. data/spec/assets/iso.xml +8 -0
  63. data/spec/assets/rice_image1.png +0 -0
  64. data/spec/assets/scripts.html +3 -0
  65. data/spec/assets/std.css +2 -0
  66. data/spec/assets/word.css +2 -0
  67. data/spec/assets/wordcover.html +3 -0
  68. data/spec/assets/wordintro.html +4 -0
  69. data/spec/examples/103_01_02.html +247 -0
  70. data/spec/examples/english.yaml +69 -0
  71. data/spec/examples/iso_123_.xml +45 -0
  72. data/spec/examples/iso_123_all_parts.xml +45 -0
  73. data/spec/examples/iso_123_no_year_note.xml +46 -0
  74. data/spec/examples/iso_124_.xml +41 -0
  75. data/spec/examples/iso_216_.xml +47 -0
  76. data/spec/examples/iso_iec_12382_.xml +48 -0
  77. data/spec/examples/rice.adoc +715 -0
  78. data/spec/examples/rice.preview.html +1877 -0
  79. data/spec/examples/rice.sh +4 -0
  80. data/spec/examples/rice_images/rice_image1.png +0 -0
  81. data/spec/examples/rice_images/rice_image2.png +0 -0
  82. data/spec/examples/rice_images/rice_image3_1.png +0 -0
  83. data/spec/examples/rice_images/rice_image3_2.png +0 -0
  84. data/spec/examples/rice_images/rice_image3_3.png +0 -0
  85. data/spec/metanorma/processor_spec.rb +70 -0
  86. data/spec/spec_helper.rb +198 -0
  87. metadata +370 -0
@@ -0,0 +1,87 @@
1
+ require "pp"
2
+
3
+ module Asciidoctor
4
+ module Standoc
5
+ module Lists
6
+ def li(xml_ul, item)
7
+ xml_ul.li do |xml_li|
8
+ if item.blocks?
9
+ xml_li.p(**id_attr(item)) { |t| t << item.text }
10
+ xml_li << item.content
11
+ else
12
+ xml_li.p(**id_attr(item)) { |p| p << item.text }
13
+ end
14
+ end
15
+ end
16
+
17
+ def ulist(node)
18
+ return reference(node) if in_norm_ref? || in_biblio?
19
+ noko do |xml|
20
+ xml.ul **id_attr(node) do |xml_ul|
21
+ node.items.each do |item|
22
+ li(xml_ul, item)
23
+ end
24
+ end
25
+ end.join("\n")
26
+ end
27
+
28
+ def olist_style(style)
29
+ return "alphabet" if style == "loweralpha"
30
+ return "roman" if style == "lowerroman"
31
+ return "roman_upper" if style == "upperroman"
32
+ return "alphabet_upper" if style == "upperalpha"
33
+ style
34
+ end
35
+
36
+ def olist(node)
37
+ noko do |xml|
38
+ xml.ol **attr_code(id: Utils::anchor_or_uuid(node),
39
+ type: olist_style(node.style)) do |xml_ol|
40
+ node.items.each { |item| li(xml_ol, item) }
41
+ end
42
+ end.join("\n")
43
+ end
44
+
45
+ def dt(terms, xml_dl)
46
+ terms.each_with_index do |dt, idx|
47
+ xml_dl.dt { |xml_dt| xml_dt << dt.text }
48
+ if idx < terms.size - 1
49
+ xml_dl.dd
50
+ end
51
+ end
52
+ end
53
+
54
+ def dd(dd, xml_dl)
55
+ if dd.nil?
56
+ xml_dl.dd
57
+ return
58
+ end
59
+ xml_dl.dd do |xml_dd|
60
+ xml_dd.p { |t| t << dd.text } if dd.text?
61
+ xml_dd << dd.content if dd.blocks?
62
+ end
63
+ end
64
+
65
+ def dlist(node)
66
+ noko do |xml|
67
+ xml.dl **id_attr(node) do |xml_dl|
68
+ node.items.each do |terms, dd|
69
+ dt(terms, xml_dl)
70
+ dd(dd, xml_dl)
71
+ end
72
+ end
73
+ end.join("\n")
74
+ end
75
+
76
+ def colist(node)
77
+ noko do |xml|
78
+ node.items.each_with_index do |item, i|
79
+ xml.annotation **attr_code(id: i + 1) do |xml_li|
80
+ xml_li.p { |p| p << item.text }
81
+ end
82
+ end
83
+ end.join("\n")
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,95 @@
1
+ require "asciidoctor/extensions"
2
+ module Asciidoctor
3
+ module Standoc
4
+ class AltTermInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
5
+ use_dsl
6
+ named :alt
7
+ parse_content_as :text
8
+ using_format :short
9
+
10
+ def process(parent, _target, attrs)
11
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
12
+ %{<admitted>#{out}</admitted>}
13
+ end
14
+ end
15
+
16
+ class DeprecatedTermInlineMacro <
17
+ Asciidoctor::Extensions::InlineMacroProcessor
18
+ use_dsl
19
+ named :deprecated
20
+ parse_content_as :text
21
+ using_format :short
22
+
23
+ def process(parent, _target, attrs)
24
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
25
+ %{<deprecates>#{out}</deprecates>}
26
+ end
27
+ end
28
+
29
+ class DomainTermInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
30
+ use_dsl
31
+ named :domain
32
+ parse_content_as :text
33
+ using_format :short
34
+
35
+ def process(parent, _target, attrs)
36
+ out = Asciidoctor::Inline.new(parent, :quoted, attrs["text"]).convert
37
+ %{<domain>#{out}</domain>}
38
+ end
39
+ end
40
+
41
+ class PlantUMLBlockMacroBackend
42
+ # https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby
43
+ def self.plantuml_installed?
44
+ cmd = "plantuml"
45
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
46
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
47
+ exts.each do |ext|
48
+ exe = File.join(path, "#{cmd}#{ext}")
49
+ return exe if File.executable?(exe) && !File.directory?(exe)
50
+ end
51
+ end
52
+ nil
53
+ end
54
+
55
+ def self.generate_file parent, reader
56
+ src = reader.source
57
+ reader.lines.first.sub(/\s+$/, "") != "@startuml" or
58
+ src = "@startuml\n#{src}\n@enduml\n"
59
+ filename = parent.document.reader.lineno
60
+ system "mkdir -p plantuml"
61
+ File.open("plantuml/#{filename}.pml", "w") { |f| f.write src }
62
+ system "plantuml plantuml/#{filename}.pml"
63
+ filename
64
+ end
65
+
66
+ def self.generate_attrs attrs
67
+ through_attrs = %w(id align float title role width height alt).
68
+ inject({}) do |memo, key|
69
+ memo[key] = attrs[key] if attrs.has_key? key
70
+ memo
71
+ end
72
+ end
73
+ end
74
+
75
+ class PlantUMLBlockMacro < Asciidoctor::Extensions::BlockProcessor
76
+ use_dsl
77
+ named :plantuml
78
+ on_context :literal
79
+ parse_content_as :raw
80
+
81
+ def process(parent, reader, attrs)
82
+ if PlantUMLBlockMacroBackend.plantuml_installed?
83
+ filename = PlantUMLBlockMacroBackend.generate_file parent, reader
84
+ through_attrs = PlantUMLBlockMacroBackend.generate_attrs attrs
85
+ through_attrs["target"] = "plantuml/#{filename}.png"
86
+ create_image_block parent, through_attrs
87
+ else
88
+ warn "PlantUML not installed"
89
+ # attrs.delete(1) : remove the style attribute
90
+ create_listing_block parent, reader.source, attrs.reject { |k, v| k == 1 }
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,187 @@
1
+ require "pp"
2
+
3
+ module Asciidoctor
4
+ module Standoc
5
+ module Lists
6
+ def iso_publisher(t, code)
7
+ code.sub(/ .*$/, "").split(/\//).each do |abbrev|
8
+ t.contributor do |c|
9
+ c.role **{ type: "publisher" }
10
+ c.organization do |org|
11
+ organization(org, abbrev)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ def plaintxt
18
+ { format: "text/plain" }
19
+ end
20
+
21
+ def ref_attributes(m)
22
+ { id: m[:anchor], type: "standard" }
23
+ end
24
+
25
+ def set_date_range(date, text)
26
+ matched = /^(?<from>[0-9]+)(-+(?<to>[0-9]+))?$/.match text
27
+ return unless matched[:from]
28
+ if matched[:to]
29
+ date.from matched[:from]
30
+ date.to matched[:to]
31
+ else
32
+ date.on matched[:from]
33
+ end
34
+ end
35
+
36
+ def use_my_anchor(ref, id)
37
+ ref.parent.elements.last["id"] = id
38
+ ref
39
+ end
40
+
41
+ def isorefmatches(xml, m)
42
+ ref = fetch_ref xml, m[:code], m[:year]
43
+ return use_my_anchor(ref, m[:anchor]) if ref
44
+ xml.bibitem **attr_code(ref_attributes(m)) do |t|
45
+ t.title(**plaintxt) { |i| i << ref_normalise(m[:text]) }
46
+ t.docidentifier m[:code]
47
+ m[:year] and t.date **{ type: "published" } do |d|
48
+ set_date_range(d, m[:year])
49
+ end
50
+ iso_publisher(t, m[:code])
51
+ end
52
+ end
53
+
54
+ def isorefmatches2(xml, m)
55
+ ref = fetch_ref xml, m[:code], nil, no_year: true, note: m[:fn]
56
+ return use_my_anchor(ref, m[:anchor]) if ref
57
+ xml.bibitem **attr_code(ref_attributes(m)) do |t|
58
+ t.title(**plaintxt) { |i| i << ref_normalise(m[:text]) }
59
+ t.docidentifier m[:code]
60
+ t.date **{ type: "published" } do |d|
61
+ d.on "--"
62
+ end
63
+ iso_publisher(t, m[:code])
64
+ t.note(**plaintxt) { |p| p << "ISO DATE: #{m[:fn]}" }
65
+ end
66
+ end
67
+
68
+ def isorefmatches3(xml, m)
69
+ hasyr = m.names.include?("year")
70
+ ref = fetch_ref xml, m[:code], hasyr ? m[:year] : nil, all_parts: true
71
+ return use_my_anchor(ref, m[:anchor]) if ref
72
+ xml.bibitem(**attr_code(ref_attributes(m))) do |t|
73
+ t.title(**plaintxt) { |i| i << ref_normalise(m[:text]) }
74
+ t.docidentifier "#{m[:code]}"
75
+ hasyr and
76
+ t.date(**{ type: "published" }) { |d| set_date_range(d, m[:year]) }
77
+ iso_publisher(t, m[:code])
78
+ t.allParts "true"
79
+ end
80
+ end
81
+
82
+ def fetch_ref(xml, code, year, **opts)
83
+ hit = @bibdb&.fetch(code, year, opts)
84
+ return nil if hit.nil?
85
+ xml.parent.add_child(hit.to_xml)
86
+ xml
87
+ rescue Algolia::AlgoliaProtocolError
88
+ nil # Render reference without an Internet connection.
89
+ end
90
+
91
+ def refitem_render(xml, m)
92
+ xml.bibitem **attr_code(id: m[:anchor]) do |t|
93
+ t.formattedref **{ format: "application/x-isodoc+xml" } do |i|
94
+ i << ref_normalise_no_format(m[:text])
95
+ end
96
+ t.docidentifier(/^\d+$/.match(m[:code]) ? "[#{m[:code]}]" : m[:code])
97
+ end
98
+ end
99
+
100
+ # TODO: alternative where only title is available
101
+ def refitem(xml, item, node)
102
+ unless m = NON_ISO_REF.match(item)
103
+ Utils::warning(node, "no anchor on reference", item)
104
+ return
105
+ end
106
+ unless m[:code] && /^\d+$/.match(m[:code])
107
+ ref = fetch_ref xml, m[:code],
108
+ m.names.include?("year") ? m[:year] : nil, {}
109
+ return use_my_anchor(ref, m[:anchor]) if ref
110
+ end
111
+ refitem_render(xml, m)
112
+ end
113
+
114
+ def ref_normalise(ref)
115
+ ref.
116
+ # gsub(/&#8201;&#8212;&#8201;/, " -- ").
117
+ gsub(/&amp;amp;/, "&amp;").
118
+ gsub(%r{^<em>(.*)</em>}, "\\1")
119
+ end
120
+
121
+ def ref_normalise_no_format(ref)
122
+ ref.
123
+ # gsub(/&#8201;&#8212;&#8201;/, " -- ").
124
+ gsub(/&amp;amp;/, "&amp;")
125
+ end
126
+
127
+ ISO_REF = %r{^<ref\sid="(?<anchor>[^"]+)">
128
+ \[(?<code>(ISO|IEC)[^0-9]*\s[0-9-]+|IEV)
129
+ (:(?<year>[0-9][0-9-]+))?\]</ref>,?\s
130
+ (?<text>.*)$}xm
131
+
132
+ ISO_REF_NO_YEAR = %r{^<ref\sid="(?<anchor>[^"]+)">
133
+ \[(?<code>(ISO|IEC)[^0-9]*\s[0-9-]+):--\]</ref>,?\s?
134
+ <fn[^>]*>\s*<p>(?<fn>[^\]]+)</p>\s*</fn>,?\s?(?<text>.*)$}xm
135
+
136
+ ISO_REF_ALL_PARTS = %r{^<ref\sid="(?<anchor>[^"]+)">
137
+ \[(?<code>(ISO|IEC)[^0-9]*\s[0-9]+)(:(?<year>[0-9][0-9-]+))?\s
138
+ \(all\sparts\)\]</ref>,?\s
139
+ (?<text>.*)$}xm
140
+
141
+ NON_ISO_REF = %r{^<ref\sid="(?<anchor>[^"]+)">
142
+ \[(?<code>[^\]]+?)([:-](?<year>(19|20)[0-9][0-9]))?\]</ref>,?\s
143
+ (?<text>.*)$}xm
144
+
145
+ # @param item [String]
146
+ # @return [Array<MatchData>]
147
+ def reference1_matches(item)
148
+ matched = ISO_REF.match item
149
+ matched2 = ISO_REF_NO_YEAR.match item
150
+ matched3 = ISO_REF_ALL_PARTS.match item
151
+ [matched, matched2, matched3]
152
+ end
153
+
154
+ # @param node [Asciidoctor::List]
155
+ # @param item [String]
156
+ # @param xml [Nokogiri::XML::Builder]
157
+ def reference1(node, item, xml)
158
+ matched, matched2, matched3 = reference1_matches(item)
159
+ if matched3.nil? && matched2.nil? && matched.nil?
160
+ refitem(xml, item, node)
161
+ # elsif fetch_ref(matched3 || matched2 || matched, xml)
162
+ elsif !matched.nil? then isorefmatches(xml, matched)
163
+ elsif !matched2.nil? then isorefmatches2(xml, matched2)
164
+ elsif !matched3.nil? then isorefmatches3(xml, matched3)
165
+ end
166
+ end
167
+
168
+ def reference(node)
169
+ noko do |xml|
170
+ node.items.each do |item|
171
+ reference1(node, item.text, xml)
172
+ end
173
+ end.join("\n")
174
+ end
175
+
176
+ def bibliocache_name(global)
177
+ global ? "#{Dir.home}/.relaton-bib.pstore" :
178
+ "#{@filename}.relaton.pstore"
179
+ end
180
+
181
+ def ievcache_name(global)
182
+ global ? "#{Dir.home}/.iev.pstore" :
183
+ "#{@filename}.iev.pstore"
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,159 @@
1
+ require "htmlentities"
2
+ require "uri"
3
+
4
+ module Asciidoctor
5
+ module Standoc
6
+ module Section
7
+ @biblio = false
8
+ @term_def = false
9
+ @norm_ref = false
10
+
11
+ def in_biblio?
12
+ @biblio
13
+ end
14
+
15
+ def in_terms?
16
+ @term_def
17
+ end
18
+
19
+ def in_norm_ref?
20
+ @norm_ref
21
+ end
22
+
23
+ def sectiontype(node)
24
+ node&.attr("heading")&.downcase || node.title.downcase
25
+ end
26
+
27
+ def section(node)
28
+ a = { id: Utils::anchor_or_uuid(node) }
29
+ noko do |xml|
30
+ case sectiontype(node)
31
+ when "introduction" then
32
+ if node.level == 1 then introduction_parse(a, xml, node)
33
+ else
34
+ clause_parse(a, xml, node)
35
+ end
36
+ when "normative references" then norm_ref_parse(a, xml, node)
37
+ when "terms and definitions",
38
+ "terms, definitions, symbols and abbreviated terms",
39
+ "terms, definitions, symbols and abbreviations",
40
+ "terms, definitions and symbols",
41
+ "terms, definitions and abbreviations",
42
+ "terms, definitions and abbreviated terms"
43
+ @term_def = true
44
+ term_def_parse(a, xml, node, true)
45
+ @term_def = false
46
+ when "symbols and abbreviated terms"
47
+ symbols_parse(a, xml, node)
48
+ when "bibliography" then bibliography_parse(a, xml, node)
49
+ else
50
+ if @term_def then term_def_subclause_parse(a, xml, node)
51
+ elsif @biblio then bibliography_parse(a, xml, node)
52
+ elsif node.attr("style") == "bibliography" && node.level == 1
53
+ bibliography_parse(a, xml, node)
54
+ elsif node.attr("style") == "appendix" && node.level == 1
55
+ annex_parse(a, xml, node)
56
+ else
57
+ clause_parse(a, xml, node)
58
+ end
59
+ end
60
+ end.join("\n")
61
+ end
62
+
63
+ def set_obligation(attrs, node)
64
+ attrs[:obligation] = if node.attributes.has_key?("obligation")
65
+ node.attr("obligation")
66
+ elsif node.parent.attributes.has_key?("obligation")
67
+ node.parent.attr("obligation")
68
+ else
69
+ "normative"
70
+ end
71
+ end
72
+
73
+ def clause_parse(attrs, xml, node)
74
+ attrs["inline-header".to_sym] = node.option? "inline-header"
75
+ attrs[:level] = node.attr("level")
76
+ set_obligation(attrs, node)
77
+ xml.send "clause", **attr_code(attrs) do |xml_section|
78
+ xml_section.title { |n| n << node.title } unless node.title.nil?
79
+ xml_section << node.content
80
+ end
81
+ end
82
+
83
+ def annex_parse(attrs, xml, node)
84
+ attrs["inline-header".to_sym] = node.option? "inline-header"
85
+ set_obligation(attrs, node)
86
+ xml.annex **attr_code(attrs) do |xml_section|
87
+ xml_section.title { |name| name << node.title }
88
+ xml_section << node.content
89
+ end
90
+ end
91
+
92
+ def bibliography_parse(attrs, xml, node)
93
+ node.attr("style") == "bibliography" or
94
+ warn "Section not marked up as [bibliography]!"
95
+ @biblio = true
96
+ xml.references **attr_code(attrs) do |xml_section|
97
+ title = node.level == 1 ? "Bibliography" : node.title
98
+ xml_section.title { |t| t << title }
99
+ xml_section << node.content
100
+ end
101
+ @biblio = false
102
+ end
103
+
104
+ def symbols_parse(attrs, xml, node)
105
+ xml.definitions **attr_code(attrs) do |xml_section|
106
+ xml_section << node.content
107
+ end
108
+ end
109
+
110
+ # subclause contains subclauses
111
+ def term_def_subclause_parse(attrs, xml, node)
112
+ sub = node.find_by(context: :section) { |s| s.level == node.level + 1 }
113
+ sub.empty? || (return term_def_parse(attrs, xml, node, false))
114
+ node.title.casecmp("symbols and abbreviated terms").zero? &&
115
+ (return symbols_parse(attrs, xml, node))
116
+ xml.term **attr_code(attrs) do |xml_section|
117
+ xml_section.preferred { |name| name << node.title }
118
+ xml_section << node.content
119
+ end
120
+ end
121
+
122
+ def term_def_title(toplevel, node)
123
+ return node.title unless toplevel
124
+ sub = node.find_by(context: :section) do |s|
125
+ s.title.casecmp("symbols and abbreviated terms").zero?
126
+ end
127
+ return "Terms and definitions" if sub.empty?
128
+ "Terms, definitions, symbols and abbreviated terms"
129
+ end
130
+
131
+ def term_def_parse(attrs, xml, node, toplevel)
132
+ xml.terms **attr_code(attrs) do |section|
133
+ section.title { |t| t << term_def_title(toplevel, node) }
134
+ (s = node.attr("source")) && s.split(/,/).each do |s1|
135
+ section.termdocsource(nil, **attr_code(bibitemid: s1, type: "inline"))
136
+ end
137
+ section << node.content
138
+ end
139
+ end
140
+
141
+ def norm_ref_parse(attrs, xml, node)
142
+ @norm_ref = true
143
+ xml.references **attr_code(attrs) do |xml_section|
144
+ xml_section.title { |t| t << "Normative References" }
145
+ xml_section << node.content
146
+ end
147
+ @norm_ref = false
148
+ end
149
+
150
+ def introduction_parse(attrs, xml, node)
151
+ xml.introduction **attr_code(attrs) do |xml_section|
152
+ xml_section.title = "Introduction"
153
+ content = node.content
154
+ xml_section << content
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end