metanorma-mpfd 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +17 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +25 -0
  7. data/README.adoc +1 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +14 -0
  10. data/bin/rspec +18 -0
  11. data/bin/setup +8 -0
  12. data/lib/asciidoctor/mpfd/biblio.rng +836 -0
  13. data/lib/asciidoctor/mpfd/converter.rb +204 -0
  14. data/lib/asciidoctor/mpfd/isodoc.rng +1041 -0
  15. data/lib/asciidoctor/mpfd/isostandard.rng +1001 -0
  16. data/lib/asciidoctor/mpfd/pdf.js +31 -0
  17. data/lib/asciidoctor/mpfd/rsd.rng +212 -0
  18. data/lib/asciidoctor/mpfd/section.rb +94 -0
  19. data/lib/asciidoctor/mpfd/version.rb +5 -0
  20. data/lib/asciidoctor/mpfd.rb +9 -0
  21. data/lib/isodoc/mpfd/html/header.html +184 -0
  22. data/lib/isodoc/mpfd/html/html_rsd_intro.html +8 -0
  23. data/lib/isodoc/mpfd/html/html_rsd_titlepage.html +58 -0
  24. data/lib/isodoc/mpfd/html/htmlstyle.scss +1094 -0
  25. data/lib/isodoc/mpfd/html/logo.jpg +0 -0
  26. data/lib/isodoc/mpfd/html/logo.svg +1 -0
  27. data/lib/isodoc/mpfd/html/mpfa-logo-no-text@4x.png +0 -0
  28. data/lib/isodoc/mpfd/html/mpfa-logo@4x.png +0 -0
  29. data/lib/isodoc/mpfd/html/rsd.scss +564 -0
  30. data/lib/isodoc/mpfd/html/scripts.html +82 -0
  31. data/lib/isodoc/mpfd/html/word_rsd_intro.html +3 -0
  32. data/lib/isodoc/mpfd/html/word_rsd_titlepage.html +42 -0
  33. data/lib/isodoc/mpfd/html/wordstyle.scss +1096 -0
  34. data/lib/isodoc/mpfd/html_convert.rb +370 -0
  35. data/lib/isodoc/mpfd/i18n-en.yaml +1 -0
  36. data/lib/isodoc/mpfd/metadata.rb +98 -0
  37. data/lib/isodoc/mpfd/pdf_convert.rb +367 -0
  38. data/lib/isodoc/mpfd/word_convert.rb +347 -0
  39. data/lib/metanorma/mpfd/processor.rb +43 -0
  40. data/lib/metanorma/mpfd.rb +7 -0
  41. data/lib/metanorma-mpfd.rb +11 -0
  42. data/metanorma-mpfd.gemspec +46 -0
  43. metadata +326 -0
