metanorma 2.0.5 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,8 @@
1
1
  require "yaml"
2
2
  require_relative "../../util/util"
3
3
  require_relative "../xrefprocess/xrefprocess"
4
+ require_relative "collection"
5
+ require "concurrent-ruby"
4
6
 
5
7
  module Metanorma
6
8
  class Collection
@@ -17,49 +19,13 @@ module Metanorma
17
19
  @fileslookup = opts[:fileslookup]
18
20
  @ident = opts[:ident]
19
21
  @isodoc = opts[:isodoc]
22
+ @document_suffix = opts[:document_suffix]
20
23
  end
21
24
 
22
25
  def ns(xpath)
23
26
  @isodoc.ns(xpath)
24
27
  end
25
28
 
26
- def build_collection
27
- collection_setup(@base, @dir)
28
- files = sectionsplit # (@input_filename, @base, @dir, @compile_opts)
29
- input_xml = Nokogiri::XML(File.read(@input_filename,
30
- encoding: "UTF-8"), &:huge)
31
- collection_manifest(@base, files, input_xml, @xml, @dir).render(
32
- { format: %i(html), output_folder: "#{@output_filename}_collection",
33
- coverpage: File.join(@dir, "cover.html") }.merge(@compile_opts),
34
- )
35
- section_split_attachments(out: "#{@output_filename}_collection")
36
- end
37
-
38
- def collection_manifest(filename, files, origxml, _presxml, dir)
39
- File.open(File.join(dir, "#{filename}.html.yaml"), "w:UTF-8") do |f|
40
- f.write(collectionyaml(files, origxml))
41
- end
42
- Metanorma::Collection.parse File.join(dir, "#{filename}.html.yaml")
43
- end
44
-
45
- def collection_setup(filename, dir)
46
- FileUtils.mkdir_p "#{filename}_collection" if filename
47
- FileUtils.mkdir_p dir
48
- File.open(File.join(dir, "cover.html"), "w:UTF-8") do |f|
49
- f.write(coll_cover)
50
- end
51
- end
52
-
53
- def coll_cover
54
- <<~COVER
55
- <html><head><meta charset="UTF-8"/></head><body>
56
- <h1>{{ doctitle }}</h1>
57
- <h2>{{ docnumber }}</h2>
58
- <nav>{{ navigation }}</nav>
59
- </body></html>
60
- COVER
61
- end
62
-
63
29
  SPLITSECTIONS =
64
30
  [["//preface/*", "preface"], ["//sections/*", "sections"],
65
31
  ["//annex", nil],
@@ -70,17 +36,37 @@ module Metanorma
70
36
  def sectionsplit
71
37
  xml = sectionsplit_prep(File.read(@input_filename), @base, @dir)
72
38
  @key = Metanorma::Collection::XrefProcess::xref_preprocess(xml, @isodoc)
73
- SPLITSECTIONS.each_with_object([]) do |n, ret|
39
+ empty = empty_doc(xml)
40
+ empty1 = empty_attachments(empty)
41
+ @mutex = Mutex.new
42
+ @pool = Concurrent::FixedThreadPool.new(4)
43
+ sectionsplit1(xml, empty, empty1, 0)
44
+ end
45
+
46
+ def sectionsplit1(xml, empty, empty1, idx)
47
+ ret = SPLITSECTIONS.each_with_object([]) do |n, m|
74
48
  conflate_floatingtitles(xml.xpath(ns(n[0]))).each do |s|
75
- ret << sectionfile(xml, emptydoc(xml, ret.size),
76
- "#{@base}.#{ret.size}", s, n[1])
49
+ sectionsplit2(xml, idx.zero? ? empty : empty1, s, n[1],
50
+ { acc: m, idx: idx })
51
+ idx += 1
77
52
  end
78
53
  end
54
+ @pool.shutdown
55
+ @pool.wait_for_termination
56
+ ret
57
+ end
58
+
59
+ def sectionsplit2(xml, empty, chunks, parentnode, opt)
60
+ @pool.post do
61
+ a = sectionfile(xml, empty, "#{@base}.#{opt[:idx]}", chunks,
62
+ parentnode)
63
+ @mutex.synchronize { opt[:acc] << a }
64
+ end
79
65
  end
80
66
 
81
67
  def block?(node)
82
68
  %w(p table formula admonition ol ul dl figure quote sourcecode example
83
- pre note pagebrreak hr bookmark requirement recommendation permission
69
+ pre note pagebreak hr bookmark requirement recommendation permission
84
70
  svgmap inputform toc passthrough review imagemap).include?(node.name)
85
71
  end
86
72
 
@@ -142,7 +128,26 @@ module Metanorma
142
128
  "//bibliography/references[not(@hidden = 'true')] | " \
143
129
  "//indexsect | //colophon"),
