Class: Slamdown::Conversion::Renderer

Inherits:
Object
  • Object
show all
Defined in:
lib/slamdown/conversion/renderer.rb

Overview

Traverses the normalised tree through shared inline and block primitives, delegating only genuine format differences to a strategy.

Constant Summary collapse

ENTITY_KINDS =
[:entity, :typographic_symbol, :smart_quote].freeze
LIST_KINDS =
[:ordered_list, :unordered_list].freeze
FAILED_RENDERING =
Object.new.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(configuration, format) ⇒ Renderer

Returns a new instance of Renderer.

Raises:

  • (ArgumentError)


18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/slamdown/conversion/renderer.rb', line 18

def initialize(configuration, format)
	raise ArgumentError, "configuration must be a Slamdown conversion configuration" unless configuration.is_a?(Configuration)
	raise ArgumentError, "format must be markdown or kramdown" unless ["markdown", "kramdown"].include?(format)

	@configuration = configuration
	@escaper = Rendering::Escaper.new
	@entity_encoder = Rendering::EntityEncoder.new(configuration.entities)
	@html = Rendering::Html.new(configuration, @entity_encoder)
	@strategy = Rendering::Strategy.build(format)
	@format = format
	@diagnostics = []
end

Class Method Details

.render(root, configuration, format) ⇒ Object



13
14
15
# File 'lib/slamdown/conversion/renderer.rb', line 13

def render(root, configuration, format)
	new(configuration, format).render(root)
end

Instance Method Details

#render(root) ⇒ Object

Raises:

  • (ArgumentError)


31
32
33
34
35
36
# File 'lib/slamdown/conversion/renderer.rb', line 31

def render(root)
	raise ArgumentError, "root must be a normalised Slamdown document" unless root.is_a?(NormalisedNode) && root.kind == :document
	@diagnostics = []

	Rendering::Result.new(canonicalise(render_blocks(root.children)), @diagnostics)
end

#render_blocks(nodes) ⇒ Object

Renders a block sequence with exactly one blank line between neighbouring constructs.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/slamdown/conversion/renderer.rb', line 39

def render_blocks(nodes)
	parts = []
	inline_run = []
	flush = lambda do
		unless inline_run.empty?
			value = render_inlines(inline_run)
			parts << value unless value.empty?
			inline_run = []
		end
	end

	nodes.each do |node|
		if block_node?(node)
			flush.call
			value = safely_render(node) { render_block(node) }
			parts << value unless value.equal?(FAILED_RENDERING) || value.empty?
		else
			inline_run << node
		end
	end
	flush.call
	parts.join("\n\n")
end

#render_container_contents(node) ⇒ Object

Renders the children of structural containers whose parser shape may be inline or block-oriented.



64
65
66
# File 'lib/slamdown/conversion/renderer.rb', line 64

def render_container_contents(node)
	node.children.any? { |child| block_node?(child) } ? render_blocks(node.children) : render_inlines(node.children)
end

#render_inlines(nodes, suppress_strong: false, line_start: true) ⇒ Object

Renders one inline sequence, with optional strong-marker suppression used by Markdown definition terms.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/slamdown/conversion/renderer.rb', line 69

def render_inlines(nodes, suppress_strong: false, line_start: true)
	result = ""
	failed_rendering = false
	nodes.each do |node|
		value = safely_render(node) { render_inline(node, line_start && result.empty?, suppress_strong) }
		if value.equal?(FAILED_RENDERING)
			failed_rendering = true
			next
		end

		# Dropping a failed inline node can make its surrounding text spaces newly adjacent, so restore the already-normalised boundary.
		if failed_rendering
			value = value.sub(/\A +/, "") if result.empty? || (result.end_with?(" ") && value.start_with?(" "))
			failed_rendering = false
		end
		result += value
	end
	failed_rendering ? result.sub(/ +\z/, "") : result
end