metanorma-iso 1.8.1 → 1.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +3 -13
  3. data/.hound.yml +3 -1
  4. data/.rubocop.yml +4 -8
  5. data/lib/asciidoctor/iso/base.rb +1 -0
  6. data/lib/asciidoctor/iso/biblio.rng +1 -0
  7. data/lib/asciidoctor/iso/cleanup.rb +17 -5
  8. data/lib/asciidoctor/iso/front.rb +3 -1
  9. data/lib/asciidoctor/iso/front_id.rb +66 -50
  10. data/lib/asciidoctor/iso/isodoc.rng +209 -4
  11. data/lib/asciidoctor/iso/isostandard-amd.rng +3 -0
  12. data/lib/asciidoctor/iso/isostandard.rng +12 -0
  13. data/lib/asciidoctor/iso/section.rb +2 -1
  14. data/lib/asciidoctor/iso/validate_section.rb +16 -9
  15. data/lib/isodoc/iso/base_convert.rb +13 -13
  16. data/lib/isodoc/iso/html/isodoc.css +475 -20
  17. data/lib/isodoc/iso/html/isodoc.scss +456 -23
  18. data/lib/isodoc/iso/html/wordstyle.css +202 -31
  19. data/lib/isodoc/iso/html/wordstyle.scss +194 -32
  20. data/lib/isodoc/iso/iso.amendment.xsl +679 -473
  21. data/lib/isodoc/iso/iso.international-standard.xsl +679 -473
  22. data/lib/isodoc/iso/metadata.rb +3 -2
  23. data/lib/isodoc/iso/presentation_xml_convert.rb +18 -9
  24. data/lib/isodoc/iso/sts_convert.rb +10 -13
  25. data/lib/isodoc/iso/word_convert.rb +153 -39
  26. data/lib/isodoc/iso/xref.rb +42 -27
  27. data/lib/metanorma/iso/version.rb +1 -1
  28. data/metanorma-iso.gemspec +4 -4
  29. data/spec/asciidoctor/base_spec.rb +426 -334
  30. data/spec/asciidoctor/blocks_spec.rb +96 -34
  31. data/spec/asciidoctor/cleanup_spec.rb +383 -25
  32. data/spec/asciidoctor/section_spec.rb +0 -14
  33. data/spec/asciidoctor/validate_spec.rb +119 -39
  34. data/spec/isodoc/amd_spec.rb +193 -201
  35. data/spec/isodoc/blocks_spec.rb +100 -88
  36. data/spec/isodoc/i18n_spec.rb +36 -36
  37. data/spec/isodoc/inline_spec.rb +282 -2
  38. data/spec/isodoc/iso_spec.rb +86 -138
  39. data/spec/isodoc/postproc_spec.rb +492 -442
  40. data/spec/isodoc/ref_spec.rb +6 -6
  41. data/spec/isodoc/section_spec.rb +301 -306
  42. data/spec/isodoc/table_spec.rb +166 -231
  43. data/spec/isodoc/terms_spec.rb +11 -8
  44. data/spec/isodoc/xref_spec.rb +147 -118
  45. data/spec/spec_helper.rb +16 -15
  46. metadata +9 -9
@@ -16,6 +16,7 @@ module IsoDoc
16
16
 
17
17
  def status_abbrev(stage, substage, iter, draft, doctype)
18
18
  return "" unless stage
19
+
19
20
  if %w(technical-report technical-specification).include?(doctype)
20
21
  stage = "DTS" if stage == "DIS"
21
22
  stage = "FDTS" if stage == "FDIS"
@@ -37,12 +38,12 @@ module IsoDoc
37
38
  set(:statusabbr, status_abbrev(docstatus["abbreviation"] || "??",
38
39
  isoxml&.at(ns("//bibdata/status/substage"))&.text,
39
40
  isoxml&.at(ns("//bibdata/status/iteration"))&.text,
40
- isoxml&.at(ns("//version/draft"))&.text,
41
+ isoxml&.at(ns("//bibdata/version/draft"))&.text,
41
42
  isoxml&.at(ns("//bibdata/ext/doctype"))&.text))
42
43
  unpublished(docstatus.text) and
43
44
  set(:stageabbr, docstatus["abbreviation"])
44
45
  end
