Class: Asciidoctor::Document
- Inherits:
-
AbstractBlock
- Object
- AbstractNode
- AbstractBlock
- Asciidoctor::Document
- Defined in:
- lib/asciidoctor/document.rb
Overview
can take the process to completion by calling the #convert method.
Defined Under Namespace
Classes: AttributeEntry, Author, Footnote, ImageReference, Title
Constant Summary
Constants included from Substitutors
Substitutors::CAN, Substitutors::CGI, Substitutors::DEL, Substitutors::ESC_R_SB, Substitutors::HighlightedPassSlotRx, Substitutors::PASS_END, Substitutors::PASS_START, Substitutors::PLUS, Substitutors::PassSlotRx, Substitutors::QuotedTextSniffRx, Substitutors::RS, Substitutors::R_SB, Substitutors::SUB_GROUPS, Substitutors::SUB_HINTS, Substitutors::SUB_OPTIONS, Substitutors::SpecialCharsRx, Substitutors::SpecialCharsTr
Instance Attribute Summary collapse
-
#backend ⇒ Object
readonly
Get the cached value of the backend attribute for this document.
-
#base_dir ⇒ Object
readonly
Get the String base directory for converting this document.
-
#catalog ⇒ Object
(also: #references)
readonly
Get the document catalog Hash.
-
#compat_mode ⇒ Object
readonly
Get the Boolean AsciiDoc compatibility mode.
-
#converter ⇒ Object
readonly
Get the Converter associated with this document.
-
#counters ⇒ Object
readonly
Get the Hash of document counters.
-
#doctype ⇒ Object
readonly
Get the cached value of the doctype attribute for this document.
-
#extensions ⇒ Object
readonly
Get the activated Extensions::Registry associated with this document.
-
#header ⇒ Object
readonly
Get the level-0 Section (i.e., doctitle).
-
#options ⇒ Object
readonly
Get the Hash of resolved options used to initialize this Document.
-
#outfilesuffix ⇒ Object
readonly
Get the outfilesuffix defined at the end of the header.
-
#parent_document ⇒ Object
readonly
Get a reference to the parent Document of this nested document.
-
#path_resolver ⇒ Object
readonly
Get/Set the PathResolver instance used to resolve paths in this Document.
-
#reader ⇒ Object
readonly
Get the Reader associated with this document.
-
#safe ⇒ Object
readonly
Public A read-only integer value indicating the level of security that should be enforced while processing this document.
-
#sourcemap ⇒ Object
Get or set the Boolean flag that indicates whether source map information should be tracked by the parser.
-
#syntax_highlighter ⇒ Object
readonly
Get the SyntaxHighlighter associated with this document.
Attributes inherited from AbstractBlock
#blocks, #caption, #content_model, #level, #numeral, #source_location, #style, #subs
Attributes inherited from AbstractNode
#attributes, #context, #document, #id, #node_name, #parent
Instance Method Summary collapse
-
#<<(block) ⇒ The
Append a content Block to this Document.
-
#attribute_locked?(name) ⇒ Boolean
Determine if the attribute has been locked by being assigned in document options.
-
#author ⇒ Object
Convenience method to retrieve the document attribute ‘author’.
-
#authors ⇒ Object
Convenience method to retrieve the authors of this document as an Array of Author objects.
- #basebackend?(base) ⇒ Boolean
- #callouts ⇒ Object
- #content ⇒ Object
-
#convert(opts = {}) ⇒ Object
(also: #render)
Convert the AsciiDoc document using the templates loaded by the Converter.
-
#counter(name, seed = nil) ⇒ Object
Get the named counter and take the next number in the sequence.
-
#delete_attribute(name) ⇒ Object
Delete the specified attribute from the document if the name is not locked.
-
#docinfo(location = :head, suffix = nil) ⇒ Object
Read the docinfo file(s) for inclusion in the document template.
- #docinfo_processors?(location = :head) ⇒ Boolean
-
#doctitle(opts = {}) ⇒ Title
(also: #name)
Resolves the primary title for the document.
- #embedded? ⇒ Boolean
- #extensions? ⇒ Boolean
- #first_section ⇒ Object
- #footnotes ⇒ Object
- #footnotes? ⇒ Boolean
- #header? ⇒ Boolean (also: #has_header?)
-
#increment_and_store_counter(counter_name, block) ⇒ Object
(also: #counter_increment)
Increment the specified counter and store it in the block’s attributes.
-
#initialize(data = nil, options = {}) ⇒ Document
constructor
Initialize a Document object.
- #nested? ⇒ Boolean
- #nofooter ⇒ Object
- #noheader ⇒ Object
- #notitle ⇒ Object
-
#parse(data = nil) ⇒ Document
Parse the AsciiDoc source stored in the Reader into an abstract syntax tree.
-
#parsed? ⇒ Boolean
Returns whether the source lines of the document have been parsed.
-
#playback_attributes(block_attributes) ⇒ Object
Replay attribute assignments at the block level.
-
#register(type, value) ⇒ Object
Register a reference in the document catalog.
-
#resolve_id(text) ⇒ Object
Scan registered references and return the ID of the first reference that matches the specified reference text.
-
#restore_attributes ⇒ Object
Restore the attributes to the previously saved state (attributes in header).
-
#revdate ⇒ Object
Convenience method to retrieve the document attribute ‘revdate’.
-
#sections? ⇒ Boolean
Check whether this Document has any child Section objects.
-
#set_attribute(name, value = '') ⇒ Object
Set the specified attribute on the document if the name is not locked.
-
#set_header_attribute(name, value = '', overwrite = true) ⇒ Boolean
Assign a value to the specified attribute in the document header.
-
#source ⇒ Object
Make the raw source for the Document available.
-
#source_lines ⇒ Object
Make the raw source lines for the Document available.
-
#title ⇒ String
Return the doctitle as a String.
-
#title=(title) ⇒ String
Set the title on the document header.
- #to_s ⇒ Object
-
#write(output, target) ⇒ void
Write the output to the specified file.
- #xreftext(xrefstyle = nil) ⇒ Object
Methods inherited from AbstractBlock
#alt, #assign_caption, #block?, #blocks?, #captioned_title, #context=, #file, #find_by, #inline?, #lineno, #list_marker_keyword, #next_adjacent_block, #number, #number=, #remove_sub, #sections, #sub?, #title?
Methods inherited from AbstractNode
#add_role, #attr, #attr?, #block?, #enabled_options, #generate_data_uri, #generate_data_uri_from_uri, #has_role?, #icon_uri, #image_uri, #inline?, #is_uri?, #media_uri, #normalize_asset_path, #normalize_system_path, #normalize_web_path, #option?, #read_asset, #read_contents, #reftext, #reftext?, #remove_attr, #remove_role, #role, #role=, #role?, #roles, #set_attr, #set_option, #update_attributes
Methods included from Substitutors
#apply_header_subs, #apply_normal_subs, #apply_reftext_subs, #apply_subs, #expand_subs, #extract_passthroughs, #highlight_source, #resolve_block_subs, #resolve_lines_to_highlight, #resolve_pass_subs, #resolve_subs, #restore_passthroughs, #sub_attributes, #sub_callouts, #sub_macros, #sub_post_replacements, #sub_quotes, #sub_replacements, #sub_source, #sub_specialchars
Methods included from Logging
#logger, #message_with_context
Constructor Details
#initialize(data = nil, options = {}) ⇒ Document
Initialize a Asciidoctor::Document object.
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'lib/asciidoctor/document.rb', line 253 def initialize data = nil, = {} super self, :document if (parent_doc = .delete :parent) @parent_document = parent_doc [:base_dir] ||= parent_doc.base_dir [:catalog_assets] = true if parent_doc.[:catalog_assets] [:to_dir] = parent_doc.[:to_dir] if parent_doc.[:to_dir] @catalog = parent_doc.catalog.merge footnotes: [] # QUESTION should we support setting attribute in parent document from nested document? @attribute_overrides = attr_overrides = (parent_doc.instance_variable_get :@attribute_overrides).merge parent_doc.attributes attr_overrides.delete 'compat-mode' parent_doctype = attr_overrides.delete 'doctype' attr_overrides.delete 'notitle' attr_overrides.delete 'showtitle' # QUESTION if toc is hard unset in parent document, should it be hard unset in nested document? attr_overrides.delete 'toc' @attributes['toc-placement'] = (attr_overrides.delete 'toc-placement') || 'auto' attr_overrides.delete 'toc-position' @safe = parent_doc.safe @attributes['compat-mode'] = '' if (@compat_mode = parent_doc.compat_mode) @outfilesuffix = parent_doc.outfilesuffix @sourcemap = parent_doc.sourcemap @timings = nil @path_resolver = parent_doc.path_resolver @converter = parent_doc.converter initialize_extensions = nil @extensions = parent_doc.extensions @syntax_highlighter = parent_doc.syntax_highlighter else @parent_document = nil @catalog = { ids: {}, # deprecated; kept for backwards compatibility with converters refs: {}, footnotes: [], links: [], images: [], callouts: Callouts.new, includes: {}, } # copy attributes map and normalize keys # attribute overrides are attributes that can only be set from the commandline # a direct assignment effectively makes the attribute a constant # a nil value or name with leading or trailing ! will result in the attribute being unassigned @attribute_overrides = attr_overrides = {} ([:attributes] || {}).each do |key, val| if key.end_with? '@' if key.start_with? '!' key, val = (key.slice 1, key.length - 2), false elsif key.end_with? '!@' key, val = (key.slice 0, key.length - 2), false else key, val = key.chop, %(#{val}@) end elsif key.start_with? '!' key, val = (key.slice 1, key.length), val == '@' ? false : nil elsif key.end_with? '!' key, val = key.chop, val == '@' ? false : nil end attr_overrides[key.downcase] = val end if ::String === (to_file = [:to_file]) attr_overrides['outfilesuffix'] = Helpers.extname to_file end # safely resolve the safe mode from const, int or string if !(safe_mode = [:safe]) @safe = SafeMode::SECURE elsif ::Integer === safe_mode # be permissive in case API user wants to define new levels @safe = safe_mode else @safe = (SafeMode.value_for_name safe_mode) rescue SafeMode::SECURE end input_mtime = .delete :input_mtime @compat_mode = attr_overrides.key? 'compat-mode' @sourcemap = [:sourcemap] @timings = .delete :timings @path_resolver = PathResolver.new initialize_extensions = (defined? ::Asciidoctor::Extensions) || (.key? :extensions) ? ::Asciidoctor::Extensions : nil @extensions = nil # initialize further down if initialize_extensions is true [:standalone] = [:header_footer] if (.key? :header_footer) && !(.key? :standalone) end @parsed = @reftexts = @header = @header_attributes = nil @counters = {} @attributes_modified = ::Set.new @docinfo_processor_extensions = {} standalone = [:standalone] (@options = ).freeze attrs = @attributes unless parent_doc attrs['attribute-undefined'] = Compliance.attribute_undefined attrs['attribute-missing'] = Compliance.attribute_missing attrs.update DEFAULT_ATTRIBUTES # TODO if lang attribute is set, @safe mode < SafeMode::SERVER, and !parent_doc, # load attributes from data/locale/attributes-<lang>.adoc end if standalone # sync embedded attribute with :standalone option value attr_overrides['embedded'] = nil attrs['copycss'] = '' attrs['iconfont-remote'] = '' attrs['stylesheet'] = '' attrs['webfonts'] = '' else # sync embedded attribute with :standalone option value attr_overrides['embedded'] = '' if (attr_overrides.key? 'showtitle') && (attr_overrides.keys & %w(notitle showtitle))[-1] == 'showtitle' attr_overrides['notitle'] = { nil => '', false => '@', '@' => false }[attr_overrides['showtitle']] elsif attr_overrides.key? 'notitle' attr_overrides['showtitle'] = { nil => '', false => '@', '@' => false }[attr_overrides['notitle']] else attrs['notitle'] = '' end end attr_overrides['asciidoctor'] = '' attr_overrides['asciidoctor-version'] = ::Asciidoctor::VERSION attr_overrides['safe-mode-name'] = (safe_mode_name = SafeMode.name_for_value @safe) attr_overrides[%(safe-mode-#{safe_mode_name})] = '' attr_overrides['safe-mode-level'] = @safe # the only way to set the max-include-depth attribute is via the API; default to 64 like AsciiDoc.py attr_overrides['max-include-depth'] ||= 64 # the only way to set the allow-uri-read attribute is via the API; disabled by default attr_overrides['allow-uri-read'] ||= nil # remap legacy attribute names attr_overrides['sectnums'] = attr_overrides.delete 'numbered' if attr_overrides.key? 'numbered' attr_overrides['hardbreaks-option'] = attr_overrides.delete 'hardbreaks' if attr_overrides.key? 'hardbreaks' # If the base_dir option is specified, it overrides docdir and is used as the root for relative # paths. Otherwise, the base_dir is the directory of the source file (docdir), if set, otherwise # the current directory. if (base_dir_val = [:base_dir]) @base_dir = (attr_overrides['docdir'] = ::File. base_dir_val) elsif attr_overrides['docdir'] @base_dir = attr_overrides['docdir'] else #logger.warn 'setting base_dir is recommended when working with string documents' unless nested? @base_dir = attr_overrides['docdir'] = ::Dir.pwd end # allow common attributes backend and doctype to be set using options hash, coerce values to string if (backend_val = [:backend]) attr_overrides['backend'] = backend_val.to_s end if (doctype_val = [:doctype]) attr_overrides['doctype'] = doctype_val.to_s end if @safe >= SafeMode::SERVER # restrict document from setting copycss, source-highlighter and backend attr_overrides['copycss'] ||= nil attr_overrides['source-highlighter'] ||= nil attr_overrides['backend'] ||= DEFAULT_BACKEND # restrict document from seeing the docdir and trim docfile to relative path if !parent_doc && attr_overrides.key?('docfile') attr_overrides['docfile'] = attr_overrides['docfile'][(attr_overrides['docdir'].length + 1)..-1] end attr_overrides['docdir'] = '' attr_overrides['user-home'] ||= '.' if @safe >= SafeMode::SECURE attr_overrides['max-attribute-value-size'] = 4096 unless attr_overrides.key? 'max-attribute-value-size' # assign linkcss (preventing css embedding) unless explicitly disabled from the commandline or API #attr_overrides['linkcss'] = (attr_overrides.fetch 'linkcss', '') || nil attr_overrides['linkcss'] = '' unless attr_overrides.key? 'linkcss' # restrict document from enabling icons attr_overrides['icons'] ||= nil end else attr_overrides['user-home'] ||= USER_HOME end # the only way to set the max-attribute-value-size attribute is via the API; disabled by default @max_attribute_value_size = (size = (attr_overrides['max-attribute-value-size'] ||= nil)) ? size.to_i.abs : nil attr_overrides.delete_if do |key, val| if val # a value ending in @ allows document to override value if ::String === val && (val.end_with? '@') val, verdict = val.chop, true end attrs[key] = val else # a nil or false value both unset the attribute; only a nil value locks it attrs.delete key verdict = val == false end verdict end if parent_doc @backend = attrs['backend'] # reset doctype unless it matches the default value unless (@doctype = attrs['doctype'] = parent_doctype) == DEFAULT_DOCTYPE update_doctype_attributes DEFAULT_DOCTYPE end # don't need to do the extra processing within our own document # FIXME line info isn't reported correctly within include files in nested document @reader = Reader.new data, [:cursor] @source_location = @reader.cursor if @sourcemap # Now parse the lines in the reader into blocks # Eagerly parse (for now) since a subdocument is not a publicly accessible object Parser.parse @reader, self # should we call some sort of post-parse function? restore_attributes @parsed = true else # setup default backend and doctype @backend = nil if (initial_backend = attrs['backend'] || DEFAULT_BACKEND) == 'manpage' @doctype = attrs['doctype'] = attr_overrides['doctype'] = 'manpage' else @doctype = (attrs['doctype'] ||= DEFAULT_DOCTYPE) end update_backend_attributes initial_backend, true # dynamic intrinstic attribute values #attrs['indir'] = attrs['docdir'] #attrs['infile'] = attrs['docfile'] # fallback directories attrs['stylesdir'] ||= '.' attrs['iconsdir'] ||= %(#{attrs.fetch 'imagesdir', './images'}/icons) fill_datetime_attributes attrs, input_mtime if initialize_extensions if (ext_registry = [:extension_registry]) # QUESTION should we warn if the value type of this option is not a registry if Extensions::Registry === ext_registry || ((defined? ::AsciidoctorJ::Extensions::ExtensionRegistry) && ::AsciidoctorJ::Extensions::ExtensionRegistry === ext_registry) @extensions = ext_registry.activate self end elsif (ext_block = [:extensions]).nil? @extensions = Extensions::Registry.new.activate self unless Extensions.groups.empty? elsif ::Proc === ext_block @extensions = Extensions.create(&ext_block).activate self end end @reader = PreprocessorReader.new self, data, (Reader::Cursor.new attrs['docfile'], @base_dir), normalize: true @source_location = @reader.cursor if @sourcemap end end |
Instance Attribute Details
#backend ⇒ Object (readonly)
Get the cached value of the backend attribute for this document
190 191 192 |
# File 'lib/asciidoctor/document.rb', line 190 def backend @backend end |
#base_dir ⇒ Object (readonly)
Get the String base directory for converting this document.
Defaults to directory of the source file. If the source is a string, defaults to the current directory.
214 215 216 |
# File 'lib/asciidoctor/document.rb', line 214 def base_dir @base_dir end |
#catalog ⇒ Object (readonly) Also known as: references
Get the document catalog Hash
199 200 201 |
# File 'lib/asciidoctor/document.rb', line 199 def catalog @catalog end |
#compat_mode ⇒ Object (readonly)
Get the Boolean AsciiDoc compatibility mode
enabling this attribute activates the following syntax changes:
* single quotes as constrained emphasis formatting marks
* single backticks parsed as inline literal, formatted as monospace
* single plus parsed as constrained, monospaced inline formatting
* double plus parsed as constrained, monospaced inline formatting
187 188 189 |
# File 'lib/asciidoctor/document.rb', line 187 def compat_mode @compat_mode end |
#converter ⇒ Object (readonly)
Get the Converter associated with this document
232 233 234 |
# File 'lib/asciidoctor/document.rb', line 232 def converter @converter end |
#counters ⇒ Object (readonly)
Get the Hash of document counters
205 206 207 |
# File 'lib/asciidoctor/document.rb', line 205 def counters @counters end |
#doctype ⇒ Object (readonly)
Get the cached value of the doctype attribute for this document
193 194 195 |
# File 'lib/asciidoctor/document.rb', line 193 def doctype @doctype end |
#extensions ⇒ Object (readonly)
Get the activated Extensions::Registry associated with this document.
238 239 240 |
# File 'lib/asciidoctor/document.rb', line 238 def extensions @extensions end |
#header ⇒ Object (readonly)
Get the level-0 Section (i.e., doctitle). (Only stores the title, not the header attributes).
208 209 210 |
# File 'lib/asciidoctor/document.rb', line 208 def header @header end |
#options ⇒ Object (readonly)
Get the Hash of resolved options used to initialize this Document
217 218 219 |
# File 'lib/asciidoctor/document.rb', line 217 def @options end |
#outfilesuffix ⇒ Object (readonly)
Get the outfilesuffix defined at the end of the header.
220 221 222 |
# File 'lib/asciidoctor/document.rb', line 220 def outfilesuffix @outfilesuffix end |
#parent_document ⇒ Object (readonly)
Get a reference to the parent Document of this nested document.
223 224 225 |
# File 'lib/asciidoctor/document.rb', line 223 def parent_document @parent_document end |
#path_resolver ⇒ Object (readonly)
Get/Set the PathResolver instance used to resolve paths in this Document.
229 230 231 |
# File 'lib/asciidoctor/document.rb', line 229 def path_resolver @path_resolver end |
#reader ⇒ Object (readonly)
Get the Reader associated with this document
226 227 228 |
# File 'lib/asciidoctor/document.rb', line 226 def reader @reader end |
#safe ⇒ Object (readonly)
Public A read-only integer value indicating the level of security that should be enforced while processing this document. The value must be set in the Document constructor using the :safe option.
A value of 0 (UNSAFE) disables any of the security features enforced by Asciidoctor (Ruby is still subject to its own restrictions).
A value of 1 (SAFE) closely parallels safe mode in AsciiDoc. In particular, it prevents access to files which reside outside of the parent directory of the source file and disables any macro other than the include directive.
A value of 10 (SERVER) disallows the document from setting attributes that would affect the conversion of the document, in addition to all the security features of SafeMode::SAFE. For instance, this level forbids changing the backend or source-highlighter using an attribute defined in the source document header. This is the most fundamental level of security for server deployments (hence the name).
A value of 20 (SECURE) disallows the document from attempting to read files from the file system and including the contents of them into the document, in addition to all the security features of SafeMode::SECURE. In particular, it disallows use of the include::[] directive and the embedding of binary content (data uri), stylesheets and JavaScripts referenced by the document. (Asciidoctor and trusted extensions may still be allowed to embed trusted content into the document).
Since Asciidoctor is aiming for wide adoption, 20 (SECURE) is the default value and is recommended for server deployments.
A value of 100 (PARANOID) is planned to disallow the use of passthrough macros and prevents the document from setting any known attributes in addition to all the security features of SafeMode::SECURE. Please note that this level is not currently implemented (and therefore not enforced)!
176 177 178 |
# File 'lib/asciidoctor/document.rb', line 176 def safe @safe end |
#sourcemap ⇒ Object
Get or set the Boolean flag that indicates whether source map information should be tracked by the parser
196 197 198 |
# File 'lib/asciidoctor/document.rb', line 196 def sourcemap @sourcemap end |
#syntax_highlighter ⇒ Object (readonly)
Get the SyntaxHighlighter associated with this document
235 236 237 |
# File 'lib/asciidoctor/document.rb', line 235 def syntax_highlighter @syntax_highlighter end |
Instance Method Details
#<<(block) ⇒ The
Append a content Block to this Document.
If the child block is a Section, assign an index to it.
807 808 809 810 |
# File 'lib/asciidoctor/document.rb', line 807 def << block assign_numeral block if block.context == :section super end |
#attribute_locked?(name) ⇒ Boolean
Determine if the attribute has been locked by being assigned in document options
900 901 902 |
# File 'lib/asciidoctor/document.rb', line 900 def attribute_locked?(name) @attribute_overrides.key?(name) end |
#author ⇒ Object
Convenience method to retrieve the document attribute ‘author’
returns the full name of the author as a String
747 748 749 |
# File 'lib/asciidoctor/document.rb', line 747 def @attributes['author'] end |
#authors ⇒ Object
Convenience method to retrieve the authors of this document as an Array of Author objects.
This method is backed by the author-related attributes on the document.
returns the authors of this document as an Array
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 |
# File 'lib/asciidoctor/document.rb', line 756 def if (attrs = @attributes).key? 'author' = [(Author.new attrs['author'], attrs['firstname'], attrs['middlename'], attrs['lastname'], attrs['authorinitials'], attrs['email'])] if ( = attrs['authorcount'] || 0) > 1 idx = 1 while idx < idx += 1 << (Author.new attrs[%(author_#{idx})], attrs[%(firstname_#{idx})], attrs[%(middlename_#{idx})], attrs[%(lastname_#{idx})], attrs[%(authorinitials_#{idx})], attrs[%(email_#{idx})]) end end else [] end end |
#basebackend?(base) ⇒ Boolean
676 677 678 |
# File 'lib/asciidoctor/document.rb', line 676 def basebackend? base @attributes['basebackend'] == base end |
#callouts ⇒ Object
650 651 652 |
# File 'lib/asciidoctor/document.rb', line 650 def callouts @catalog[:callouts] end |
#content ⇒ Object
1009 1010 1011 1012 1013 |
# File 'lib/asciidoctor/document.rb', line 1009 def content # NOTE per AsciiDoc-spec, remove the title before converting the body @attributes.delete('title') super end |
#convert(opts = {}) ⇒ Object Also known as: render
Convert the AsciiDoc document using the templates loaded by the Converter. If a :template_dir is not specified, or a template is missing, the converter will fall back to using the appropriate built-in template.
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 |
# File 'lib/asciidoctor/document.rb', line 929 def convert opts = {} @timings.start :convert if @timings parse unless @parsed unless @safe >= SafeMode::SERVER || opts.empty? # QUESTION should we store these on the Document object? @attributes.delete 'outfile' unless (@attributes['outfile'] = opts['outfile']) @attributes.delete 'outdir' unless (@attributes['outdir'] = opts['outdir']) end # QUESTION should we add extensions that execute before conversion begins? if doctype == 'inline' if (block = @blocks[0] || @header) if block.content_model == :compound || block.content_model == :empty logger.warn 'no inline candidate; use the inline doctype to convert a single paragragh, verbatim, or raw block' else output = block.content end end else if opts.key? :standalone transform = opts[:standalone] ? 'document' : 'embedded' elsif opts.key? :header_footer transform = opts[:header_footer] ? 'document' : 'embedded' else transform = @options[:standalone] ? 'document' : 'embedded' end output = @converter.convert self, transform end unless @parent_document if (exts = @extensions) && exts.postprocessors? exts.postprocessors.each do |ext| output = ext.process_method[self, output] end end end @timings.record :convert if @timings output end |
#counter(name, seed = nil) ⇒ Object
Get the named counter and take the next number in the sequence.
567 568 569 570 571 572 573 574 575 576 577 578 |
# File 'lib/asciidoctor/document.rb', line 567 def counter name, seed = nil return @parent_document.counter name, seed if @parent_document if ((locked = attribute_locked? name) && (curr_val = @counters[name])) || !(curr_val = @attributes[name]).nil_or_empty? next_val = @counters[name] = Helpers.nextval curr_val elsif seed next_val = @counters[name] = seed == seed.to_i.to_s ? seed.to_i : seed else next_val = @counters[name] = 1 end @attributes[name] = next_val unless locked next_val end |
#delete_attribute(name) ⇒ Object
Delete the specified attribute from the document if the name is not locked
If the attribute is locked, false is returned. Otherwise, the attribute is deleted.
885 886 887 888 889 890 891 892 893 |
# File 'lib/asciidoctor/document.rb', line 885 def delete_attribute(name) if attribute_locked?(name) false else @attributes.delete(name) @attributes_modified << name true end end |
#docinfo(location = :head, suffix = nil) ⇒ Object
Read the docinfo file(s) for inclusion in the document template
If the docinfo1 attribute is set, read the docinfo.ext file. If the docinfo attribute is set, read the doc-name.docinfo.ext file. If the docinfo2 attribute is set, read both files in that order.
1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 |
# File 'lib/asciidoctor/document.rb', line 1027 def docinfo location = :head, suffix = nil if safe < SafeMode::SECURE qualifier = %(-#{location}) unless location == :head suffix ||= @outfilesuffix if (docinfo = @attributes['docinfo']).nil_or_empty? if @attributes.key? 'docinfo2' docinfo = ['private', 'shared'] elsif @attributes.key? 'docinfo1' docinfo = ['shared'] else docinfo = docinfo ? ['private'] : nil end else docinfo = docinfo.split(',').map {|it| it.strip } end if docinfo content = [] docinfo_file, docinfo_dir, docinfo_subs = %(docinfo#{qualifier}#{suffix}), @attributes['docinfodir'], resolve_docinfo_subs unless (docinfo & ['shared', %(shared-#{location})]).empty? docinfo_path = normalize_system_path docinfo_file, docinfo_dir # NOTE normalizing the lines is essential if we're performing substitutions if (shared_docinfo = read_asset docinfo_path, normalize: true) content << (apply_subs shared_docinfo, docinfo_subs) end end unless @attributes['docname'].nil_or_empty? || (docinfo & ['private', %(private-#{location})]).empty? docinfo_path = normalize_system_path %(#{@attributes['docname']}-#{docinfo_file}), docinfo_dir # NOTE normalizing the lines is essential if we're performing substitutions if (private_docinfo = read_asset docinfo_path, normalize: true) content << (apply_subs private_docinfo, docinfo_subs) end end end end # TODO allow document to control whether extension docinfo is contributed if @extensions && (docinfo_processors? location) ((content || []).concat @docinfo_processor_extensions[location].map {|ext| ext.process_method[self] }.compact).join LF elsif content content.join LF else '' end end |
#docinfo_processors?(location = :head) ⇒ Boolean
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 |
# File 'lib/asciidoctor/document.rb', line 1075 def docinfo_processors?(location = :head) if @docinfo_processor_extensions.key?(location) # false means we already performed a lookup and didn't find any @docinfo_processor_extensions[location] != false elsif @extensions && @document.extensions.docinfo_processors?(location) !!(@docinfo_processor_extensions[location] = @document.extensions.docinfo_processors(location)) else @docinfo_processor_extensions[location] = false end end |
#doctitle(opts = {}) ⇒ Title Also known as: name
Resolves the primary title for the document
Searches the locations to find the first non-empty value:
* document-level attribute named title
* header title (known as the document title)
* title of the first section
* document-level attribute named untitled-label (if :use_fallback option is set)
If no value can be resolved, nil is returned.
If the :partition attribute is specified, the value is parsed into an Document::Title object. If the :sanitize attribute is specified, XML elements are removed from the value.
TODO separate sanitization by type (:cdata for HTML/XML, :plain_text for non-SGML, false for none)
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 |
# File 'lib/asciidoctor/document.rb', line 721 def doctitle opts = {} unless (val = @attributes['title']) if (sect = first_section) val = sect.title elsif !(opts[:use_fallback] && (val = @attributes['untitled-label'])) return end end if (separator = opts[:partition]) Title.new val, opts.merge({ separator: (separator == true ? @attributes['title-separator'] : separator) }) elsif opts[:sanitize] && val.include?('<') val.gsub(XmlSanitizeRx, '').squeeze(' ').strip else val end end |
#embedded? ⇒ Boolean
658 659 660 |
# File 'lib/asciidoctor/document.rb', line 658 def @attributes.key? 'embedded' end |
#extensions? ⇒ Boolean
662 663 664 |
# File 'lib/asciidoctor/document.rb', line 662 def extensions? @extensions ? true : false end |
#first_section ⇒ Object
791 792 793 |
# File 'lib/asciidoctor/document.rb', line 791 def first_section @header || @blocks.find {|e| e.context == :section } end |
#footnotes ⇒ Object
646 647 648 |
# File 'lib/asciidoctor/document.rb', line 646 def footnotes @catalog[:footnotes] end |
#footnotes? ⇒ Boolean
642 643 644 |
# File 'lib/asciidoctor/document.rb', line 642 def footnotes? @catalog[:footnotes].empty? ? false : true end |
#header? ⇒ Boolean Also known as: has_header?
795 796 797 |
# File 'lib/asciidoctor/document.rb', line 795 def header? @header ? true : false end |
#increment_and_store_counter(counter_name, block) ⇒ Object Also known as: counter_increment
Increment the specified counter and store it in the block’s attributes
586 587 588 |
# File 'lib/asciidoctor/document.rb', line 586 def increment_and_store_counter counter_name, block ((AttributeEntry.new counter_name, (counter counter_name)).save_to block.attributes).value end |
#nested? ⇒ Boolean
654 655 656 |
# File 'lib/asciidoctor/document.rb', line 654 def nested? @parent_document ? true : false end |
#nofooter ⇒ Object
787 788 789 |
# File 'lib/asciidoctor/document.rb', line 787 def @attributes.key? 'nofooter' end |
#noheader ⇒ Object
783 784 785 |
# File 'lib/asciidoctor/document.rb', line 783 def noheader @attributes.key? 'noheader' end |
#notitle ⇒ Object
779 780 781 |
# File 'lib/asciidoctor/document.rb', line 779 def notitle @attributes.key? 'notitle' end |
#parse(data = nil) ⇒ Document
Parse the AsciiDoc source stored in the Reader into an abstract syntax tree.
If the data parameter is not nil, create a new PreprocessorReader and assigned it to the reader property of this object. Otherwise, continue with the reader that was created in #initialize. Pass the reader to Parser.parse to parse the source data into an abstract syntax tree.
If parsing has already been performed, this method returns without performing any processing.
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
# File 'lib/asciidoctor/document.rb', line 520 def parse data = nil if @parsed self else doc = self # create reader if data is provided (used when data is not known at the time the Document object is created) if data @reader = PreprocessorReader.new doc, data, (Reader::Cursor.new @attributes['docfile'], @base_dir), normalize: true @source_location = @reader.cursor if @sourcemap end if (exts = @parent_document ? nil : @extensions) && exts.preprocessors? exts.preprocessors.each do |ext| @reader = ext.process_method[doc, @reader] || @reader end end # Now parse the lines in the reader into blocks Parser.parse @reader, doc, header_only: @options[:parse_header_only] # should we call sort of post-parse function? restore_attributes if exts && exts.tree_processors? exts.tree_processors.each do |ext| if (result = ext.process_method[doc]) && Document === result && result != doc doc = result end end end @parsed = true doc end end |
#parsed? ⇒ Boolean
Returns whether the source lines of the document have been parsed.
557 558 559 |
# File 'lib/asciidoctor/document.rb', line 557 def parsed? @parsed end |
#playback_attributes(block_attributes) ⇒ Object
Replay attribute assignments at the block level
825 826 827 828 829 830 831 832 833 834 835 836 837 838 |
# File 'lib/asciidoctor/document.rb', line 825 def playback_attributes(block_attributes) if block_attributes.key? :attribute_entries block_attributes[:attribute_entries].each do |entry| name = entry.name if entry.negate @attributes.delete name @compat_mode = false if name == 'compat-mode' else @attributes[name] = entry.value @compat_mode = true if name == 'compat-mode' end end end end |
#register(type, value) ⇒ Object
Register a reference in the document catalog
593 594 595 596 597 598 599 600 601 602 603 604 605 |
# File 'lib/asciidoctor/document.rb', line 593 def register type, value case type when :ids # deprecated register :refs, [(id = value[0]), (Inline.new self, :anchor, value[1], type: :ref, id: id)] when :refs @catalog[:refs][value[0]] ||= (ref = value[1]) ref when :footnotes @catalog[type] << value else @catalog[type] << (type == :images ? (ImageReference.new value, @attributes['imagesdir']) : value) if @options[:catalog_assets] end end |
#resolve_id(text) ⇒ Object
Scan registered references and return the ID of the first reference that matches the specified reference text.
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 |
# File 'lib/asciidoctor/document.rb', line 612 def resolve_id text if @reftexts @reftexts[text] elsif @parsed # @reftexts is set eagerly to prevent nested lazy init (@reftexts = {}).tap {|accum| @catalog[:refs].each {|id, ref| accum[ref.xreftext] ||= id } }[text] else resolved_id = nil # @reftexts is set eagerly to prevent nested lazy init @reftexts = accum = {} @catalog[:refs].each do |id, ref| # NOTE short-circuit early since we're throwing away this table anyway if (xreftext = ref.xreftext) == text resolved_id = id break end accum[xreftext] ||= id end @reftexts = nil resolved_id end end |
#restore_attributes ⇒ Object
Restore the attributes to the previously saved state (attributes in header)
841 842 843 844 |
# File 'lib/asciidoctor/document.rb', line 841 def restore_attributes @catalog[:callouts].rewind unless @parent_document @attributes.replace @header_attributes end |
#revdate ⇒ Object
Convenience method to retrieve the document attribute ‘revdate’
returns the date of last revision for the document as a String
775 776 777 |
# File 'lib/asciidoctor/document.rb', line 775 def revdate @attributes['revdate'] end |
#sections? ⇒ Boolean
Check whether this Document has any child Section objects.
638 639 640 |
# File 'lib/asciidoctor/document.rb', line 638 def sections? @next_section_index > 0 end |
#set_attribute(name, value = '') ⇒ Object
Set the specified attribute on the document if the name is not locked
If the attribute is locked, false is returned. Otherwise, the value is assigned to the attribute name after first performing attribute substitutions on the value. If the attribute name is ‘backend’ or ‘doctype’, then the value of backend-related attributes are updated.
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 |
# File 'lib/asciidoctor/document.rb', line 857 def set_attribute name, value = '' unless attribute_locked? name value = apply_attribute_value_subs value unless value.empty? # NOTE if @header_attributes is set, we're beyond the document header if @header_attributes @attributes[name] = value else case name when 'backend' update_backend_attributes value, (@attributes_modified.delete? 'htmlsyntax') && value == @backend when 'doctype' update_doctype_attributes value else @attributes[name] = value end @attributes_modified << name end value end end |
#set_header_attribute(name, value = '', overwrite = true) ⇒ Boolean
Assign a value to the specified attribute in the document header.
The assignment will be visible when the header attributes are restored, typically between processor phases (e.g., between parse and convert).
915 916 917 918 919 920 921 922 923 |
# File 'lib/asciidoctor/document.rb', line 915 def set_header_attribute name, value = '', overwrite = true attrs = @header_attributes || @attributes if overwrite == false && (attrs.key? name) false else attrs[name] = value true end end |
#source ⇒ Object
Make the raw source for the Document available.
667 668 669 |
# File 'lib/asciidoctor/document.rb', line 667 def source @reader.source if @reader end |
#source_lines ⇒ Object
Make the raw source lines for the Document available.
672 673 674 |
# File 'lib/asciidoctor/document.rb', line 672 def source_lines @reader.source_lines if @reader end |
#title ⇒ String
Return the doctitle as a String
683 684 685 |
# File 'lib/asciidoctor/document.rb', line 683 def title doctitle end |
#title=(title) ⇒ String
Set the title on the document header
Set the title of the document header to the specified value. If the header does not exist, it is first created.
695 696 697 698 699 700 |
# File 'lib/asciidoctor/document.rb', line 695 def title= title unless (sect = @header) (sect = (@header = Section.new self, 0)).sectname = 'header' end sect.title = title end |
#to_s ⇒ Object
1086 1087 1088 |
# File 'lib/asciidoctor/document.rb', line 1086 def to_s %(#<#{self.class}@#{object_id} {doctype: #{doctype.inspect}, doctitle: #{(@header && @header.title).inspect}, blocks: #{@blocks.size}}>) end |
#write(output, target) ⇒ void
This method returns an undefined value.
Write the output to the specified file
If the converter responds to :write, delegate the work of writing the output to that method. Otherwise, write the output to the specified file. In the latter case, this method ensures the output has a trailing newline if the target responds to write and the output is not empty.
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 |
# File 'lib/asciidoctor/document.rb', line 986 def write output, target @timings.start :write if @timings if Writer === @converter @converter.write output, target else if target.respond_to? :write # QUESTION should we set encoding using target.set_encoding? unless output.nil_or_empty? target.write output.chomp # ensure there's a trailing endline target.write LF end else ::File.write target, output, mode: FILE_WRITE_MODE end if @backend == 'manpage' && ::String === target && (@converter.class.respond_to? :write_alternate_pages) @converter.class.write_alternate_pages @attributes['mannames'], @attributes['manvolnum'], target end end @timings.record :write if @timings nil end |
#xreftext(xrefstyle = nil) ⇒ Object
740 741 742 |
# File 'lib/asciidoctor/document.rb', line 740 def xreftext xrefstyle = nil (val = reftext) && !val.empty? ? val : title end |