metanorma-standoc 1.3.24 → 1.3.29
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/macos.yml +10 -1
- data/.github/workflows/ubuntu.yml +13 -3
- data/.github/workflows/windows.yml +8 -1
- data/lib/asciidoctor/standoc/base.rb +29 -11
- data/lib/asciidoctor/standoc/biblio.rng +75 -28
- data/lib/asciidoctor/standoc/blocks.rb +12 -5
- data/lib/asciidoctor/standoc/cleanup.rb +17 -8
- data/lib/asciidoctor/standoc/cleanup_block.rb +3 -0
- data/lib/asciidoctor/standoc/cleanup_boilerplate.rb +1 -3
- data/lib/asciidoctor/standoc/cleanup_inline.rb +3 -0
- data/lib/asciidoctor/standoc/cleanup_ref.rb +15 -6
- data/lib/asciidoctor/standoc/cleanup_section.rb +36 -8
- data/lib/asciidoctor/standoc/front.rb +5 -3
- data/lib/asciidoctor/standoc/inline.rb +43 -18
- data/lib/asciidoctor/standoc/isodoc.rng +31 -1
- data/lib/asciidoctor/standoc/macros.rb +2 -1
- data/lib/asciidoctor/standoc/macros_yaml2text.rb +142 -0
- data/lib/asciidoctor/standoc/ref.rb +6 -4
- data/lib/asciidoctor/standoc/section.rb +41 -9
- data/lib/asciidoctor/standoc/utils.rb +2 -11
- data/lib/asciidoctor/standoc/validate.rb +8 -2
- data/lib/asciidoctor/standoc/validate_section.rb +1 -3
- data/lib/metanorma/standoc/latexml_requirement.rb +14 -12
- data/lib/metanorma/standoc/version.rb +1 -1
- data/metanorma-standoc.gemspec +2 -2
- data/spec/asciidoctor-standoc/base_spec.rb +8 -0
- data/spec/asciidoctor-standoc/blocks_spec.rb +74 -2
- data/spec/asciidoctor-standoc/cleanup_spec.rb +75 -28
- data/spec/asciidoctor-standoc/inline_spec.rb +4 -3
- data/spec/asciidoctor-standoc/macros_spec.rb +9 -8
- data/spec/asciidoctor-standoc/macros_yaml2text_spec.rb +564 -0
- data/spec/asciidoctor-standoc/refs_dl_spec.rb +91 -3
- data/spec/asciidoctor-standoc/refs_spec.rb +272 -166
- data/spec/asciidoctor-standoc/section_spec.rb +197 -6
- data/spec/asciidoctor-standoc/validate_spec.rb +67 -2
- data/spec/assets/codes.yml +695 -0
- data/spec/assets/xref_error.adoc +7 -0
- data/spec/examples/codes_table.html +3174 -0
- data/spec/metanorma/processor_spec.rb +2 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +77 -271
- data/spec/vcr_cassettes/isobib_get_123.yml +36 -82
- data/spec/vcr_cassettes/isobib_get_123_2001.yml +17 -40
- data/spec/vcr_cassettes/isobib_get_124.yml +19 -101
- data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +8 -8
- data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +34 -34
- metadata +11 -6
@@ -131,10 +131,13 @@ module Asciidoctor
|
|
131
131
|
def note_cleanup(xmldoc)
|
132
132
|
q = "//note[following-sibling::*[not(local-name() = 'note')]]"
|
133
133
|
xmldoc.xpath(q).each do |n|
|
134
|
+
next if n["keep-separate"] == "true"
|
134
135
|
next unless n.ancestors("table").empty?
|
135
136
|
prev = n.previous_element || next
|
136
137
|
n.parent = prev if ELEMS_ALLOW_NOTES.include? prev.name
|
137
138
|
end
|
139
|
+
xmldoc.xpath("//note[@keep-separate]").each { |n| n.delete("keep-separate") }
|
140
|
+
xmldoc.xpath("//termnote[@keep-separate]").each { |n| n.delete("keep-separate") }
|
138
141
|
end
|
139
142
|
|
140
143
|
def requirement_cleanup(x)
|
@@ -18,7 +18,6 @@ module Asciidoctor
|
|
18
18
|
source.each do |s|
|
19
19
|
@anchors[s["bibitemid"]] or
|
20
20
|
@log.add("Crossreferences", nil, "term source #{s['bibitemid']} not referenced")
|
21
|
-
#warn "term source #{s['bibitemid']} not referenced"
|
22
21
|
end
|
23
22
|
if source.empty? && term.nil?
|
24
23
|
div.next = @no_terms_boilerplate
|
@@ -49,8 +48,7 @@ module Asciidoctor
|
|
49
48
|
TERM_CLAUSE = "//sections/terms | "\
|
50
49
|
"//sections/clause[descendant::terms]".freeze
|
51
50
|
|
52
|
-
NORM_REF = "//bibliography/references[
|
53
|
-
"title = 'Normative references']".freeze
|
51
|
+
NORM_REF = "//bibliography/references[@normative = 'true']".freeze
|
54
52
|
|
55
53
|
def boilerplate_isodoc(xmldoc)
|
56
54
|
x = xmldoc.dup
|
@@ -90,6 +90,9 @@ module Asciidoctor
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def origin_cleanup(xmldoc)
|
93
|
+
xmldoc.xpath("//origin/concept[termref]").each do |x|
|
94
|
+
x.replace(x.children)
|
95
|
+
end
|
93
96
|
xmldoc.xpath("//origin").each do |x|
|
94
97
|
x["citeas"] = @anchors&.dig(x["bibitemid"], :xref) ||
|
95
98
|
@log.add("Crossreferences", x,
|
@@ -5,7 +5,7 @@ module Asciidoctor
|
|
5
5
|
module Standoc
|
6
6
|
module Cleanup
|
7
7
|
def biblio_reorder(xmldoc)
|
8
|
-
xmldoc.xpath("//references[
|
8
|
+
xmldoc.xpath("//references[@normative = 'false']").each do |r|
|
9
9
|
biblio_reorder1(r)
|
10
10
|
end
|
11
11
|
end
|
@@ -49,8 +49,8 @@ module Asciidoctor
|
|
49
49
|
# consecutively, but that standards codes are preserved as is:
|
50
50
|
# only numeric references are renumbered
|
51
51
|
def biblio_renumber(xmldoc)
|
52
|
-
r = xmldoc.at("//references[
|
53
|
-
"//clause[
|
52
|
+
r = xmldoc.at("//references[@normative = 'false'] | "\
|
53
|
+
"//clause[.//references[@normative = 'false']]") or return
|
54
54
|
r.xpath(".//bibitem[not(ancestor::bibitem)]").each_with_index do |b, i|
|
55
55
|
next unless docid = b.at("./docidentifier[@type = 'metanorma']")
|
56
56
|
next unless /^\[\d+\]$/.match(docid.text)
|
@@ -67,18 +67,23 @@ module Asciidoctor
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def normref_cleanup(xmldoc)
|
70
|
-
r = xmldoc.at(NORM_REF) || return
|
71
|
-
|
72
|
-
preface = r.xpath("./title/following-sibling::*") &
|
70
|
+
r = xmldoc.at(self.class::NORM_REF) || return
|
71
|
+
preface = r.xpath("./title/following-sibling::*") & # intersection
|
73
72
|
r.xpath("./bibitem[1]/preceding-sibling::*")
|
74
73
|
preface.each { |n| n.remove }
|
75
74
|
end
|
76
75
|
|
77
76
|
def biblio_cleanup(xmldoc)
|
78
77
|
biblio_reorder(xmldoc)
|
78
|
+
biblio_nested(xmldoc)
|
79
79
|
biblio_renumber(xmldoc)
|
80
|
+
end
|
81
|
+
|
82
|
+
def biblio_nested(xmldoc)
|
80
83
|
xmldoc.xpath("//references[references]").each do |t|
|
81
84
|
t.name = "clause"
|
85
|
+
t.xpath("./references").each { |r| r["normative"] = t["normative"] }
|
86
|
+
t.delete("normative")
|
82
87
|
end
|
83
88
|
end
|
84
89
|
|
@@ -187,6 +192,10 @@ module Asciidoctor
|
|
187
192
|
end
|
188
193
|
bib
|
189
194
|
end
|
195
|
+
|
196
|
+
def fetch_termbase(termbase, id)
|
197
|
+
""
|
198
|
+
end
|
190
199
|
end
|
191
200
|
end
|
192
201
|
end
|
@@ -11,7 +11,7 @@ module Asciidoctor
|
|
11
11
|
module Cleanup
|
12
12
|
def make_preface(x, s)
|
13
13
|
if x.at("//foreword | //introduction | //acknowledgements | "\
|
14
|
-
"
|
14
|
+
"//*[@preface]")
|
15
15
|
preface = s.add_previous_sibling("<preface/>").first
|
16
16
|
f = x.at("//foreword") and preface.add_child f.remove
|
17
17
|
f = x.at("//introduction") and preface.add_child f.remove
|
@@ -22,7 +22,7 @@ module Asciidoctor
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def move_clauses_into_preface(x, preface)
|
25
|
-
x.xpath("
|
25
|
+
x.xpath("//*[@preface]").each do |c|
|
26
26
|
c.delete("preface")
|
27
27
|
preface.add_child c.remove
|
28
28
|
end
|
@@ -66,9 +66,22 @@ module Asciidoctor
|
|
66
66
|
def sections_order_cleanup(x)
|
67
67
|
s = x.at("//sections")
|
68
68
|
make_preface(x, s)
|
69
|
+
make_annexes(x)
|
69
70
|
make_bibliography(x, s)
|
70
71
|
x.xpath("//sections/annex").reverse_each { |r| s.next = r.remove }
|
71
72
|
end
|
73
|
+
|
74
|
+
def make_annexes(x)
|
75
|
+
x.xpath("//*[@annex]").each do |y|
|
76
|
+
y.delete("annex")
|
77
|
+
next if y.name == "annex" || !y.ancestors("annex").empty?
|
78
|
+
y.wrap("<annex/>")
|
79
|
+
y.parent["id"] = "_#{UUIDTools::UUID.random_create}"
|
80
|
+
y.parent["obligation"] = y["obligation"]
|
81
|
+
y.parent["language"] = y["language"]
|
82
|
+
y.parent["script"] = y["script"]
|
83
|
+
end
|
84
|
+
end
|
72
85
|
|
73
86
|
def maxlevel(x)
|
74
87
|
max = 5
|
@@ -117,7 +130,7 @@ module Asciidoctor
|
|
117
130
|
end
|
118
131
|
|
119
132
|
def obligations_cleanup_inherit(x)
|
120
|
-
x.xpath("//annex | //clause").each do |r|
|
133
|
+
x.xpath("//annex | //clause[not(ancestor::boilerplate)]").each do |r|
|
121
134
|
r["obligation"] = "normative" unless r["obligation"]
|
122
135
|
end
|
123
136
|
x.xpath(Utils::SUBCLAUSE_XPATH).each do |r|
|
@@ -192,7 +205,16 @@ module Asciidoctor
|
|
192
205
|
end
|
193
206
|
end
|
194
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
|
+
|
195
216
|
def termdef_cleanup(xmldoc)
|
217
|
+
termdef_from_termbase(xmldoc)
|
196
218
|
termdef_unnest_cleanup(xmldoc)
|
197
219
|
termdef_stem_cleanup(xmldoc)
|
198
220
|
termdomain_cleanup(xmldoc)
|
@@ -209,15 +231,21 @@ module Asciidoctor
|
|
209
231
|
# Numbers sort *after* letters; we use thorn to force that sort order.
|
210
232
|
def symbol_key(x)
|
211
233
|
key = x.dup
|
212
|
-
key.
|
213
|
-
|
234
|
+
key.traverse do |n|
|
235
|
+
next unless n.name == "math"
|
236
|
+
n.replace(grkletters(MathML2AsciiMath.m2a(n.to_xml)))
|
214
237
|
end
|
215
|
-
ret = Nokogiri::XML(
|
216
|
-
HTMLEntities.new.decode(ret.text).
|
238
|
+
ret = Nokogiri::XML(key.to_xml)
|
239
|
+
HTMLEntities.new.decode(ret.text).
|
240
|
+
gsub(/[\[\]\{\}<>\(\)]/, "").strip.
|
217
241
|
gsub(/[[:punct]]|[_^]/, ":\\0").gsub(/`/, "").
|
218
242
|
gsub(/[0-9]+/, "þ\\0")
|
219
243
|
end
|
220
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
|
+
|
221
249
|
def extract_symbols_list(dl)
|
222
250
|
dl_out = []
|
223
251
|
dl.xpath("./dt | ./dd").each do |dtd|
|
@@ -233,7 +261,7 @@ module Asciidoctor
|
|
233
261
|
def symbols_cleanup(docxml)
|
234
262
|
docxml.xpath("//definitions/dl").each do |dl|
|
235
263
|
dl_out = extract_symbols_list(dl)
|
236
|
-
dl_out.sort! { |a, b| a[:key] <=> b[:key] }
|
264
|
+
dl_out.sort! { |a, b| a[:key] <=> b[:key] || a[:dt] <=> b[:dt] }
|
237
265
|
dl.children = dl_out.map { |d| d[:dt].to_s + d[:dd].to_s }.join("\n")
|
238
266
|
end
|
239
267
|
docxml
|
@@ -78,7 +78,9 @@ module Asciidoctor
|
|
78
78
|
|
79
79
|
def datetypes
|
80
80
|
%w{ published accessed created implemented obsoleted
|
81
|
-
confirmed updated issued circulated unchanged received
|
81
|
+
confirmed updated issued circulated unchanged received
|
82
|
+
vote-started vote-ended
|
83
|
+
}
|
82
84
|
end
|
83
85
|
|
84
86
|
def metadata_date(node, xml)
|
@@ -190,8 +192,8 @@ module Asciidoctor
|
|
190
192
|
["en"].each do |lang|
|
191
193
|
at = { language: lang, format: "text/plain" }
|
192
194
|
xml.title **attr_code(at) do |t|
|
193
|
-
t << Utils::asciidoc_sub(node.attr("title") || node.attr("title-en") ||
|
194
|
-
|
195
|
+
t << (Utils::asciidoc_sub(node.attr("title") || node.attr("title-en")) ||
|
196
|
+
node.title)
|
195
197
|
end
|
196
198
|
end
|
197
199
|
end
|
@@ -3,6 +3,7 @@ require "htmlentities"
|
|
3
3
|
require "unicode2latex"
|
4
4
|
require "mime/types"
|
5
5
|
require "base64"
|
6
|
+
require 'English'
|
6
7
|
|
7
8
|
module Asciidoctor
|
8
9
|
module Standoc
|
@@ -106,23 +107,47 @@ module Asciidoctor
|
|
106
107
|
gsub(/"/, '"').gsub(/
/, "\n")
|
107
108
|
end
|
108
109
|
|
110
|
+
def latex_run1(lxm_input, cmd)
|
111
|
+
IO.popen(cmd, "r+", external_encoding: "UTF-8") do |io|
|
112
|
+
io.write(lxm_input)
|
113
|
+
io.close_write
|
114
|
+
io.read
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def latex_run(lxm_input)
|
119
|
+
results = nil
|
120
|
+
Metanorma::Standoc::Requirements[:latexml].cmd.each_with_index do |cmd, i|
|
121
|
+
warn "Retrying with #{cmd}" if i > 0
|
122
|
+
results = latex_run1(lxm_input, cmd)
|
123
|
+
if $CHILD_STATUS.to_i.zero?
|
124
|
+
warn "Success!" if i > 0
|
125
|
+
break
|
126
|
+
end
|
127
|
+
end
|
128
|
+
$CHILD_STATUS.to_i.zero? ? results : nil
|
129
|
+
end
|
130
|
+
|
131
|
+
def latex_parse(text)
|
132
|
+
lxm_input = Unicode2LaTeX.unicode2latex(HTMLEntities.new.decode(text))
|
133
|
+
results = latex_run(lxm_input)
|
134
|
+
results.nil? and
|
135
|
+
@log.add('Math', nil,
|
136
|
+
"latexmlmath failed to process equation:\n#{lxm_input}")
|
137
|
+
results
|
138
|
+
end
|
139
|
+
|
109
140
|
def stem_parse(text, xml, style)
|
110
141
|
if /<([^:>&]+:)?math(\s+[^>&]+)?> |
|
111
142
|
<([^:>&]+:)?math(\s+[^>&]+)?>/x.match text
|
112
143
|
math = xml_encode(text)
|
113
144
|
xml.stem math, **{ type: "MathML" }
|
114
145
|
elsif style == :latexmath
|
115
|
-
|
116
|
-
latexmlmath_input =
|
117
|
-
Unicode2LaTeX::unicode2latex(HTMLEntities.new.decode(text)).
|
118
|
-
gsub(/'/, '\\').gsub(/\n/, " ")
|
119
|
-
latex = IO.popen(latex_cmd, "r+", external_encoding: "UTF-8") do |io|
|
120
|
-
io.write(latexmlmath_input)
|
121
|
-
io.close_write
|
122
|
-
io.read
|
123
|
-
end
|
146
|
+
latex = latex_parse(text) or return xml.stem **{ type: "MathML" }
|
124
147
|
xml.stem **{ type: "MathML" } do |s|
|
125
|
-
|
148
|
+
math = Nokogiri::XML.fragment(latex.sub(/<\?[^>]+>/, "")).elements[0]
|
149
|
+
math.delete("alttext")
|
150
|
+
s.parent.children = math
|
126
151
|
end
|
127
152
|
else
|
128
153
|
xml.stem text, **{ type: "AsciiMath" }
|
@@ -172,14 +197,14 @@ module Asciidoctor
|
|
172
197
|
types = /^data:/.match(uri) ? datauri2mime(uri) : MIME::Types.type_for(uri)
|
173
198
|
type = types.first.to_s
|
174
199
|
uri = uri.sub(%r{^data:image/\*;}, "data:#{type};")
|
175
|
-
attr_code(src:
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
200
|
+
attr_code(src: uri, #@datauriimage ? datauri(uri) : uri,
|
201
|
+
id: Utils::anchor_or_uuid,
|
202
|
+
mimetype: type,
|
203
|
+
height: node.attr("height") || "auto",
|
204
|
+
width: node.attr("width") || "auto" ,
|
205
|
+
filename: node.attr("filename"),
|
206
|
+
title: node.attr("titleattr"),
|
207
|
+
alt: node.alt == node.attr("default-alt") ? nil : node.alt)
|
183
208
|
end
|
184
209
|
|
185
210
|
def inline_image(node)
|
@@ -129,6 +129,9 @@
|
|
129
129
|
</choice>
|
130
130
|
</attribute>
|
131
131
|
</optional>
|
132
|
+
<attribute name="normative">
|
133
|
+
<data type="boolean"/>
|
134
|
+
</attribute>
|
132
135
|
<optional>
|
133
136
|
<ref name="section-title"/>
|
134
137
|
</optional>
|
@@ -305,6 +308,21 @@
|
|
305
308
|
</define>
|
306
309
|
</include>
|
307
310
|
<!-- end overrides -->
|
311
|
+
<define name="TextElement" combine="choice">
|
312
|
+
<ref name="concept"/>
|
313
|
+
</define>
|
314
|
+
<define name="concept">
|
315
|
+
<element name="concept">
|
316
|
+
<optional>
|
317
|
+
<attribute name="term"/>
|
318
|
+
</optional>
|
319
|
+
<choice>
|
320
|
+
<ref name="eref"/>
|
321
|
+
<ref name="xref"/>
|
322
|
+
<ref name="termref"/>
|
323
|
+
</choice>
|
324
|
+
</element>
|
325
|
+
</define>
|
308
326
|
<define name="BasicBlock" combine="choice">
|
309
327
|
<choice>
|
310
328
|
<ref name="requirement"/>
|
@@ -911,7 +929,10 @@
|
|
911
929
|
</define>
|
912
930
|
<define name="origin">
|
913
931
|
<element name="origin">
|
914
|
-
<
|
932
|
+
<choice>
|
933
|
+
<ref name="erefType"/>
|
934
|
+
<ref name="termref"/>
|
935
|
+
</choice>
|
915
936
|
</element>
|
916
937
|
</define>
|
917
938
|
<define name="modification">
|
@@ -919,6 +940,15 @@
|
|
919
940
|
<ref name="paragraph"/>
|
920
941
|
</element>
|
921
942
|
</define>
|
943
|
+
<define name="termref">
|
944
|
+
<element name="termref">
|
945
|
+
<attribute name="base"/>
|
946
|
+
<attribute name="target"/>
|
947
|
+
<optional>
|
948
|
+
<text/>
|
949
|
+
</optional>
|
950
|
+
</element>
|
951
|
+
</define>
|
922
952
|
<define name="structuredidentifier">
|
923
953
|
<element name="structuredidentifier">
|
924
954
|
<optional>
|
@@ -2,6 +2,7 @@ require "asciidoctor/extensions"
|
|
2
2
|
require "fileutils"
|
3
3
|
require "uuidtools"
|
4
4
|
require_relative "./macros_plantuml.rb"
|
5
|
+
require_relative "./macros_yaml2text.rb"
|
5
6
|
|
6
7
|
module Asciidoctor
|
7
8
|
module Standoc
|
@@ -58,7 +59,7 @@ module Asciidoctor
|
|
58
59
|
named :concept
|
59
60
|
name_positional_attributes "id", "word", "term"
|
60
61
|
#match %r{concept:(?<target>[^\[]*)\[(?<content>|.*?[^\\])\]$}
|
61
|
-
match /\{\{(?<content>|.*?[^\\])\}\}
|
62
|
+
match /\{\{(?<content>|.*?[^\\])\}\}/
|
62
63
|
using_format :short
|
63
64
|
|
64
65
|
# deal with locality attrs and their disruption of positional attrs
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Asciidoctor
|
4
|
+
module Standoc
|
5
|
+
class YamlBlockStruct < OpenStruct
|
6
|
+
def to_a
|
7
|
+
@table.to_h.keys
|
8
|
+
end
|
9
|
+
|
10
|
+
def values
|
11
|
+
@table.to_h.values
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
return to_a.each unless block_given?
|
16
|
+
|
17
|
+
to_a.each do |key|
|
18
|
+
yield(key)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class YamlContextRenderer
|
24
|
+
attr_reader :context_object, :context_name
|
25
|
+
|
26
|
+
def initialize(context_object:, context_name:)
|
27
|
+
@context_object = context_object
|
28
|
+
@context_name = context_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def respond_to_missing?(name)
|
32
|
+
respond_to?(name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(name, *_args)
|
36
|
+
return context_object if name.to_s == context_name
|
37
|
+
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
def render(template)
|
42
|
+
ERB.new(template).result(binding)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Yaml2TextPreprocessor < Asciidoctor::Extensions::Preprocessor
|
47
|
+
BLOCK_START_REGEXP = /\{(.+?)\.\*,(.+),(.+)\}/.freeze
|
48
|
+
BLOCK_END_REGEXP = /\A\{[A-Z]+\}\z/.freeze
|
49
|
+
# search document for block `yaml2text`
|
50
|
+
# after that take template from block and read file into this template
|
51
|
+
# example:
|
52
|
+
# [yaml2text,foobar.yaml]
|
53
|
+
# ----
|
54
|
+
# === {item.name}
|
55
|
+
# {item.desc}
|
56
|
+
#
|
57
|
+
# {item.symbol}:: {item.symbol_def}
|
58
|
+
# ----
|
59
|
+
#
|
60
|
+
# with content of `foobar.yaml` file equal to:
|
61
|
+
# - name: spaghetti
|
62
|
+
# desc: wheat noodles of 9mm diameter
|
63
|
+
# symbol: SPAG
|
64
|
+
# symbol_def: the situation is message like spaghetti at a kid's meal
|
65
|
+
#
|
66
|
+
# will produce:
|
67
|
+
# === spaghetti
|
68
|
+
# wheat noodles of 9mm diameter
|
69
|
+
#
|
70
|
+
# SPAG:: the situation is message like spaghetti at a kid's meal
|
71
|
+
def process(document, reader)
|
72
|
+
input_lines = reader.readlines.to_enum
|
73
|
+
Reader.new(processed_lines(document, input_lines))
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def processed_lines(document, input_lines)
|
79
|
+
result = []
|
80
|
+
loop do
|
81
|
+
line = input_lines.next
|
82
|
+
if yaml_block_match = line.match(/^\[yaml2text,(.+?),(.+?)\]/)
|
83
|
+
mark = input_lines.next
|
84
|
+
current_yaml_block = []
|
85
|
+
while (yaml_block_line = input_lines.next) != mark
|
86
|
+
current_yaml_block.push(yaml_block_line)
|
87
|
+
end
|
88
|
+
content = nested_open_struct_from_yaml(yaml_block_match[1], document)
|
89
|
+
result.push(*
|
90
|
+
parse_blocks_recursively(lines: current_yaml_block,
|
91
|
+
attributes: content,
|
92
|
+
context_name: yaml_block_match[2]))
|
93
|
+
else
|
94
|
+
result.push(line)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
result
|
98
|
+
end
|
99
|
+
|
100
|
+
def nested_open_struct_from_yaml(file_path, document)
|
101
|
+
docfile_directory = File.dirname(document.attributes['docfile'] || '.')
|
102
|
+
yaml_file_path = document.path_resolver.system_path(file_path, docfile_directory)
|
103
|
+
content = YAML.safe_load(File.read(yaml_file_path))
|
104
|
+
# Load content as json, then parse with JSON as nested open_struct
|
105
|
+
JSON.parse(content.to_json, object_class: YamlBlockStruct)
|
106
|
+
end
|
107
|
+
|
108
|
+
def parse_blocks_recursively(lines:,
|
109
|
+
attributes:,
|
110
|
+
context_name:,
|
111
|
+
parent_context: nil)
|
112
|
+
lines = lines.to_enum
|
113
|
+
result = []
|
114
|
+
loop do
|
115
|
+
line = lines.next
|
116
|
+
if line.match(BLOCK_START_REGEXP)
|
117
|
+
line.gsub!(BLOCK_START_REGEXP, '<% \1.each.with_index do |\2,index| %>')
|
118
|
+
end
|
119
|
+
|
120
|
+
if line.match(BLOCK_END_REGEXP)
|
121
|
+
line.gsub!(BLOCK_END_REGEXP, '<% end %>')
|
122
|
+
end
|
123
|
+
line = line.gsub(/{(.+?[^}]*)}/, '<%= \1 %>').gsub(/[a-z\.]+\#/, 'index')
|
124
|
+
result.push(line)
|
125
|
+
end
|
126
|
+
result = parse_context_block(context_lines: result,
|
127
|
+
context_items: attributes,
|
128
|
+
context_name: context_name,
|
129
|
+
parent_context: parent_context)
|
130
|
+
result
|
131
|
+
end
|
132
|
+
|
133
|
+
def parse_context_block(context_lines:,
|
134
|
+
context_items:,
|
135
|
+
context_name:,
|
136
|
+
parent_context: nil)
|
137
|
+
renderer = YamlContextRenderer.new(context_object: context_items, context_name: context_name)
|
138
|
+
renderer.render(context_lines.join('\n')).split('\n')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|