45
- revdate = isoxml.at(ns("//version/revision-date"))
46
+ revdate = isoxml.at(ns("//bibdata/version/revision-date"))
46
47
  set(:revdate, revdate&.text)
47
48
  end
48
49
 
@@ -45,7 +45,7 @@ module IsoDoc
45
45
  prefix_name(node, " — ", lbl, "name")
46
46
  end
47
47
 
48
- def eref_localities1_zh(target, type, from, to, n, delim)
48
+ def eref_localities1_zh(target, type, from, upto, node, delim)
49
49
  subsection = from&.text&.match(/\./)
50
50
  ret = if delim == ";"
51
51
  ";"
@@ -53,32 +53,31 @@ module IsoDoc
53
53
  type == "list" ? "" : delim
54
54
  end
55
55
  ret += " 第#{from.text}" if from
56
- ret += "–#{to.text}" if to
56
+ ret += "–#{upto.text}" if upto
57
57
  loc = (@i18n.locality[type] || type.sub(/^locality:/, "").capitalize)
58
58
  ret += " #{loc}" unless subsection && type == "clause" ||
59
59
  type == "list" || target.match(/^IEV$|^IEC 60050-/) ||
60
- n["droploc"] == "true"
60
+ node["droploc"] == "true"
61
61
  ret += ")" if type == "list"
62
62
  ret
63
63
  end
64
64
 
65
- def eref_localities1(target, type, from, to, delim, n, lang = "en")
65
+ def eref_localities1(target, type, from, upto, delim, node, lang = "en")
66
66
  return "" if type == "anchor"
67
67
 
68
68
  subsection = from&.text&.match(/\./)
69
69
  type = type.downcase
70
70
  lang == "zh" and
71
- return l10n(eref_localities1_zh(target, type, from, to, n, delim))
72
- ret = if delim == ";"
73
- ";"
71
+ return l10n(eref_localities1_zh(target, type, from, upto, node, delim))
72
+ ret = if delim == ";" then ";"
74
73
  else
75
74
  type == "list" ? "" : delim
76
75
  end
77
- ret += eref_locality_populate(type, n) unless subsection &&
76
+ ret += eref_locality_populate(type, node) unless subsection &&
78
77
  type == "clause" || type == "list" ||
79
78
  target.match(/^IEV$|^IEC 60050-/)
80
79
  ret += " #{from.text}" if from
81
- ret += "–#{to.text}" if to
80
+ ret += "–#{upto.text}" if upto
82
81
  ret += ")" if type == "list"
83
82
  l10n(ret)
84
83
  end
@@ -113,6 +112,16 @@ module IsoDoc
113
112
  end
114
113
  end
115
114
 
115
+ def concept1(node)
116
+ node&.at(ns("./refterm"))&.remove
117
+ node&.at(ns("./renderterm"))&.name = "em"
118
+ r = node.at(ns("./xref | ./eref | ./termref"))
119
+ r.name == "termref" and
120
+ r.replace(@i18n.term_defined_in.sub(/%/, r.to_xml)) or
121
+ r.replace("(#{r.to_xml})")
122
+ node.replace(node.children)
123
+ end
124
+
116
125
  include Init
117
126
  end
118
127
  end
@@ -4,28 +4,25 @@ require "mn2sts"
4
4
  module IsoDoc
5
5
  module Iso
6
6
 
7
- # A {Converter} implementation that generates HTML output, and a document
8
- # schema encapsulation of the document for validation
9
- #
10
7
  class StsConvert < IsoDoc::XslfoPdfConvert
11
- def initialize(options)
8
+ def initialize(_options) # rubocop:disable Lint/MissingSuper
12
9
  @libdir = File.dirname(__FILE__)
13
10
  @format = :sts
14
11
  @suffix = "sts.xml"
15
12
  end
16
13
 
17
- def convert(input_filename, file = nil, debug = false, output_filename = nil)
18
- file = File.read(input_filename, encoding: "utf-8") if file.nil?
19
- docxml, filename, dir = convert_init(file, input_filename, debug)
20
- /\.xml$/.match(input_filename) or
21
- input_filename = Tempfile.open([filename, ".xml"], encoding: "utf-8") do |f|
22
- f.write file
23
- f.path
14
+ def convert(in_fname, file = nil, debug = false, out_fname = nil)
15
+ file = File.read(in_fname, encoding: "utf-8") if file.nil?
16
+ _docxml, filename, dir = convert_init(file, in_fname, debug)
17
+ unless /\.xml$/.match?(in_fname)
18
+ in_fname = Tempfile.open([filename, ".xml"], encoding: "utf-8") do |f|
19
+ f.write file
20
+ f.path
21
+ end
24
22
  end
