collection.cr

require "sixteen"
require "./crycco"

module Crycco

A Collection is a group of sources that will be processed together and saved to the same output directory while preserving the directory structure of the sources.

This way the logic for path manipulation is centrallized here and the Document class can be simpler.

  class Collection
    @docs : Array(Document)

On initialization, we create documents for each source file

    def initialize(sources : Array(String),
                   out_dir : String,
                   template : String,
                   mode : String,
                   theme : String = "default-dark")
      @docs = sources.map { |source|
        Path[source].expand.normalize
      }.sort!.map { |source|
        Document.new source, template, mode
      }

      @out_dir = out_dir
      @template = template
      @mode = mode
      @base_dir = Path[common_prefix]

FIXME: make the sixteen theme accessible from tartrazine to avoid setting two themes here.

      @theme = Sixteen.theme(theme)
      @tartrazine_theme = Tartrazine.theme(theme)
      @formatter = Tartrazine::Html.new
      @code_css = @formatter.style_defs
    end

Save the documents to the output directory.

As extra context for rendering, we pass links to all the documents in the collection and the theme context which contains a selection of colors from the theme.

    def save
      @docs.each do |doc|
        dst = dst_path doc
        puts "#{doc.path} -> #{dst}"
        links = {} of String => String
        @docs.each do |doclink|
          target = dst_path(doclink).relative_to(@out_dir).to_s
          target = "#" if doclink == doc
          links[doclink.path.relative_to(@base_dir).to_s] = target
        end
        doc.save dst, {
          "links"    => links,
          "code_css" => @code_css,
        }.merge(@theme.context("_"))
      end
    end

Calculate destionation paths for the documents. If the as_source option is set, the output should be a source file, so it will have the language's extension and use the source template.

If the source is literate (eg: foo.yml.md), the destination will have the same name as the source but without the final ".md"

When the output is a document, ".html" is appended to the destination.

    def dst_path(doc : Document) : Path
      dst = (Path[@out_dir] / Path[doc.path].relative_to(@base_dir)).to_s
      case @mode
      when "docs"
        dst += ".html"
      when "markdown"
        dst = Path[dst].dirname + "/" + Path[dst].stem + ".md"
      when "literate"
        dst += ".md"
      end
      if doc.@literate && File.extname(dst) == ".md"
        dst = dst[...-3]
      end
      Path[dst]
    end

Find the common prefix of the sources, this is used to preserve the directory structure when saving the documents.

    def common_prefix : String
      sources = @docs.map &.path
      candidate = Path[sources[0]].dirname
      until sources.all? { |source| Path[source].dirname.starts_with? candidate }
        candidate = Path[candidate].dirname
      end
      candidate
    end
  end
end