class Document
Represents a Markdown document with optional source code cross-references.
Definitions
def initialize(text, base = nil, definition: nil, default_language: nil)
Initialize a document from Markdown text.
Signature
-
parameter
textString The Markdown source text.
-
parameter
baseBase | Nil The project used to resolve source code references.
-
parameter
definitionDecode::Definition | Nil The definition that provides the lexical context.
-
parameter
default_languageDecode::Language::Generic | Nil The default language for source code references.
Implementation
def initialize(text, base = nil, definition: nil, default_language: nil)
@text = text
@base = base
@index = base&.index
@definition = definition
@default_language = default_language
@root = nil
end
def root
Parse and resolve the document root.
Signature
-
returns
Markly::Node The root document node.
Implementation
def root
@root ||= resolve(Markly.parse(@text, flags: Markly::INLINE_CODE_INFO, extensions: [:table]))
end
def title
Extract the leading heading as the document title.
Signature
-
returns
String | Nil The title, if the document starts with a heading.
Implementation
def title
child = self.root.first_child
if child && child.type == :header
return child.first_child.to_plaintext
end
end
def first_child
Get the first node in the document.
Signature
-
returns
Markly::Node | Nil The first child node.
Implementation
def first_child
self.root.first_child
end
def replace_section(name, children: false)
Remove a named section and yield its heading for replacement.
Signature
-
parameter
nameString A fragment of the heading text to match.
-
parameter
childrenBoolean Whether to remove nested subsections too.
-
yields
{|header| ...} The matched heading node.
-
parameter
headerMarkly::Node The matched heading.
-
parameter
Implementation
def replace_section(name, children: false)
child = self.first_child
while child
if child.type == :header
header = child
# We found the matched header:
if header.first_child.to_plaintext.include?(name)
# Now subsequent children:
current = header.next
# Delete everything in the section until we encounter another header:
while current
if current.type == :header
# If we are removing all children, keep on going until we reach a header of the same level or higher:
if children
break if current.header_level <= header.header_level
else
break
end
end
current_next = current.next
current.delete
current = current_next
end
return yield(header)
end
end
child = child.next
end
end
def to_markdown(**options)
Render the document as Markdown.
Signature
-
returns
String The rendered Markdown.
Implementation
def to_markdown(**options)
self.root.to_markdown(**options)
end
def to_html(node = self.root, **options)
Render a document node as HTML.
Signature
-
parameter
nodeMarkly::Node The node to render.
-
returns
XRB::MarkupString The rendered HTML markup.
Implementation
def to_html(node = self.root, **options)
renderer = Renderer.new(
inline_code_resolver: (@index ? method(:reference_node) : nil),
ids: true,
flags: Markly::UNSAFE,
**options
)
XRB::Markup.raw(renderer.render(node))
end
def paragraph_node(child)
Wrap a node in a paragraph.
Signature
-
parameter
childMarkly::Node The node to wrap.
-
returns
Markly::Node The paragraph node.
Implementation
def paragraph_node(child)
node = Markly::Node.new(:paragraph)
node.append_child(child)
return node
end
def html_node(content, type = :html)
Build an HTML block node.
Signature
-
parameter
contentString The raw HTML content.
-
parameter
typeSymbol The node type retained for compatibility.
-
returns
Markly::Node The HTML node.
Implementation
def html_node(content, type = :html)
node = Markly::Node.new(:html)
node.string_content = content
return node
end
def inline_html_node(content)
Build an inline HTML node.
Signature
-
parameter
contentString The raw HTML content.
-
returns
Markly::Node The inline HTML node.
Implementation
def inline_html_node(content)
node = Markly::Node.new(:inline_html)
node.string_content = content
return node
end
def text_node(content)
Build a text node.
Signature
-
parameter
contentString The text content.
-
returns
Markly::Node The text node.
Implementation
def text_node(content)
node = Markly::Node.new(:text)
node.string_content = content
return node
end
def link_node(title, url, child)
Build a link node around a child node.
Signature
-
parameter
titleString | Nil The link title.
-
parameter
urlString | XRB::Reference The link target.
-
parameter
childMarkly::Node The linked child node.
-
returns
Markly::Node The link node.
Implementation
def link_node(title, url, child)
node = Markly::Node.new(:link)
node.title = title
node.url = url.to_s
node.append_child(child)
return node
end
def code_node(content, language = nil)
Build an inline code node.
Signature
-
parameter
contentString The code content.
-
parameter
languageString | Nil The source language name.
-
returns
Markly::Node The code node.
Implementation
def code_node(content, language = nil)
node = Markly::Node.new(:code)
node.string_content = content
node.code_info = language if language
return node
end
def reference_node(content, language: nil)
Resolve a source code reference to HTML.
Signature
-
parameter
contentString The source code reference.
-
parameter
languageString | Nil The explicit source language.
-
returns
Markly::Node The inline HTML node.
Implementation
def reference_node(content, language: nil)
reference, definition = resolve_reference(content, language: language)
if definition
content = definition.qualified_form
language = reference.language.name
elsif reference
content = reference.identifier
language = reference.language.name
end
attributes = {}
attributes[:class] = "language-#{language}" if language
markup = XRB::Builder.fragment do |builder|
builder.inline("code", attributes) do
if definition
builder.inline("a", href: @base.link_for(definition), title: reference.identifier) do
builder.text(content)
end
else
builder.text(content)
end
end
end
return inline_html_node(markup.to_s)
end
def resolve_reference(content, language: nil)
Resolve source code reference metadata and its indexed definition.
Signature
-
parameter
contentString The source code reference.
-
parameter
languageString | Nil The explicit source language.
-
returns
Array The parsed reference and resolved definition.
Implementation
def resolve_reference(content, language: nil)
reference = if language
@index.languages.reference_for(language, content)
else
@index.languages.parse_reference(content, default_language: @default_language)
end
definition = @index.lookup(reference, relative_to: @definition) if reference
return reference, definition
end