Class: Giblish::DefaultConverter

Inherits:
Object
  • Object
show all
Defined in:
lib/giblish/treeconverter.rb

Constant Summary collapse

DEFAULT_ADOC_DOC_ATTRIBS =
{
  "data-uri" => true,
  "hide-uri-scheme" => true,
  "xrefstyle" => "short",
  "source-highlighter" => "rouge",
  "source-linenums-option" => true
}
DEFAULT_ADOC_API_OPTS =
{
  # backend: "html5",
  # base_dir:
  # catalog_assets: false,
  # converter:
  # doctype: "article",
  # eruby:
  # ignore extention stuff
  # header_only: false,
  # logger:
  # mkdirs: false,
  # parse: true,
  safe: :unsafe,
  sourcemap: true,
  # template stuff TBD,
  # to_file:
  # to_dir:
  standalone: true
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger, opts) ⇒ DefaultConverter

opts:

adoc_log_level
adoc_api_opts
adoc_doc_attribs
conversion_cb {
   success: lambda(src, dst, dst_rel_path, doc, logstr)
   fail: lambda(src,dst,exc)
}


187
188
189
190
191
192
193
194
195
196
197
# File 'lib/giblish/treeconverter.rb', line 187

def initialize(logger, opts)
  @logger = logger
  @adoc_log_level = opts.fetch(:adoc_log_level, Logger::Severity::WARN)
  @conv_cb = opts.fetch(:conversion_cb, {
    success: ->(src, dst, dst_rel_path, doc, logstr) { TreeConverter.on_success(src, dst, dst_rel_path, doc, logstr) },
    failure: ->(src, dst, dst_rel_path, ex, logstr) { TreeConverter.on_failure(src, dst, dst_rel_path, ex, logstr) }
  })

  # cache external configuration
  @config_opts = opts.dup
end

Instance Attribute Details

#adoc_api_optsObject

Returns the value of attribute adoc_api_opts.



148
149
150
# File 'lib/giblish/treeconverter.rb', line 148

def adoc_api_opts
  @adoc_api_opts
end

Instance Method Details

#convert(src_node, dst_node, dst_top) ⇒ Object

require the following methods to be available from the src node: adoc_source

the following methods will be called if supported: document_attributes api_options

src_node

the PathTree node containing the info on adoc source and any

added api_options or doc_attributes

dst_node

the PathTree node where conversion info is to be stored

dst_top

the PathTree node representing the top dir of the destination

under which all converted files are written.



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/giblish/treeconverter.rb', line 270

def convert(src_node, dst_node, dst_top)
  @logger&.info { "Converting #{src_node.pathname} and store result under #{dst_node.parent.pathname}" }

  # merge the common api opts with node specific
  api_opts = DEFAULT_ADOC_API_OPTS.dup
  api_opts.merge!(@config_opts.fetch(:adoc_api_opts, {}))
  api_opts.merge!(src_node.api_options(src_node, dst_node, dst_top)) if src_node.respond_to?(:api_options)

  # use a new logger instance for each conversion
  adoc_logger = Giblish::AsciidoctorLogger.new(@logger, @adoc_log_level)

  begin
    doc_src = src_node.adoc_source(src_node, dst_node, dst_top)

    node_attr = src_node.respond_to?(:document_attributes) ?
      src_node.document_attributes(src_node, dst_node, dst_top) : {}
    doc_attr = resolve_doc_attributes(doc_src, node_attr)
    # piggy-back our own info on the doc attributes hash so that
    # asciidoctor extensions can use this info later on
    doc_attr["giblish-info"] = {
      src_node: src_node,
      dst_node: dst_node,
      dst_top: dst_top
    }

    # load the source to enable access to doc attributes and properties
    #
    # NOTE: 'parse' is set to false to prevent preprocessor extensions to be run as part
    # of loading the document. We want them to run during the 'convert' call later when
    # doc attribs have been amended.
    #
    # NOTE2: by trial-and-error, it seems that some document attributes must be set when
    # calling 'load' and not added after the call and before the 'convert' call to have
    # the expected effect (e.g. idprefix).
    doc = Asciidoctor.load(doc_src, api_opts.merge(
      {
        attributes: doc_attr,
        parse: false,
        logger: adoc_logger
      }
    ))

    # update the destination node with the correct file suffix. This is dependent
    # on the type of conversion performed
    dst_node.name = dst_node.name.sub_ext(doc.attributes["outfilesuffix"])
    d = dst_node.pathname

    # make sure the dst dir exists
    d.dirname.mkpath

    # do the conversion and write the converted doc to file
    output = doc.convert(api_opts)
    doc.write(output, d.to_s)

    # give the user the opportunity to eg store the result of the conversion
    # as data in the destination node
    @conv_cb[:success]&.call(src_node, dst_node, dst_top, doc, adoc_logger.in_mem_storage.string)
    true
  rescue => ex
    @logger&.error { "Conversion failed for #{src_node.pathname}" }
    @logger&.error { ex.message }
    @logger&.error { ex.backtrace }
    @conv_cb[:failure]&.call(src_node, dst_node, dst_top, ex, adoc_logger.in_mem_storage.string)
    false
  end
end

#resolve_doc_attributes(doc_src, node_attr) ⇒ Object

Resolve the document attributes according to the precedence.

According to docs.asciidoctor.org/asciidoc/latest/attributes/assignment-precedence/ The attribute precedence is:

  1. An attribute passed to the API or CLI whose value does not end in @

  2. An attribute defined in the document

  3. An attribute passed to the API or CLI whose value or name ends in @

  4. The default value of the attribute, if applicable

giblish adds the following rules: 1.5 An attribute defined in an attribute provider for a specific source node 3.5 The default value set by giblish, if applicable



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/giblish/treeconverter.rb', line 211

def resolve_doc_attributes(doc_src, node_attr)
  # rule 3.5
  doc_attr = DEFAULT_ADOC_DOC_ATTRIBS.dup

  # sort attribs into soft and hard (rule 1 and 3)
  soft_attr = {}
  hard_attr = {}
  @config_opts.fetch(:adoc_doc_attribs, {}).each do |k, v|
    ks = k.to_s.strip
    vs = v.to_s.strip

    if ks.end_with?("@")
      soft_attr[ks[0..]] = vs
      next
    end
    if vs.end_with?("@")
      soft_attr[ks] = vs[0..]
      next
    end
    hard_attr[ks] = vs
  end

  # rule 3.
  doc_attr.merge!(soft_attr)

  # rule 2
  Giblish.process_header_lines(doc_src.lines) do |line|
    a = /^:(.+):(.*)$/.match(line)
    next unless a
    @logger.debug { "got header attr from doc: #{a[1]} : #{a[2]}" }
    doc_attr[a[1].strip] = a[2].strip
  end

  @logger.debug { "idprefix before: #{doc_attr["idprefix"]}" }

  # rule 1.5
  doc_attr.merge!(node_attr)

  # rule 1.
  doc_attr.merge!(hard_attr)

  @logger.debug { "idprefix after: #{doc_attr["idprefix"]}" }

  # @logger&.debug { "Header attribs: #{doc_attr}" }
  doc_attr
end