Class: Markbridge::Renderers::Discourse::Renderer
- Inherits:
-
Object
- Object
- Markbridge::Renderers::Discourse::Renderer
- Defined in:
- lib/markbridge/renderers/discourse/renderer.rb
Overview
Renders AST to Discourse-flavored Markdown in-memory.
Instance Attribute Summary collapse
-
#postprocessor ⇒ Object
readonly
Returns the value of attribute postprocessor.
Instance Method Summary collapse
-
#initialize(tag_library: nil, escaper: nil, html_escaper: nil, postprocessor: nil) ⇒ Renderer
constructor
A new instance of Renderer.
-
#render(node, context: RenderContext.new) ⇒ String
Render a node to Markdown.
-
#render_children(node, context:) {|result, child| ... } ⇒ String
Render all children of a node.
-
#render_default(node, context: RenderContext.new) ⇒ String
Render a node with the stock tag for its class, ignoring any override registered in this renderer's tag library.
Constructor Details
#initialize(tag_library: nil, escaper: nil, html_escaper: nil, postprocessor: nil) ⇒ Renderer
Returns a new instance of Renderer.
10 11 12 13 14 15 16 17 18 |
# File 'lib/markbridge/renderers/discourse/renderer.rb', line 10 def initialize(tag_library: nil, escaper: nil, html_escaper: nil, postprocessor: nil) @tag_library = tag_library || TagLibrary.shared_default @escaper = escaper || MarkdownEscaper.new @html_escaper = html_escaper || HtmlEscaper @postprocessor = postprocessor || Postprocessor::DEFAULT # @interface_cache, @resolved_tags, and @resolved_default_tags # are lazily initialized during a top-level #render / # #render_default call and reset to nil after the call completes. end |
Instance Attribute Details
#postprocessor ⇒ Object (readonly)
Returns the value of attribute postprocessor.
8 9 10 |
# File 'lib/markbridge/renderers/discourse/renderer.rb', line 8 def postprocessor @postprocessor end |
Instance Method Details
#render(node, context: RenderContext.new) ⇒ String
Render a node to Markdown
28 29 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 |
# File 'lib/markbridge/renderers/discourse/renderer.rb', line 28 def render(node, context: RenderContext.new) root_call = @interface_cache.nil? @interface_cache = {} if root_call # Exact-class hit first (a single Hash lookup, the common case), # then the memoized ancestry fallback so a subclass without its # own tag renders through its nearest ancestor's tag. tag = @tag_library[node.class] || resolved_tag(node.class) if tag result = tag.render(node, interface_for(context)) unless result.is_a?(String) raise TypeError, "#{tag.class} rendered #{node.class} to " \ "#{result.inspect} — tags must return a String " \ "(use interface.render_default(node) to fall back " \ "to the stock rendering)" end return result end render_without_tag(node, context) ensure if root_call @interface_cache = nil @resolved_tags = nil @resolved_default_tags = nil end end |
#render_children(node, context:) {|result, child| ... } ⇒ String
Render all children of a node
With a block, the block runs at every join point, right before a non-empty child output is appended. It receives the buffer built so far and the child about to be rendered into it, and may change the buffer in place. A tag uses this to adjust the text in front of a specific child without iterating the children itself, which would lose the emphasis-boundary rule below.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/markbridge/renderers/discourse/renderer.rb', line 108 def render_children(node, context:) result = +"" node.children.each do |child| part = render(child, context:) next if part.empty? yield(result, child) if block_given? # Integer-byte check avoids allocating substrings for the # per-child adjacency probe. EMPHASIS_DELIMITER_BYTES.include? # over a 4-element Set is O(1). On an empty buffer getbyte # returns nil, which matches no byte of a non-empty part, so # the first child needs no extra guard. if (last_byte = result.getbyte(-1)) == part.getbyte(0) && EMPHASIS_DELIMITER_BYTES.include?(last_byte) result << EMPHASIS_BOUNDARY end result << part end result end |
#render_default(node, context: RenderContext.new) ⇒ String
Render a node with the stock tag for its class, ignoring any override registered in this renderer's tag library. Lets a custom tag intercept only the nodes it cares about and delegate the rest:
library.register(AST::Quote, Tag.new do |node, interface|
next interface.render_default(node) unless node.username&.start_with?("legacy_")
...custom rendering...
end)
Children still render through this renderer, so overrides for other node classes keep applying inside the delegated subtree.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/markbridge/renderers/discourse/renderer.rb', line 73 def render_default(node, context: RenderContext.new) root_call = @interface_cache.nil? @interface_cache = {} if root_call tag = default_tag_library[node.class] || resolved_default_tag(node.class) return tag.render(node, interface_for(context)) if tag render_without_tag(node, context) ensure if root_call @interface_cache = nil @resolved_tags = nil @resolved_default_tags = nil end end |