class Asciidoctor::Renderer
using eRuby templates.
Public: Methods for rendering Asciidoc Documents, Sections, and Blocks
def self.camelcase_to_underscore(str)
# => 'block_ulist'
Renderer.camelcase_to_underscore('BlockUlist')
# => 'block_sidebar'
Renderer.camelcase_to_underscore('BlockSidebar')
Examples
Internal: Convert a CamelCase word to an underscore-delimited word
def self.camelcase_to_underscore(str) str.gsub(/([[:upper:]]+)([[:upper:]][[:alpha:]])/, '\1_\2'). gsub(/([[:lower:]])([[:upper:]])/, '\1_\2').downcase end
def self.extract_view_mapping(qualified_class)
# => ['block_sidebar', 'docbook45']
Renderer.extract_view_mapping(Asciidoctor::DocBook45::BlockSidebarTemplate)
# => ['document', 'html5']
Renderer.extract_view_mapping(Asciidoctor::HTML5::DocumentTemplate)
Examples
qualified_class - The Class or String qualified class name from which to extract the view name and backend
Template suffix are stripped as the first step in the conversion.
we have control over these class names. The Asciidoctor:: prefix and
which a built-in template class maps. We can make certain assumption since
The purpose of this method is to determine the view name and backend to
Internal: Extracts the view name and backend from a qualified Ruby class
def self.extract_view_mapping(qualified_class) view_name, backend = qualified_class.to_s. gsub(/^Asciidoctor::/, ''). gsub(/Template$/, ''). split('::').reverse view_name = camelcase_to_underscore(view_name) backend = backend.downcase unless backend.nil? [view_name, backend] end
def initialize(options={})
Public: Initialize an Asciidoctor::Renderer object.
def initialize(options={}) @debug = !!options[:debug] @views = {} @compact = options[:compact] backend = options[:backend] case backend when 'html5', 'docbook45' eruby = load_eruby options[:eruby] #Asciidoctor.require_library 'asciidoctor/backends/' + backend require 'asciidoctor/backends/' + backend # Load up all the template classes that we know how to render for this backend Asciidoctor::BaseTemplate.template_classes.each do |tc| if tc.to_s.downcase.include?('::' + backend + '::') # optimization view_name, view_backend = self.class.extract_view_mapping(tc) if view_backend == backend @views[view_name] = tc.new(view_name, eruby) end end end else Asciidoctor.debug { "No built-in templates for backend: #{backend}" } end # If user passed in a template dir, let them override our base templates if template_dir = options.delete(:template_dir) Asciidoctor.require_library 'tilt' Asciidoctor.debug { msg = [] msg << "Views going in are like so:" msg << @views.map {|k, v| "#{k}: #{v}"} msg << '=' * 60 msg * "\n" } # Grab the files in the top level of the directory (we're not traversing) files = Dir.glob(File.join(template_dir, '*')).select{|f| File.stat(f).file?} files.inject(@views) do |view_hash, view| name = File.basename(view).split('.').first view_hash.merge!(name => Tilt.new(view, nil, :trim => '<>', :attr_wrapper => '"')) end Asciidoctor.debug { msg = [] msg << "Views going in are like so:" msg << @views.map {|k, v| "#{k}: #{v}"} msg << '=' * 60 msg * "\n" } end @render_stack = [] end
def load_eruby(name)
name - the String name of the eRuby implementation (default: 'erb')
Internal: Load the eRuby implementation
def load_eruby(name) if name.nil? || !['erb', 'erubis'].include?(name) name = 'erb' end Asciidoctor.require_library name if name == 'erb' ::ERB elsif name == 'erubis' ::Erubis::FastEruby end end
def render(view, object, locals = {})
object - the Object to be used as an evaluation scope.
view - the String view template name.
Public: Render an Asciidoc object with a specified view template.
def render(view, object, locals = {}) @render_stack.push([view, object]) if !@views.has_key? view raise "Couldn't find a view in @views for #{view}" else Asciidoctor.debug { "View for #{view} is #{@views[view]}, object is #{object}" } end ret = @views[view].render(object, locals) if @debug prefix = '' STDERR.puts '=' * 80 STDERR.puts "Rendering:" @render_stack.each do |stack_view, stack_obj| obj_info = case stack_obj when Asciidoctor::Section; "SECTION #{stack_obj.title}" when Asciidoctor::Block; if stack_obj.context == :dlist dt_list = stack_obj.buffer.map{|dt,dd| dt.content.strip}.join(', ') "BLOCK :dlist (#{dt_list})" #else # "BLOCK #{stack_obj.context.inspect}" end else stack_obj.class end STDERR.puts "#{prefix}#{stack_view}: #{obj_info}" prefix << ' ' end STDERR.puts '-' * 80 #STDERR.puts ret.inspect STDERR.puts '=' * 80 STDERR.puts end @render_stack.pop ret end
def views
def views readonly_views = @views.dup readonly_views.freeze readonly_views end