module Asciidoctor
Public: Methods for parsing Asciidoc input files and rendering documents using eRuby templates.
Asciidoc documents comprise a header followed by zero or more sections. Sections are composed of blocks of content. For example:
= Doc Title == Section 1 This is a paragraph block in the first section. == Section 2 This section has a paragraph block and an olist block. . Item 1 . Item 2
Examples:
Use built-in templates:
lines = File.readlines("your_file.asc") doc = Asciidoctor::Document.new(lines) html = doc.render File.open("your_file.html", "w+") do |file| file.puts html end
Use custom (Tilt-supported) templates:
lines = File.readlines("your_file.asc") doc = Asciidoctor::Document.new(lines, :template_dir => 'templates') html = doc.render File.open("your_file.html", "w+") do |file| file.puts html end
NOTE once we decide to make DocBook 5 the default, we'll load the files the other way around
Constants
- ADMONITION_STYLES
- ASCIIDOC_EXTENSIONS
Set of file extensions recognized as AsciiDoc documents (stored as a truth hash)
- BACKEND_ALIASES
Pointers to the preferred version for a given backend.
- BLANK_LINE_PATTERN
NOTE allows for empty space in line as it could be left by the template engine
- BREAK_LINES
- COMPLIANCE
Flags to control compliance with the behavior of AsciiDoc
- DEFAULT_BACKEND
The backend determines the format of the rendered output, default to html5
- DEFAULT_DOCTYPE
The default document type Can influence markup generated by render templates
- DEFAULT_EXTENSIONS
Default extensions for the respective base backends
- DEFAULT_PAGE_WIDTHS
Default page widths for calculating absolute widths
- DEFAULT_STYLESHEET_KEYS
- DEFAULT_STYLESHEET_NAME
- DELIMITED_BLOCKS
- DELIMITED_BLOCK_LEADERS
- EOL
The endline character to use when rendering output
- FLEXIBLE_ATTRIBUTES
attributes which be changed within the content of the document (but not header) because it has semantic meaning; ex. numbered
- FORCE_ENCODING
Flag to indicate whether encoding of external strings needs to be forced to UTF-8 All input data must be force encoded to UTF-8 if Encoding.default_external is not UTF-8 Address failures performing string operations that are reported as “invalid byte sequence in US-ASCII” Ruby 1.8 doesn't seem to experience this problem (perhaps because it isn't validating the encodings)
- FORCE_UNICODE_LINE_LENGTH
Flag to indicate that line length should be calculated using a unicode mode hint
- INTRINSICS
- LINE_BREAK
- LINE_FEED_ENTITY
- LIST_CONTINUATION
- NESTABLE_LIST_CONTEXTS
LIST_CONTEXTS = [:ulist, :olist, :dlist, :colist]
- ORDERED_LIST_KEYWORDS
- ORDERED_LIST_MARKER_PATTERNS
- ORDERED_LIST_STYLES
TODO validate use of explicit style name above ordered list (this list is for selecting an implicit style)
- PARAGRAPH_STYLES
- QUOTE_SUBS
- unconstrained quotes
-
can appear anywhere
- constrained quotes
-
must be bordered by non-word characters
NOTE these substituions are processed in the order they appear here and the order in which they are replaced is important
- REGEXP
The following pattern, which appears frequently, captures the contents between square brackets, ignoring escaped closing brackets (closing brackets prefixed with a backslash '' character)
Pattern: (?:[((?:\]|[^]])*?)]) Matches:
- enclosed text here
-
or [enclosed [text] here]
- REPLACEMENTS
NOTE in Ruby 1.8.7, [^\] does not match start of line, so we need to match it explicitly order is significant
- ROOT_PATH
The root path of the Asciidoctor gem
- SECTION_LEVELS
- SPECIAL_CHARS
- SPECIAL_CHARS_PATTERN
- VERBATIM_STYLES
- VERSION
Public Class Methods
Public: Parse the AsciiDoc source input into an Asciidoctor::Document
Accepts input as an IO (or StringIO), String or String Array object. If the input is a File, information about the file is stored in attributes on the Document object.
input - the AsciiDoc source as a IO, String or Array. options - a String, Array or Hash of options to control processing (default: {})
String and Array values are converted into a Hash. See Asciidoctor::Document#initialize for details about options.
returns the Asciidoctor::Document
# File lib/asciidoctor.rb, line 742 def self.load(input, options = {}) if (monitor = options.fetch(:monitor, false)) start = Time.now end attrs = (options[:attributes] ||= {}) if attrs.is_a?(Hash) || (RUBY_ENGINE == 'jruby' && attrs.is_a?(Java::JavaUtil::Map)) # all good; placed here as optimization elsif attrs.is_a? Array attrs = options[:attributes] = attrs.inject({}) do |accum, entry| k, v = entry.split '=', 2 accum[k] = v || '' accum end elsif attrs.is_a? String # convert non-escaped spaces into null character, so we split on the # correct spaces chars, and restore escaped spaces attrs = attrs.gsub(REGEXP[:space_delim], "\\1\0").gsub(REGEXP[:escaped_space], '\1') attrs = options[:attributes] = attrs.split("\0").inject({}) do |accum, entry| k, v = entry.split '=', 2 accum[k] = v || '' accum end elsif attrs.respond_to?('keys') && attrs.respond_to?('[]') # convert it to a Hash as we know it original_attrs = attrs attrs = options[:attributes] = {} original_attrs.keys.each do |key| attrs[key] = original_attrs[key] end else raise ArgumentError, "illegal type for attributes option: #{attrs.class.ancestors}" end lines = nil if input.is_a? File lines = input.readlines input_mtime = input.mtime input_path = File.expand_path(input.path) # hold off on setting infile and indir until we get a better sense of their purpose attrs['docfile'] = input_path attrs['docdir'] = File.dirname(input_path) attrs['docname'] = File.basename(input_path, File.extname(input_path)) attrs['docdate'] = input_mtime.strftime('%Y-%m-%d') attrs['doctime'] = input_mtime.strftime('%H:%M:%S %Z') attrs['docdatetime'] = [attrs['docdate'], attrs['doctime']] * ' ' elsif input.respond_to?(:readlines) input.rewind rescue nil lines = input.readlines elsif input.is_a?(String) lines = input.lines.entries elsif input.is_a?(Array) lines = input.dup else raise "Unsupported input type: #{input.class}" end if monitor read_time = Time.now - start start = Time.now end doc = Document.new(lines, options) if monitor parse_time = Time.now - start monitor[:read] = read_time monitor[:parse] = parse_time monitor[:load] = read_time + parse_time end doc end
Public: Parse the contents of the AsciiDoc source file into an Asciidoctor::Document
Accepts input as an IO, String or String Array object. If the input is a File, information about the file is stored in attributes on the Document.
input - the String AsciiDoc source filename options - a String, Array or Hash of options to control processing (default: {})
String and Array values are converted into a Hash. See Asciidoctor::Document#initialize for details about options.
returns the Asciidoctor::Document
# File lib/asciidoctor.rb, line 827 def self.load_file(filename, options = {}) Asciidoctor.load(File.new(filename), options) end
Public: Parse the AsciiDoc source input into an Asciidoctor::Document and render it to the specified backend format
Accepts input as an IO, String or String Array object. If the input is a File, information about the file is stored in attributes on the Document.
If the :in_place option is true, and the input is a File, the output is written to a file adjacent to the input file, having an extension that corresponds to the backend format. Otherwise, if the :to_file option is specified, the file is written to that file. If :to_file is not an absolute path, it is resolved relative to :to_dir, if given, otherwise the Asciidoctor::Document#base_dir. If the target directory does not exist, it will not be created unless the :mkdirs option is set to true. If the file cannot be written because the target directory does not exist, or because it falls outside of the Asciidoctor::Document#base_dir in safe mode, an IOError is raised.
If the output is going to be written to a file, the header and footer are rendered unless specified otherwise (writing to a file implies creating a standalone document). Otherwise, the header and footer are not rendered by default and the rendered output is returned.
input - the String AsciiDoc source filename options - a String, Array or Hash of options to control processing (default: {})
String and Array values are converted into a Hash. See Asciidoctor::Document#initialize for details about options.
returns the Document object if the rendered result String is written to a file, otherwise the rendered result String
# File lib/asciidoctor.rb, line 860 def self.render(input, options = {}) in_place = options.delete(:in_place) || false to_file = options.delete(:to_file) to_dir = options.delete(:to_dir) mkdirs = options.delete(:mkdirs) || false monitor = options.fetch(:monitor, false) write_in_place = in_place && input.is_a?(File) write_to_target = to_file || to_dir stream_output = !to_file.nil? && to_file.respond_to?(:write) if write_in_place && write_to_target raise ArgumentError, 'the option :in_place cannot be used with either the :to_dir or :to_file option' end if !options.has_key?(:header_footer) && (write_in_place || write_to_target) options[:header_footer] = true end doc = Asciidoctor.load(input, options) if to_file == '/dev/null' return doc elsif write_in_place to_file = File.join(File.dirname(input.path), "#{doc.attributes['docname']}#{doc.attributes['outfilesuffix']}") elsif !stream_output && write_to_target working_dir = options.has_key?(:base_dir) ? File.expand_path(options[:base_dir]) : File.expand_path(Dir.pwd) # QUESTION should the jail be the working_dir or doc.base_dir??? jail = doc.safe >= SafeMode::SAFE ? working_dir : nil if to_dir to_dir = doc.normalize_system_path(to_dir, working_dir, jail, :target_name => 'to_dir', :recover => false) if to_file to_file = doc.normalize_system_path(to_file, to_dir, nil, :target_name => 'to_dir', :recover => false) # reestablish to_dir as the final target directory (in the case to_file had directory segments) to_dir = File.dirname(to_file) else to_file = File.join(to_dir, "#{doc.attributes['docname']}#{doc.attributes['outfilesuffix']}") end elsif to_file to_file = doc.normalize_system_path(to_file, working_dir, jail, :target_name => 'to_dir', :recover => false) # establish to_dir as the final target directory (in the case to_file had directory segments) to_dir = File.dirname(to_file) end if !File.directory? to_dir if mkdirs Helpers.require_library 'fileutils' FileUtils.mkdir_p to_dir else raise IOError, "target directory does not exist: #{to_dir}" end end end start = Time.now if monitor output = doc.render if monitor render_time = Time.now - start monitor[:render] = render_time monitor[:load_render] = monitor[:load] + render_time end if to_file start = Time.now if monitor if stream_output to_file.write output.rstrip # ensure there's a trailing endline to_file.write EOL else File.open(to_file, 'w') {|file| file.write output } # these assignments primarily for testing, diagnostics or reporting doc.attributes['outfile'] = outfile = File.expand_path(to_file) doc.attributes['outdir'] = File.dirname(outfile) end if monitor write_time = Time.now - start monitor[:write] = write_time monitor[:total] = monitor[:load_render] + write_time end # NOTE document cannot control this behavior if safe >= SafeMode::SERVER if !stream_output && doc.safe < SafeMode::SECURE && (doc.attr? 'basebackend-html') && (doc.attr? 'linkcss') && (doc.attr? 'copycss') copy_asciidoctor_stylesheet = DEFAULT_STYLESHEET_KEYS.include?(stylesheet = (doc.attr 'stylesheet')) #copy_user_stylesheet = !copy_asciidoctor_stylesheet && (doc.attr? 'copycss') copy_coderay_stylesheet = (doc.attr? 'source-highlighter', 'coderay') && (doc.attr 'coderay-css', 'class') == 'class' copy_pygments_stylesheet = (doc.attr? 'source-highlighter', 'pygments') && (doc.attr 'pygments-css', 'class') == 'class' if copy_asciidoctor_stylesheet || copy_coderay_stylesheet || copy_pygments_stylesheet Helpers.require_library 'fileutils' outdir = doc.attr('outdir') stylesdir = doc.normalize_system_path(doc.attr('stylesdir'), outdir, doc.safe >= SafeMode::SAFE ? outdir : nil) Helpers.mkdir_p stylesdir if mkdirs if copy_asciidoctor_stylesheet File.open(File.join(stylesdir, DEFAULT_STYLESHEET_NAME), 'w') {|f| f.write Asciidoctor::HTML5.default_asciidoctor_stylesheet } end #if copy_user_stylesheet #end if copy_coderay_stylesheet File.open(File.join(stylesdir, 'asciidoctor-coderay.css'), 'w') {|f| f.write Asciidoctor::HTML5.default_coderay_stylesheet } end if copy_pygments_stylesheet File.open(File.join(stylesdir, 'asciidoctor-pygments.css'), 'w') {|f| f.write Asciidoctor::HTML5.pygments_stylesheet(doc.attr 'pygments-style') } end end end doc else output end end
Public: Parse the contents of the AsciiDoc source file into an Asciidoctor::Document and render it to the specified backend format
input - the String AsciiDoc source filename options - a String, Array or Hash of options to control processing (default: {})
String and Array values are converted into a Hash. See Asciidoctor::Document#initialize for details about options.
returns the Document object if the rendered result String is written to a file, otherwise the rendered result String
# File lib/asciidoctor.rb, line 992 def self.render_file(filename, options = {}) Asciidoctor.render(File.new(filename), options) end