class Asciidoctor::Converter::TemplateConverter
will be issued.
safe. If this gem is not present, there is no such guarantee and a warning
concurrent-ruby} gem is installed, these caches are guaranteed to be thread
of the Ruby process. If the {rubygems.org/gems/concurrent-ruby<br>As an optimization, scan results and templates are cached for the lifetime
backend format (e.g., “html5”).
convert a paragraph {Block} object from the parsed AsciiDoc tree to an HTML
be registered as the “paragraph” transform. The template is then used to
For example, the template file “path/to/templates/paragraph.html.slim” will
table and use it to convert the node.
is invoked, the transform argument is used to select the template from this
key under which to store the template. When the {Converter#convert} method
extensions from the basename of the file and uses the resulting name as the
files that have a matching extension (e.g., “.slim”). The scanner trims any
options Hash passed to the constructor, the scan is restricted to template
supported by Tilt. If an engine name (e.g., “slim”) is specified in the
The converter scans the specified directories for template files that are
format.
{AbstractNode} objects from a parsed AsciiDoc document tree to the backend
languages supported by {github.com/rtomayko/tilt Tilt} to convert
A {Converter} implementation that uses templates composed in template
def self.caches
def self.caches @caches end
def self.clear_caches
def self.clear_caches @caches[:scans].clear if @caches[:scans] @caches[:templates].clear if @caches[:templates] end
def convert node, template_name = nil, opts = nil
template. (optional, default: nil)
opts - an optional Hash that is passed as local variables to the
not specified. (optional, default: nil)
the node_name property on the node if a template name is
template_name - the String name of the template to use, or the value of
node - the AbstractNode to convert
value of the {AbstractNode#node_name} property.
Looks for a template that matches the value of the template name or, if the template name is not specified, the
Public: Convert an {AbstractNode} to the backend format using the named template.
def convert node, template_name = nil, opts = nil unless (template = @templates[template_name ||= node.node_name]) raise %(Could not find a custom template to handle transform: #{template_name}) end # Slim doesn't include helpers in the template's execution scope (like HAML), so do it ourselves node.extend ::Slim::Helpers if (defined? ::Slim::Helpers) && (::Slim::Template === template) # NOTE opts become locals in the template if template_name == 'document' (template.render node, opts).strip else (template.render node, opts).rstrip end end
def handles? name
Returns a [Boolean] that indicates whether a Tilt template is registered for the
name - the String template name
Public: Checks whether there is a Tilt template registered with the specified name.
def handles? name @templates.key? name end
def initialize backend, template_dirs, opts = {}
def initialize backend, template_dirs, opts = {} Helpers.require_library 'tilt' unless defined? ::Tilt.new @backend = backend @templates = {} @template_dirs = template_dirs @eruby = opts[:eruby] @safe = opts[:safe] @active_engines = {} @engine = opts[:template_engine] @engine_options = {}.tap {|accum| DEFAULT_ENGINE_OPTIONS.each {|engine, engine_opts| accum[engine] = engine_opts.merge } } if opts[:htmlsyntax] == 'html' # if not set, assume xml since this converter is also used for DocBook (which doesn't specify htmlsyntax) @engine_options[:haml][:format] = :html5 @engine_options[:slim][:format] = :html end @engine_options[:slim][:include_dirs] = template_dirs.reverse.map {|dir| ::File.expand_path dir } if (overrides = opts[:template_engine_options]) overrides.each do |engine, override_opts| (@engine_options[engine] ||= {}).update override_opts end end case opts[:template_cache] when true logger.warn 'optional gem \'concurrent-ruby\' is not available. This gem is recommended when using the default template cache.' unless defined? ::Concurrent::Hash @caches = self.class.caches when ::Hash @caches = opts[:template_cache] else @caches = {} # the empty Hash effectively disables caching end scan end
def load_eruby name
Returns an [Array] containing the Tilt template Class for the eRuby implementation
name - the String name of the eRuby implementation
Internal: Load the eRuby implementation
def load_eruby name if !name || name == 'erb' require 'erb' unless defined? ::ERB.version [::Tilt::ERBTemplate, {}] elsif name == 'erubis' Helpers.require_library 'erubis' unless defined? ::Erubis::FastEruby [::Tilt::ErubisTemplate, { engine_class: ::Erubis::FastEruby }] else raise ::ArgumentError, %(Unknown ERB implementation: #{name}) end end
def register name, template
template - the Tilt template object to register
name - the String template name
Public: Registers a Tilt template with this converter.
def register name, template @templates[name] = if (template_cache = @caches[:templates]) template_cache[template.file] = template else template end #create_handler name, template end
def scan
{TemplateConverter#templates} method.
templates, loads the templates and stores the in a Hash that is accessible via the
Internal: Scans the template directories specified in the constructor for Tilt-supported
def scan path_resolver = PathResolver.new backend = @backend engine = @engine @template_dirs.each do |template_dir| # FIXME need to think about safe mode restrictions here next unless ::File.directory?(template_dir = (path_resolver.system_path template_dir)) if engine file_pattern = %(*.#{engine}) # example: templates/haml if ::File.directory?(engine_dir = %(#{template_dir}/#{engine})) template_dir = engine_dir end else # NOTE last matching template wins for template name if no engine is given file_pattern = '*' end # example: templates/html5 (engine not set) or templates/haml/html5 (engine set) if ::File.directory?(backend_dir = %(#{template_dir}/#{backend})) template_dir = backend_dir end pattern = %(#{template_dir}/#{file_pattern}) if (scan_cache = @caches[:scans]) template_cache = @caches[:templates] unless (templates = scan_cache[pattern]) templates = scan_cache[pattern] = scan_dir template_dir, pattern, template_cache end templates.each do |name, template| @templates[name] = template_cache[template.file] = template end else @templates.update scan_dir(template_dir, pattern, @caches[:templates]) end nil end end
def scan_dir template_dir, pattern, template_cache = nil
a Tilt template for each matched file.
Internal: Scan the specified directory for template files matching pattern and instantiate
def scan_dir template_dir, pattern, template_cache = nil result, helpers = {}, nil # Grab the files in the top level of the directory (do not recurse) ::Dir.glob(pattern).select {|match| ::File.file? match }.each do |file| if (basename = ::File.basename file) == 'helpers.rb' helpers = file next elsif (path_segments = basename.split '.').size < 2 next end if (name = path_segments[0]) == 'block_ruler' name = 'thematic_break' elsif name.start_with? 'block_' name = name.slice 6, name.length end unless template_cache && (template = template_cache[file]) template_class, extra_engine_options, extsym = ::Tilt, {}, path_segments[-1].to_sym case extsym when :slim unless @active_engines[extsym] # NOTE slim doesn't get automatically loaded by Tilt Helpers.require_library 'slim' unless defined? ::Slim::Engine require 'slim/include' unless defined? ::Slim::Include ::Slim::Engine.define_options asciidoc: {} # align safe mode of AsciiDoc embedded in Slim template with safe mode of current document # NOTE safe mode won't get updated if using template cache and changing safe mode (@engine_options[extsym][:asciidoc] ||= {})[:safe] ||= @safe if @safe @active_engines[extsym] = true end when :haml unless @active_engines[extsym] Helpers.require_library 'haml' unless defined? ::Haml::Engine # NOTE Haml 5 dropped support for pretty printing @engine_options[extsym].delete :ugly if defined? ::Haml::TempleEngine @active_engines[extsym] = true end when :erb template_class, extra_engine_options = (@active_engines[extsym] ||= (load_eruby @eruby)) when :rb next else next unless ::Tilt.registered? extsym.to_s end template = template_class.new file, 1, (@engine_options[extsym] ||= {}).merge(extra_engine_options) end result[name] = template end if helpers || ::File.file?(helpers = %(#{template_dir}/helpers.rb)) require helpers end result end
def templates
Public: Retrieves the templates that this converter manages.
def templates @templates.merge end