144
130
  ).each(&:remove)
145
- ordinal.zero? or out.xpath(ns("//metanorma-ext//attachment"))
131
+ ordinal.zero? or out.xpath(ns("//metanorma-ext//attachment | " \
132
+ "//semantic__metanorma-ext//semantic__attachment"))
133
+ .each(&:remove) # keep only one copy of attachments
134
+ out
135
+ end
136
+
137
+ def empty_doc(xml)
138
+ out = xml.dup
139
+ out.xpath(
140
+ ns("//preface | //sections | //annex | //bibliography/clause | " \
141
+ "//bibliography/references[not(@hidden = 'true')] | " \
142
+ "//indexsect | //colophon"),
143
+ ).each(&:remove)
144
+ out
145
+ end
146
+
147
+ def empty_attachments(xml)
148
+ out = xml.dup
149
+ out.xpath(ns("//metanorma-ext//attachment | " \
150
+ "//semantic__metanorma-ext//semantic__attachment"))
146
151
  .each(&:remove) # keep only one copy of attachments
147
152
  out
148
153
  end
@@ -158,11 +163,36 @@ module Metanorma
158
163
  sectionfile_insert(ins, chunks, parentnode)
159
164
  Metanorma::Collection::XrefProcess::xref_process(out, xml, @key,
160
165
  @ident, @isodoc)
166
+ truncate_semxml(out, chunks)
161
167
  outname = "#{file}.xml"
162
- File.open(File.join(@splitdir, outname), "w:UTF-8") { |f| f.write(out) }
168
+ File.open(File.join(@splitdir, outname), "w:UTF-8") do |f|
169
+ f.write(out)
170
+ end
163
171
  outname
164
172
  end
165
173
 
174
+ def semantic_xml_ids_gather(out)
175
+ out.at(ns("//semantic__bibdata")) or return
176
+ SPLITSECTIONS.each_with_object({}) do |s, m|
177
+ out.xpath(ns(s[0].sub("//", "//semantic__"))).each do |x|
178
+ x["id"] or next
179
+ m[x["id"].sub(/^semantic__/, "")] = x
180
+ end
181
+ end
182
+ end
183
+
184
+ def semxml_presxml_nodes_match(nodes, chunks)
185
+ chunks.each do |x|
186
+ nodes[x["id"]] and nodes.delete(x["id"])
187
+ end
188
+ end
189
+
190
+ def truncate_semxml(out, chunks)
191
+ nodes = semantic_xml_ids_gather(out) or return
192
+ semxml_presxml_nodes_match(nodes, chunks)
193
+ nodes.each_value(&:remove)
194
+ end
195
+
166
196
  def sectionfile_insert(ins, chunks, parentnode)
167
197
  if parentnode
168
198
  ins.next = "<#{parentnode}/>"
@@ -180,64 +210,6 @@ module Metanorma
180
210
  .each { |x| x.replace(x.children) }
181
211
  t.children.to_xml
182
212
  end
