Skip to content

Compile templates-based Asciidoctor converter (backend) into a single Ruby file

License

Notifications You must be signed in to change notification settings

jirutka/asciidoctor-templates-compiler

Repository files navigation

Asciidoctor Templates Compiler

CI Status Test Coverage Codacy Code quality Gem Version

This tool allows to precompile Slim templates into Ruby code and assemble them into a single-file pure Ruby converter (backend).

Installation

Add this line to your application’s Gemfile:

group :development do
  gem 'asciidoctor-templates-compiler', '~> 0.7.0'
end

or to your gemspec:

s.add_development_dependency 'asciidoctor-templates-compiler', '~> 0.7.0'

and then execute:

$ bundle install

Usage

The main entry point is method Asciidoctor::TemplatesCompiler::Slim#compile_converter (for Slim) that accepts the following keyword arguments.

backend_info

A hash of keys for backend_info: basebackend, outfilesuffix, filetype, htmlsyntax, supports_templates.

class_name

Full name of the converter class to generate (e.g. My::HTML::Converter). This argument is required.

delegate_backend

Name of the backend (converter) to use as a fallback for AST nodes not supported by your converter. If not specified (default), no fallback will be used and converter will raise NoMethodError when it try to convert an unsupported node.

engine_opts

A Hash of options to pass into the templating engine that compiles templates into Ruby code.

ignore_convert_opts

Ignore (i.e. do not set as local variables) options passed to the #convert method (i.e. to the templates). This is needed only for Opal.

output

An output stream (IO object like opened file, $stdout, …) to write the generated converter into. Default is StringIO.new (it’s the return value of #compile_converter).

pretty

Enable pretty-formatting of the generated Ruby code (generated by Slim/Temple)? Default is false.

register_for

An array of backend names that the generated converter should be registered in Asciidoctor to handle. Default is empty.

templates_dir

Path of the directory where to look for templates (*.slim files not starting with _, in the case of Slim) and (optional) helpers.rb. This argument is required.

Examples

Minimal example
require 'asciidoctor-templates-compiler'

File.open('converter.rb', 'w') do |file|
  Asciidoctor::TemplatesCompiler::Slim.compile_converter(
      templates_dir: 'data/templates',
      class_name: 'ShinyHtml::Converter',
      delegate_backend: 'html5',
      register_for: ['shiny-html'],
      backend_info: {
        basebackend: 'html',
        outfilesuffix: '.html',
        filetype: 'html',
      },
      pretty: true,
      output: file)
end
Example of usage in Rakefile
#!/usr/bin/env rake

CONVERTER_FILE = 'lib/asciidoctor/shiny_html/converter.rb'
TEMPLATES_DIR = 'data/templates'

namespace :build do

  file CONVERTER_FILE, [:mode] => FileList["#{TEMPLATES_DIR}/*"] do |t, args|
    require 'asciidoctor-templates-compiler'

    File.open(CONVERTER_FILE, 'w') do |file|
      $stderr.puts "Generating #{file.path}."
      Asciidoctor::TemplatesCompiler::Slim.compile_converter(
          templates_dir: TEMPLATES_DIR,
          class_name: 'Asciidoctor::ShinyHtml::Converter',
          delegate_backend: 'html5',
          register_for: ['shiny-html'],
          backend_info: {
            basebackend: 'html',
            outfilesuffix: '.html',
            filetype: 'html',
          },
          pretty: (args[:mode] == :pretty),
          output: file)
    end
  end

  namespace :converter do
    desc 'Compile Slim templates and generate converter.rb (pretty mode)'
    task :pretty do
      Rake::Task[CONVERTER_FILE].invoke(:pretty)
    end

    desc 'Compile Slim templates and generate converter.rb (fast mode)'
    task :fast do
      Rake::Task[CONVERTER_FILE].invoke
    end
  end

  task :converter => 'converter:pretty'
end

task :build => 'build:converter:pretty'

task :clean do
  rm_rf CONVERTER_FILE
end

You can also look into asciidoctor-html5s for a real-world example including integration with Asciidoctor::DocTest.

Opal Caveats

The generated converter code can be transpiled into JavaScript using Opal. However, there’s one feature that is known to not work: passing options to the #convert method.

Consider the following example:

toc.html.slim:
nav id='toc'
  = converter.convert document, 'outline', toclevels: 5
outline.html.slim:
- toclevels ||= document.attr('toclevels').to_i

Variable toclevels in outline.html.slim should be initialized to 5 when this template is called from the toc.html.slim template. This is implemented using Kernel#binding and Binding#local_variable_set which is not supported by Opal. In such case you get exception like this:

RuntimeError: node_modules/opal-runtime/src/opal.js
         throw exception;
         ^

binding: undefined method `binding` for [some Asciidoctor class]

Unfortunately I don’t know how to implement this feature without using Binding, but you can use the following workaround.

Enable ignore_convert_opts (see Usage) to remove the code calling Kernel#binding from the converter. The options will be still passed, but not binded to the template local variables. If you examine the generated code, you can see that the options are passed to the convert methods via argument named opts. You can exploit this fact and do something like:

outline.html.slim:
- toclevels = opts[:toclevels] || document.attr('toclevels').to_i

License

This project is licensed under MIT License. For the full text of the license, see the LICENSE file.

About

Compile templates-based Asciidoctor converter (backend) into a single Ruby file

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Contributors 4

  •  
  •  
  •  
  •  

Languages