class Asciidoctor::Document
noheader - The header block (h1 heading, author, revision info) should not be shown
notitle - The h1 heading should not be shown
Keep in mind that you’ll want to honor these document settings:
header.title - title of section level 0
first_section.title - title of first section in document, if present
title - value of the title attribute, or nil if not present
name - an alias of doctitle
otherwise nil
otherwise title of first section in document, if present
doctitle - value of title attribute, if assigned and non-empty,
There are several strategies for getting the title of the document:
using erb templates.
Public: Methods for parsing Asciidoc documents and rendering them
def content
def content # per AsciiDoc-spec, remove the title after rendering the header @attributes.delete('title') @blocks.map {|b| b.render }.join end
def counter(name, seed = nil)
seed - the initial value as a String or Integer
name - the String name of the counter
Public: Get the named counter and take the next number in the sequence.
def counter(name, seed = nil) if !@counters.has_key? name if seed.nil? seed = nextval(@attributes.has_key?(name) ? @attributes[name] : 0) elsif seed.to_i.to_s == seed seed = seed.to_i end @counters[name] = seed else @counters[name] = nextval(@counters[name]) end (@attributes[name] = @counters[name]) end
def doctitle
def doctitle if !(title = @attributes.fetch('title', '')).empty? title elsif !(sect = first_section).nil? && sect.title? sect.title else nil end end
def doctype
def doctype @attributes['doctype'] end
def first_section
def first_section has_header? ? @header : (@blocks || []).detect{|e| e.is_a? Section} end
def has_header?
def has_header? !@header.nil? end
def initialize(data = [], options = {}, &block)
doc = Asciidoctor::Document.new(data)
data = File.readlines(filename)
Examples
data to include in this document.
block - A block that can be used to retrieve external Asciidoc
(default: {})
suppressing the header/footer (:header_footer) and attribute overrides (:attributes)
options - A Hash of options to control processing, such as setting the safe mode (:safe),
data - The Array of Strings holding the Asciidoc source document. (default: [])
Public: Initialize an Asciidoc object.
def initialize(data = [], options = {}, &block) super(self, :document) @renderer = nil if options[:parent] @parent_document = options.delete(:parent) # should we dup here? options[:attributes] = @parent_document.attributes options[:safe] ||= @parent_document.safe options[:base_dir] ||= @parent_document.base_dir @renderer = @parent_document.renderer else @parent_document = nil end @header = nil @references = { :ids => {}, :footnotes => [], :links => [], :images => [], :indexterms => [] } @counters = {} @callouts = Callouts.new @options = options @safe = @options.fetch(:safe, SafeMode::SECURE).to_i @options[:header_footer] = @options.fetch(:header_footer, false) @attributes['asciidoctor'] = '' @attributes['asciidoctor-version'] = VERSION @attributes['sectids'] = '' @attributes['encoding'] = 'UTF-8' attribute_overrides = options[:attributes] || {} # the only way to set the include-depth attribute is via the document options # 10 is the AsciiDoc default, though currently Asciidoctor only supports 1 level attribute_overrides['include-depth'] ||= 10 # if the base_dir option is specified, it overrides docdir as the root for relative paths # otherwise, the base_dir is the directory of the source file (docdir) or the current # directory of the input is a string if options[:base_dir].nil? if attribute_overrides['docdir'] @base_dir = attribute_overrides['docdir'] = File.expand_path(attribute_overrides['docdir']) else # perhaps issue a warning here? @base_dir = attribute_overrides['docdir'] = Dir.pwd end else @base_dir = attribute_overrides['docdir'] = File.expand_path(options[:base_dir]) end if @safe >= SafeMode::SERVER # restrict document from setting source-highlighter and backend attribute_overrides['source-highlighter'] ||= nil attribute_overrides['backend'] ||= DEFAULT_BACKEND # restrict document from seeing the docdir and trim docfile to relative path if attribute_overrides.has_key?('docfile') && @parent_document.nil? attribute_overrides['docfile'] = attribute_overrides['docfile'][(attribute_overrides['docdir'].length + 1)..-1] end attribute_overrides['docdir'] = '' # restrict document from enabling icons if @safe >= SafeMode::SECURE attribute_overrides['icons'] ||= nil end end attribute_overrides.delete_if {|key, val| verdict = false # a nil or negative key undefines the attribute if val.nil? || key[-1..-1] == '!' @attributes.delete(key.chomp '!') # otherwise it's an attribute assignment else # a value ending in @ indicates this attribute does not override # an attribute with the same key in the document souce if val.is_a?(String) && val.end_with?('@') val.chop! verdict = true end @attributes[key] = val end verdict } @attributes['backend'] ||= DEFAULT_BACKEND @attributes['doctype'] ||= DEFAULT_DOCTYPE update_backend_attributes if !@parent_document.nil? # don't need to do the extra processing within our own document @reader = Reader.new(data) else @reader = Reader.new(data, self, attribute_overrides, &block) end # dynamic intrinstic attribute values now = Time.new @attributes['localdate'] ||= now.strftime('%Y-%m-%d') @attributes['localtime'] ||= now.strftime('%H:%M:%S %Z') @attributes['localdatetime'] ||= [@attributes['localdate'], @attributes['localtime']] * ' ' # docdate, doctime and docdatetime should default to # localdate, localtime and localdatetime if not otherwise set @attributes['docdate'] ||= @attributes['localdate'] @attributes['doctime'] ||= @attributes['localtime'] @attributes['docdatetime'] ||= @attributes['localdatetime'] @attributes['iconsdir'] ||= File.join(@attributes.fetch('imagesdir', 'images'), 'icons') # Now parse the lines in the reader into blocks Lexer.parse(@reader, self) # or we could make it... #self << *Lexer.parse(@reader, self) @callouts.rewind Asciidoctor.debug { msg = [] msg << "Found #{@blocks.size} blocks in this document:" @blocks.each {|b| msg << b } msg * "\n" } end
def nested?
def nested? !@parent_document.nil? end
def nextval(current)
current - the value to increment as a String or Integer
Handles both integer and character sequences.
Internal: Get the next value in the sequence.
def nextval(current) if current.is_a?(Integer) current + 1 else intval = current.to_i if intval.to_s != current.to_s (current[0].ord + 1).chr else intval + 1 end end end
def noheader
def noheader @attributes.has_key? 'noheader' end
def notitle
def notitle @attributes.has_key? 'notitle' end
def register(type, value)
def register(type, value) case type when :ids if value.is_a?(Array) @references[:ids][value[0]] = (value[1] || '[' + value[0] + ']') else @references[:ids][value] = '[' + value + ']' end when :footnotes, :indexterms @references[type] << value else if @options[:catalog_assets] @references[type] << value end end end
def render(opts = {})
or a template is missing, the renderer will fall back to
loaded by Renderer. If a :template_dir is not specified,
Public: Render the Asciidoc document using the templates
def render(opts = {}) r = renderer(opts) @options.merge(opts)[:header_footer] ? r.render('document', self).strip : r.render('embedded', self) end
def renderer(opts = {})
def renderer(opts = {}) return @renderer if @renderer render_options = {} # Load up relevant Document @options if @options[:template_dir] render_options[:template_dir] = @options[:template_dir] end render_options[:backend] = @attributes.fetch('backend', 'html5') render_options[:eruby] = @options.fetch(:eruby, 'erb') render_options[:compact] = @options.fetch(:compact, false) # Override Document @option settings with options passed in render_options.merge! opts @renderer = Renderer.new(render_options) end
def source
def source @reader.source if @reader end
def splain
def splain Asciidoctor.debug { msg = '' if @header msg = "Header is #{@header}" else msg = "No header" end msg += "I have #{@blocks.count} blocks" @blocks.each_with_index do |block, i| msg += "v" * 60 msg += "Block ##{i} is a #{block.class}" msg += "Name is #{block.title rescue 'n/a'}" block.splain(0) if block.respond_to? :splain msg += "^" * 60 end } nil end
def title
def title @attributes['title'] end
def title=(title)
def title=(title) @header = Section.new self @header.title = title end
def to_s
def to_s %[#{super.to_s} - #{doctitle}] end
def update_backend_attributes()
def update_backend_attributes() backend = @attributes['backend'] if BACKEND_ALIASES.has_key? backend backend = @attributes['backend'] = BACKEND_ALIASES[backend] end basebackend = backend.sub(/[[:digit:]]+$/, '') page_width = DEFAULT_PAGE_WIDTHS[basebackend] if page_width @attributes['pagewidth'] = page_width else @attributes.delete('pagewidth') end @attributes["backend-#{backend}"] = '' @attributes['basebackend'] = basebackend @attributes["basebackend-#{basebackend}"] = '' # REVIEW cases for the next two assignments @attributes["#{backend}-#{@attributes['doctype']}"] = '' @attributes["#{basebackend}-#{@attributes['doctype']}"] = '' ext = DEFAULT_EXTENSIONS[basebackend] || '.html' @attributes['outfilesuffix'] = ext file_type = ext[1..-1] @attributes['filetype'] = file_type @attributes["filetype-#{file_type}"] = '' end