183
-
184
- def collectionyaml(files, xml)
185
- ret = {
186
- directives: ["presentation-xml", "bare-after-first"],
187
- bibdata: {
188
- title: {
189
- type: "title-main", language: @lang,
190
- content: xml.at(ns("//bibdata/title")).text
191
- },
192
- type: "collection",
193
- docid: {
194
- type: xml.at(ns("//bibdata/docidentifier/@type")).text,
195
- id: xml.at(ns("//bibdata/docidentifier")).text,
196
- },
197
- },
198
- manifest: {
199
- level: "collection", title: "Collection",
200
- docref: files.sort_by { |f| f[:order] }.each.map do |f|
201
- { fileref: f[:url], identifier: f[:title] }
202
- end
203
- },
204
- }
205
- ::Metanorma::Util::recursive_string_keys(ret).to_yaml
206
- end
207
-
208
- def section_split_cover(col, ident, _one_doc_coll)
209
- dir = File.dirname(col.file)
210
- collection_setup(nil, dir)
211
- r = ::Metanorma::Collection::Renderer
212
- .new(col, dir, output_folder: "#{ident}_collection",
213
- format: %i(html), coverpage: File.join(dir, "cover.html"))
214
- r.coverpage
215
- section_split_cover1(ident, r, dir, _one_doc_coll)
216
- end
217
-
218
- def att_dir(file)
219
- "_#{File.basename(file, '.*')}_attachments"
220
- end
221
-
222
- def section_split_attachments(out: nil)
223
- attachments = att_dir(@tmp_filename)
224
- File.directory?(attachments) or return
225
- dir = out || File.dirname(@input_filename)
226
- ret = File.join(dir, att_dir(@output_filename))
227
- FileUtils.rm_rf ret
228
- FileUtils.mv attachments, ret
229
- File.basename(ret)
230
- end
231
-
232
- def section_split_cover1(ident, renderer, dir, _one_doc_coll)
233
- # filename = one_doc_coll ? "#{ident}_index.html" : "index.html"
234
- filename = File.basename("#{ident}_index.html")
235
- # ident can be a directory with YAML indirection
236
- FileUtils.mv File.join(renderer.outdir, "index.html"),
237
- File.join(dir, filename)
238
- FileUtils.rm_rf renderer.outdir
239
- filename
240
- end
241
213
  end
242
214
  end
243
215
  end
@@ -30,8 +30,7 @@ module Metanorma
30
30
  end
31
31
  end
32
32
 
33
- def add_suffix_to_attributes(doc, suffix, tag_name, attr_name,
34
- isodoc)
33
+ def add_suffix_to_attrs(doc, suffix, tag_name, attr_name, isodoc)
35
34
  (suffix.nil? || suffix.empty?) and return
36
35
  doc.xpath(isodoc.ns("//#{tag_name}[@#{attr_name}]")).each do |elem|
37
36
  a = elem.attributes[attr_name].value
@@ -62,8 +61,8 @@ isodoc)
62
61
  def attr(_key); end
63
62
  end
64
63
 
65
- def load_isodoc(doctype)
66
- x = Asciidoctor.load nil, backend: doctype.to_sym
64
+ def load_isodoc(flavor)
65
+ x = Asciidoctor.load nil, backend: flavor.to_sym
67
66
  x.converter.html_converter(Dummy.new) # to obtain Isodoc class
68
67
  end
69
68
  end
@@ -10,9 +10,9 @@ module Metanorma
10
10
  key = (0...8).map { rand(65..90).chr }.join # random string
11
11
  xml.root["type"] = key
12
12
  Metanorma::Utils::anchor_attributes
