Class: Metanorma::Standoc::EmbedIncludeProcessor
- Inherits:
-
Asciidoctor::Extensions::Preprocessor
- Object
- Asciidoctor::Extensions::Preprocessor
- Metanorma::Standoc::EmbedIncludeProcessor
- Defined in:
- lib/metanorma/converter/macros_embed.rb
Instance Method Summary collapse
- #embed(line, acc, headings, status) ⇒ Object
- #embed_acc(doc, reader) ⇒ Object
- #embed_recurse(ret, doc, reader, headings, status) ⇒ Object
- #filename(line, acc) ⇒ Object
- #filter_sections(lines, headings) ⇒ Object
-
#flatten_embeds(emb) ⇒ Object
lines can contain recursive embed structs, which are resolved into a flat listing of included line chunks (top level doc has { file: nil } ).
- #process(doc, reader) ⇒ Object
- #process_embed(acc, embed, prev) ⇒ Object
- #process_embed_anchor(acc, embed, prev) ⇒ Object
- #process_line(line, acc, headings, status) ⇒ Object
- #read(inc_path) ⇒ Object
-
#read_flattened_embeds(ret, doc) ⇒ Object
lines can contain recursive embed structs, containing the lines to read and the file they are in; read these into the (new) reader.
- #readlines_safe(file) ⇒ Object
-
#return_to_document(doc, embed) ⇒ Object
presupposes single embed.
- #strip_header(lines) ⇒ Object
- #update_embeds(lines, acc, emb) ⇒ Object
Instance Method Details
#embed(line, acc, headings, status) ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/metanorma/converter/macros_embed.rb', line 155 def (line, acc, headings, status) fname, inc_path = filename(line, acc) lines = filter_sections(read(inc_path), headings) n = Asciidoctor::Document .new [], { safe: :safe, base_dir: File.dirname(inc_path) } r = ::Asciidoctor::PreprocessorNoIfdefsReader.new n, lines ret = (n, r).merge(strip_header(r.readlines)) .merge(file: fname, path: inc_path, orig: acc[:orig]) ret[:hdr] or raise "Embedding an incomplete document with no header: #{ret[:path]}" (ret, n, r, headings, status) end |
#embed_acc(doc, reader) ⇒ Object
50 51 52 53 54 |
# File 'lib/metanorma/converter/macros_embed.rb', line 50 def (doc, reader) { lines: [], hdr: [], id: [], orig: doc, doc:, file: nil, path: nil, reader:, prev: nil } end |
#embed_recurse(ret, doc, reader, headings, status) ⇒ Object
168 169 170 171 172 173 174 175 176 |
# File 'lib/metanorma/converter/macros_embed.rb', line 168 def (ret, doc, reader, headings, status) ret1 = ret[:lines].each_with_object((doc, reader)) do |line, m| process_line(line, m, headings, status) end ret.merge( { lines: ret1[:lines], id: ret[:id] + ret1[:id], hdr: { text: ret[:hdr].join("\n"), child: ret1[:hdr] } }, ) end |
#filename(line, acc) ⇒ Object
132 133 134 135 136 137 138 139 140 141 |
# File 'lib/metanorma/converter/macros_embed.rb', line 132 def filename(line, acc) m = /^embed::([^\[]+)\[/.match(line) f = acc[:doc].normalize_system_path m[1], acc[:reader].dir, nil, target_name: "include file" unless File.exist?(f) err = "Missing embed file: #{line}" raise err end [m[1], f] end |
#filter_sections(lines, headings) ⇒ Object
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/metanorma/converter/macros_embed.rb', line 189 def filter_sections(lines, headings) skip = false lines.each_with_index.with_object([]) do |(l, i), m| if headings.include?(l.strip) skip = true m.pop while !m.empty? && /^\S/.match?(m[-1]) elsif skip && /^== |^embed::|^include::/.match?(l) skip = false j = i j -= 1 while j >= 0 && /^\S/.match?(m[j]) lines[j..i].each { |n| m << n } else skip or m << l end end end |
#flatten_embeds(emb) ⇒ Object
lines can contain recursive embed structs, which are resolved into a flat listing of included line chunks (top level doc has { file: nil } )
84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/metanorma/converter/macros_embed.rb', line 84 def (emb) acc = [] ret = emb[:lines].each_with_object([]) do |l, m| if l.is_a?(Hash) acc, m = (acc, m, emb) (l).each { |x| m << x } else acc << l end end acc, ret = (acc, ret, emb) ret end |
#process(doc, reader) ⇒ Object
38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/metanorma/converter/macros_embed.rb', line 38 def process(doc, reader) reader.eof? and return reader r = ::Asciidoctor::PreprocessorNoIfdefsReader.new doc, reader.lines p = Metanorma::Utils::LineStatus.new lines = r.readlines headings = lines.grep(/^== /).map(&:strip) ret = lines.each_with_object((doc, r)) do |line, m| process_line(line, m, headings, p) end return_to_document(doc, ret) end |
#process_embed(acc, embed, prev) ⇒ Object
115 116 117 118 119 120 121 |
# File 'lib/metanorma/converter/macros_embed.rb', line 115 def (acc, , prev) acc, = (acc, , prev) acc[:lines] << acc[:hdr] << [:hdr] acc[:id] += [:id] acc end |
#process_embed_anchor(acc, embed, prev) ⇒ Object
123 124 125 126 127 128 129 130 |
# File 'lib/metanorma/converter/macros_embed.rb', line 123 def (acc, , prev) if /^\[\[.+\]\]/.match?(prev) # anchor acc[:id] << prev.sub(/^\[\[/, "").sub(/\]\]$/, "") i = [:lines].index { |x| /^== /.match?(x) } and [:lines][i] += " #{prev}" # => bookmark end [acc, ] end |
#process_line(line, acc, headings, status) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/metanorma/converter/macros_embed.rb', line 103 def process_line(line, acc, headings, status) status.process(line) if !status.pass && /^embed::/.match?(line) e = (line, acc, headings, status) acc = (acc, e, acc[:prev]) else acc[:lines] << line end acc[:prev] = line acc end |
#read(inc_path) ⇒ Object
149 150 151 152 153 |
# File 'lib/metanorma/converter/macros_embed.rb', line 149 def read(inc_path) ::File.open inc_path, "r" do |fd| readlines_safe(fd).map(&:chomp) end end |
#read_flattened_embeds(ret, doc) ⇒ Object
lines can contain recursive embed structs, containing the lines to read and the file they are in; read these into the (new) reader. This is intended to resolve any file crossreferences, with file paths resolved relative to current file directory – but it won’t: github.com/metanorma/metanorma-standoc/issues/802
68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/metanorma/converter/macros_embed.rb', line 68 def (ret, doc) reader = ::Asciidoctor::PreprocessorReader.new doc Pathname.new doc.base_dir ret.reverse_each do |l| # if l[:file] # new = Pathname.new(l[:path]).relative_path_from(b).to_s # reader.push_include l[:lines], new, l[:path] reader.unshift_lines l[:lines] # else reader.unshift_lines l[:lines] # end end reader end |
#readlines_safe(file) ⇒ Object
143 144 145 146 147 |
# File 'lib/metanorma/converter/macros_embed.rb', line 143 def readlines_safe(file) if file.eof? then [] else file.readlines end end |
#return_to_document(doc, embed) ⇒ Object
presupposes single embed
57 58 59 60 61 |
# File 'lib/metanorma/converter/macros_embed.rb', line 57 def return_to_document(doc, ) doc.attributes["embed_hdr"] = [:hdr] doc.attributes["embed_id"] = [:id] ((), doc) end |
#strip_header(lines) ⇒ Object
178 179 180 181 182 183 184 185 186 187 |
# File 'lib/metanorma/converter/macros_embed.rb', line 178 def strip_header(lines) return { lines:, hdr: nil } unless !lines.empty? && lines.first.start_with?("= ") skip = true lines.each_with_object({ hdr: [], lines: [] }) do |l, m| m[skip ? :hdr : :lines] << l skip = false if !/\S/.match?(l) end end |
#update_embeds(lines, acc, emb) ⇒ Object
97 98 99 100 101 |
# File 'lib/metanorma/converter/macros_embed.rb', line 97 def (lines, acc, emb) lines.empty? or acc << { file: emb[:file], path: emb[:path], lines: } [[], acc] end |