class Giblish::DocidCollector

Parse all adoc files for :docid: attributes

Constants

ID_MAX_LENGTH

The maximum number of characters required for a valid doc id

ID_MIN_LENGTH

The minimum number of characters required for a valid doc id

Attributes

docid_cache[R]
docid_deps[R]

Public Class Methods

clear_cache() click to toggle source
# File lib/giblish/docid.rb, line 20
def clear_cache
  @docid_cache = {}
end
clear_deps() click to toggle source
# File lib/giblish/docid.rb, line 24
def clear_deps
  @docid_deps = {}
end

Public Instance Methods

add_source_dep(src_path) click to toggle source

add a new source document to the docid_deps

# File lib/giblish/docid.rb, line 59
def add_source_dep(src_path)
  return if docid_deps.key? src_path

  docid_deps[src_path] = []
end
parse_file(path) click to toggle source

Check if a :docid: <id> entry exists in the header. According to www.methods.co.nz/asciidoc/userguide.html#X95 the header is optional, but if it exists it:

  • must start with a titel (=+ <My Title>)

  • ends with one or more blank lines

  • does not contain any blank line

# File lib/giblish/docid.rb, line 47
def parse_file(path)
  Giblog.logger.debug { "parsing file #{path} for docid..." }
  Giblish.process_header_lines_from_file(path) do |line|
    m = /^:docid: +(.*)$/.match(line)
    if m
      # There is a docid defined, cache the path and doc id
      validate_and_add m[1], path
    end
  end
end
process(document, reader) click to toggle source

This hook is called by Asciidoctor once for each document before Asciidoctor processes the adoc content.

It replaces references of the format <<:docid: ID-1234,Hello >> with references to a resolved relative path.

# File lib/giblish/docid.rb, line 70
def process(document, reader)
  # Add doc as a source dependency for doc ids
  src_path = document.attributes["docfile"]

  # Note: the nil check is there to prevent us adding generated
  # asciidoc docs that does not exist in the file system (e.g. the
  # generated index pages). This is a bit hackish and should maybe be
  # done differently
  return if src_path.nil?

  add_source_dep src_path

  # Convert all docid refs to valid relative refs
  reader.lines.each do |line|
    line.gsub!(/<<\s*:docid:\s*(.*?)>>/) do |_m|
      # parse the ref
      target_id, section, display_str =
        parse_doc_id_ref Regexp.last_match(1)

      # The result is a valid ref in the form
      # <<target_doc.adoc#[section][,display_str]>>
      Giblog.logger.debug { "Replace docid ref in doc #{src_path}..." }
      if docid_cache.key? target_id
        # add the referenced doc id as a target dependency of this document
        docid_deps[src_path] << target_id
        docid_deps[src_path] = docid_deps[src_path].uniq

        # resolve the doc id ref to a valid relative path
        "<<#{get_rel_path(src_path, target_id)}##{section}#{display_str}>>"
      else
        "<<UNKNOWN_DOC, Could not resolve doc id reference !!!>>"
      end
    end
  end
  reader
end

Private Instance Methods

doc_id_ok?(doc_id) click to toggle source

make sure the id is within the designated length and does not contain a '#' symbol

# File lib/giblish/docid.rb, line 149
def doc_id_ok?(doc_id)
  (doc_id.length.between?(ID_MIN_LENGTH, ID_MAX_LENGTH) &&
     !doc_id.include?("#"))
end
docid_cache() click to toggle source

Helper method to shorten calls to docid_cache from instance methods

# File lib/giblish/docid.rb, line 110
def docid_cache
  self.class.docid_cache
end
docid_deps() click to toggle source
# File lib/giblish/docid.rb, line 114
def docid_deps
  self.class.docid_deps
end
get_rel_path(src_path, doc_id) click to toggle source

Get the relative path from the src doc to the doc with the given doc id

# File lib/giblish/docid.rb, line 120
def get_rel_path(src_path, doc_id)
  raise ArgumentError("unknown doc id: #{doc_id}") unless docid_cache.key? doc_id

  rel_path = docid_cache[doc_id]
             .dirname
             .relative_path_from(Pathname.new(src_path).dirname) +
             docid_cache[doc_id].basename
  rel_path.to_s
end
parse_doc_id_ref(input_str) click to toggle source

input_str shall be the expression between <<:docid:<input_str>>> where the <input_str> is in the form <id>[,display_str]

returns an array with [id, section, display_str]

# File lib/giblish/docid.rb, line 135
def parse_doc_id_ref(input_str)
  ref, display_str = input_str.split(",").each(&:strip)
  id, section = ref.split "#"

  display_str = id.dup if display_str.nil?
  display_str.prepend ","

  section = "" if section.nil?

  [id, section, display_str]
end
validate_and_add(doc_id, path) click to toggle source
# File lib/giblish/docid.rb, line 154
def validate_and_add(doc_id, path)
  id = doc_id.strip
  Giblog.logger.debug { "found possible docid: #{id}" }

  unless doc_id_ok? doc_id
    Giblog.logger.error { "Invalid docid: #{id} in file #{path}, this will be ignored!" }
    return
  end

  if docid_cache.key? id
    Giblog.logger.warn { "Found same doc id twice (#{id})." }
    Giblog.logger.warn { "Assigning this id to the file #{path}." }
    Giblog.logger.warn { "Discarding this id from the file #{docid_cache[id]}." }
  end
  docid_cache[id] = Pathname(path)
end