13
- .each do |(tag_name, attribute_name)|
14
- ::Metanorma::Collection::Util::add_suffix_to_attributes(
15
- xml, xml.root["document_suffix"], tag_name, attribute_name, isodoc
13
+ .each do |(tag_name, attr_name)|
14
+ ::Metanorma::Collection::Util::add_suffix_to_attrs(
15
+ xml, xml.root["document_suffix"], tag_name, attr_name, isodoc
16
16
  )
17
17
  end
18
18
  key
@@ -33,6 +33,7 @@ module Metanorma
33
33
  relaton_export(isodoc, options)
34
34
  extract(isodoc, options[:extract], options[:extract_type])
35
35
  process_exts(filename, extensions, file, isodoc, options)
36
+ ensure
36
37
  clean_exit(options)
37
38
  end
38
39
 
@@ -113,6 +114,14 @@ module Metanorma
113
114
  fnames = { xml: f.sub(/\.[^.]+$/, ".xml"), f: f,
114
115
  orig_filename: File.expand_path(filename),
115
116
  presentationxml: f.sub(/\.[^.]+$/, ".presentation.xml") }
117
+ if extensions == %i(presentation)
118
+ process_ext(:presentation, file, isodoc, fnames, options)
119
+ else
120
+ process_exts_queue(fnames, extensions, file, isodoc, options)
121
+ end
122
+ end
123
+
124
+ def process_exts_queue(fnames, extensions, file, isodoc, options)
116
125
  @queue = ::Metanorma::Util::WorkersPool
117
126
  .new(ENV["METANORMA_PARALLEL"]&.to_i || 3)
118
127
  gather_and_install_fonts(file, options.dup, extensions)
@@ -33,15 +33,15 @@ module Metanorma
33
33
  "support the standard type #{stdtype}. Exiting.", :fatal)
34
34
  end
35
35
 
36
- private
37
-
38
- STDTYPE2FLAVOR = {}.freeze
39
-
40
36
  def stdtype2flavor(stdtype)
41
37
  flavor = STDTYPE2FLAVOR[stdtype] || stdtype
42
38
  "metanorma-#{flavor}"
43
39
  end
44
40
 
41
+ private
42
+
43
+ STDTYPE2FLAVOR = {}.freeze
44
+
45
45
  def require_flavor(flavor)
46
46
  require flavor
47
47
  Util.log("[metanorma] Info: gem `#{flavor}` loaded.", :info)
@@ -1,8 +1,7 @@
1
1
  module Metanorma
2
2
  class Compile
3
3
  def relaton_export(isodoc, options)
4
- return unless options[:relaton]
5
-
4
+ options[:relaton] or return
6
5
  xml = Nokogiri::XML(isodoc, &:huge)
7
6
  bibdata = xml.at("//bibdata") || xml.at("//xmlns:bibdata")
8
7
  # docid = bibdata&.at("./xmlns:docidentifier")&.text || options[:filename]
@@ -18,8 +17,7 @@ module Metanorma
18
17
  end
19
18
 
20
19
  def extract(isodoc, dirname, extract_types)
21
- return unless dirname
22
-
20
+ dirname or return
23
21
  extract_types.nil? || extract_types.empty? and
24
22
  extract_types = %i[sourcecode image requirement]
25
23
  FileUtils.rm_rf dirname
@@ -10,39 +10,20 @@ module Metanorma
10
10
  novalid: options[:novalid],
11
11
  attributes: ["nodoc", "stem", "docfile=#{filename}",
12
12
  "output_dir=#{options[:output_dir]}"] }
13
- unless asciidoctor_validate(file, filename, out_opts)
14
- warn "Cannot continue compiling Asciidoctor document"
15
- abort
16
- end
17
13
  ::Asciidoctor.convert(file, out_opts)
18
14
  end
19
15
 