25
23
  FileUtils.rm_rf dir
26
- Mn2sts.convert(input_filename, output_filename || "#{filename}.#{@suffix}")
24
+ Mn2sts.convert(in_fname, out_fname || "#{filename}.#{@suffix}")
27
25
  end
28
26
  end
29
27
  end
30
28
  end
31
-
@@ -14,34 +14,34 @@ module IsoDoc
14
14
  @htmlToClevels = 3 if @htmlToClevels.zero?
15
15
  end
16
16
 
17
+ def font_choice(options)
18
+ if options[:script] == "Hans" then '"Source Han Sans",serif'
19
+ else '"Cambria",serif'
20
+ end
21
+ end
22
+
17
23
  def default_fonts(options)
18
- {
19
- bodyfont: (options[:script] == "Hans" ? '"Source Han Sans",serif' :
20
- '"Cambria",serif'),
21
- headerfont: (options[:script] == "Hans" ? '"Source Han Sans",sans-serif' :
22
- '"Cambria",serif'),
23
- monospacefont: '"Courier New",monospace',
24
- normalfontsize: "11.0pt",
25
- monospacefontsize: "9.0pt",
26
- smallerfontsize: "10.0pt",
27
- footnotefontsize: "10.0pt",
28
- }
24
+ { bodyfont: font_choice(options),
25
+ headerfont: font_choice(options),
26
+ monospacefont: '"Courier New",monospace',
27
+ normalfontsize: "11.0pt",
28
+ monospacefontsize: "9.0pt",
29
+ smallerfontsize: "10.0pt",
30
+ footnotefontsize: "10.0pt" }
29
31
  end
30
32
 
31
33
  def default_file_locations(options)
32
- {
33
- htmlstylesheet: (options[:alt] ? html_doc_path("style-human.scss") :
34
- html_doc_path("style-iso.scss")),
35
- htmlcoverpage: html_doc_path("html_iso_titlepage.html"),
36
- htmlintropage: html_doc_path("html_iso_intro.html"),
37
- wordstylesheet: html_doc_path("wordstyle.scss"),
38
- standardstylesheet: html_doc_path("isodoc.scss"),
39
- header: html_doc_path("header.html"),
40
- wordcoverpage: html_doc_path("word_iso_titlepage.html"),
41
- wordintropage: html_doc_path("word_iso_intro.html"),
42
- ulstyle: "l3",
43
- olstyle: "l2",
44
- }
34
+ a = options[:alt] ? "style-human.scss" : "style-iso.scss"
35
+ { htmlstylesheet: html_doc_path(a),
36
+ htmlcoverpage: html_doc_path("html_iso_titlepage.html"),
37
+ htmlintropage: html_doc_path("html_iso_intro.html"),
38
+ wordstylesheet: html_doc_path("wordstyle.scss"),
39
+ standardstylesheet: html_doc_path("isodoc.scss"),
40
+ header: html_doc_path("header.html"),
41
+ wordcoverpage: html_doc_path("word_iso_titlepage.html"),
42
+ wordintropage: html_doc_path("word_iso_intro.html"),
43
+ ulstyle: "l3",
44
+ olstyle: "l2" }
45
45
  end
46
46
 
47
47
  def make_body(xml, docxml)
@@ -54,9 +54,10 @@ module IsoDoc
54
54
  end
55
55
  end
56
56
 
57
- def colophon(body, docxml)
58
- stage = @meta.get[:stage_int]
57
+ def colophon(body, _docxml)
58
+ stage = @meta.get[:stage_int]
59
59
  return if !stage.nil? && stage < 60
60
+
60
61
  body.br **{ clear: "all", style: "page-break-before:left;"\
61
62
  "mso-break-type:section-break" }
62
63
  body.div **{ class: "colophon" } do |div|
@@ -67,35 +68,55 @@ module IsoDoc
67
68
  super
68
69
  xml.xpath("//div[@class = 'figure']//table[@class = 'dl']").each do |t|
69
70
  t["class"] = "figdl"
