Class: Metanorma::Standoc::EmbedIncludeProcessor
- Inherits:
-
Asciidoctor::Extensions::Preprocessor
- Object
- Asciidoctor::Extensions::Preprocessor
- Metanorma::Standoc::EmbedIncludeProcessor
- Defined in:
- lib/metanorma/standoc/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
153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 153 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
49 50 51 52 53 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 49 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
166 167 168 169 170 171 172 173 174 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 166 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
130 131 132 133 134 135 136 137 138 139 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 130 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
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 187 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 } )
83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 83 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
37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 37 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
113 114 115 116 117 118 119 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 113 def (acc, , prev) acc, = (acc, , prev) acc[:lines] << acc[:hdr] << [:hdr] acc[:id] += [:id] acc end |
#process_embed_anchor(acc, embed, prev) ⇒ Object
121 122 123 124 125 126 127 128 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 121 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
101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 101 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
147 148 149 150 151 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 147 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
67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 67 def (ret, doc) reader = ::Asciidoctor::PreprocessorReader.new doc b = 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
141 142 143 144 145 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 141 def readlines_safe(file) if file.eof? then [] else file.readlines end end |
#return_to_document(doc, embed) ⇒ Object
presupposes single embed
56 57 58 59 60 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 56 def return_to_document(doc, ) doc.attributes["embed_hdr"] = [:hdr] doc.attributes["embed_id"] = [:id] ((), doc) end |
#strip_header(lines) ⇒ Object
176 177 178 179 180 181 182 183 184 185 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 176 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
95 96 97 98 99 |
# File 'lib/metanorma/standoc/macros_embed.rb', line 95 def (lines, acc, emb) lines.empty? or acc << { file: emb[:file], path: emb[:path], lines: } [[], acc] end |