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.
This commit is contained in:
parent
f92d6639e6
commit
82c3ee365f
|
@ -172,6 +172,7 @@ end
|
|||
require_all 'jekyll/commands'
|
||||
require_all 'jekyll/converters'
|
||||
require_all 'jekyll/converters/markdown'
|
||||
require_all 'jekyll/drops'
|
||||
require_all 'jekyll/generators'
|
||||
require_all 'jekyll/tags'
|
||||
|
||||
|
|
|
@ -170,14 +170,7 @@ module Jekyll
|
|||
#
|
||||
# Returns a representation of this collection for use in Liquid.
|
||||
def to_liquid
|
||||
metadata.merge({
|
||||
"label" => label,
|
||||
"docs" => docs,
|
||||
"files" => files,
|
||||
"directory" => directory,
|
||||
"output" => write?,
|
||||
"relative_directory" => relative_directory
|
||||
})
|
||||
Drops::CollectionDrop.new self
|
||||
end
|
||||
|
||||
# Whether the collection's documents ought to be written as individual
|
||||
|
|
|
@ -210,13 +210,8 @@ module Jekyll
|
|||
|
||||
while layout
|
||||
Jekyll.logger.debug "Rendering Layout:", path
|
||||
payload = Utils.deep_merge_hashes(
|
||||
payload,
|
||||
{
|
||||
"content" => output,
|
||||
"layout" => layout.data
|
||||
}
|
||||
)
|
||||
payload.content = output
|
||||
payload.layout = layout.data
|
||||
|
||||
self.output = render_liquid(layout.content,
|
||||
payload,
|
||||
|
@ -250,11 +245,11 @@ module Jekyll
|
|||
|
||||
Jekyll.logger.debug "Pre-Render Hooks:", self.relative_path
|
||||
Jekyll::Hooks.trigger hook_owner, :pre_render, self, payload
|
||||
info = { :filters => [Jekyll::Filters], :registers => { :site => site, :page => payload['page'] } }
|
||||
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
|
||||
payload.highlighter_prefix = converters.first.highlighter_prefix
|
||||
payload.highlighter_suffix = converters.first.highlighter_suffix
|
||||
|
||||
if render_with_liquid?
|
||||
Jekyll.logger.debug "Rendering Liquid:", self.relative_path
|
||||
|
|
|
@ -38,12 +38,10 @@ module Jekyll
|
|||
end
|
||||
|
||||
def output=(output)
|
||||
@to_liquid = nil
|
||||
@output = output
|
||||
end
|
||||
|
||||
def content=(content)
|
||||
@to_liquid = nil
|
||||
@content = content
|
||||
end
|
||||
|
||||
|
@ -181,27 +179,7 @@ module Jekyll
|
|||
#
|
||||
# Returns the Hash of key-value pairs for replacement in the URL.
|
||||
def url_placeholders
|
||||
{
|
||||
collection: collection.label,
|
||||
path: cleaned_relative_path,
|
||||
output_ext: output_ext,
|
||||
name: Utils.slugify(basename_without_ext),
|
||||
title: Utils.slugify(data['slug'], mode: "pretty", cased: true) || Utils
|
||||
.slugify(basename_without_ext, mode: "pretty", cased: true),
|
||||
slug: Utils.slugify(data['slug']) || Utils.slugify(basename_without_ext),
|
||||
year: date.strftime("%Y"),
|
||||
month: date.strftime("%m"),
|
||||
day: date.strftime("%d"),
|
||||
hour: date.strftime("%H"),
|
||||
minute: date.strftime("%M"),
|
||||
second: date.strftime("%S"),
|
||||
i_day: date.strftime("%-d"),
|
||||
i_month: date.strftime("%-m"),
|
||||
categories: (data['categories'] || []).map { |c| c.to_s.downcase }.uniq.join('/'),
|
||||
short_month: date.strftime("%b"),
|
||||
short_year: date.strftime("%y"),
|
||||
y_day: date.strftime("%j"),
|
||||
}
|
||||
@url_placeholders ||= Drops::UrlDrop.new(self)
|
||||
end
|
||||
|
||||
# The permalink for this Document.
|
||||
|
@ -278,8 +256,6 @@ module Jekyll
|
|||
#
|
||||
# Returns nothing.
|
||||
def read(opts = {})
|
||||
@to_liquid = nil
|
||||
|
||||
Jekyll.logger.debug "Reading:", relative_path
|
||||
|
||||
if yaml_file?
|
||||
|
@ -353,21 +329,7 @@ module Jekyll
|
|||
#
|
||||
# Returns a Hash representing this Document's data.
|
||||
def to_liquid
|
||||
@to_liquid ||= if data.is_a?(Hash)
|
||||
Utils.deep_merge_hashes Utils.deep_merge_hashes({
|
||||
"output" => output,
|
||||
"content" => content,
|
||||
"relative_path" => relative_path,
|
||||
"path" => relative_path,
|
||||
"url" => url,
|
||||
"collection" => collection.label,
|
||||
"next" => next_doc,
|
||||
"previous" => previous_doc,
|
||||
"id" => id,
|
||||
}, data), { 'excerpt' => data['excerpt'].to_s }
|
||||
else
|
||||
data
|
||||
end
|
||||
@to_liquid ||= Drops::DocumentDrop.new(self)
|
||||
end
|
||||
|
||||
# The inspect string for this document.
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# encoding: UTF-8
|
||||
require "jekyll/drops/immutable_drop"
|
||||
|
||||
module Jekyll
|
||||
module Drops
|
||||
class CollectionDrop < ImmutableDrop
|
||||
extend Forwardable
|
||||
|
||||
def_delegators :@obj, :label, :docs, :files, :directory, :relative_directory
|
||||
|
||||
def output
|
||||
@obj.write?
|
||||
end
|
||||
|
||||
private
|
||||
def data
|
||||
@obj.metadata
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
module Jekyll
|
||||
module Drops
|
||||
class DocumentDrop < ImmutableDrop
|
||||
|
||||
def output
|
||||
@obj.output
|
||||
end
|
||||
|
||||
def content
|
||||
@obj.content
|
||||
end
|
||||
|
||||
def relative_path
|
||||
@obj.relative_path
|
||||
end
|
||||
alias_method :path, :relative_path
|
||||
|
||||
def url
|
||||
@obj.url
|
||||
end
|
||||
|
||||
def collection
|
||||
@obj.collection.label
|
||||
end
|
||||
|
||||
def next
|
||||
@obj.next_doc
|
||||
end
|
||||
|
||||
def previous
|
||||
@obj.previous_doc
|
||||
end
|
||||
|
||||
def id
|
||||
@obj.id
|
||||
end
|
||||
|
||||
def excerpt
|
||||
data['excerpt'].to_s
|
||||
end
|
||||
|
||||
def data
|
||||
@obj.data
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
module Jekyll
|
||||
module Drops
|
||||
class ImmutableDrop < Liquid::Drop
|
||||
|
||||
def initialize(obj)
|
||||
@obj = obj
|
||||
end
|
||||
|
||||
def [](key)
|
||||
if respond_to? key
|
||||
public_send key
|
||||
else
|
||||
data[key]
|
||||
end
|
||||
end
|
||||
|
||||
def []=(key, val)
|
||||
if respond_to? key
|
||||
raise ArgumentError.new("Key #{key} cannot be set in the drop.")
|
||||
else
|
||||
data[key] = val
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
module Jekyll
|
||||
module Drops
|
||||
class JekyllDrop < Liquid::Drop
|
||||
class << self
|
||||
def global
|
||||
@global ||= JekyllDrop.new
|
||||
end
|
||||
end
|
||||
|
||||
def version
|
||||
Jekyll::VERSION
|
||||
end
|
||||
|
||||
def environment
|
||||
Jekyll.env
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,28 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
module Jekyll
|
||||
module Drops
|
||||
class MutableDrop < Liquid::Drop
|
||||
|
||||
def initialize(obj)
|
||||
@obj = obj
|
||||
@mutations = {}
|
||||
end
|
||||
|
||||
def [](key)
|
||||
if @mutations.key? key
|
||||
@mutations[key]
|
||||
elsif respond_to? key
|
||||
public_send key
|
||||
else
|
||||
data[key]
|
||||
end
|
||||
end
|
||||
|
||||
def []=(key, val)
|
||||
@mutations[key] = val
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
module Jekyll
|
||||
module Drops
|
||||
class SiteDrop < ImmutableDrop
|
||||
extend Forwardable
|
||||
|
||||
def_delegator :@obj, :site_data, :data
|
||||
def_delegators :@obj, :time, :pages, :static_files, :documents
|
||||
|
||||
def posts
|
||||
@site_posts ||= @obj.posts.docs.sort { |a, b| b <=> a }
|
||||
end
|
||||
|
||||
def html_pages
|
||||
@site_html_pages ||= @obj.pages.select { |page| page.html? || page.url.end_with?("/") }
|
||||
end
|
||||
|
||||
def categories
|
||||
@site_categories ||= @obj.post_attr_hash('categories')
|
||||
end
|
||||
|
||||
def tags
|
||||
@site_tags ||= @obj.post_attr_hash('tags')
|
||||
end
|
||||
|
||||
def collections
|
||||
@site_collections ||= @obj.collections.values.map(&:to_liquid)
|
||||
end
|
||||
|
||||
private
|
||||
def data
|
||||
@obj.config
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
module Jekyll
|
||||
module Drops
|
||||
class UnifiedPayloadDrop < Liquid::Drop
|
||||
|
||||
attr_accessor :page, :layout, :content, :paginator
|
||||
attr_accessor :highlighter_prefix, :highlighter_suffix
|
||||
|
||||
def initialize(site)
|
||||
@site = site
|
||||
end
|
||||
|
||||
def jekyll
|
||||
JekyllDrop.global
|
||||
end
|
||||
|
||||
def site
|
||||
@site_drop ||= SiteDrop.new(@site)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,52 @@
|
|||
# encoding: UTF-8
|
||||
|
||||
module Jekyll
|
||||
module Drops
|
||||
class UrlDrop < ImmutableDrop
|
||||
def collection
|
||||
@obj.collection.label
|
||||
end
|
||||
|
||||
def path
|
||||
@obj.cleaned_relative_path
|
||||
end
|
||||
|
||||
def output_ext
|
||||
@obj.output_ext
|
||||
end
|
||||
|
||||
def name
|
||||
Utils.slugify(@obj.basename_without_ext)
|
||||
end
|
||||
|
||||
def title
|
||||
Utils.slugify(@obj.data['slug'], mode: "pretty", cased: true) ||
|
||||
Utils.slugify(@obj.basename_without_ext, mode: "pretty", cased: true)
|
||||
end
|
||||
|
||||
def slug
|
||||
Utils.slugify(@obj.data['slug']) || Utils.slugify(@obj.basename_without_ext)
|
||||
end
|
||||
|
||||
def categories
|
||||
category_set = Set.new
|
||||
Array(@obj.data['categories']).each do |category|
|
||||
category_set << category.to_s.downcase
|
||||
end
|
||||
category_set.to_a.join('/')
|
||||
end
|
||||
|
||||
def year; @obj.date.strftime("%Y"); end
|
||||
def month; @obj.date.strftime("%m"); end
|
||||
def day; @obj.date.strftime("%d"); end
|
||||
def hour; @obj.date.strftime("%H"); end
|
||||
def minute; @obj.date.strftime("%M"); end
|
||||
def second; @obj.date.strftime("%S"); end
|
||||
def i_day; @obj.date.strftime("%-d"); end
|
||||
def i_month; @obj.date.strftime("%-m"); end
|
||||
def short_month; @obj.date.strftime("%b"); end
|
||||
def short_year; @obj.date.strftime("%y"); end
|
||||
def y_day; @obj.date.strftime("%j"); end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -117,12 +117,10 @@ module Jekyll
|
|||
#
|
||||
# Returns nothing.
|
||||
def render(layouts, site_payload)
|
||||
payload = Utils.deep_merge_hashes({
|
||||
"page" => to_liquid,
|
||||
'paginator' => pager.to_liquid
|
||||
}, site_payload)
|
||||
site_payload.page = to_liquid
|
||||
site_payload.paginator = pager.to_liquid
|
||||
|
||||
do_layout(payload, layouts)
|
||||
do_layout(site_payload, layouts)
|
||||
end
|
||||
|
||||
# The path to the source file
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
module Jekyll
|
||||
class Renderer
|
||||
|
||||
attr_reader :document, :site, :site_payload
|
||||
attr_reader :document, :site, :payload
|
||||
|
||||
def initialize(site, document, site_payload = nil)
|
||||
@site = site
|
||||
@document = document
|
||||
@site_payload = site_payload
|
||||
@site = site
|
||||
@document = document
|
||||
@payload = site_payload || site.site_payload
|
||||
end
|
||||
|
||||
# Determine which converters to use based on this document's
|
||||
|
@ -33,12 +33,10 @@ module Jekyll
|
|||
def run
|
||||
Jekyll.logger.debug "Rendering:", document.relative_path
|
||||
|
||||
payload = Utils.deep_merge_hashes({
|
||||
"page" => document.to_liquid
|
||||
}, site_payload || site.site_payload)
|
||||
payload.page = document.to_liquid
|
||||
|
||||
if document.collection.label == 'posts' && document.is_a?(Document)
|
||||
payload['site']['related_posts'] = document.related_posts
|
||||
payload.site['related_posts'] = document.related_posts
|
||||
end
|
||||
|
||||
Jekyll.logger.debug "Pre-Render Hooks:", document.relative_path
|
||||
|
@ -46,12 +44,12 @@ module Jekyll
|
|||
|
||||
info = {
|
||||
filters: [Jekyll::Filters],
|
||||
registers: { :site => site, :page => payload['page'] }
|
||||
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
|
||||
payload.highlighter_prefix = converters.first.highlighter_prefix
|
||||
payload.highlighter_suffix = converters.first.highlighter_suffix
|
||||
|
||||
output = document.content
|
||||
|
||||
|
@ -135,14 +133,9 @@ module Jekyll
|
|||
used = Set.new([layout])
|
||||
|
||||
while layout
|
||||
payload = Utils.deep_merge_hashes(
|
||||
payload,
|
||||
{
|
||||
"content" => output,
|
||||
"page" => document.to_liquid,
|
||||
"layout" => layout.data
|
||||
}
|
||||
)
|
||||
payload.content = output
|
||||
payload.page = document.to_liquid
|
||||
payload.layout = layout.data
|
||||
|
||||
output = render_liquid(
|
||||
layout.content,
|
||||
|
|
|
@ -259,25 +259,7 @@ module Jekyll
|
|||
# "tags" - The Hash of tag values and Posts.
|
||||
# See Site#post_attr_hash for type info.
|
||||
def site_payload
|
||||
{
|
||||
"jekyll" => {
|
||||
"version" => Jekyll::VERSION,
|
||||
"environment" => Jekyll.env
|
||||
},
|
||||
"site" => Utils.deep_merge_hashes(config,
|
||||
Utils.deep_merge_hashes(Hash[collections.map{|label, coll| [label, coll.docs]}], {
|
||||
"time" => time,
|
||||
"posts" => posts.docs.sort { |a, b| b <=> a },
|
||||
"pages" => pages,
|
||||
"static_files" => static_files,
|
||||
"html_pages" => pages.select { |page| page.html? || page.url.end_with?("/") },
|
||||
"categories" => post_attr_hash('categories'),
|
||||
"tags" => post_attr_hash('tags'),
|
||||
"collections" => collections.values.map(&:to_liquid),
|
||||
"documents" => documents,
|
||||
"data" => site_data
|
||||
}))
|
||||
}
|
||||
Drops::UnifiedPayloadDrop.new self
|
||||
end
|
||||
|
||||
# Get the implementation class for the given Converter.
|
||||
|
|
|
@ -59,6 +59,14 @@ module Jekyll
|
|||
#
|
||||
# Returns the unsanitized String URL
|
||||
def generate_url(template)
|
||||
if @placeholders.is_a? Drops::UrlDrop
|
||||
generate_url_from_drop(template)
|
||||
else
|
||||
generate_url_from_hash(template)
|
||||
end
|
||||
end
|
||||
|
||||
def generate_url_from_hash(template)
|
||||
@placeholders.inject(template) do |result, token|
|
||||
break result if result.index(':').nil?
|
||||
if token.last.nil?
|
||||
|
@ -70,6 +78,12 @@ module Jekyll
|
|||
end
|
||||
end
|
||||
|
||||
def generate_url_from_drop(template)
|
||||
template.gsub(/(:[a-z_]+)/) do |match|
|
||||
@placeholders.public_send(match.sub(':', ''))
|
||||
end.gsub(/\/\//, '/')
|
||||
end
|
||||
|
||||
# Returns a sanitized String URL, stripping "../../" and multiples of "/",
|
||||
# as well as the beginning "/" so we can enforce and ensure it.
|
||||
|
||||
|
|
Loading…
Reference in New Issue