70
- d = t.add_previous_sibling("<div class='figdl'/>")
71
+ d = t.add_previous_sibling("<div class='figdl' "\
72
+ "style='page-break-after:avoid;'/>")
71
73
  t.parent = d.first
72
74
  end
73
75
  end
74
76
 
75
77
  # force Annex h2 down to be p.h2Annex, so it is not picked up by ToC
76
- def word_annex_cleanup1(docxml, i)
77
- docxml.xpath("//h#{i}[ancestor::*[@class = 'Section3']]").each do |h2|
78
+ def word_annex_cleanup1(docxml, lvl)
79
+ docxml.xpath("//h#{lvl}[ancestor::*[@class = 'Section3']]").each do |h2|
78
80
  h2.name = "p"
79
- h2["class"] = "h#{i}Annex"
81
+ h2["class"] = "h#{lvl}Annex"
80
82
  end
81
83
  end
82
84
 
83
85
  def word_annex_cleanup(docxml)
84
- word_annex_cleanup1(docxml, 2)
85
- word_annex_cleanup1(docxml, 3)
86
- word_annex_cleanup1(docxml, 4)
87
- word_annex_cleanup1(docxml, 5)
88
- word_annex_cleanup1(docxml, 6)
86
+ (2..6).each { |i| word_annex_cleanup1(docxml, i) }
87
+ end
88
+
89
+ def word_annex_cleanup_h1(docxml)
90
+ docxml.xpath("//h1[@class = 'Annex']").each do |h|
91
+ h.name = "p"
92
+ h["class"] = "ANNEX"
93
+ end
94
+ %w(BiblioTitle ForewordTitle IntroTitle).each do |s|
95
+ docxml.xpath("//*[@class = '#{s}']").each do |h|
96
+ h.name = "p"
97
+ end
98
+ end
99
+ end
100
+
101
+ def style_cleanup(docxml)
102
+ word_annex_cleanup_h1(docxml)
103
+ style_cleanup1(docxml)
104
+ end
105
+
106
+ def style_cleanup1(docxml)
107
+ docxml.xpath("//*[@class = 'example']").each do |p|
108
+ p["class"] = "Example"
109
+ end
89
110
  end
90
111
 
91
112
  def authority_hdr_cleanup(docxml)
92
- docxml&.xpath("//div[@class = 'boilerplate-license']").each do |d|
113
+ docxml&.xpath("//div[@class = 'boilerplate-license']")&.each do |d|
93
114
  d.xpath(".//h1").each do |p|
94
115
  p.name = "p"
95
116
  p["class"] = "zzWarningHdr"
96
117
  end
97
118
  end
98
- docxml&.xpath("//div[@class = 'boilerplate-copyright']").each do |d|
119
+ docxml&.xpath("//div[@class = 'boilerplate-copyright']")&.each do |d|
99
120
  d.xpath(".//h1").each do |p|
100
121
  p.name = "p"
101
122
  p["class"] = "zzCopyrightHdr"
@@ -120,11 +141,104 @@ module IsoDoc
120
141
  def word_cleanup(docxml)
121
142
  authority_hdr_cleanup(docxml)
122
143
  super
144
+ style_cleanup(docxml)
123
145
  docxml
124
146
  end
125
147
 