20
- def asciidoctor_validate(file, filename, options)
21
- err = nil
22
- begin
23
- previous_stderr = $stderr
24
- $stderr = StringIO.new
25
- ::Asciidoctor.load(file, options)
26
- %r{(\n|^)asciidoctor: ERROR: ['"]?#{Regexp.escape(filename ||
27
- '<empty>')}['"]?: line \d+: include file not found: }
28
- .match($stderr.string) and err = $stderr.string
29
- ensure
30
- $stderr = previous_stderr
31
- end
32
- warn err unless err.nil?
33
- err.nil?
34
- end
35
-
36
16
  def extract_metanorma_options(file)
37
- headerextract = file.sub(/\n\n.*$/m, "\n")
38
- /\n:mn-document-class:\s+(?<type>\S[^\n]*)\n/ =~ headerextract
39
- /\n:mn-output-extensions:\s+(?<extensions>\S[^\n]*)\n/ =~ headerextract
40
- /\n:mn-relaton-output-file:\s+(?<relaton>\S[^\n]*)\n/ =~ headerextract
41
- /\n(?<asciimath>:mn-keep-asciimath:[^\n]*)\n/ =~ headerextract
42
- /\n(?<novalid>:novalid:[^\n]*)\n/ =~ headerextract
43
- asciimath = if defined?(asciimath)
44
- !asciimath.nil? && asciimath != ":mn-keep-asciimath: false"
45
- end
17
+ hdr = file.sub(/\n\n.*$/m, "\n")
18
+ /\n:(?:mn-)?(?:document-class|flavor):\s+(?<type>\S[^\n]*)\n/ =~ hdr
19
+ /\n:(?:mn-)?output-extensions:\s+(?<extensions>\S[^\n]*)\n/ =~ hdr
20
+ /\n:(?:mn-)?relaton-output-file:\s+(?<relaton>\S[^\n]*)\n/ =~ hdr
21
+ /\n(?<asciimath>:(?:mn-)?keep-asciimath:[^\n]*)\n/ =~ hdr
22
+ /\n(?<novalid>:novalid:[^\n]*)\n/ =~ hdr
23
+ if defined?(asciimath)
24
+ asciimath =
25
+ !asciimath.nil? && !/keep-asciimath: false/.match?(asciimath)
26
+ end
46
27
  asciimath = nil if asciimath == false
47
28
  {
48
29
  type: defined?(type) ? type&.strip : nil,
@@ -82,7 +63,7 @@ module Metanorma
82
63
  toc-tables toc-recommendations).freeze
83
64
 
84
65
  def attr_name_normalise(name)
85
- name.gsub("-", "").sub(/override$/, "_override").sub(/pdf$/, "_pdf")
66
+ name.delete("-").sub(/override$/, "_override").sub(/pdf$/, "_pdf")
86
67
  .to_sym
87
68
  end
88
69
 
@@ -1,3 +1,3 @@
1
1
  module Metanorma
2
- VERSION = "2.0.5".freeze
2
+ VERSION = "2.0.7".freeze
3
3
  end
data/metanorma.gemspec CHANGED
@@ -24,10 +24,11 @@ Gem::Specification.new do |spec|
24
24
  spec.required_ruby_version = ">= 3.1.0"
25
25
 
26
26
  spec.add_runtime_dependency "asciidoctor"
27
+ spec.add_runtime_dependency "concurrent-ruby"
27
28
  spec.add_runtime_dependency "fontist", ">= 1.14.3"
28
29
  spec.add_runtime_dependency "htmlentities"
29
30
  spec.add_runtime_dependency "isodoc", ">= 2.6.3"
30
- spec.add_runtime_dependency "mn2pdf", "~> 1"
31
+ spec.add_runtime_dependency "mn2pdf", "~> 2"
31
32
  spec.add_runtime_dependency "nokogiri"
32
33
  spec.add_runtime_dependency "shale"
33
34
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.5
4
+ version: 2.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-30 00:00:00.000000000 Z
11
+ date: 2024-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: concurrent-ruby
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: fontist
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,14 +86,14 @@ dependencies:
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '1'
89
+ version: '2'
76
90
  type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '1'
96
+ version: '2'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: nokogiri
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -316,7 +330,9 @@ files:
316
330
  - lib/metanorma/collection/renderer/navigation.rb
317
331
  - lib/metanorma/collection/renderer/render_word.rb
318
332
  - lib/metanorma/collection/renderer/renderer.rb
333
+ - lib/metanorma/collection/renderer/svg.rb
319
334
  - lib/metanorma/collection/renderer/utils.rb
335
+ - lib/metanorma/collection/sectionsplit/collection.rb
320
336
  - lib/metanorma/collection/sectionsplit/sectionsplit.rb
321
337
  - lib/metanorma/collection/util/disambig_files.rb
322
338
  - lib/metanorma/collection/util/util.rb