lifer 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +110 -25
- data/LICENSE +18 -0
- data/README.md +79 -14
- data/Rakefile +2 -4
- data/bin/lifer +4 -2
- data/lib/lifer/brain.rb +171 -21
- data/lib/lifer/builder/html/from_erb.rb +92 -0
- data/lib/lifer/builder/html/from_liquid/drops/collection_drop.rb +40 -0
- data/lib/lifer/builder/html/from_liquid/drops/collections_drop.rb +40 -0
- data/lib/lifer/builder/html/from_liquid/drops/entry_drop.rb +63 -0
- data/lib/lifer/builder/html/from_liquid/drops/frontmatter_drop.rb +45 -0
- data/lib/lifer/builder/html/from_liquid/drops/settings_drop.rb +42 -0
- data/lib/lifer/builder/html/from_liquid/drops.rb +15 -0
- data/lib/lifer/builder/html/from_liquid/filters.rb +27 -0
- data/lib/lifer/builder/html/from_liquid/layout_tag.rb +67 -0
- data/lib/lifer/builder/html/from_liquid.rb +116 -0
- data/lib/lifer/builder/html.rb +107 -51
- data/lib/lifer/builder/rss.rb +113 -0
- data/lib/lifer/builder/txt.rb +60 -0
- data/lib/lifer/builder.rb +100 -1
- data/lib/lifer/cli.rb +105 -0
- data/lib/lifer/collection.rb +87 -8
- data/lib/lifer/config.rb +159 -31
- data/lib/lifer/dev/response.rb +61 -0
- data/lib/lifer/dev/router.rb +44 -0
- data/lib/lifer/dev/server.rb +97 -0
- data/lib/lifer/entry/html.rb +39 -0
- data/lib/lifer/entry/markdown.rb +162 -0
- data/lib/lifer/entry/txt.rb +41 -0
- data/lib/lifer/entry.rb +142 -41
- data/lib/lifer/message.rb +58 -0
- data/lib/lifer/selection/all_markdown.rb +16 -0
- data/lib/lifer/selection/included_in_feeds.rb +15 -0
- data/lib/lifer/selection.rb +79 -0
- data/lib/lifer/shared/finder_methods.rb +35 -0
- data/lib/lifer/shared.rb +6 -0
- data/lib/lifer/templates/cli.txt.erb +10 -0
- data/lib/lifer/templates/config.yaml +77 -0
- data/lib/lifer/templates/its-a-living.png +0 -0
- data/lib/lifer/templates/layout.html.erb +1 -1
- data/lib/lifer/uri_strategy/pretty.rb +14 -6
- data/lib/lifer/uri_strategy/pretty_root.rb +24 -0
- data/lib/lifer/uri_strategy/pretty_yyyy_mm_dd.rb +32 -0
- data/lib/lifer/uri_strategy/root.rb +17 -0
- data/lib/lifer/uri_strategy/simple.rb +10 -6
- data/lib/lifer/uri_strategy.rb +46 -6
- data/lib/lifer/utilities.rb +117 -0
- data/lib/lifer/version.rb +3 -0
- data/lib/lifer.rb +130 -23
- data/lifer.gemspec +12 -6
- data/locales/en.yml +54 -0
- metadata +142 -9
- data/lib/lifer/layout.rb +0 -25
- data/lib/lifer/templates/config +0 -4
- data/lib/lifer/uri_strategy/base.rb +0 -15
@@ -0,0 +1,92 @@
|
|
1
|
+
require "erb"
|
2
|
+
|
3
|
+
class Lifer::Builder::HTML
|
4
|
+
# If the HTML builder is given an ERB template, it uses this class to parse
|
5
|
+
# the ERB into HTML. Lifer project metadata is provided as context. For
|
6
|
+
# example:
|
7
|
+
#
|
8
|
+
# <html>
|
9
|
+
# <head>
|
10
|
+
# <title><%= my_collection.name %></title>
|
11
|
+
# </head>
|
12
|
+
#
|
13
|
+
# <body>
|
14
|
+
# <h1><%= my_collection.name %></h1>
|
15
|
+
#
|
16
|
+
# <% my_collection.entries.each do |entry| %>
|
17
|
+
# <section>
|
18
|
+
# <h2><%= entry.title %></h2>
|
19
|
+
# <p><%= entry.summary %></p>
|
20
|
+
# <a href="<%= entry.permalink %>">Read more</a>
|
21
|
+
# </section>
|
22
|
+
# <% end %>
|
23
|
+
# </body>
|
24
|
+
# </html>
|
25
|
+
#
|
26
|
+
class FromERB
|
27
|
+
class << self
|
28
|
+
# Build and render an entry.
|
29
|
+
#
|
30
|
+
# @param entry [Lifer::Entry] The entry to be rendered.
|
31
|
+
# @return [String] The rendered entry.
|
32
|
+
def build(entry:)
|
33
|
+
new(entry: entry).render
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Reads the entry as ERB, given our renderer context (see the documentation
|
38
|
+
# for `#build_binding_context`) and renders the production-ready entry.
|
39
|
+
#
|
40
|
+
# @return [String] The rendered entry.
|
41
|
+
def render
|
42
|
+
ERB.new(File.read layout_file).result context
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_reader :context, :entry, :layout_file
|
48
|
+
|
49
|
+
# @private
|
50
|
+
# @param entry [Lifer::Entry] The entry to be rendered.
|
51
|
+
# @return [void]
|
52
|
+
def initialize(entry:)
|
53
|
+
@entry = entry
|
54
|
+
@layout_file = entry.collection.layout_file
|
55
|
+
@context = build_binding_context
|
56
|
+
end
|
57
|
+
|
58
|
+
# @private
|
59
|
+
# Each collection name is provided as a local variable. This allows you to
|
60
|
+
# make ERB files that contain loops like:
|
61
|
+
#
|
62
|
+
# <% my_collection_name.entries.each do |entry| %>
|
63
|
+
# <%= entry.title %>
|
64
|
+
# <% end %>
|
65
|
+
#
|
66
|
+
# @return [Binding] A binding object with preset context from the current
|
67
|
+
# Lifer project and in-scope entry.
|
68
|
+
def build_binding_context
|
69
|
+
binding.tap { |binding|
|
70
|
+
Lifer.collections.each do |collection|
|
71
|
+
binding.local_variable_set collection.name, collection
|
72
|
+
|
73
|
+
collection_context_class.define_method(collection.name) do
|
74
|
+
collection
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
collections = collection_context_class.new Lifer.collections.to_a
|
79
|
+
|
80
|
+
binding.local_variable_set :collections, collections
|
81
|
+
binding.local_variable_set :settings, Lifer.settings
|
82
|
+
binding.local_variable_set :content,
|
83
|
+
ERB.new(entry.to_html).result(binding)
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
# @private
|
88
|
+
def collection_context_class
|
89
|
+
@collection_context_class ||= Class.new(Array) do end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Lifer::Builder::HTML::FromLiquid::Drops
|
2
|
+
# This drop allows users to access Lifer collection information from within
|
3
|
+
# Liquid templates. Example:
|
4
|
+
#
|
5
|
+
# {{ collection.name }}
|
6
|
+
#
|
7
|
+
# {% for entries in collection.entries %}
|
8
|
+
# {{ entry.title }}
|
9
|
+
# {% endfor %}
|
10
|
+
#
|
11
|
+
class CollectionDrop < Liquid::Drop
|
12
|
+
attr_accessor :lifer_collection
|
13
|
+
|
14
|
+
def initialize(lifer_collection) = (@lifer_collection = lifer_collection)
|
15
|
+
|
16
|
+
# The collection name.
|
17
|
+
#
|
18
|
+
# @return [Symbol]
|
19
|
+
def name = (@name ||= lifer_collection.name)
|
20
|
+
|
21
|
+
# Gets all entries in a collection and converts them to entry drops that can
|
22
|
+
# be accessed in Liquid templates. Example:
|
23
|
+
#
|
24
|
+
# {% for entry in collections.root.entries %}
|
25
|
+
# {{ entry.title }}
|
26
|
+
# {% endfor %}
|
27
|
+
#
|
28
|
+
# @return [Array<EntryDrop>]
|
29
|
+
def entries
|
30
|
+
@entries ||= lifer_collection.entries.map {
|
31
|
+
EntryDrop.new _1, collection: self
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
# The collection's layout file path.
|
36
|
+
#
|
37
|
+
# @return [String] The path to the layout file.
|
38
|
+
def layout_file = (@lifer_collection.layout_file)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Lifer::Builder::HTML::FromLiquid::Drops
|
2
|
+
# This drop allows users to iterate over their Lifer collections in Liquid
|
3
|
+
# templates. Example:
|
4
|
+
#
|
5
|
+
# {% for collection in collections %}
|
6
|
+
# {{ collection.name }}
|
7
|
+
# {% endfor %}
|
8
|
+
#
|
9
|
+
class CollectionsDrop < Liquid::Drop
|
10
|
+
attr_accessor :collections
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@collections = Lifer.collections.map { CollectionDrop.new _1 }
|
14
|
+
end
|
15
|
+
|
16
|
+
# Allow collections to be iterable in Liquid templates.
|
17
|
+
#
|
18
|
+
# @yield [CollectionDrop] All available collection drops.
|
19
|
+
def each(&block)
|
20
|
+
|
21
|
+
collections.each(&block)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Allow collections to be rendered as an array in Liquid templates.
|
25
|
+
#
|
26
|
+
# @return [Array]
|
27
|
+
def to_a = @collections
|
28
|
+
|
29
|
+
# Dynamically define Liquid accessors based on the Lifer project's
|
30
|
+
# collection names. For example, to get the root collection's name:
|
31
|
+
#
|
32
|
+
# {{ collections.root.name }}
|
33
|
+
#
|
34
|
+
# @param arg [String] The name of a collection.
|
35
|
+
# @return [CollectionDrop, NilClass]
|
36
|
+
def liquid_method_missing(arg)
|
37
|
+
collections.detect { arg.to_sym == _1.name }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Lifer::Builder::HTML::FromLiquid::Drops
|
2
|
+
# This drop represents a Lifer entry and allows users to access entry
|
3
|
+
# metadata and content in Liquid templates.
|
4
|
+
#
|
5
|
+
# Example usage:
|
6
|
+
#
|
7
|
+
# <h1>{{ entry.title }}</h1>
|
8
|
+
# <small>Published on <datetime>{{ entry.date }}</datetime></small>
|
9
|
+
#
|
10
|
+
class EntryDrop < Liquid::Drop
|
11
|
+
attr_accessor :lifer_entry, :collection
|
12
|
+
|
13
|
+
def initialize(lifer_entry, collection:)
|
14
|
+
@lifer_entry = lifer_entry
|
15
|
+
@collection = collection
|
16
|
+
end
|
17
|
+
|
18
|
+
# The entry author (or authors).
|
19
|
+
#
|
20
|
+
# @return [String]
|
21
|
+
def author = authors
|
22
|
+
|
23
|
+
# The entry authors (or author).
|
24
|
+
#
|
25
|
+
# @return [String]
|
26
|
+
def authors = (@authors ||= lifer_entry.authors.join(", "))
|
27
|
+
|
28
|
+
# The entry content.
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
def content = (@content ||= lifer_entry.to_html)
|
32
|
+
|
33
|
+
# The entry date (as a string).
|
34
|
+
#
|
35
|
+
# @return [String]
|
36
|
+
def date = (@date ||= lifer_entry.date)
|
37
|
+
|
38
|
+
# The entry frontmatter data.
|
39
|
+
#
|
40
|
+
# @return [FrontmatterDrop]
|
41
|
+
def frontmatter = (@frontmatter ||= FrontmatterDrop.new(lifer_entry))
|
42
|
+
|
43
|
+
# The path to the entry.
|
44
|
+
#
|
45
|
+
# @return [String] The path to the entry.
|
46
|
+
def path = (@path ||= lifer_entry.path)
|
47
|
+
|
48
|
+
# The entry permalink.
|
49
|
+
#
|
50
|
+
# @return [String] The entry permalink.
|
51
|
+
def permalink = (@permalink ||= lifer_entry.permalink)
|
52
|
+
|
53
|
+
# The summary of the entry.
|
54
|
+
#
|
55
|
+
# @return [String] The summary of the entry.
|
56
|
+
def summary = (@summary ||= lifer_entry.summary)
|
57
|
+
|
58
|
+
# The entry title.
|
59
|
+
#
|
60
|
+
# @return [String] The entry title.
|
61
|
+
def title = (@title ||= lifer_entry.title)
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Lifer::Builder::HTML::FromLiquid::Drops
|
2
|
+
# Markdown entries may contain YAML frontmatter. And if they do, we need a way
|
3
|
+
# for the Liquid templates to access that data.
|
4
|
+
#
|
5
|
+
# Example usage:
|
6
|
+
#
|
7
|
+
# {{ entry.frontmatter.any_available_frontmatter_key }}
|
8
|
+
#
|
9
|
+
class FrontmatterDrop < Liquid::Drop
|
10
|
+
def initialize(entry)
|
11
|
+
@frontmatter = Lifer::Utilities.stringify_keys(entry.frontmatter)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Ensure that the frontmatter can be output wholly into a rendered template
|
15
|
+
# if need be.
|
16
|
+
#
|
17
|
+
# @return [String]
|
18
|
+
def to_s = frontmatter.to_json
|
19
|
+
|
20
|
+
# Dynamically define Liquid accessors based on the Lifer settings object.
|
21
|
+
# For example, to get a collections URI strategy:
|
22
|
+
#
|
23
|
+
# {{ settings.my_collection.uri_strategy }}
|
24
|
+
#
|
25
|
+
# @param arg [String] The name of a collection.
|
26
|
+
# @return [CollectionDrop, NilClass]
|
27
|
+
def liquid_method_missing(arg)
|
28
|
+
value = frontmatter[arg]
|
29
|
+
|
30
|
+
if value.is_a?(Hash)
|
31
|
+
as_drop(value)
|
32
|
+
elsif value.is_a?(Array) && value.all? { _1.is_a?(Hash) }
|
33
|
+
value.map { as_drop(_1) }
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :frontmatter
|
42
|
+
|
43
|
+
def as_drop(hash) = self.class.new(hash)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Lifer::Builder::HTML::FromLiquid::Drops
|
2
|
+
# This drop allows users to access the current Lifer project settings from
|
3
|
+
# Liquid templates. Example:
|
4
|
+
#
|
5
|
+
# {{ settings.my_collection.uri_strategy }}
|
6
|
+
#
|
7
|
+
class SettingsDrop < Liquid::Drop
|
8
|
+
def initialize(settings = Lifer.settings)
|
9
|
+
@settings = Lifer::Utilities.stringify_keys(settings)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Ensure the settings tree can be output to a rendered template if need be.
|
13
|
+
#
|
14
|
+
# @return [String]
|
15
|
+
def to_s = settings.to_json
|
16
|
+
|
17
|
+
# Dynamically define Liquid accessors based on the Lifer settings object.
|
18
|
+
# For example, to get a collections URI strategy:
|
19
|
+
#
|
20
|
+
# {{ settings.my_collection.uri_strategy }}
|
21
|
+
#
|
22
|
+
# @param arg [String] The name of a collection.
|
23
|
+
# @return [CollectionDrop, NilClass]
|
24
|
+
def liquid_method_missing(arg)
|
25
|
+
value = settings[arg]
|
26
|
+
|
27
|
+
if value.is_a?(Hash)
|
28
|
+
as_drop(value)
|
29
|
+
elsif value.is_a?(Array) && value.all? { _1.is_a?(Hash) }
|
30
|
+
value.map { as_drop(_1) }
|
31
|
+
else
|
32
|
+
value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_accessor :settings
|
39
|
+
|
40
|
+
def as_drop(hash) = self.class.new(hash)
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Lifer::Builder::HTML::FromLiquid
|
2
|
+
# This module contains all of custom Liquid data drops used in order to render
|
3
|
+
# Lifer entries.
|
4
|
+
#
|
5
|
+
# For more information about drops, see the `liquid` gem source code. (The
|
6
|
+
# docs are awful.)
|
7
|
+
#
|
8
|
+
module Drops; end
|
9
|
+
end
|
10
|
+
|
11
|
+
require_relative "drops/collection_drop"
|
12
|
+
require_relative "drops/collections_drop"
|
13
|
+
require_relative "drops/entry_drop"
|
14
|
+
require_relative "drops/frontmatter_drop"
|
15
|
+
require_relative "drops/settings_drop"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# This module provides Liquid filters to be used within Liquid templates.
|
2
|
+
# In many cases these utilities exist to be pseudo-compatible with Jekyll.
|
3
|
+
#
|
4
|
+
# For example, a filter (in a Liquid template):
|
5
|
+
#
|
6
|
+
# {{ entry.date | date_to_xmlschema }}
|
7
|
+
#
|
8
|
+
module Lifer::Builder::HTML::FromLiquid::Filters
|
9
|
+
# @!visibility private
|
10
|
+
Util = Lifer::Utilities
|
11
|
+
|
12
|
+
# Converts date to ISO-8601 format.
|
13
|
+
#
|
14
|
+
# @param input [String] A date string, I hope.
|
15
|
+
# @return [String] The transformed date string.
|
16
|
+
def date_to_xmlschema(input) = Util.date_as_iso8601(input)
|
17
|
+
|
18
|
+
# Transforms a string to kabab-case.
|
19
|
+
#
|
20
|
+
# For example:
|
21
|
+
#
|
22
|
+
# Before: hello_there
|
23
|
+
# After: hello-there
|
24
|
+
# @param input [String] A string.
|
25
|
+
# @return [String] The transformed string.
|
26
|
+
def handleize(input) = Util.handleize(input)
|
27
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Lifer::Builder::HTML::FromLiquid
|
2
|
+
# Note that if you want to learn more about the shape of this class, check out
|
3
|
+
# `Liquid::Block` in the `liquid` gem.
|
4
|
+
#
|
5
|
+
# The layout tag is a bit magic. The idea here is to emulate how Jekyll
|
6
|
+
# handles `layout:` YAML frontmatter within entries to change the normal
|
7
|
+
# parent layout to an override parent layout--but without the need for
|
8
|
+
# frontmatter.
|
9
|
+
#
|
10
|
+
# The reason we took this strategy was to avoid pre-processing every entry for
|
11
|
+
# frontmatter when we didn't need to. Maybe in the long run this was a bad
|
12
|
+
# call? I don't know.
|
13
|
+
#
|
14
|
+
# Example usage (from a Liquid template):
|
15
|
+
#
|
16
|
+
# {% layout "path/to/my_liquid_layout_template" %}
|
17
|
+
#
|
18
|
+
# (The required `endlayout` tag will be appended to the end of the file
|
19
|
+
# on render if you do not insert it yourself.
|
20
|
+
#
|
21
|
+
class LayoutTag < Liquid::Block
|
22
|
+
# The name of the tag in Liquid templates, `layout`.
|
23
|
+
#
|
24
|
+
NAME = :layout
|
25
|
+
|
26
|
+
# The end name of the tag in Liquid templates, `endlayout`.
|
27
|
+
#
|
28
|
+
ENDNAME = ("end%s" % NAME).to_sym
|
29
|
+
|
30
|
+
def initialize(layout, path, options)
|
31
|
+
@path = path.delete("\"").strip
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
# A layout tag wraps an entire document and outputs it inside of whatever
|
36
|
+
# the `@layout` is. This lets a child document specify a parernt layout!
|
37
|
+
# Very confusing stuff.
|
38
|
+
#
|
39
|
+
# @param context [Liquid::Context] All of the context of the Liquid
|
40
|
+
# document that would be rendered.
|
41
|
+
# @return [String] A rendered document.
|
42
|
+
def render(context)
|
43
|
+
document_context = context.environments.first
|
44
|
+
parse_options = document_context["parse_options"]
|
45
|
+
liquid_file_system = parse_options[:environment].file_system
|
46
|
+
render_options = document_context["render_options"]
|
47
|
+
|
48
|
+
current_layout_file = File
|
49
|
+
.read(document_context["entry"]["collection"]["layout_file"])
|
50
|
+
.gsub(/\{%\s*#{tag_name}.+%\}/, "")
|
51
|
+
|
52
|
+
content_with_layout = Liquid::Template
|
53
|
+
.parse(current_layout_file, error_mode: :strict)
|
54
|
+
.render(document_context, render_options)
|
55
|
+
|
56
|
+
Liquid::Template
|
57
|
+
.parse(
|
58
|
+
liquid_file_system.read_template_file(@path),
|
59
|
+
**parse_options
|
60
|
+
)
|
61
|
+
.render(
|
62
|
+
document_context.merge({"content" => content_with_layout}),
|
63
|
+
**render_options
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require "liquid"
|
2
|
+
|
3
|
+
require_relative "from_liquid/drops"
|
4
|
+
require_relative "from_liquid/filters"
|
5
|
+
require_relative "from_liquid/layout_tag"
|
6
|
+
|
7
|
+
class Lifer::Builder::HTML
|
8
|
+
# If the HTML builder is given a Liquid template, it uses this class to parse
|
9
|
+
# the Liquid into HTML. Lifer project metadata is provided as context. For
|
10
|
+
# example:
|
11
|
+
#
|
12
|
+
# <html>
|
13
|
+
# <head>
|
14
|
+
# <title>{{ collections.my_collection.name }}</title>
|
15
|
+
# </head>
|
16
|
+
#
|
17
|
+
# <body>
|
18
|
+
# <h1>{{ collections.my_collection.name }}</h1>
|
19
|
+
#
|
20
|
+
# {% for entry in collections.my_collection.entries %}
|
21
|
+
# <section>
|
22
|
+
# <h2>{{ entry.title }}</h2>
|
23
|
+
# <p>{{ entry.summary }}</p>
|
24
|
+
# <a href="{{ entry.permalink }}">Read more</a>
|
25
|
+
# </section>
|
26
|
+
# {% endfor %}
|
27
|
+
# </body>
|
28
|
+
# </html>
|
29
|
+
#
|
30
|
+
class FromLiquid
|
31
|
+
class << self
|
32
|
+
# Render and build a Lifer entry.
|
33
|
+
#
|
34
|
+
# @param entry [Lifer::Entry] The entry to render.
|
35
|
+
# @return [String] The rendered entry, ready for output.
|
36
|
+
def build(entry:) = new(entry:).render
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_accessor :entry, :layout_file
|
40
|
+
|
41
|
+
# Reads the entry as Liquid, given our document context, and renders
|
42
|
+
# an entry.
|
43
|
+
#
|
44
|
+
# @return [String] The rendered entry.
|
45
|
+
def render
|
46
|
+
document_context = context.merge!(
|
47
|
+
"content" => Liquid::Template
|
48
|
+
.parse(entry.to_html, **parse_options)
|
49
|
+
.render(context, **render_options)
|
50
|
+
)
|
51
|
+
Liquid::Template
|
52
|
+
.parse(layout, **parse_options)
|
53
|
+
.render(document_context, **render_options)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def initialize(entry:)
|
59
|
+
@entry = entry
|
60
|
+
@layout_file = entry.collection.layout_file
|
61
|
+
end
|
62
|
+
|
63
|
+
def context
|
64
|
+
collections = Drops::CollectionsDrop.new
|
65
|
+
collection = collections
|
66
|
+
.to_a
|
67
|
+
.detect { _1.name.to_sym == entry.collection.name }
|
68
|
+
|
69
|
+
{
|
70
|
+
"collections" => collections,
|
71
|
+
"entry" => Drops::EntryDrop.new(entry, collection:),
|
72
|
+
"parse_options" => parse_options,
|
73
|
+
"render_options" => render_options,
|
74
|
+
"settings" => Drops::SettingsDrop.new
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
# @private
|
79
|
+
# It's possible for the provided layout to request a parent layout, which
|
80
|
+
# makes this method a bit complicated.
|
81
|
+
#
|
82
|
+
# @return [String] A Liquid layout document, ready for parsing.
|
83
|
+
def layout
|
84
|
+
contents = File.read layout_file
|
85
|
+
|
86
|
+
return contents unless contents.match?(/\{%\s*#{LayoutTag::NAME}.*%\}/)
|
87
|
+
|
88
|
+
contents + "\n{% #{LayoutTag::ENDNAME} %}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def liquid_environment
|
92
|
+
@liquid_environment ||= Liquid::Environment.build do |environment|
|
93
|
+
environment.file_system =
|
94
|
+
Liquid::LocalFileSystem.new(Lifer.root, "%s.html.liquid")
|
95
|
+
|
96
|
+
environment.register_filter Lifer::Builder::HTML::FromLiquid::Filters
|
97
|
+
environment.register_tag "layout",
|
98
|
+
Lifer::Builder::HTML::FromLiquid::LayoutTag
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def parse_options
|
103
|
+
{
|
104
|
+
environment: liquid_environment,
|
105
|
+
error_mode: :strict
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
def render_options
|
110
|
+
{
|
111
|
+
strict_variables: true,
|
112
|
+
strict_filters: true
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|