126
- def footnote_reference_format(a)
127
- a.children = "<span class='MsoFootnoteReference'>#{a.children.to_xml}</span>)"
148
+ def word_toc_preface(level)
149
+ <<~TOC.freeze
150
+ <span lang="EN-GB"><span
151
+ style='mso-element:field-begin'></span><span
152
+ style='mso-spacerun:yes'>&#xA0;</span>TOC
153
+ \\o &quot;1-#{level}&quot; \\h \\z \\t &quot;Heading
154
+ 1;1;ANNEX;1;Biblio Title;1;Foreword Title;1;Intro Title;1&quot; <span
155
+ style='mso-element:field-separator'></span></span>
156
+ TOC
157
+ end
158
+
159
+ def footnote_reference_format(link)
160
+ link.children =
161
+ "<span class='MsoFootnoteReference'>#{link.children.to_xml}</span>)"
162
+ end
163
+
164
+ def bibliography_attrs
165
+ { class: "BiblioTitle" }
166
+ end
167
+
168
+ def bibliography(xml, out)
169
+ f = xml.at(ns(bibliography_xpath)) and f["hidden"] != "true" or return
170
+ page_break(out)
171
+ out.div do |div|
172
+ div.h1 **bibliography_attrs do |h1|
173
+ f&.at(ns("./title"))&.children&.each { |c2| parse(c2, h1) }
174
+ end
175
+ biblio_list(f, div, true)
176
+ end
177
+ end
178
+
179
+ def bibliography_parse(node, out)
180
+ node["hidden"] != true or return
181
+ out.div do |div|
182
+ clause_parse_title(node, div, node.at(ns("./title")), out,
183
+ bibliography_attrs)
184
+ biblio_list(node, div, true)
185
+ end
186
+ end
187
+
188
+ def para_class(node)
189
+ if !node.ancestors("definition").empty? && !@in_footnote
190
+ "Definition"
191
+ elsif !node.ancestors("foreword").empty? && !@in_footnote
192
+ "ForewordText"
193
+ else
194
+ super
195
+ end
196
+ end
197
+
198
+ def termref_attrs
199
+ { class: "Source" }
200
+ end
201
+
202
+ def termref_parse(node, out)
203
+ out.p **termref_attrs do |p|
204
+ p << "[TERMREF]"
205
+ node.children.each { |n| parse(n, p) }
206
+ p << "[/TERMREF]"
207
+ end
208
+ end
209
+
210
+ def figure_name_attrs(node)
211
+ s = node.ancestors("annex").empty? ? "FigureTitle" : "AnnexFigureTitle"
212
+ { class: s, style: "text-align:center;" }
213
+ end
214
+
215
+ def figure_name_parse(node, div, name)
216
+ return if name.nil?
217
+
218
+ div.p **figure_name_attrs(node) do |p|
219
+ name.children.each { |n| parse(n, p) }
220
+ end
221
+ end
222
+
223
+ def table_title_attrs(node)
224
+ s = node.ancestors("annex").empty? ? "Tabletitle" : "AnnexTableTitle"
225
+ { class: s, style: "text-align:center;" }
226
+ end
227
+
228
+ def table_title_parse(node, out)
229
+ name = node.at(ns("./name")) or return
230
+ out.p **table_title_attrs(node) do |p|
231
+ name&.children&.each { |n| parse(n, p) }
232
+ end
233
+ end
234
+
235
+ def annex_name(_annex, name, div)
236
+ return if name.nil?
237
+
238
+ name&.at(ns("./strong"))&.remove # supplied by CSS list numbering
239
+ div.h1 **{ class: "Annex" } do |t|
240
+ name.children.each { |c2| parse(c2, t) }
241
+ end
128
242
  end
129
243
 
130
244
  include BaseConvert
@@ -4,25 +4,35 @@ module IsoDoc
4
4
  end
5
5
 
6
6
  class Xref < IsoDoc::Xref
7
- def initial_anchor_names(d)
8
- if @klass.amd(d)
9
- d.xpath(ns("//preface/*")).each { |c| c.element? and preface_names(c) }
10
- sequential_asset_names(d.xpath(ns("//preface/*")))
11
- d.xpath(ns("//sections/clause")).each { |c| c.element? and preface_names(c) }
12
- middle_section_asset_names(d)
13
- termnote_anchor_names(d)
14
- termexample_anchor_names(d)
7
+ def initial_anchor_names(doc)
8
+ if @klass.amd(doc)
9
+ initial_anchor_names_amd(doc)
15
10
  else
16
11
  super
17
12
  end
18
- introduction_names(d.at(ns("//introduction")))
13
+ introduction_names(doc.at(ns("//introduction")))
14
+ end
15
+
16
+ def initial_anchor_names_amd(doc)
17
+ doc.xpath(ns("//preface/*")).each do |c|
18
+ c.element? and preface_names(c)
19
+ end
20
+ sequential_asset_names(doc.xpath(ns("//preface/*")))
21
+ doc.xpath(ns("//sections/clause")).each do |c|
22
+ c.element? and preface_names(c)
23
+ end
24
+ middle_section_asset_names(doc)
25
+ termnote_anchor_names(doc)
26
+ termexample_anchor_names(doc)
19
27
  end
20
28
 
21
29
  # we can reference 0-number clauses in introduction
22
30
  def introduction_names(clause)
23
31
  return if clause.nil?