@@ -0,0 +1,370 @@
1
+ require "isodoc"
2
+ require_relative "metadata"
3
+
4
+ module IsoDoc
5
+ module Mpfd
6
+
7
+ # A {Converter} implementation that generates HTML output, and a document
8
+ # schema encapsulation of the document for validation
9
+ #
10
+ class HtmlConvert < IsoDoc::HtmlConvert
11
+ def rsd_html_path(file)
12
+ File.join(File.dirname(__FILE__), File.join("html", file))
13
+ end
14
+
15
+ def initialize(options)
16
+ super
17
+ @htmlstylesheet = generate_css(rsd_html_path("htmlstyle.scss"), true, default_fonts(options))
18
+ @htmlcoverpage = rsd_html_path("html_rsd_titlepage.html")
19
+ @htmlintropage = rsd_html_path("html_rsd_intro.html")
20
+ @scripts = rsd_html_path("scripts.html")
21
+ system "cp #{rsd_html_path('logo.jpg')} logo.jpg"
22
+ system "cp #{rsd_html_path('mpfa-logo-no-text@4x.png')} mpfa-logo-no-text@4x.png"
23
+ @files_to_delete << "logo.jpg"
24
+ @files_to_delete << "mpfa-logo-no-text@4x.png"
25
+ end
26
+
27
+ def default_fonts(options)
28
+ b = options[:bodyfont] ||
29
+ (options[:script] == "Hans" ? '"SimSun",serif' :
30
+ '"Titillium Web",sans-serif')
31
+ h = options[:headerfont] ||
32
+ (options[:script] == "Hans" ? '"SimHei",sans-serif' :
33
+ '"Titillium Web",sans-serif')
34
+ m = options[:monospacefont] || '"Space Mono",monospace'
35
+ "$bodyfont: #{b};\n$headerfont: #{h};\n$monospacefont: #{m};\n"
36
+ end
37
+
38
+ def metadata_init(lang, script, labels)
39
+ @meta = Metadata.new(lang, script, labels)
40
+ end
41
+
42
+ def html_head
43
+ <<~HEAD.freeze
44
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
45
+
46
+ <!--TOC script import-->
47
+ <script type="text/javascript" src="https://cdn.rawgit.com/jgallen23/toc/0.3.2/dist/toc.min.js"></script>
48
+
49
+ <!--Google fonts-->
50
+ <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i|Space+Mono:400,700" rel="stylesheet">
51
+ <link href="https://fonts.googleapis.com/css?family=Overpass:300,300i,600,900" rel="stylesheet">
52
+ <link href="https://fonts.googleapis.com/css?family=Titillium+Web:400,400i,700,700i" rel="stylesheet">
53
+ <!--Font awesome import for the link icon-->
54
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/solid.css" integrity="sha384-v2Tw72dyUXeU3y4aM2Y0tBJQkGfplr39mxZqlTBDUZAb9BGoC40+rdFCG0m10lXk" crossorigin="anonymous">
55
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/fontawesome.css" integrity="sha384-q3jl8XQu1OpdLgGFvNRnPdj5VIlCvgsDQTQB6owSOHWlAurxul7f+JpUOVdAiJ5P" crossorigin="anonymous">
56
+ <style class="anchorjs"></style>
57
+ HEAD
58
+ end
59
+
60
+ def make_body(xml, docxml)
61
+ body_attr = { lang: "EN-US", link: "blue", vlink: "#954F72", "xml:lang": "EN-US", class: "container" }
62
+ xml.body **body_attr do |body|
63
+ make_body1(body, docxml)
64
+ make_body2(body, docxml)
65
+ make_body3(body, docxml)
66
+ end
67
+ end
68
+
69
+ def html_toc(docxml)
70
+ docxml
71
+ end
72
+
73
+ def annex_name(annex, name, div)
74
+ div.h1 **{ class: "Annex" } do |t|
75
+ t << "#{get_anchors[annex['id']][:label]} "
76
+ t << "<b>#{name.text}</b>"
77
+ end
78
+ end
79
+
80
+ def annex_name_lbl(clause, num)
81
+ obl = l10n("(#{@inform_annex_lbl})")
82
+ obl = l10n("(#{@norm_annex_lbl})") if clause["obligation"] == "normative"
83
+ l10n("<b>#{@annex_lbl} #{num}</b> #{obl}")
84
+ end
85
+
86
+ def pre_parse(node, out)
87
+ out.pre node.text # content.gsub(/</, "&lt;").gsub(/>/, "&gt;")
88
+ end
89
+
90
+ def term_defs_boilerplate(div, source, term, preface)
91
+ if source.empty? && term.nil?
92
+ div << @no_terms_boilerplate
93
+ else
94
+ div << term_defs_boilerplate_cont(source, term)
95
+ end
96
+ end
97
+
98
+ def i18n_init(lang, script)
99
+ super
100
+ @annex_lbl = "Appendix"
101
+ end
102
+
103
+ def error_parse(node, out)
104
+ # catch elements not defined in ISO
105
+ case node.name
106
+ when "pre"
107
+ pre_parse(node, out)
108
+ when "keyword"
109
+ out.span node.text, **{ class: "keyword" }
110
+ else
111
+ super
112
+ end
113
+ end
114
+
115
+ def fileloc(loc)
116
+ File.join(File.dirname(__FILE__), loc)
117
+ end
118
+
119
+ def info(isoxml, out)
120
+ @meta.security isoxml, out
121
+ super
122
+ end
123
+
124
+ def annex_name(annex, name, div)
125
+ div.h1 **{ class: "Annex" } do |t|
126
+ t << "#{get_anchors[annex['id']][:label]} "
127
+ t << "<b>#{name.text}</b>"
128
+ end
129
+ end
130
+
131
+ def annex_name_lbl(clause, num)
132
+ obl = l10n("(#{@inform_annex_lbl})")
133
+ obl = l10n("(#{@norm_annex_lbl})") if clause["obligation"] == "normative"
134
+ l10n("<b>#{@annex_lbl} #{num}</b> #{obl}")
135
+ end
136
+
137
+ def pre_parse(node, out)
138
+ out.pre node.text # content.gsub(/</, "&lt;").gsub(/>/, "&gt;")
139
+ end
140
+
141
+ def term_defs_boilerplate(div, source, term, preface)
142
+ if source.empty? && term.nil?
143
+ div << @no_terms_boilerplate
144
+ else
145
+ div << term_defs_boilerplate_cont(source, term)
146
+ end
147
+ end
148
+
149
+ def i18n_init(lang, script)
150
+ super
151
+ @annex_lbl = "Appendix"
152
+ end
153
+
154
+ def error_parse(node, out)
155
+ # catch elements not defined in ISO
156
+ case node.name
157
+ when "pre"
158
+ pre_parse(node, out)
159
+ when "keyword"
160
+ out.span node.text, **{ class: "keyword" }
161
+ else
162
+ super
163
+ end
164
+ end
165
+
166
+ def fileloc(loc)
167
+ File.join(File.dirname(__FILE__), loc)
168
+ end
169
+
170
+ def i18n_init(lang, script)
171
+ super
172
+ y = if lang == "en"
173
+ YAML.load_file(File.join(File.dirname(__FILE__), "i18n-en.yaml"))
174
+ elsif lang == "zh" && script == "Hans"
175
+ YAML.load_file(File.join(File.dirname(__FILE__),
176
+ "i18n-zh-Hans.yaml"))
177
+ else
178
+ YAML.load_file(File.join(File.dirname(__FILE__), "i18n-zh-Hans.yaml"))
179
+ end
180
+ @labels = @labels.merge(y)
181
+ @clause_lbl = y["clause"]
182
+ end
183
+
184
+ def terms_defs_title(f)
185
+ return f&.at(ns("./title"))&.content
186
+ end
187
+
188
+ TERM_CLAUSE = "//preface/terms | "\
189
+ "//preface/clause[descendant::terms]".freeze
190
+
191
+ def terms_defs(isoxml, out, num)
192
+ f = isoxml.at(ns(TERM_CLAUSE)) or return num
193
+ out.div **attr_code(id: f["id"]) do |div|
194
+ clause_name(nil, terms_defs_title(f), div, nil)
195
+ f.elements.each do |e|
196
+ parse(e, div) unless %w{title source}.include? e.name
197
+ end
198
+ end
199
+ num
200
+ end
201
+
202
+ FRONT_CLAUSE = "//*[parent::preface]".freeze
203
+
204
+ def preface(isoxml, out)
205
+ isoxml.xpath(ns(FRONT_CLAUSE)).each do |c|
206
+ if c.name == "terms" then terms_defs isoxml, out, 0
207
+ else
208
+ out.div **attr_code(id: c["id"]) do |s|
209
+ clause_name(get_anchors[c['id']][:label],
210
+ c&.at(ns("./title"))&.content, s, nil)
211
+ c.elements.reject { |c1| c1.name == "title" }.each do |c1|
212
+ parse(c1, s)
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ def make_body3(body, docxml)
220
+ body.div **{ class: "main-section" } do |div3|
221
+ preface docxml, div3
222
+ middle docxml, div3
223
+ footnotes div3
224
+ comments div3
225
+ end
226
+ end
227
+
228
+ def middle(isoxml, out)
229
+ middle_title(out)
230
+ clause isoxml, out
231
+ annex isoxml, out
232
+ bibliography isoxml, out
233
+ end
234
+
235
+ def termdef_parse(node, out)
236
+ set_termdomain("")
237
+ node.children.each { |n| parse(n, out) }
238
+ end
239
+
240
+ def initial_anchor_names(d)
241
+ d.xpath(ns(FRONT_CLAUSE)).each do |c|
242
+ preface_names(c)
243
+ sequential_asset_names(c)
244
+ end
245
+ middle_section_asset_names(d)
246
+ clause_names(d, 0)
247
+ termnote_anchor_names(d)
248
+ termexample_anchor_names(d)
249
+ end
250
+
251
+ def annex_name_lbl(clause, num)
252
+ l10n("<b>#{@annex_lbl} #{num}</b>")
253
+ end
254
+
255
+ def xclause_names(docxml, _sect_num)
256
+ q = "//clause[parent::sections]"
257
+ @topnum = nil
258
+ docxml.xpath(ns(q)).each do |c|
259
+ section_names(c, @topnum, 1)
260
+ end
261
+ end
262
+
263
+ def clause_names(docxml, sect_num)
264
+ q = "//clause[parent::sections]"
265
+ @topnum = nil
266
+ lvl = 0
267
+ docxml.xpath(ns(q)).each do |c|
268
+ container_names(c, 0)
269
+ sect_num, lvl = sect_names(c, nil, sect_num, 0, lvl)
270
+ end
271
+ end
272
+
273
+ def container_names(clause, lvl)
274
+ if clause["container"]
275
+ @anchors[clause["id"]] =
276
+ { label: nil, xref: clause.at(ns("./title"))&.text, level: lvl+1 }
277
+ end
278
+ clause.xpath(ns("./clause | ./term | ./terms | "\
279
+ "./definitions")).each do |c|
280
+ container_names(c, clause["container"] ? lvl+1 : lvl)
281
+ end
282
+ end
283
+
284
+ def sect_names(clause, num, i, lvl, prev_lvl)
285
+ return i if clause.nil?
286
+ curr = i
287
+ if clause["container"]
288
+ retlvl = lvl+1
289
+ else
290
+ retlvl = lvl
291
+ i+=1
292
+ curr = i
293
+ name = num.nil? ? i.to_s : "#{num}.#{i}"
294
+ @anchors[clause["id"]] = { label: name, xref: l10n("#{@clause_lbl} #{name}"), level: lvl+1 }
295
+ end
296
+ prev = lvl
297
+ j = 0
298
+ clause.xpath(ns("./clause | ./term | ./terms | "\
299
+ "./definitions")).each do |c|
300
+ if clause["container"]
301
+ i, lvl = sect_names(c, num, i, lvl, lvl)
302
+ else
303
+ j, prev = sect_names(c, name, j, lvl+1, prev)
304
+ end
305
+ end
306
+ i = j if j >0
307
+ i = curr if lvl < prev
308
+ [i, prev]
309
+ end
310
+
311
+ def annex_naming(c, num, lvl, i)
312
+ if c["guidance"] then annex_names1(c, "#{num}E", lvl + 1)
313
+ else
314
+ i+= 1
315
+ annex_names1(c, "#{num}.#{i}", lvl + 1)
316
+ end
317
+ i
318
+ end
319
+
320
+ def annex_names(clause, num)
321
+ @anchors[clause["id"]] = { label: annex_name_lbl(clause, num),
322
+ xref: "#{@annex_lbl} #{num}", level: 1 }
323
+ i = 0
324
+ clause.xpath(ns("./clause")).each do |c|
325
+ i = annex_naming(c, num, 1, i)
326
+ end
327
+ hierarchical_asset_names(clause, num)
328
+ end
329
+
330
+ def annex_names1(clause, num, level)
331
+ @anchors[clause["id"]] = { label: num, xref: "#{@annex_lbl} #{num}",
332
+ level: level }
333
+ i = 0
334
+ clause.xpath(ns("./clause")).each do |c|
335
+ i = annex_naming(c, num, level, i)
336
+ end
337
+ end
338
+
339
+ def clause(isoxml, out)
340
+ isoxml.xpath(ns(MIDDLE_CLAUSE)).each do |c|
341
+ out.div **attr_code(id: c["id"]) do |s|
342
+ clause_name(get_anchors[c['id']][:label],
343
+ c&.at(ns("./title"))&.content, s, class: c["container"] ? "containerhdr" : nil )
344
+ c.elements.reject { |c1| c1.name == "title" }.each do |c1|
345
+ parse(c1, s)
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ def clause_parse_title(node, div, c1, out)
352
+ if node["inline-header"] == "true"
353
+ inline_header_title(out, node, c1)
354
+ else
355
+ attrs = { class: node["container"] ? "containerhdr" : nil }
356
+ div.send "h#{get_anchors[node['id']][:level]}", **attr_code(attrs) do |h|
357
+ lbl = get_anchors[node['id']][:label]
358
+ h << "#{lbl}. " if lbl
359
+ c1&.children&.each { |c2| parse(c2, h) }
360
+ end
361
+ end
362
+ end
363
+
364
+ def ol_depth(node)
365
+ ol_style(node["type"])
366
+ end
367
+ end
368
+ end
369
+ end
370
+
@@ -0,0 +1 @@
1
+ clause: Paragraph
@@ -0,0 +1,98 @@
1
+ require "isodoc"
2
+ require "twitter_cldr"
3
+
4
+ module IsoDoc
5
+ module Mpfd
6
+
7
+ class Metadata < IsoDoc::Metadata
8
+ def initialize(lang, script, labels)
9
+ super
10
+ set(:status, "XXX")
11
+ end
12
+
13
+ def title(isoxml, _out)
14
+ main = isoxml&.at(ns("//title[@language='en']"))&.text
15
+ set(:doctitle, main)
16
+ end
17
+
18
+ def subtitle(_isoxml, _out)
19
+ nil
20
+ end
21
+
22
+ def author(isoxml, _out)
23
+ tc = isoxml.at(ns("//editorialgroup/committee"))
24
+ set(:tc, tc.text) if tc
25
+ end
26
+
27
+ def docid(isoxml, _out)
28
+ docnumber = isoxml.at(ns("//bibdata/docidentifier"))
29
+ docstatus = isoxml.at(ns("//bibdata/status"))
30
+ dn = docnumber&.text
31
+ if docstatus
32
+ set(:status, status_print(docstatus.text))
33
+ abbr = status_abbr(docstatus.text)
34
+ dn = "#{dn}(#{abbr})" unless abbr.empty?
35
+ end
36
+ set(:docnumber, dn)
37
+ end
38
+
39
+ def doctype(isoxml, _out)
40
+ b = isoxml.at(ns("//bibdata")) || return
41
+ return unless b["type"]
42
+ t = b["type"].split(/[- ]/).
43
+ map{ |w| w.capitalize unless w == "MPF" }.join(" ")
44
+ set(:doctype, t)
45
+ end
46
+
47
+ def status_print(status)
48
+ status.split(/-/).map{ |w| w.capitalize }.join(" ")
49
+ end
50
+
51
+ def status_abbr(status)
52
+ case status
53
+ when "working-draft" then "wd"
54
+ when "committee-draft" then "cd"
55
+ when "draft-standard" then "d"
56
+ else
57
+ ""
58
+ end
59
+ end
60
+
61
+ def version(isoxml, _out)
62
+ super
63
+ revdate = get[:revdate]
64
+ set(:revdate_monthyear, monthyr(revdate))
65
+ edition = isoxml.at(ns("//version/edition")) and
66
+ set(:edition, edition.text.to_i.localize.
67
+ to_rbnf_s("SpelloutRules", "spellout-ordinal").
68
+ split(/(\W)/).map(&:capitalize).join)
69
+ end
70
+
71
+ MONTHS = {
72
+ "01": "January",
73
+ "02": "February",
74
+ "03": "March",
75
+ "04": "April",
76
+ "05": "May",
77
+ "06": "June",
78
+ "07": "July",
79
+ "08": "August",
80
+ "09": "September",
81
+ "10": "October",
82
+ "11": "November",
83
+ "12": "December",
84
+ }.freeze
85
+
86
+ def monthyr(isodate)
87
+ m = /(?<yr>\d\d\d\d)-(?<mo>\d\d)/.match isodate
88
+ return isodate unless m && m[:yr] && m[:mo]
89
+ return "#{MONTHS[m[:mo].to_sym]} #{m[:yr]}"
90
+ end
91
+
92
+ def security(isoxml, _out)
93
+ security = isoxml.at(ns("//bibdata/security")) || return
94
+ set(:security, security.text)
95
+ end
96
+ end
97
+ end
98
+ end