Class: Metanorma::Collection::Renderer
- Inherits:
-
Object
- Object
- Metanorma::Collection::Renderer
- Defined in:
- lib/metanorma/collection/renderer/svg.rb,
lib/metanorma/collection/renderer/utils.rb,
lib/metanorma/collection/renderer/renderer.rb,
lib/metanorma/collection/renderer/fileparse.rb,
lib/metanorma/collection/renderer/navigation.rb,
lib/metanorma/collection/renderer/fileprocess.rb,
lib/metanorma/collection/renderer/render_word.rb,
lib/metanorma/collection/renderer/filelocation.rb
Defined Under Namespace
Classes: DocOptionsNode, PdfOptionsNode
Constant Summary collapse
- FORMATS =
%i[html xml doc pdf pdf-portfolio].freeze
- ANCHOR_XPATH =
"xmlns:locality[@type = 'anchor']/xmlns:referenceFrom" .freeze
- BIBITEM_NOT_REPO_XPATH =
<<~XPATH.strip //bibitem[not(ancestor::bibitem)][not(ancestor::bibdata)][not(./docidentifier[@type = 'repository'])] XPATH
- SECTION_BREAK =
'<p class="MsoNormal"><br clear="all" class="section"/></p>'.freeze
- DIV1 =
'<div class="WordSection1"> </div>'.freeze
- DIV2 =
'<div class="WordSection2"> </div>'.freeze
Instance Attribute Summary collapse
-
#compile ⇒ Object
readonly
Returns the value of attribute compile.
-
#compile_options ⇒ Object
readonly
Returns the value of attribute compile_options.
-
#documents ⇒ Object
readonly
Returns the value of attribute documents.
-
#fatal_errors ⇒ Object
readonly
Returns the value of attribute fatal_errors.
-
#isodoc ⇒ Object
Returns the value of attribute isodoc.
-
#isodoc_presxml ⇒ Object
Returns the value of attribute isodoc_presxml.
-
#manifest ⇒ Object
readonly
Returns the value of attribute manifest.
-
#outdir ⇒ Object
readonly
Returns the value of attribute outdir.
-
#xml ⇒ Object
readonly
Returns the value of attribute xml.
Class Method Summary collapse
Instance Method Summary collapse
- #add_hidden_bibliography(xml, refs, current_id = nil) ⇒ Object
-
#apply_custom_filename_pattern(ident, custom_fname, output_fname, format) ⇒ Object
Apply custom filename pattern with substitutions.
-
#apply_directory_preservation(fname, output_fname, format) ⇒ Object
Apply directory preservation for files with directory structure.
- #bilingual_output(options, pres) ⇒ Object
- #build_indexfile1(mnf) ⇒ Object
- #cleanup_indexfile1(ret) ⇒ Object
- #collect_erefs(docxml, presxml) ⇒ Object
- #collection_coverpages(conv, docs) ⇒ Object
- #compile_options_base(identifier) ⇒ Object
- #compile_options_update(identifier) ⇒ Object
- #concat_extract_files(filename) ⇒ Object
- #concatenate(col, options) ⇒ Object
- #concatenate1(out, ext) ⇒ Object
- #concatenate_outputs(options) ⇒ Object
- #concatenate_outputs_prep(_options) ⇒ Object
- #concatenate_prep(col, options) ⇒ Object
- #concatenate_presentation(xml) ⇒ Object
- #concatenate_presentation?(options) ⇒ Boolean
- #copy_file_to_dest(identifier) ⇒ Object
-
#coverpage ⇒ Object
populate liquid template of ARGV with metadata extracted from collection manifest.
-
#custom_basename_with_extension(fname, output_basename) ⇒ Object
Generate custom basename with extension.
- #deep_detached_clone(node) ⇒ Object
- #dir_name_cleanse(name) ⇒ Object
- #directives_normalise(directives) ⇒ Object
- #directives_normalise_coverpage_pdf_portfolio(directives) ⇒ Object
- #directives_normalise_keystore_pdf_portfolio(directives) ⇒ Object
- #directives_resolve_filepath(directives, name, val) ⇒ Object
- #docconv(added_options = {}) ⇒ Object
- #docconv_convert(filename) ⇒ Object
- #docconv_convert1(docs) ⇒ Object
- #docid_to_citeas(bib) ⇒ Object
- #docid_xml(val) ⇒ Object
- #docref_ident(docref) ⇒ Object
- #docrefs(mnf, builder) ⇒ Object
-
#document_ref_html(identifier) ⇒ Object
Use :outputs if available (after compilation), otherwise convert :out_path to HTML (before compilation), following ref_file_xml2html.
- #dup_bibitem(docid, bib) ⇒ Object
- #extract_added_fonts(pres) ⇒ Object
-
#file_compile(file, filename, identifier) ⇒ Object
compile and output individual file in collection warn "metanorma compile -x html #ff.path".
- #file_compile_failure_log(identifier, errors, missing) ⇒ Object
- #file_compile_failure_msg(identifier, errors, missing) ⇒ Object
-
#file_compile_format(fname, ident, format, outputs, new_output_fname) ⇒ Object
Compile single format for a file and update outputs hash.
- #file_compile_formats(filename, identifier, opts) ⇒ Object
-
#file_compile_verify(identifier, errors) ⇒ Object
A member whose rendering raised produces no output file, but the collection build used to continue, exit 0, and link the absent document from index.html -- silent data loss (#586).
-
#files ⇒ Object
process each file in the collection files are held in memory, and altered as postprocessing.
-
#flavor ⇒ Object
TODO: infer flavor from publisher when available.
- #flush_files ⇒ Object
-
#gather_internal_refs ⇒ Object
gather internal bibitem references.
- #gather_internal_refs1(file, ident, refs) ⇒ Object
- #gather_internal_refs_indirect(doc, refs) ⇒ Object
- #gather_internal_refs_sectionsplit(_doc, ident, key, refs) ⇒ Object
- #get_bibitem_docid(bib, identifier) ⇒ Object
-
#handle_existing_destination(output_with_dir, output_src) ⇒ Object
Handle case where destination already exists.
-
#handle_new_output_filename(output_fname, new_output_fname) ⇒ Object
Move file to new output filename if specified.
- #index?(mnf) ⇒ Boolean
-
#index_link(docref, ident) ⇒ Object
Check if file has a recognized MIME type (other than XML) If so, don't append .html (e.g., .svg, .png, .jpg, etc.).
-
#index_object(mnf) ⇒ Object
object to construct navigation out of in Liquid.
- #index_object_children(mnf) ⇒ Object
- #index_object_docrefs(mnf) ⇒ Object
-
#indexfile(mnf) ⇒ Object
single level navigation list, with hierarchical nesting.
- #indexfile1(mnf) ⇒ Object
-
#indexfile_docref(mnf, builder) ⇒ Object
uses the identifier to label documents; other attributes (title) can be looked up in @files[:bibdata].
- #indexfile_title(entry) ⇒ String
- #indirect_ref_key(schema, id, doc_suffix, add_suffix) ⇒ Object
-
#initialize(collection, folder, options = {}) ⇒ Renderer
constructor
This is only going to render the HTML collection We presuppose that the bibdata of the document is equivalent to that of the collection, and that the flavour gem can sensibly process it.
- #liquid_docrefs(mnfs) ⇒ Object
-
#locate_internal_refs ⇒ Object
resolve file location for the target of each internal reference.
- #locate_internal_refs1(refs, identifier, ident) ⇒ Object
- #locate_internal_refs1_prep(file) ⇒ Object
- #make_relative_path(from_file, to_file) ⇒ Object
-
#member_content_hash(source) ⇒ Object
Persist an isolated member's stub-bearing Semantic XML and its anchor contribution to the content-addressed store, so a later reinflation pass can relink the stubs and a re-run can resume without recompiling.
-
#member_stored?(ident, source) ⇒ Boolean
Resume predicate: is this member already compiled and stored for its current input content? If so the isolated compile can skip it.
-
#move_file_to_subdirectory(fname_dir, output_basename) ⇒ Object
Move file from root to subdirectory.
- #new_hidden_ref(xml) ⇒ Object
- #out_path_to_html(out_path) ⇒ Object
-
#output_filename_with_extension(fname, format) ⇒ Object
Generate output filename with correct extension.
- #overall_docconv_converter(body) ⇒ Object
- #overall_docconv_cover(collection_conv) ⇒ Object
- #pdf_portfolio_mn2pdf_options ⇒ Object
- #populate_internal_refs(refs) ⇒ Object
-
#preserve_output_dir_structure(fname, output_fname, format = nil, explicit_custom: false) ⇒ Object
Preserve directory structure from input filename in output.
-
#referencing_html_location(identifier, attachment) ⇒ Object
Location of the HTML that will carry the cross-reference to the target, used as the base for relativising the attachment/citation URL.
- #rxl(options) ⇒ Object
-
#sectionsplit_ref_html(identifier) ⇒ Object
The split section files sit at the sectionsplit output directory: the collection root, or the directory of a configured sectionsplit_filename.
- #set_displayorder_wrapping_doc(doc) ⇒ Object
-
#should_move_to_subdirectory?(ext, output_basename, explicit_custom) ⇒ Boolean
Determine if file should be moved to subdirectory.
- #store_member_artefacts(ident, source, semantic_xml) ⇒ Object
- #strip_eref(eref) ⇒ Object
-
#strip_unresolved_repo_erefs(_document_id, bib_docid, erefs, bibitem) ⇒ Object
strip erefs if they are repository erefs, but do not point to a document within the current collection.
-
#suffix_anchor_indirect(prefix, suffix) ⇒ Object
encode both prefix and suffix to NCName.
- #supply_repo_ids(doc) ⇒ Object
-
#svg_datauri(docxml, docid) ⇒ Object
Converts SVG images to data URIs for inline embedding.
-
#svgmap_resolve(docxml, docid, presxml) ⇒ Object
Resolves SVG map references and processes SVG ID disambiguation.
-
#svgmap_resolve_prep(docxml, docid, presxml) ⇒ Object
Prepares document and context for svgmap resolution.
-
#update_anchor_create_loc(_bib, eref, docid) ⇒ Object
if there is a crossref to another document, with no anchor, retrieve the anchor given the locality, and insert it into the crossref.
-
#update_anchors(bib, docid, erefs, erefs_no_anchor, erefs_anchors) ⇒ Object
bottleneck.
- #update_anchors1(docid, ncn_docid, anchor) ⇒ Object
- #update_anchors_prep(docid) ⇒ Object
- #update_bibitem(bib, identifier) ⇒ Object
- #update_bibitem_prep(bib, identifier) ⇒ Object
-
#update_direct_refs_to_docs(xml, identifier, presxml) ⇒ Object
repo(current-metanorma-collection/ISO 17301-1:2016) replaced by bibdata of "ISO 17301-1:2016" in situ as bibitem.
-
#update_direct_refs_to_docs_prep(docxml, presxml) ⇒ Object
Hash(docid) of arrays.
- #update_indirect_refs_prep(docxml, presxml) ⇒ Object
-
#update_indirect_refs_to_docs(docxml, _docid, internal_refs, presxml) ⇒ Object
Resolve erefs to a container of ids in another doc, to an anchor eref (direct link).
- #update_indirect_refs_to_docs1(filec, key, file, bibitems, erefs) ⇒ Object
- #update_indirect_refs_to_docs_anchor(eref, file, url, parentid) ⇒ Object
- #update_indirect_refs_to_docs_docid(bib, file) ⇒ Object
- #update_sectionsplit_eref_to_doc(eref, internal_refs, doclist, opts) ⇒ Object
- #update_sectionsplit_refs_to_docs(docxml, docid, internal_refs, presxml) ⇒ Object
-
#update_xrefs(file, docid, internal_refs) ⇒ String
Resolves references to other files in the collection.
-
#update_xrefs_prep(file, docid) ⇒ Object
sso (sectionsplit_output) truthy => Presentation XML, else Semantic.
-
#with_nested ⇒ Object
Run the block with the renderer in nested mode, restoring the previous mode afterwards.
-
#with_preserve_unresolved ⇒ Object
Run the block with the renderer preserving unresolved cross-document references as stubs instead of stripping them -- for an isolated build of a collection member (compiled without the rest of its collection present).
- #wrapping_doc(doc, xml) ⇒ Object
- #wrapping_doc_body(doc) ⇒ Object
- #wrapping_doc_intro_outro(xml, sections) ⇒ Object
Constructor Details
#initialize(collection, folder, options = {}) ⇒ Renderer
This is only going to render the HTML collection We presuppose that the bibdata of the document is equivalent to that of the collection, and that the flavour gem can sensibly process it. We may need to enhance metadata in the flavour gems isodoc/metadata.rb with collection metadata
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 62 def initialize(collection, folder, = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength @xml = Nokogiri::XML collection.to_xml # @xml is the collection manifest @lang = Array(collection.bibdata.language).first || "en" @script = Array(collection.bibdata.script).first || "Latn" @locale = @xml.at("//xmlns:bibdata/xmlns:locale")&.text @registry = Metanorma::Registry.instance @flavor = [:flavor] || flavor @compile = Compile.new @compile.load_flavor(@flavor) # output processor for flavour @isodoc = Util::isodoc_create(Util::taste2flavor(@flavor), @lang, @script, @xml) @isodoc_presxml = Util::isodoc_create(Util::taste2flavor(@flavor), @lang, @script, @xml, presxml: true) @outdir = dir_name_cleanse([:output_folder]) @format = ::Metanorma::Util.sort_extensions_execution([:format]) @compile_options = [:compile] || {} @compile_options[:install_fonts] = true if [:install_fonts] @log = [:log] @log&.add_msg(METANORMA_LOG_MESSAGES) @bibdata = collection.bibdata @documents = collection.documents @bibdatas = collection.documents @directives = collection.directives @dirname = collection.dirname @manifest = collection.manifest.config @disambig = Util::DisambigFiles.new @prefatory = collection.prefatory @final = collection.final @c = HTMLEntities.new @files_to_delete = [] # Per-member rendering failures (missing outputs, pooled compile # errors), accumulated by file_compile_verify; Collection#render # aborts on them once every member has rendered (#586). @fatal_errors = [] @nested = [:nested] # if false, this is the root instance of Renderer # if true, then this is not the last time Renderer will be run # (e.g. this is sectionsplit) # Isolated/incremental build: preserve unresolved cross-document # references as stubs instead of resolving or stripping them, so each # member compiles independently and a later reinflation pass relinks. @preserve_unresolved = [:preserve_unresolved] # Durable content-addressed store for staged artefacts. Opt-in: a plain # build sets neither :preserve_unresolved nor :artifact_store_dir, so it # gets the no-op Null store and is unaffected. Staging (:preserve_unresolved) # defaults the store directory to ArtifactStore::DEFAULT_DIRNAME when no # :artifact_store_dir is given, so callers need not name it. (Reinflation # reads stored stubs via the manifest, not this object, so it does not # trigger the default -- that would only create an empty directory.) @artifact_store = if (dir = [:artifact_store_dir]) || [:preserve_unresolved] ArtifactStore.new(dir || ArtifactStore::DEFAULT_DIRNAME) else NullArtifactStore.new end # Reinflation pass: the input is a stored stub-bearing Semantic XML that # already has intra-doc xrefs and the document suffix applied, so run # only the cross-document resolution, not the passes already done. @reinflate = [:reinflate] # Cache retention: by default keep only each document's latest artefacts, # pruning superseded content-hash versions on write; keep_cache retains # every version (history / multiple states side by side). @keep_cache = [:keep_cache] @coverpage = [:coverpage] || collection.coverpage @coverpage_pdf_portflio = [:coverpage_pdf_portfolio] || collection.coverpage_pdf_portfolio || Util::taste2coverpage_pdf_portfolio(@flavor) collection.directives = directives_normalise(collection.directives) @directives = collection.directives # list of files in the collection @files = Metanorma::Collection::FileLookup.new(folder, self) @files.add_section_split isodoc_populate create_non_existing_directory(@outdir) end |
Instance Attribute Details
#compile ⇒ Object (readonly)
Returns the value of attribute compile.
21 22 23 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 21 def compile @compile end |
#compile_options ⇒ Object (readonly)
Returns the value of attribute compile_options.
21 22 23 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 21 def @compile_options end |
#documents ⇒ Object (readonly)
Returns the value of attribute documents.
21 22 23 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 21 def documents @documents end |
#fatal_errors ⇒ Object (readonly)
Returns the value of attribute fatal_errors.
21 22 23 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 21 def fatal_errors @fatal_errors end |
#isodoc ⇒ Object
Returns the value of attribute isodoc.
20 21 22 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 20 def isodoc @isodoc end |
#isodoc_presxml ⇒ Object
Returns the value of attribute isodoc_presxml.
20 21 22 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 20 def isodoc_presxml @isodoc_presxml end |
#manifest ⇒ Object (readonly)
Returns the value of attribute manifest.
21 22 23 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 21 def manifest @manifest end |
#outdir ⇒ Object (readonly)
Returns the value of attribute outdir.
21 22 23 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 21 def outdir @outdir end |
#xml ⇒ Object (readonly)
Returns the value of attribute xml.
21 22 23 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 21 def xml @xml end |
Class Method Details
.render(col, options = {}) ⇒ Object
184 185 186 187 188 189 190 191 192 193 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 184 def self.render(col, = {}) warn "\n\n\n\n\nRender Init: #{DateTime.now.strftime('%H:%M:%S')}" cr = new(col, File.dirname(col.file), ) cr.files cr.rxl() cr.concatenate(col, ) [:format]&.include?(:html) and cr.coverpage cr.flush_files cr end |
Instance Method Details
#add_hidden_bibliography(xml, refs, current_id = nil) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 74 def add_hidden_bibliography(xml, refs, current_id = nil) ins = new_hidden_ref(xml) current_html = if current_id @files.get(current_id, :outputs)&.dig(:html) else nil end refs.each do |k, v| url = @files.url(v, {}) url = make_relative_path(current_html, url) if current_html ins << <<~XML <bibitem id="#{k}" anchor="#{k}">#{docid_xml(v)}<uri type='citation'>#{url}</uri></bibitem> XML end end |
#apply_custom_filename_pattern(ident, custom_fname, output_fname, format) ⇒ Object
Apply custom filename pattern with substitutions
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 43 def apply_custom_filename_pattern(ident, custom_fname, output_fname, format) idx = @files.get(ident, :idx) original_file = @files.get(ident, :ref) basename = File.basename(original_file, ".*") basename_legacy = File.basename(original_file) custom_fname = @files.substitute_filename_pattern( custom_fname, document_num: idx, basename: basename, basename_legacy: basename_legacy ) if File.dirname(custom_fname) == "." output_fname else preserve_output_dir_structure(custom_fname, output_fname, format, explicit_custom: true) end end |
#apply_directory_preservation(fname, output_fname, format) ⇒ Object
Apply directory preservation for files with directory structure
62 63 64 65 66 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 62 def apply_directory_preservation(fname, output_fname, format) fname_dir = File.dirname(fname) output_fname = File.join(fname_dir, output_fname) preserve_output_dir_structure(fname, output_fname, format) end |
#bilingual_output(options, pres) ⇒ Object
285 286 287 288 289 290 291 292 293 294 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 285 def bilingual_output(, pres) @directives.detect { |d| d.key == "bilingual" } && [:format].include?(:html) and Metanorma::Collection::Multilingual.new( { flavor: Util::taste2flavor(flavor).to_sym, converter_options: PdfOptionsNode.new(Util::taste2flavor(flavor), @compile_options), outdir: @outdir }, ).to_html(pres) end |
#build_indexfile1(mnf) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 80 def build_indexfile1(mnf) Nokogiri::HTML::Builder.new do |b| if mnf.file then docrefs(mnf, b) else b.li do |l| l << indexfile_title(mnf) l.ul do |u| Array(mnf.entry).each { |e| u << indexfile1(e) } end end end end end |
#cleanup_indexfile1(ret) ⇒ Object
94 95 96 97 98 99 100 101 102 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 94 def cleanup_indexfile1(ret) ret = ret.doc.root ret.xpath("/ul").each do |u| if u.at("./li/ul") && !u.at("./li[text()]") u.replace(u.xpath("./li/ul")) end end ret.to_html end |
#collect_erefs(docxml, presxml) ⇒ Object
60 61 62 63 64 65 66 67 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 60 def collect_erefs(docxml, presxml) tag = presxml ? "fmt-eref" : "eref" docxml.xpath(ns("//#{tag}")) .each_with_object({ citeas: {}, bibitemid: {} }) do |i, m| m[:citeas][i["citeas"]] = true m[:bibitemid][i["bibitemid"]] = true end end |
#collection_coverpages(conv, docs) ⇒ Object
74 75 76 77 78 79 80 81 82 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 74 def collection_coverpages(conv, docs) conv.wordintropage and [DIV2, SECTION_BREAK].reverse_each do |s| docs.unshift(Nokogiri::XML(s).root) end conv.wordcoverpage and [DIV1, SECTION_BREAK].reverse_each do |s| docs.unshift(Nokogiri::XML(s).root) end docs end |
#compile_options_base(identifier) ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 78 def (identifier) e = @files.get(identifier, :extract_opts) { format: :asciidoc, extension_keys: @files.get(identifier, :format), fonts: e&.dig(:fonts), output_dir: @outdir, pdffile: @files.get(identifier, :pdffile), type: Util::taste2flavor(@flavor), } end |
#compile_options_update(identifier) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 90 def (identifier) ret = @compile_options.dup @directives.detect { |d| d.key == "presentation-xml" } || @files.get(identifier, :presentationxml) and ret.merge!(passthrough_presentation_xml: true) @files.get(identifier, :sectionsplit) == true and ret.merge!(sectionsplit: true) @files.get(identifier, :bare) == true and ret.merge!(bare: true) ret end |
#concat_extract_files(filename) ⇒ Object
13 14 15 16 17 18 19 20 21 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 13 def concat_extract_files(filename) xml = Nokogiri::XML(File.read(filename, encoding: "UTF-8"), &:huge) docs = xml.xpath(ns("//doc-container")).each_with_object([]) do |x, m| n = Nokogiri::XML::Document.new n.add_child(x.elements.first.remove) m << n end [wrapping_doc(docs.first.dup, xml), docs] end |
#concatenate(col, options) ⇒ Object
204 205 206 207 208 209 210 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 204 def concatenate(col, ) warn "\n\n\n\n\nConcatenate: #{DateTime.now.strftime('%H:%M:%S')}" concatenate_presentation?() and [:format] << :presentation concatenate_prep(col, ) concatenate_outputs() end |
#concatenate1(out, ext) ⇒ Object
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 296 def concatenate1(out, ext) out.directives << ::Metanorma::Collection::Config::Directive .new(key: "documents-inline") out.bibdatas.each_key do |ident| id = @isodoc.docid_prefix(nil, ident.dup) @files.get(id, :attachment) and next # A non-attachment document with no compiled output for THIS format # cannot be inlined: leaving it in place serialises as a bibdata-only, # namespace-less <metanorma> that mn2pdf silently drops. Skip loudly # rather than crash on a nil path or corrupt the collection PDF. # (Sectionsplit parents get a :presentation output upstream, so they # inline whole for the PDF/presentation path.) outputs = @files.get(id, :outputs) # The registered path may exist without the file: a member whose # rendering failed registers its intended outputs but writes # nothing (#586), so check the disk, not just the registration. if outputs.nil? || outputs[ext].nil? || !File.exist?(outputs[ext]) warn "[metanorma] collection document '#{id}' has no compiled " \ "#{ext} output to inline; skipping (its doc-container would " \ "otherwise be bibdata-only)." next end out.documents[Util::key id] = Metanorma::Collection::Document.raw_file(outputs[ext]) end out end |
#concatenate_outputs(options) ⇒ Object
238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 238 def concatenate_outputs() pres, compile_opts = concatenate_outputs_prep() warn pp compile_opts [:format].include?(:pdf) and pdfconv(compile_opts).convert(pres) [:format].include?(:"pdf-portfolio") and pdfconv() .convert(pres, nil, nil, File.join(@outdir, "collection.portfolio.pdf")) [:format].include?(:doc) and docconv_convert(pres) bilingual_output(, pres) end |
#concatenate_outputs_prep(_options) ⇒ Object
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 250 def concatenate_outputs_prep() pres = File.join(@outdir, "collection.presentation.xml") fonts = extract_added_fonts(pres) if fonts # Install fonts before trying to locate them = @compile_options.merge({ fonts: fonts }) ::Metanorma::Util::FontistHelper.install_fonts(@compile.processor, ) mn2pdf = { font_manifest: ::Metanorma::Util::FontistHelper .location_manifest(@compile.processor, { fonts: fonts }), } end [pres, { fonts: fonts, mn2pdf: mn2pdf }.compact] end |
#concatenate_prep(col, options) ⇒ Object
218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 218 def concatenate_prep(col, ) warn [:format] %i(xml presentation).each do |e| [:format].include?(e) or next ext = e == :presentation ? "presentation.xml" : e.to_s File.open(File.join(@outdir, "collection.#{ext}"), "w:UTF-8") do |f| b = concatenate1(col.clone, e).to_xml e == :presentation and b = concatenate_presentation(b) f.write(b) end end end |
#concatenate_presentation(xml) ⇒ Object
231 232 233 234 235 236 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 231 def concatenate_presentation(xml) @directives.detect { |d| d.key == "bilingual" } and xml = Metanorma::Collection::Multilingual .new({ align_cross_elements: %w(p note) }).to_bilingual(xml) xml end |
#concatenate_presentation?(options) ⇒ Boolean
212 213 214 215 216 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 212 def concatenate_presentation?() !([:format] & %i(pdf doc)).empty? || (@directives.detect { |d| d.key == "bilingual" } && [:format].include?(:html)) end |
#copy_file_to_dest(identifier) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 153 def copy_file_to_dest(identifier) out = Pathname.new(@files.get(identifier, :out_path)).cleanpath out.absolute? and out = out.relative_path_from(File.(FileUtils.pwd)) dest = File.join(@outdir, @disambig.source2dest_filename(out.to_s, preserve_dirs: true)) FileUtils.mkdir_p(File.dirname(dest)) source = @files.get(identifier, :ref) source != dest and FileUtils.cp_r source, dest, remove_destination: true end |
#coverpage ⇒ Object
populate liquid template of ARGV with metadata extracted from collection manifest
332 333 334 335 336 337 338 339 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 332 def coverpage @coverpage or return @coverpage_path = Util::rel_path_resolve(@dirname, @coverpage) warn "\n\n\n\n\nCoverpage: #{DateTime.now.strftime('%H:%M:%S')}" File.open(File.join(@outdir, "index.html"), "w:UTF-8") do |f| f.write @isodoc.populate_template(File.read(@coverpage_path)) end end |
#custom_basename_with_extension(fname, output_basename) ⇒ Object
Generate custom basename with extension
123 124 125 126 127 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 123 def custom_basename_with_extension(fname, output_basename) custom_basename = File.basename(fname, ".*") ext = File.extname(output_basename) "#{custom_basename}#{ext}" end |
#deep_detached_clone(node) ⇒ Object
25 26 27 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 25 def deep_detached_clone(node) Nokogiri::XML(node.to_xml).root end |
#dir_name_cleanse(name) ⇒ Object
6 7 8 9 10 11 12 13 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 6 def dir_name_cleanse(name) path = Pathname.new(name) clean_regex = /[<>:"|?*\p{Zs}]/ fallback_sym = "_" path.absolute? or return name.gsub(clean_regex, fallback_sym) File.join(path.dirname, path.basename.to_s.gsub(clean_regex, fallback_sym)) end |
#directives_normalise(directives) ⇒ Object
142 143 144 145 146 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 142 def directives_normalise(directives) @coverpage_pdf_portflio and directives = directives_normalise_coverpage_pdf_portfolio(directives) directives_normalise_keystore_pdf_portfolio(directives) end |
#directives_normalise_coverpage_pdf_portfolio(directives) ⇒ Object
148 149 150 151 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 148 def directives_normalise_coverpage_pdf_portfolio(directives) directives_resolve_filepath(directives, "coverpage-pdf-portfolio", @coverpage_pdf_portflio) end |
#directives_normalise_keystore_pdf_portfolio(directives) ⇒ Object
153 154 155 156 157 158 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 153 def directives_normalise_keystore_pdf_portfolio(directives) f = directives.find { |d| d.key == "keystore-pdf-portfolio" } f.nil? || f.value.nil? and return directives directives_resolve_filepath(directives, "keystore-pdf-portfolio", f.value) end |
#directives_resolve_filepath(directives, name, val) ⇒ Object
160 161 162 163 164 165 166 167 168 169 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 160 def directives_resolve_filepath(directives, name, val) abs = Pathname.new(val).absolute? directives.reject! { |d| d.key == name } val = Util::rel_path_resolve(@dirname, val) abs or val = Pathname.new(val).relative_path_from(Pathname.new(@outdir)).to_s directives << ::Metanorma::Collection::Config::Directive .new(key: name, value: val) directives end |
#docconv(added_options = {}) ⇒ Object
4 5 6 7 8 9 10 11 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 4 def docconv( = {}) @tempfile_cache ||= [] flavor = Util::taste2flavor(@flavor).to_sym opts = Util::taste2isodoc_attrs(@flavor, :doc) x = Asciidoctor.load nil, backend: flavor x.converter.doc_converter(DocOptionsNode.new(@directives, @dirname, .merge(opts))) end |
#docconv_convert(filename) ⇒ Object
84 85 86 87 88 89 90 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 84 def docconv_convert(filename) pref_file, docs = concat_extract_files(filename) body = docconv_convert1(docs) collection_conv = overall_docconv_converter(body) collection_coverpages(collection_conv, body) collection_conv.convert(filename, pref_file.to_xml, false) end |
#docconv_convert1(docs) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 61 def docconv_convert1(docs) docs.each_with_index.with_object([]) do |(d, i), m| conv = docconv conv.convert_init(d.to_xml(encoding: "UTF-8"), "xxxx", false) html = conv.postprocess_cleanup(conv.convert1(d, "xxx", ".")) @tempfile_cache += conv.tempfile_cache # hold on to the temp img files b = Nokogiri::XML(html).at("//body") i == docs.size - 1 or b << '<p class="MsoNormal"><br clear="all" class="section"/></p>' m << b.children end end |
#docid_to_citeas(bib) ⇒ Object
54 55 56 57 58 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 54 def docid_to_citeas(bib) docid = bib.at(ns("./docidentifier[@primary = 'true']")) || bib.at(ns("./docidentifier")) or return ::Metanorma::Collection::Util::key(docid_prefix(docid)) end |
#docid_xml(val) ⇒ Object
69 70 71 72 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 69 def docid_xml(val) "<docidentifier type='repository'>current-metanorma-collection/" \ "#{val}</docidentifier>" end |
#docref_ident(docref) ⇒ Object
37 38 39 40 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 37 def docref_ident(docref) ident = docref.identifier.dup @c.decode(@isodoc.docid_prefix(nil, ident)) end |
#docrefs(mnf, builder) ⇒ Object
26 27 28 29 30 31 32 33 34 35 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 26 def docrefs(mnf, builder) ident = docref_ident(mnf) builder.li do |li| li.a href: index_link(mnf, ident) do |a| a << ident.split(/([<>&])/).map do |x| /[<>&]/.match?(x) ? x : @c.encode(x, :hexadecimal) end.join end end end |
#document_ref_html(identifier) ⇒ Object
Use :outputs if available (after compilation), otherwise convert :out_path to HTML (before compilation), following ref_file_xml2html.
309 310 311 312 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 309 def document_ref_html(identifier) @files.get(identifier, :outputs)&.dig(:html) || out_path_to_html(@files.get(identifier, :out_path)) end |
#dup_bibitem(docid, bib) ⇒ Object
15 16 17 18 19 20 21 22 23 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 15 def dup_bibitem(docid, bib) newbib = deep_detached_clone(@files.get(docid, :bibdata)) newbib.name = "bibitem" newbib["hidden"] = "true" newbib&.at("./*[local-name() = 'ext']")&.remove newbib["id"] = bib["id"] bib["anchor"] and newbib["anchor"] = bib["anchor"] newbib end |
#extract_added_fonts(pres) ⇒ Object
267 268 269 270 271 272 273 274 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 267 def extract_added_fonts(pres) File.exist?(pres) or return xml = Nokogiri::XML(File.read(pres, encoding: "UTF-8"), &:huge) x = xml.xpath("//*[local-name() = 'presentation-metadata']/" \ "*[local-name() = 'fonts']") x.empty? and return x.map(&:text).join(";") end |
#file_compile(file, filename, identifier) ⇒ Object
compile and output individual file in collection warn "metanorma compile -x html #Metanorma::Collection::Renderer.ff.path"
15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 15 def file_compile(file, filename, identifier) sectionsplit_val = @files.get(identifier, :sectionsplit) sectionsplit_val and return opts = (identifier) .merge((identifier)) err_count = @compile.errors.size @compile.compile file, opts @files.set(identifier, :outputs, {}) file_compile_formats(filename, identifier, opts) file_compile_verify(identifier, @compile.errors[err_count..] || []) end |
#file_compile_failure_log(identifier, errors, missing) ⇒ Object
60 61 62 63 64 65 66 67 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 60 def file_compile_failure_log(identifier, errors, missing) missing.each_value do |path| @log&.add("METANORMA_4", nil, params: [identifier, path]) end errors.each do |e| @log&.add("METANORMA_5", nil, params: [identifier, e]) end end |
#file_compile_failure_msg(identifier, errors, missing) ⇒ Object
69 70 71 72 73 74 75 76 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 69 def file_compile_failure_msg(identifier, errors, missing) ret = [] missing.empty? or ret << "expected output not generated: " \ "#{missing.values.join(', ')}" ret += errors "Failed to render collection member #{identifier}: #{ret.join('; ')}" end |
#file_compile_format(fname, ident, format, outputs, new_output_fname) ⇒ Object
Compile single format for a file and update outputs hash
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 69 def file_compile_format(fname, ident, format, outputs, new_output_fname) ext = @compile.processor.output_formats[format] output_fname = output_filename_with_extension(fname, format) output_fname = handle_new_output_filename(output_fname, new_output_fname) if !new_output_fname && (custom = @files.preserve_directory_structure?(ident)) output_fname = apply_custom_filename_pattern(ident, custom, output_fname, format) elsif !new_output_fname && File.dirname(fname) != "." output_fname = apply_directory_preservation(fname, output_fname, format) end should_skip = /html$/.match?(ext) && @files.get(ident, :sectionsplit) should_skip or outputs[format] = File.join(@outdir, output_fname) end |
#file_compile_formats(filename, identifier, opts) ⇒ Object
6 7 8 9 10 11 12 13 14 15 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 6 def file_compile_formats(filename, identifier, opts) f = @files.get(identifier, :outputs) format = opts[:extension_keys] concatenate_presentation?({ format: }) and format << :presentation format.each do |e| e == :pdf and output_filename = opts[:pdffile] file_compile_format(filename, identifier, e, f, output_filename) end @files.set(identifier, :outputs, f) end |
#file_compile_verify(identifier, errors) ⇒ Object
A member whose rendering raised produces no output file, but the collection build used to continue, exit 0, and link the absent document from index.html -- silent data loss (#586). Two complementary checks close that hole. (1) Compile pools rescued error messages in @compile.errors for its caller to surface; the standalone CLI does, but the collection pipeline never read the pool. The pool is shared across members and never reset, so the slice appended during this member's compile is this member's errors -- sound while members compile sequentially (the current design; @compile's own format-level parallelism is joined before compile returns). (2) Independently of whether anything was pooled, verify the outputs registered for the member exist on disk. Failures are reported here and accumulated; the collection renders every remaining member before Collection#render aborts, so one run reports all failed members.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 43 def file_compile_verify(identifier, errors) # Section-split parts (marked with :parentid) register format # slots they never produce -- their :xml slot in particular is # never written, and under filename renaming it aliases to the # parent's name -- so verifying them is a false positive. #586 # was scoped to the non-sectionsplit path; parts are excluded # like their parents (which return early above). @files.get(identifier, :parentid) and return missing = (@files.get(identifier, :outputs) || {}) .reject { |_fmt, path| File.exist?(path) } errors.empty? && missing.empty? and return file_compile_failure_log(identifier, errors, missing) msg = file_compile_failure_msg(identifier, errors, missing) ::Metanorma::Util.log("[metanorma] Error: #{msg}", :error) fatal_errors << msg end |
#files ⇒ Object
process each file in the collection files are held in memory, and altered as postprocessing
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 113 def files # rubocop:disable Metrics/AbcSize, Metrics/MethodLength warn "\n\n\n\n\nRender Files: #{DateTime.now.strftime('%H:%M:%S')}" internal_refs = locate_internal_refs @files.keys.each_with_index do |ident, i| i.positive? && @directives.detect do |d| d.key == "bare-after-first" end and @compile_options.merge!(bare: true) if @files.get(ident, :attachment) then copy_file_to_dest(ident) else file, fname = @files.targetfile_id(ident, read: true) @preserve_unresolved && member_stored?(ident, file) and next warn "\n\n\n\n\nProcess #{fname}: #{DateTime.now.strftime('%H:%M:%S')}" collection_xml = update_xrefs(file, ident, internal_refs) @preserve_unresolved and store_member_artefacts(ident, file, collection_xml) # Strip .xml or .html extension, but NOT section numbers like .0 fname_base = File.basename(fname) collection_filename = fname_base /\.(xml|html)$/.match?(fname_base) and collection_filename = fname_base.sub(/\.(xml|html)$/, "") collection_xml_path = File.join(Dir.tmpdir, "#{collection_filename}.xml") File.write collection_xml_path, collection_xml, encoding: "UTF-8" file_compile(collection_xml_path, fname, ident) FileUtils.rm_f(collection_xml_path) end end end |
#flavor ⇒ Object
TODO: infer flavor from publisher when available
325 326 327 328 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 325 def flavor dt = @xml.at("//bibdata/ext/flavor")&.text or return "standoc" @registry.alias(dt.to_sym)&.to_s || dt end |
#flush_files ⇒ Object
171 172 173 174 175 176 177 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 171 def flush_files warn "\n\n\n\n\nDone: #{DateTime.now.strftime('%H:%M:%S')}" warn "\nFiles to delete:\n" warn @files.files_to_delete @files.files_to_delete.each { |f| FileUtils.rm_f(f) } @files_to_delete.each { |f| FileUtils.rm_f(f) } end |
#gather_internal_refs ⇒ Object
gather internal bibitem references
169 170 171 172 173 174 175 176 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 169 def gather_internal_refs @files.keys.each_with_object({}) do |i, refs| @files.get(i, :attachment) and next @files.get(i, :sectionsplit) and next file, = @files.targetfile_id(i, read: true) gather_internal_refs1(file, i, refs) end end |
#gather_internal_refs1(file, ident, refs) ⇒ Object
178 179 180 181 182 183 184 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 178 def gather_internal_refs1(file, ident, refs) f = Nokogiri::XML(file, &:huge) !@files.get(ident, :sectionsplit) and gather_internal_refs_indirect(f, refs) key = @files.get(ident, :indirect_key) and gather_internal_refs_sectionsplit(f, ident, key, refs) end |
#gather_internal_refs_indirect(doc, refs) ⇒ Object
186 187 188 189 190 191 192 193 194 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 186 def gather_internal_refs_indirect(doc, refs) doc.xpath(ns("//bibitem[@type = 'internal']/" \ "docidentifier[@type = 'repository']")).each do |d| a = d.text.split(%r{/}, 2) a.size > 1 or next refs[a[0]] ||= {} refs[a[0]][a[1]] = false end end |
#gather_internal_refs_sectionsplit(_doc, ident, key, refs) ⇒ Object
196 197 198 199 200 201 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 196 def gather_internal_refs_sectionsplit(_doc, ident, key, refs) refs[key] ||= {} @files.get(ident, :ids).each_key do |k| refs[key][k] = false end end |
#get_bibitem_docid(bib, identifier) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 29 def get_bibitem_docid(bib, identifier) docid = bib.at(ns("./docidentifier[@type = 'metanorma-collection']")) || bib.at(ns("./docidentifier[not(@type)]")) || bib.at(ns("./docidentifier")) docid &&= docid_prefix(docid) if @files.get(docid) then docid else fail_update_bibitem(docid, identifier) nil end end |
#handle_existing_destination(output_with_dir, output_src) ⇒ Object
Handle case where destination already exists
111 112 113 114 115 116 117 118 119 120 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 111 def handle_existing_destination(output_with_dir, output_src) output_dest = File.join(@outdir, output_with_dir) return nil unless File.exist?(output_dest) return output_with_dir unless File.exist?(output_src) FileUtils.rm_f(output_src) err_src = output_src.sub(/\.html$/, ".err.html") FileUtils.rm_f(err_src) if File.exist?(err_src) output_with_dir end |
#handle_new_output_filename(output_fname, new_output_fname) ⇒ Object
Move file to new output filename if specified. A member that failed to render has nothing to move: keep the original name registered so output verification reports it as missing, rather than crashing the whole collection on the mv (#586).
33 34 35 36 37 38 39 40 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 33 def handle_new_output_filename(output_fname, new_output_fname) return output_fname unless new_output_fname src = File.join(@outdir, output_fname) File.exist?(src) or return output_fname FileUtils.mv(src, File.join(@outdir, new_output_fname)) new_output_fname end |
#index?(mnf) ⇒ Boolean
70 71 72 73 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 70 def index?(mnf) mnf.index and return true mnf.entry&.detect { |e| index?(e) } end |
#index_link(docref, ident) ⇒ Object
Check if file has a recognized MIME type (other than XML) If so, don't append .html (e.g., .svg, .png, .jpg, etc.)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 44 def index_link(docref, ident) if docref.file out_path = @files.get(ident, :out_path) # Ensure the path ends with .html for documents, but not for recognized file types if Util::mime_file_recognised?(out_path) && !out_path.end_with?(".xml") # File has a recognized extension (like .svg, .png), keep it as is out_path elsif out_path.end_with?(".xml") out_path.sub(/\.xml$/, ".html") elsif out_path.end_with?(".html") out_path else "#{out_path}.html" end else "#{docref.id}.html" end end |
#index_object(mnf) ⇒ Object
object to construct navigation out of in Liquid
105 106 107 108 109 110 111 112 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 105 def index_object(mnf) mnf = Array(mnf).first ret = { title: indexfile_title(mnf), level: mnf.type, docrefs: index_object_docrefs(mnf), children: index_object_children(mnf) }.compact ret.keys == [:children] and ret = ret[:children] ret end |
#index_object_children(mnf) ⇒ Object
114 115 116 117 118 119 120 121 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 114 def index_object_children(mnf) nonfiles = Array(mnf.entry).reject(&:file) c = nonfiles.each_with_object([]) do |d, b| b << index_object(d) end.flatten c.empty? and c = nil c end |
#index_object_docrefs(mnf) ⇒ Object
123 124 125 126 127 128 129 130 131 132 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 123 def index_object_docrefs(mnf) files = Array(mnf.entry).select(&:file) files.empty? and return nil r = Nokogiri::HTML::Builder.new do |b| b.ul do |u| files.each { |f| docrefs(f, u) } end end r.doc.root&.to_html&.tr("\n", " ") end |
#indexfile(mnf) ⇒ Object
single level navigation list, with hierarchical nesting
64 65 66 67 68 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 64 def indexfile(mnf) mnfs = Array(mnf) mnfs.empty? and return "" mnfs.map { |m| "<ul>#{indexfile1(m)}</ul>" }.join("\n") end |
#indexfile1(mnf) ⇒ Object
75 76 77 78 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 75 def indexfile1(mnf) index?(mnf) or return "" cleanup_indexfile1(build_indexfile1(mnf)) end |
#indexfile_docref(mnf, builder) ⇒ Object
uses the identifier to label documents; other attributes (title) can be looked up in @files[:bibdata]
21 22 23 24 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 21 def indexfile_docref(mnf, builder) Array(mnf.entry).detect(&:index) or return "" builder.ul { |b| docrefs(mnf, b) } end |
#indexfile_title(entry) ⇒ String
6 7 8 9 10 11 12 13 14 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 6 def indexfile_title(entry) titles = entry.bibdata && Array(entry.bibdata.title) if titles && !titles.empty? && (x = titles.detect { |t| t.type == "main" } || titles.first) x.content else entry.title end end |
#indirect_ref_key(schema, id, doc_suffix, add_suffix) ⇒ Object
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 182 def indirect_ref_key(schema, id, doc_suffix, add_suffix) /^#{schema}_/.match?(id) and return id x = @indirect_keys.dig(schema, id) and return x @indirect_keys[schema] ||= {} @indirect_keys[schema][id] = if add_suffix "#{schema}_#{id}_#{doc_suffix}" else "#{schema}_#{id}" end end |
#liquid_docrefs(mnfs) ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/metanorma/collection/renderer/navigation.rb', line 134 def liquid_docrefs(mnfs) Array(mnfs).select(&:index).each_with_object([]) do |d, m| if d.file ident = @c.decode(@isodoc.docid_prefix(nil, d.identifier.dup)) m << { "identifier" => ident, "file" => index_link(d, ident), "title" => indexfile_title(d), "level" => d.type } else liquid_docrefs(d.entry).each { |m1| m << m1 } end end end |
#locate_internal_refs ⇒ Object
resolve file location for the target of each internal reference
214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 214 def locate_internal_refs warn "\n\n\n\n\nInternal Refs: #{DateTime.now.strftime('%H:%M:%S')}" refs = populate_internal_refs(gather_internal_refs) refs.each do |schema, ids| ids.each do |id, key| key and next refs[schema][id] = "Missing:#{schema}:#{id}" @log&.add("METANORMA_1", nil, params: [refs[schema][id]]) end end refs end |
#locate_internal_refs1(refs, identifier, ident) ⇒ Object
227 228 229 230 231 232 233 234 235 236 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 227 def locate_internal_refs1(refs, identifier, ident) file, = @files.targetfile_id(ident, read: true) t = locate_internal_refs1_prep(file) refs.each do |schema, ids| ids.keys.select { |id| t[id] }.each do |id| t[id].at("./ancestor-or-self::*[@type = '#{schema}']") and refs[schema][id] = identifier end end end |
#locate_internal_refs1_prep(file) ⇒ Object
238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 238 def locate_internal_refs1_prep(file) xml = Nokogiri::XML(file, &:huge) r = xml.root["document_suffix"] ret = xml.xpath("//*[@id]").each_with_object({}) do |i, x| x[i["id"]] = i r and x[i["id"].sub(/_#{r}$/, "")] = i end xml.xpath("//*[@anchor]").each do |i| ret[i["anchor"]] = i r and ret[i["anchor"].sub(/_#{r}$/, "")] = i end ret end |
#make_relative_path(from_file, to_file) ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 91 def make_relative_path(from_file, to_file) return to_file if to_file.nil? || to_file.to_s.empty? return to_file if to_file.start_with?("http://", "https://", "#") from_dir = File.dirname(from_file) return to_file if from_dir == "." from_path = Pathname.new(from_dir) to_path = Pathname.new(to_file) to_path.relative_path_from(from_path).to_s end |
#member_content_hash(source) ⇒ Object
Persist an isolated member's stub-bearing Semantic XML and its anchor contribution to the content-addressed store, so a later reinflation pass can relink the stubs and a re-run can resume without recompiling. Within-campaign content key for a member. (Cross-build soundness needs the full input closure -- source + includes + templates + schemas + versions; see the plan gotcha. Here the source bytes + tool version suffice because inputs are frozen across a single build campaign.)
150 151 152 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 150 def member_content_hash(source) ArtifactStore.content_hash(source, ::Metanorma::VERSION) end |
#member_stored?(ident, source) ⇒ Boolean
Resume predicate: is this member already compiled and stored for its current input content? If so the isolated compile can skip it.
156 157 158 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 156 def member_stored?(ident, source) @artifact_store.key?(ident, member_content_hash(source), :semantic) end |
#move_file_to_subdirectory(fname_dir, output_basename) ⇒ Object
Move file from root to subdirectory
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 99 def move_file_to_subdirectory(fname_dir, output_basename) output_with_dir = File.join(fname_dir, output_basename) output_dest = File.join(@outdir, output_with_dir) output_src = File.join(@outdir, output_basename) return nil unless File.exist?(output_src) && output_src != output_dest FileUtils.mkdir_p(File.dirname(output_dest)) FileUtils.mv(output_src, output_dest) output_with_dir end |
#new_hidden_ref(xml) ⇒ Object
42 43 44 45 46 47 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 42 def new_hidden_ref(xml) ins = xml.at(ns("bibliography")) or xml.root << "<bibliography/>" and ins = xml.at(ns("bibliography")) ins.at(ns("./references[@hidden = 'true']")) or ins.add_child("<references hidden='true' normative='false'/>").first end |
#out_path_to_html(out_path) ⇒ Object
314 315 316 317 318 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 314 def out_path_to_html(out_path) out_path or return nil out_path.end_with?(".xml") and return out_path.sub(/\.xml$/, ".html") "#{out_path}.html" end |
#output_filename_with_extension(fname, format) ⇒ Object
Generate output filename with correct extension
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 18 def output_filename_with_extension(fname, format) ext = @compile.processor.output_formats[format] fname_base = File.basename(fname) # ONLY replace .xml or .html extensions, NEVER remove section numbers if /\.(xml|html)$/.match?(fname_base) fname_base.sub(/\.(xml|html)$/, ".#{ext}") else "#{fname_base}.#{ext}" end end |
#overall_docconv_converter(body) ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 101 def overall_docconv_converter(body) collection_conv = docconv collection_conv.[:collection_doc] = body.map(&:to_xml).join overall_docconv_cover(collection_conv) def collection_conv.postprocess_cleanup(result) ret = to_xhtml(super) b = ret.at("//div[@id = '_collection_placeholder']") b.replace(@options[:collection_doc]) from_xhtml(ret) end collection_conv end |
#overall_docconv_cover(collection_conv) ⇒ Object
92 93 94 95 96 97 98 99 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 92 def overall_docconv_cover(collection_conv) p = Util::hash_key_detect(@directives, "collection-word-coverpage", nil) collection_conv.wordcoverpage = Util::rel_path_resolve(@dirname, p) p = Util::hash_key_detect(@directives, "collection-word-intropage", nil) collection_conv.wordintropage = Util::rel_path_resolve(@dirname, p) end |
#pdf_portfolio_mn2pdf_options ⇒ Object
276 277 278 279 280 281 282 283 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 276 def f1 = @directives.find { |d| d.key == "keystore-pdf-portfolio" }&.value f2 = @directives.find do |d| d.key == "keystore-password-pdf-portfolio" end&.value { "pdf-portfolio": "true", pdfkeystore: f1, pdfkeystorepassword: f2 }.compact end |
#populate_internal_refs(refs) ⇒ Object
203 204 205 206 207 208 209 210 211 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 203 def populate_internal_refs(refs) @files.keys.reject do |k| @files.get(k, :attachment) || @files.get(k, :sectionsplit) end.each do |ident| locate_internal_refs1(refs, ident, @isodoc.docid_prefix("", ident.dup)) end refs end |
#preserve_output_dir_structure(fname, output_fname, format = nil, explicit_custom: false) ⇒ Object
Preserve directory structure from input filename in output
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 130 def preserve_output_dir_structure(fname, output_fname, format = nil, explicit_custom: false) fname_dir = File.dirname(fname) return output_fname if fname_dir == "." output_basename = File.basename(output_fname) ext = format ? @compile.processor.output_formats[format].to_s : "" should_move = should_move_to_subdirectory?(ext, output_basename, explicit_custom) if should_move result = move_file_to_subdirectory(fname_dir, output_basename) return result if result handle_existing_destination(File.join(fname_dir, output_basename), File.join(@outdir, output_basename)) || output_fname elsif explicit_custom custom_basename_with_extension(fname, output_basename) else output_basename end end |
#referencing_html_location(identifier, attachment) ⇒ Object
Location of the HTML that will carry the cross-reference to the target, used as the base for relativising the attachment/citation URL.
Normally this is the referencing document's own output (:outputs after compilation, else :out_path converted to .html before it).
But when the referencing document is sectionsplit, its content is not emitted at its own out_path: it is split into section files written at the sectionsplit output location (the collection root, unless a sectionsplit_filename directory is configured). Relativising an attachment URL against the unsplit out_path then overshoots -- the ../../ climbs above the split file and the attachment link breaks (https://github.com/metanorma/iso-10303/issues/208). So for attachment targets of a sectionsplit document, base the relative path on the sectionsplit output directory instead.
294 295 296 297 298 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 294 def referencing_html_location(identifier, ) && @files.get(identifier, :sectionsplit) and return sectionsplit_ref_html(identifier) document_ref_html(identifier) end |
#rxl(options) ⇒ Object
195 196 197 198 199 200 201 202 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 195 def rxl() @bibdata or return [:site_generate] and [:format] << :xml [:format].include?(:rxl) or return File.open(File.join(@outdir, "collection.rxl"), "w:UTF-8") do |f| f.write(@bibdata.to_xml(bibdata: true)) end end |
#sectionsplit_ref_html(identifier) ⇒ Object
The split section files sit at the sectionsplit output directory: the collection root, or the directory of a configured sectionsplit_filename.
302 303 304 305 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 302 def sectionsplit_ref_html(identifier) d = @files.preserve_directory_structure?(identifier) d ? File.join(File.dirname(d), "x.html") : "x.html" end |
#set_displayorder_wrapping_doc(doc) ⇒ Object
48 49 50 51 52 53 54 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 48 def set_displayorder_wrapping_doc(doc) doc.xpath(ns("//preface/* | //sections/* | //annex")) .each_with_index do |x, i| x["displayorder"] = i + 1 end doc end |
#should_move_to_subdirectory?(ext, output_basename, explicit_custom) ⇒ Boolean
Determine if file should be moved to subdirectory
86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/metanorma/collection/renderer/filelocation.rb', line 86 def should_move_to_subdirectory?(ext, output_basename, explicit_custom) if explicit_custom # For explicit output-filename: move html, doc, pdf, presentation.xml ext.end_with?("html") || ext == "doc" || ext == "pdf" || output_basename.end_with?(".presentation.xml") else # Default: only HTML and presentation files ext.end_with?("html") || output_basename.end_with?(".html", ".presentation.xml") end end |
#store_member_artefacts(ident, source, semantic_xml) ⇒ Object
160 161 162 163 164 165 166 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 160 def store_member_artefacts(ident, source, semantic_xml) hash = member_content_hash(source) @artifact_store.write(ident, hash, :semantic, semantic_xml) @artifact_store.write(ident, hash, :anchors, JSON.generate(@files.get(ident, :anchors) || {})) @keep_cache or @artifact_store.prune_superseded(ident, hash) end |
#strip_eref(eref) ⇒ Object
49 50 51 52 |
# File 'lib/metanorma/collection/renderer/utils.rb', line 49 def strip_eref(eref) eref.xpath(ns("./locality | ./localityStack")).each(&:remove) eref.replace(eref.children) end |
#strip_unresolved_repo_erefs(_document_id, bib_docid, erefs, bibitem) ⇒ Object
strip erefs if they are repository erefs, but do not point to a document within the current collection. This can happen if a collection consists of many documents, but not all are included in the current collection. Do not do this if this is a sectionsplit collection or a nested manifest. Return false if bibitem is not to be further processed
145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 145 def strip_unresolved_repo_erefs(_document_id, bib_docid, erefs, bibitem) if %r{^current-metanorma-collection/(?!Missing:)}.match?(bib_docid.text) # Isolated build: keep the cross-document ref as a stub (its bibitemid # and repository docidentifier intact) for a later reinflation pass to # relink, rather than resolving it now against an absent target. @preserve_unresolved and return false return true end @nested and return false erefs[bibitem["id"]]&.each { |x| x.parent and strip_eref(x) } false end |
#suffix_anchor_indirect(prefix, suffix) ⇒ Object
encode both prefix and suffix to NCName
249 250 251 252 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 249 def suffix_anchor_indirect(prefix, suffix) k = "#{prefix}_#{suffix}" @ncnames[k] ||= Metanorma::Utils::to_ncname(k) end |
#supply_repo_ids(doc) ⇒ Object
94 95 96 97 98 99 100 101 102 103 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 94 def supply_repo_ids(doc) doc.xpath(ns(BIBITEM_NOT_REPO_XPATH)).each do |b| b.xpath(ns("./docidentifier")).each do |docid| id = @isodoc.docid_prefix(docid["type"], docid.children.to_xml) @files.get(id) or next @files.get(id, :indirect_key) and next # will resolve as indirect key docid.next = docid_xml(id) end end end |
#svg_datauri(docxml, docid) ⇒ Object
Converts SVG images to data URIs for inline embedding
5 6 7 8 9 10 11 12 |
# File 'lib/metanorma/collection/renderer/svg.rb', line 5 def svg_datauri(docxml, docid) rel = @files.get(docid, :rel_path) parent = @files.get(docid, :parentid) and rel = @files.get(parent, :rel_path) # if sectionsplit, use orig file dir dir = File.join(@dirname, File.dirname(rel)) datauri_encode(docxml, dir) end |
#svgmap_resolve(docxml, docid, presxml) ⇒ Object
Resolves SVG map references and processes SVG ID disambiguation.
Delegates SVG manipulation to Vectory gem, which handles:
- Document-level suffixing for cross-document ID disambiguation
- Index-based suffixing for multiple svgmaps within one document
- Link remapping and SVG extraction
Metanorma's role: State requirements and coordinate the workflow. Vectory's role: Handle all SVG ID manipulation internally.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/metanorma/collection/renderer/svg.rb', line 27 def svgmap_resolve(docxml, docid, presxml) ids, docxml, isodoc, tag = svgmap_resolve_prep(docxml, docid, presxml) # Stage 1: Resolve EREF references to their targets resolve_svgmap_erefs(docxml, tag, isodoc, ids, presxml) # Stage 2: Normalize prefixes (Vectory expects eref, not fmt-eref) normalize_svgmap_prefixes(docxml) # Stage 3: Process with Vectory # Pass document suffix to Vectory as id_suffix for proper SVG ID disambiguation. # Vectory handles both id_suffix (document-level) and index suffix internally. doc_suffix = @files.get(docid, :document_suffix) Vectory::SvgMapping.new(docxml, "", id_suffix: doc_suffix).call # Stage 4: Extract processed SVG content extract_svgmap_content(docxml, isodoc) end |
#svgmap_resolve_prep(docxml, docid, presxml) ⇒ Object
Prepares document and context for svgmap resolution
47 48 49 50 51 52 53 54 |
# File 'lib/metanorma/collection/renderer/svg.rb', line 47 def svgmap_resolve_prep(docxml, docid, presxml) ids = @files.get(docid, :ids) docxml = svg_unnest(svg_datauri(docxml, docid)) isodoc = IsoDoc::PresentationXMLConvert.new({}) isodoc.bibitem_lookup(docxml) tag = presxml ? "fmt-eref" : "eref" [ids, docxml, isodoc, tag] end |
#update_anchor_create_loc(_bib, eref, docid) ⇒ Object
if there is a crossref to another document, with no anchor, retrieve the anchor given the locality, and insert it into the crossref
256 257 258 259 260 261 262 263 264 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 256 def update_anchor_create_loc(_bib, eref, docid) ins = eref.at(ns("./localityStack")) or return type = ins.at(ns("./locality/@type"))&.text type = "clause" if type == "annex" ref = ins.at(ns("./locality/referenceFrom"))&.text a = @files.get(docid, :anchors).dig(type, ref) or return ins << "<locality type='anchor'><referenceFrom>#{a}" \ "</referenceFrom></locality>" end |
#update_anchors(bib, docid, erefs, erefs_no_anchor, erefs_anchors) ⇒ Object
bottleneck
223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 223 def update_anchors(bib, docid, erefs, erefs_no_anchor, erefs_anchors) @files.get(docid) or error_anchor(erefs, docid) has_anchors, url, ncn_docid = update_anchors_prep(docid) erefs_no_anchor.each do |e| update_anchor_create_loc(bib, e, docid) end !url && has_anchors or return erefs_anchors.each do |e| update_anchors1(docid, ncn_docid, e) end end |
#update_anchors1(docid, ncn_docid, anchor) ⇒ Object
235 236 237 238 239 240 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 235 def update_anchors1(docid, ncn_docid, anchor) @concat_anchors[anchor.text] ||= "#{ncn_docid}_#{anchor.text}" if @files.get(docid).dig(:anchors_lookup, @concat_anchors[anchor.text]) anchor.content = @concat_anchors[anchor.text] end end |
#update_anchors_prep(docid) ⇒ Object
242 243 244 245 246 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 242 def update_anchors_prep(docid) @concat_anchors = {} [@files.get(docid)&.key?(:anchors_lookup), @files.url?(docid), Metanorma::Utils::to_ncname(docid)] end |
#update_bibitem(bib, identifier) ⇒ Object
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 252 def update_bibitem(bib, identifier) newbib, url, = update_bibitem_prep(bib, identifier) newbib or return dest = begin newbib.at("./docidentifier") || newbib.at(ns("./docidentifier")) rescue StandardError nil end dest or dest = newbib.elements[-1] # An attachment carries both a <uri type="attachment"> (which drives # isodoc's fmt-link attachment="true") and the citation uri; the # attachment uri goes first. metanorma/iso-10303#208. and dest.previous = "<uri type='attachment'>#{url}</uri>" dest.previous = "<uri type='citation'>#{url}</uri>" bib.replace(newbib) end |
#update_bibitem_prep(bib, identifier) ⇒ Object
269 270 271 272 273 274 275 276 277 |
# File 'lib/metanorma/collection/renderer/fileprocess.rb', line 269 def update_bibitem_prep(bib, identifier) docid = get_bibitem_docid(bib, identifier) or return [nil, nil, nil] newbib = dup_bibitem(docid, bib) = @files.get(docid, :attachment) url = @files.url(docid, relative: true, doc: !) current_html = referencing_html_location(identifier, ) url = make_relative_path(current_html, url) if current_html [newbib, url, ] end |
#update_direct_refs_to_docs(xml, identifier, presxml) ⇒ Object
repo(current-metanorma-collection/ISO 17301-1:2016) replaced by bibdata of "ISO 17301-1:2016" in situ as bibitem. Any erefs to that bibitem id are replaced with relative URL Preferably with anchor, and is a job to realise dynamic lookup of localities.
110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 110 def update_direct_refs_to_docs(xml, identifier, presxml) erefs, erefs_no_anchor, anchors, erefs1 = update_direct_refs_to_docs_prep(xml, presxml) x = xml.xpath(ns("//bibitem")) - xml.xpath(ns("//bibdata//bibitem")) x.each do |b| docid = b.at(ns("./docidentifier[@type = 'repository']")) or next strip_unresolved_repo_erefs(identifier, docid, erefs1, b) or next update_bibitem(b, identifier) docid = docid_to_citeas(b) or next erefs[docid] and update_anchors(b, docid, erefs[docid], erefs_no_anchor[docid], anchors[docid]) end end |
#update_direct_refs_to_docs_prep(docxml, presxml) ⇒ Object
Hash(docid) of arrays
126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 126 def update_direct_refs_to_docs_prep(docxml, presxml) erefs = Util::gather_citeases(docxml, presxml) no_anchor = erefs.keys.each_with_object({}) { |k, m| m[k] = [] } anchors = erefs.keys.each_with_object({}) { |k, m| m[k] = [] } erefs.each do |k, v| v.each do |e| if loc = e.at(".//#{ANCHOR_XPATH}") then anchors[k] << loc else no_anchor[k] << e end end end [erefs, no_anchor, anchors, Util::gather_bibitemids(docxml, presxml)] end |
#update_indirect_refs_prep(docxml, presxml) ⇒ Object
175 176 177 178 179 180 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 175 def update_indirect_refs_prep(docxml, presxml) @updated_anchors = {} @indirect_keys = {} [Util::gather_bibitems(docxml), Util::gather_bibitemids(docxml, presxml), docxml.root["document_suffix"], docxml.root["type"], {}] end |
#update_indirect_refs_to_docs(docxml, _docid, internal_refs, presxml) ⇒ Object
Resolve erefs to a container of ids in another doc, to an anchor eref (direct link)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 160 def update_indirect_refs_to_docs(docxml, _docid, internal_refs, presxml) bib, erefs, doc_suffix, doc_type, f = update_indirect_refs_prep(docxml, presxml) internal_refs.each do |schema, ids| add_suffix = doc_suffix && doc_type && doc_type != schema ids.each do |id, file| f[file] ||= { url: @files.url?(file), parentid: @files.get(file) && @files.get(file, :parentid) } k = indirect_ref_key(schema, id, doc_suffix, add_suffix) update_indirect_refs_to_docs1(f[file], k, file, bib, erefs) end end end |
#update_indirect_refs_to_docs1(filec, key, file, bibitems, erefs) ⇒ Object
193 194 195 196 197 198 199 200 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 193 def update_indirect_refs_to_docs1(filec, key, file, bibitems, erefs) erefs[key]&.each do |e| e["citeas"] = file update_indirect_refs_to_docs_anchor(e, file, filec[:url], filec[:parentid]) end update_indirect_refs_to_docs_docid(bibitems[key], file) end |
#update_indirect_refs_to_docs_anchor(eref, file, url, parentid) ⇒ Object
202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 202 def update_indirect_refs_to_docs_anchor(eref, file, url, parentid) a = eref.at(".//#{ANCHOR_XPATH}") or return parentid and file = "#{parentid}_#{file}" existing = a.text anchor = if url then existing else @indirect_keys[existing] ||= {} @indirect_keys[existing][file] ||= Metanorma::Utils::to_ncname("#{existing}_#{file}") end @updated_anchors[existing] or a.children = anchor @updated_anchors[anchor] = true end |
#update_indirect_refs_to_docs_docid(bib, file) ⇒ Object
215 216 217 218 219 220 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 215 def update_indirect_refs_to_docs_docid(bib, file) docid = bib&.at(ns("./docidentifier[@type = 'repository']")) or return docid.children = "current-metanorma-collection/#{file}" docid.previous = "<docidentifier type='metanorma-collection'>#{file}</docidentifier>" end |
#update_sectionsplit_eref_to_doc(eref, internal_refs, doclist, opts) ⇒ Object
81 82 83 84 85 86 87 88 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 81 def update_sectionsplit_eref_to_doc(eref, internal_refs, doclist, opts) a = eref.at("./xmlns:localityStack/#{ANCHOR_XPATH}") or return doc = internal_refs[opts[:key]]["#{a.text}_#{opts[:target_suffix]}"] bibitemid = Metanorma::Utils::to_ncname("#{doc}_#{opts[:source_suffix]}") eref["bibitemid"] = bibitemid doclist[bibitemid] ||= doc doclist end |
#update_sectionsplit_refs_to_docs(docxml, docid, internal_refs, presxml) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 64 def update_sectionsplit_refs_to_docs(docxml, docid, internal_refs, presxml) Util::gather_citeases(docxml, presxml).each do |k, v| (@files.get(k) && @files.get(k, :sectionsplit)) or next opts = { key: @files.get(k, :indirect_key), source_suffix: docxml.root["document_suffix"], target_suffix: @files.get(k, :document_suffix) } refs = v.each_with_object({}) do |eref, m| update_sectionsplit_eref_to_doc(eref, internal_refs, m, opts) end add_hidden_bibliography(docxml, refs, docid) end end |
#update_xrefs(file, docid, internal_refs) ⇒ String
Resolves references to other files in the collection. Three routines:
- Eref to a document that has been split into multiple documents (sectionsplit) are resolved to direct eref to the split document
- Indirect erefs to a file anchor in an unknown file in the collection (bibitem[@type = 'internal'] ) are resolved to direct eref to the containing document
- Direct erefs to other files in collection
(repo(current-metanorma-collection/x) are resolved to hyperlinks
Each pass below mutates the SAME Nokogiri tree in place; the inline
comments state the post-condition each pass guarantees on exit. The
contract between passes is "the tree is now in state X" -- there is no
intermediate typed representation, so the ordering is load-bearing.
ssotruthy (sectionsplit_output) =>xmlis Presentation XML and the semantic-only passes are skipped; otherwisexmlis Semantic XML. See the pipeline map in the collection architecture review plan.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 24 def update_xrefs(file, docid, internal_refs) xml, sso = update_xrefs_prep(file, docid) # post: repository docidentifiers supplied on bibitems naming a # collection file; `sso` resolved (Presentation vs Semantic). @nested || sso || @reinflate or Metanorma::Collection::XrefProcess::xref_process(xml, xml, nil, docid, @isodoc, sso) # post (semantic only): intra-doc xref/eref turned into internal erefs; # repo bibitems copied; indirect bibliography inserted. @ncnames = {} @nested or update_indirect_refs_to_docs(xml, docid, internal_refs, sso) # post: bibitem[@type='internal'] anchors resolved to the containing # collection document. @reinflate or @files.add_document_suffix(docid, xml) # post: every @id/@anchor namespaced with this doc's NCName suffix, so # concatenated documents do not collide. @nested or update_sectionsplit_refs_to_docs(xml, docid, internal_refs, sso) # post: erefs targeting a sectionsplit document point at the specific # split section file that holds the anchor. update_direct_refs_to_docs(xml, docid, sso) # post: repo(current-metanorma-collection/x) bibitems replaced in situ # with resolved bibdata + citation URI; their erefs become hyperlinks. ::Metanorma::Collection::Util::hide_refs(xml) # post: references containers with only hidden bibitems flagged hidden. sso and eref2link(xml, sso) @nested || @reinflate or svgmap_resolve(xml, docid, sso) xml.to_xml end |
#update_xrefs_prep(file, docid) ⇒ Object
sso (sectionsplit_output) truthy => Presentation XML, else Semantic.
This is the single discriminator that decides which grammar xml
carries and therefore which passes in update_xrefs run.
57 58 59 60 61 62 |
# File 'lib/metanorma/collection/renderer/fileparse.rb', line 57 def update_xrefs_prep(file, docid) docxml = file.is_a?(String) ? Nokogiri::XML(file, &:huge) : file supply_repo_ids(docxml) sso = @files.get(docid, :sectionsplit_output) [docxml, sso] end |
#with_nested ⇒ Object
Run the block with the renderer in nested mode, restoring the previous mode afterwards. Nested mode (used by sectionsplit, which re-enters this renderer's update_xrefs on the pre-split document) preserves unresolved erefs and skips the finalising reference passes.
28 29 30 31 32 33 34 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 28 def with_nested saved = @nested @nested = true yield ensure @nested = saved end |
#with_preserve_unresolved ⇒ Object
Run the block with the renderer preserving unresolved cross-document
references as stubs instead of stripping them -- for an isolated build of
a collection member (compiled without the rest of its collection
present). Unlike with_nested, the ordinary intra-document passes still
run (xref_process, svgmap); only the cross-document resolve/strip is
turned into preserve, so a later reinflation pass can relink the stubs.
42 43 44 45 46 47 48 |
# File 'lib/metanorma/collection/renderer/renderer.rb', line 42 def with_preserve_unresolved saved = @preserve_unresolved @preserve_unresolved = true yield ensure @preserve_unresolved = saved end |
#wrapping_doc(doc, xml) ⇒ Object
23 24 25 26 27 28 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 23 def wrapping_doc(doc, xml) doc.at(ns("//bibdata")).replace(xml.at(ns("//bibdata")).to_xml) sections = wrapping_doc_body(doc) wrapping_doc_intro_outro(xml, sections) set_displayorder_wrapping_doc(doc) end |
#wrapping_doc_body(doc) ⇒ Object
37 38 39 40 41 42 43 44 45 46 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 37 def wrapping_doc_body(doc) doc.xpath(ns("//annex | //preface | //bibliography")).each(&:remove) s = doc.at(ns("//sections")) || doc.root.elements[-1].after("<sections/>").next repl = <<~BODY <sections><clause id='_collection_placeholder'><p>PLACEHOLDER</p></clause></sections> BODY s.replace(repl) doc.at(ns("//sections")) end |
#wrapping_doc_intro_outro(xml, sections) ⇒ Object
30 31 32 33 34 35 |
# File 'lib/metanorma/collection/renderer/render_word.rb', line 30 def wrapping_doc_intro_outro(xml, sections) p = xml.at(ns("//prefatory-content")) and sections.previous = "<preface>#{p.children.to_xml}</preface>" p = xml.at(ns("//final-content")) and sections.next = "<annex>#{p.children.to_xml}</annex>" end |