24
- clause.at(ns("./clause")) and @anchors[clause["id"]] =
25
- { label: "0", level: 1, xref: clause.at(ns("./title"))&.text, type: "clause" }
32
+
33
+ clause.at(ns("./clause")) and
34
+ @anchors[clause["id"]] = { label: "0", level: 1, type: "clause",
35
+ xref: clause.at(ns("./title"))&.text }
26
36
  i = Counter.new
27
37
  clause.xpath(ns("./clause")).each do |c|
28
38
  i.increment(c)
@@ -35,17 +45,19 @@ module IsoDoc
35
45
  super
36
46
  end
37
47
 
38
- def appendix_names(clause, num)
48
+ def appendix_names(clause, _num)
39
49
  i = Counter.new
40
50
  clause.xpath(ns("./appendix")).each do |c|
41
51
  i.increment(c)
42
- @anchors[c["id"]] = anchor_struct(i.print, nil, @labels["appendix"], "clause")
52
+ @anchors[c["id"]] = anchor_struct(i.print, nil, @labels["appendix"],
53
+ "clause")
43
54
  @anchors[c["id"]][:level] = 2
44
55
  @anchors[c["id"]][:container] = clause["id"]
45
56
  j = Counter.new
46
57
  c.xpath(ns("./clause | ./references")).each do |c1|
47
58
  j.increment(c1)
48
- appendix_names1(c1, l10n("#{@labels["appendix"]} #{i.print}.#{j.print}"), 3, clause["id"])
59
+ lbl = "#{@labels['appendix']} #{i.print}.#{j.print}"
60
+ appendix_names1(c1, l10n(lbl), 3, clause["id"])
49
61
  end
50
62
  end
51
63
  end
@@ -73,7 +85,8 @@ module IsoDoc
73
85
  end
74
86
 
75
87
  def appendix_names1(clause, num, level, container)
76
- @anchors[clause["id"]] = { label: num, xref: num, level: level, container: container }
88
+ @anchors[clause["id"]] = { label: num, xref: num, level: level,
89
+ container: container }
77
90
  i = Counter.new
78
91
  clause.xpath(ns("./clause | ./references")).each do |c|
79
92
  i.increment(c)
@@ -86,28 +99,30 @@ module IsoDoc
86
99
  clause.xpath(ns(".//formula")).each do |t|
87
100
  next if t["id"].nil? || t["id"].empty?
88
101
 
89
- @anchors[t["id"]] =
90
- anchor_struct("#{num}#{hiersep}#{c.increment(t).print}", t,
91
- t["inequality"] ? @labels["inequality"] : @labels["formula"],
92
- "formula", t["unnumbered"])
102
+ @anchors[t["id"]] = anchor_struct(
103
+ "#{num}#{hiersep}#{c.increment(t).print}", t,
104
+ t["inequality"] ? @labels["inequality"] : @labels["formula"],
105
+ "formula", t["unnumbered"]
106
+ )
93
107
  end
94
108
  end
95
109
 
96
- def figure_anchor(t, sublabel, label)
97
- @anchors[t["id"]] = anchor_struct(
110
+ def figure_anchor(elem, sublabel, label)
111
+ @anchors[elem["id"]] = anchor_struct(
98
112
  (sublabel ? "#{label} #{sublabel}" : label),
99
- nil, @labels["figure"], "figure", t["unnumbered"])
100
- sublabel && t["unnumbered"] != "true" and
101
- @anchors[t["id"]][:label] = sublabel
113
+ nil, @labels["figure"], "figure", elem["unnumbered"]
114
+ )
115
+ sublabel && elem["unnumbered"] != "true" and
116
+ @anchors[elem["id"]][:label] = sublabel
102
117
  end
103
118
 
104
119
  def sequential_figure_names(clause)
105
120
  c = IsoDoc::XrefGen::Counter.new
106
121
  j = 0
107
- clause.xpath(ns(".//figure | .//sourcecode[not(ancestor::example)]")).
108
- each do |t|
122
+ clause.xpath(ns(".//figure | .//sourcecode[not(ancestor::example)]"))
123
+ .each do |t|
109
124
  j = subfigure_increment(j, c, t)
110
- sublabel = j.zero? ? nil : "#{(j+96).chr})"
125
+ sublabel = j.zero? ? nil : "#{(j + 96).chr})"
111
126
  next if t["id"].nil? || t["id"].empty?
112
127
 
113
128
  figure_anchor(t, sublabel, c.print)