Files
jekyll/lib/jekyll/renderer.rb
Parker Moore 82c3ee365f Initial work on using Liquid::Drops instead of Hashes.
The properties of Liquid::Drops are only evaluated when they're asked for
and therefore save computation time. This prevents a lot of GC time cleaning
up objects that are not needed, because they're not created unless requested.
Additionally, this saves time for actual computation of those values because
they can be computed only if needed.

It's funny how much it helps when you only do what is needed. Far less overhead.
2015-12-21 22:47:30 -05:00

167 lines
4.8 KiB
Ruby

# encoding: UTF-8
module Jekyll
class Renderer
attr_reader :document, :site, :payload
def initialize(site, document, site_payload = nil)
@site = site
@document = document
@payload = site_payload || site.site_payload
end
# Determine which converters to use based on this document's
# extension.
#
# Returns an array of Converter instances.
def converters
@converters ||= site.converters.select { |c| c.matches(document.extname) }
end
# Determine the extname the outputted file should have
#
# Returns the output extname including the leading period.
def output_ext
@output_ext ||= converters.first.output_ext(document.extname)
end
######################
## DAT RENDER THO
######################
def run
Jekyll.logger.debug "Rendering:", document.relative_path
payload.page = document.to_liquid
if document.collection.label == 'posts' && document.is_a?(Document)
payload.site['related_posts'] = document.related_posts
end
Jekyll.logger.debug "Pre-Render Hooks:", document.relative_path
document.trigger_hooks(:pre_render, payload)
info = {
filters: [Jekyll::Filters],
registers: { :site => site, :page => payload.page }
}
# render and transform content (this becomes the final content of the object)
payload.highlighter_prefix = converters.first.highlighter_prefix
payload.highlighter_suffix = converters.first.highlighter_suffix
output = document.content
if document.render_with_liquid?
Jekyll.logger.debug "Rendering Liquid:", document.relative_path
output = render_liquid(output, payload, info, document.path)
end
Jekyll.logger.debug "Rendering Markup:", document.relative_path
output = convert(output)
document.content = output
if document.place_in_layout?
Jekyll.logger.debug "Rendering Layout:", document.relative_path
place_in_layouts(
output,
payload,
info
)
else
output
end
end
# Convert the given content using the converters which match this renderer's document.
#
# content - the raw, unconverted content
#
# Returns the converted content.
def convert(content)
converters.reduce(content) do |output, converter|
begin
converter.convert output
rescue => e
Jekyll.logger.error "Conversion error:", "#{converter.class} encountered an error while converting '#{document.relative_path}':"
Jekyll.logger.error("", e.to_s)
raise e
end
end
end
# Render the given content with the payload and info
#
# content -
# payload -
# info -
# path - (optional) the path to the file, for use in ex
#
# Returns the content, rendered by Liquid.
def render_liquid(content, payload, info, path = nil)
site.liquid_renderer.file(path).parse(content).render!(payload, info)
rescue Tags::IncludeTagError => e
Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{e.path}, included in #{path || document.relative_path}"
raise e
rescue Exception => e
Jekyll.logger.error "Liquid Exception:", "#{e.message} in #{path || document.relative_path}"
raise e
end
# Checks if the layout specified in the document actually exists
#
# layout - the layout to check
#
# Returns true if the layout is invalid, false if otherwise
def invalid_layout?(layout)
!document.data["layout"].nil? && layout.nil?
end
# Render layouts and place given content inside.
#
# content - the content to be placed in the layout
#
#
# Returns the content placed in the Liquid-rendered layouts
def place_in_layouts(content, payload, info)
output = content.dup
layout = site.layouts[document.data["layout"]]
Jekyll.logger.warn("Build Warning:", "Layout '#{document.data["layout"]}' requested in #{document.relative_path} does not exist.") if invalid_layout? layout
used = Set.new([layout])
while layout
payload.content = output
payload.page = document.to_liquid
payload.layout = layout.data
output = render_liquid(
layout.content,
payload,
info,
File.join(site.config['layouts_dir'], layout.name)
)
# Add layout to dependency tree
site.regenerator.add_dependency(
site.in_source_dir(document.path),
site.in_source_dir(layout.path)
) if document.write?
if layout = site.layouts[layout.data["layout"]]
if used.include?(layout)
layout = nil # avoid recursive chain
else
used << layout
end
end
end
output
end
end
end