Module: Presently::Slide::Parser
- Defined in:
- lib/presently/slide.rb
Overview
Parses a Markdown slide file into structured data for Presently::Slide.
Handles YAML front_matter extraction, presenter note separation, and Markdown-to-HTML rendering using the Markly AST.
Constant Summary collapse
- EXTENSIONS =
Markly extensions enabled for all slide Markdown rendering.
[:table, :tasklist, :strikethrough, :autolink]
Class Method Summary collapse
-
.load(path) ⇒ Object
Parse the file and return a Presently::Slide.
-
.parse_sections(nodes) ⇒ Object
Parse a list of AST nodes into sections based on top-level Markdown headings.
-
.render_nodes(nodes) ⇒ Object
Render a list of AST nodes to HTML via a temporary document.
Class Method Details
.load(path) ⇒ Object
Parse the file and return a Presently::Slide.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/presently/slide.rb', line 30 def load(path) raw = File.read(path) # Parse once, with native front matter support. document = Markly.parse(raw, flags: Markly::UNSAFE | Markly::FRONT_MATTER, extensions: EXTENSIONS) # Extract front matter from the first AST node if present. front_matter = nil if (front_matter_node = document.first_child) && front_matter_node.type == :front_matter front_matter = YAML.safe_load(front_matter_node.string_content) front_matter_node.delete end # Find the last hrule, which acts as the separator between slide content and presenter notes. last_hrule = nil document.each{|node| last_hrule = node if node.type == :hrule} if last_hrule notes_fragment = Markly::Node.new(:document) while child = last_hrule.next notes_fragment.append_child(child) end last_hrule.delete # Extract the last javascript code block from the notes as the slide script. script_node = nil notes_fragment.each do |node| if node.type == :code_block && node.fence_info.to_s.strip == "javascript" script_node = node end end script = nil if script_node script = script_node.string_content script_node.delete end content = parse_sections(document.each) notes = render_nodes(notes_fragment.each) else content = parse_sections(document.each) notes = nil script = nil end Slide.new(path, front_matter: front_matter, content: content, notes: notes, script: script) end |
.parse_sections(nodes) ⇒ Object
Parse a list of AST nodes into sections based on top-level Markdown headings. Each heading becomes a named key; content before the first heading is collected under ‘“body”`. Headings inside code blocks are invisible to this method as they never appear as top-level AST nodes.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/presently/slide.rb', line 85 def parse_sections(nodes) sections = {} current_key = "body" current_nodes = [] nodes.each do |node| if node.type == :header sections[current_key] = render_nodes(current_nodes) unless current_nodes.empty? current_key = node.to_plaintext.strip.downcase.gsub(/\s+/, "_") current_nodes = [] else current_nodes << node end end sections[current_key] = render_nodes(current_nodes) unless current_nodes.empty? sections end |
.render_nodes(nodes) ⇒ Object
Render a list of AST nodes to HTML via a temporary document.
108 109 110 111 112 |
# File 'lib/presently/slide.rb', line 108 def render_nodes(nodes) doc = Markly::Node.new(:document) nodes.each{|node| doc.append_child(node.dup)} Renderer.new(flags: Markly::UNSAFE, extensions: EXTENSIONS).render(doc) end |