bunto 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.markdown +59 -0
- data/bin/bunto +51 -0
- data/lib/bunto.rb +179 -0
- data/lib/bunto/cleaner.rb +105 -0
- data/lib/bunto/collection.rb +205 -0
- data/lib/bunto/command.rb +65 -0
- data/lib/bunto/commands/build.rb +77 -0
- data/lib/bunto/commands/clean.rb +42 -0
- data/lib/bunto/commands/doctor.rb +114 -0
- data/lib/bunto/commands/help.rb +31 -0
- data/lib/bunto/commands/new.rb +82 -0
- data/lib/bunto/commands/serve.rb +204 -0
- data/lib/bunto/commands/serve/servlet.rb +61 -0
- data/lib/bunto/configuration.rb +323 -0
- data/lib/bunto/converter.rb +48 -0
- data/lib/bunto/converters/identity.rb +21 -0
- data/lib/bunto/converters/markdown.rb +92 -0
- data/lib/bunto/converters/markdown/kramdown_parser.rb +117 -0
- data/lib/bunto/converters/markdown/rdiscount_parser.rb +33 -0
- data/lib/bunto/converters/markdown/redcarpet_parser.rb +102 -0
- data/lib/bunto/converters/smartypants.rb +34 -0
- data/lib/bunto/convertible.rb +297 -0
- data/lib/bunto/deprecator.rb +46 -0
- data/lib/bunto/document.rb +444 -0
- data/lib/bunto/drops/bunto_drop.rb +21 -0
- data/lib/bunto/drops/collection_drop.rb +22 -0
- data/lib/bunto/drops/document_drop.rb +27 -0
- data/lib/bunto/drops/drop.rb +176 -0
- data/lib/bunto/drops/site_drop.rb +38 -0
- data/lib/bunto/drops/unified_payload_drop.rb +25 -0
- data/lib/bunto/drops/url_drop.rb +83 -0
- data/lib/bunto/entry_filter.rb +72 -0
- data/lib/bunto/errors.rb +10 -0
- data/lib/bunto/excerpt.rb +127 -0
- data/lib/bunto/external.rb +59 -0
- data/lib/bunto/filters.rb +367 -0
- data/lib/bunto/frontmatter_defaults.rb +188 -0
- data/lib/bunto/generator.rb +3 -0
- data/lib/bunto/hooks.rb +101 -0
- data/lib/bunto/layout.rb +49 -0
- data/lib/bunto/liquid_extensions.rb +22 -0
- data/lib/bunto/liquid_renderer.rb +39 -0
- data/lib/bunto/liquid_renderer/file.rb +50 -0
- data/lib/bunto/liquid_renderer/table.rb +94 -0
- data/lib/bunto/log_adapter.rb +115 -0
- data/lib/bunto/mime.types +800 -0
- data/lib/bunto/page.rb +180 -0
- data/lib/bunto/plugin.rb +96 -0
- data/lib/bunto/plugin_manager.rb +95 -0
- data/lib/bunto/post.rb +329 -0
- data/lib/bunto/publisher.rb +21 -0
- data/lib/bunto/reader.rb +126 -0
- data/lib/bunto/readers/collection_reader.rb +20 -0
- data/lib/bunto/readers/data_reader.rb +69 -0
- data/lib/bunto/readers/layout_reader.rb +53 -0
- data/lib/bunto/readers/page_reader.rb +21 -0
- data/lib/bunto/readers/post_reader.rb +62 -0
- data/lib/bunto/readers/static_file_reader.rb +21 -0
- data/lib/bunto/regenerator.rb +175 -0
- data/lib/bunto/related_posts.rb +56 -0
- data/lib/bunto/renderer.rb +191 -0
- data/lib/bunto/site.rb +391 -0
- data/lib/bunto/static_file.rb +141 -0
- data/lib/bunto/stevenson.rb +58 -0
- data/lib/bunto/tags/highlight.rb +122 -0
- data/lib/bunto/tags/include.rb +190 -0
- data/lib/bunto/tags/post_url.rb +88 -0
- data/lib/bunto/url.rb +136 -0
- data/lib/bunto/utils.rb +287 -0
- data/lib/bunto/utils/ansi.rb +59 -0
- data/lib/bunto/utils/platforms.rb +30 -0
- data/lib/bunto/version.rb +3 -0
- data/lib/site_template/.gitignore +3 -0
- data/lib/site_template/_config.yml +21 -0
- data/lib/site_template/_includes/footer.html +38 -0
- data/lib/site_template/_includes/head.html +12 -0
- data/lib/site_template/_includes/header.html +27 -0
- data/lib/site_template/_includes/icon-github.html +1 -0
- data/lib/site_template/_includes/icon-github.svg +1 -0
- data/lib/site_template/_includes/icon-twitter.html +1 -0
- data/lib/site_template/_includes/icon-twitter.svg +1 -0
- data/lib/site_template/_layouts/default.html +20 -0
- data/lib/site_template/_layouts/page.html +14 -0
- data/lib/site_template/_layouts/post.html +15 -0
- data/lib/site_template/_posts/0000-00-00-welcome-to-bunto.markdown.erb +25 -0
- data/lib/site_template/_sass/_base.scss +206 -0
- data/lib/site_template/_sass/_layout.scss +242 -0
- data/lib/site_template/_sass/_syntax-highlighting.scss +71 -0
- data/lib/site_template/about.md +15 -0
- data/lib/site_template/css/main.scss +53 -0
- data/lib/site_template/feed.xml +30 -0
- data/lib/site_template/index.html +23 -0
- metadata +252 -0
@@ -0,0 +1,141 @@
|
|
1
|
+
module Bunto
|
2
|
+
class StaticFile
|
3
|
+
# The cache of last modification times [path] -> mtime.
|
4
|
+
@@mtimes = {}
|
5
|
+
|
6
|
+
attr_reader :relative_path, :extname
|
7
|
+
|
8
|
+
# Initialize a new StaticFile.
|
9
|
+
#
|
10
|
+
# site - The Site.
|
11
|
+
# base - The String path to the <source>.
|
12
|
+
# dir - The String path between <source> and the file.
|
13
|
+
# name - The String filename of the file.
|
14
|
+
def initialize(site, base, dir, name, collection = nil)
|
15
|
+
@site = site
|
16
|
+
@base = base
|
17
|
+
@dir = dir
|
18
|
+
@name = name
|
19
|
+
@collection = collection
|
20
|
+
@relative_path = File.join(*[@dir, @name].compact)
|
21
|
+
@extname = File.extname(@name)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns source file path.
|
25
|
+
def path
|
26
|
+
File.join(*[@base, @dir, @name].compact)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Obtain destination path.
|
30
|
+
#
|
31
|
+
# dest - The String path to the destination dir.
|
32
|
+
#
|
33
|
+
# Returns destination file path.
|
34
|
+
def destination(dest)
|
35
|
+
@site.in_dest_dir(*[dest, destination_rel_dir, @name].compact)
|
36
|
+
end
|
37
|
+
|
38
|
+
def destination_rel_dir
|
39
|
+
if @collection
|
40
|
+
File.dirname(url)
|
41
|
+
else
|
42
|
+
@dir
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def modified_time
|
47
|
+
@modified_time ||= File.stat(path).mtime
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns last modification time for this file.
|
51
|
+
def mtime
|
52
|
+
modified_time.to_i
|
53
|
+
end
|
54
|
+
|
55
|
+
# Is source path modified?
|
56
|
+
#
|
57
|
+
# Returns true if modified since last write.
|
58
|
+
def modified?
|
59
|
+
@@mtimes[path] != mtime
|
60
|
+
end
|
61
|
+
|
62
|
+
# Whether to write the file to the filesystem
|
63
|
+
#
|
64
|
+
# Returns true unless the defaults for the destination path from
|
65
|
+
# _config.yml contain `published: false`.
|
66
|
+
def write?
|
67
|
+
defaults.fetch('published', true)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Write the static file to the destination directory (if modified).
|
71
|
+
#
|
72
|
+
# dest - The String path to the destination dir.
|
73
|
+
#
|
74
|
+
# Returns false if the file was not modified since last time (no-op).
|
75
|
+
def write(dest)
|
76
|
+
dest_path = destination(dest)
|
77
|
+
|
78
|
+
return false if File.exist?(dest_path) && !modified?
|
79
|
+
@@mtimes[path] = mtime
|
80
|
+
|
81
|
+
FileUtils.mkdir_p(File.dirname(dest_path))
|
82
|
+
FileUtils.rm(dest_path) if File.exist?(dest_path)
|
83
|
+
FileUtils.cp(path, dest_path)
|
84
|
+
File.utime(@@mtimes[path], @@mtimes[path], dest_path)
|
85
|
+
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
# Reset the mtimes cache (for testing purposes).
|
90
|
+
#
|
91
|
+
# Returns nothing.
|
92
|
+
def self.reset_cache
|
93
|
+
@@mtimes = {}
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_liquid
|
98
|
+
{
|
99
|
+
"extname" => extname,
|
100
|
+
"modified_time" => modified_time,
|
101
|
+
"path" => File.join("", relative_path)
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
def placeholders
|
106
|
+
{
|
107
|
+
:collection => @collection.label,
|
108
|
+
:path => relative_path[
|
109
|
+
@collection.relative_directory.size..relative_path.size],
|
110
|
+
:output_ext => '',
|
111
|
+
:name => '',
|
112
|
+
:title => ''
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
# Applies a similar URL-building technique as Bunto::Document that takes
|
117
|
+
# the collection's URL template into account. The default URL template can
|
118
|
+
# be overriden in the collection's configuration in _config.yml.
|
119
|
+
def url
|
120
|
+
@url ||= if @collection.nil?
|
121
|
+
relative_path
|
122
|
+
else
|
123
|
+
::Bunto::URL.new({
|
124
|
+
:template => @collection.url_template,
|
125
|
+
:placeholders => placeholders
|
126
|
+
})
|
127
|
+
end.to_s.gsub(/\/$/, '')
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns the type of the collection if present, nil otherwise.
|
131
|
+
def type
|
132
|
+
@type ||= @collection.nil? ? nil : @collection.label.to_sym
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the front matter defaults defined for the file's URL and/or type
|
136
|
+
# as defined in _config.yml.
|
137
|
+
def defaults
|
138
|
+
@defaults ||= @site.frontmatter_defaults.all url, type
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Bunto
|
2
|
+
class Stevenson < ::Logger
|
3
|
+
def initialize
|
4
|
+
@progname = nil
|
5
|
+
@level = DEBUG
|
6
|
+
@default_formatter = Formatter.new
|
7
|
+
@logdev = $stdout
|
8
|
+
@formatter = proc do |_, _, _, msg|
|
9
|
+
"#{msg}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(severity, message = nil, progname = nil, &block)
|
14
|
+
severity ||= UNKNOWN
|
15
|
+
@logdev = set_logdevice(severity)
|
16
|
+
|
17
|
+
if @logdev.nil? || severity < @level
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
progname ||= @progname
|
21
|
+
if message.nil?
|
22
|
+
if block_given?
|
23
|
+
message = yield
|
24
|
+
else
|
25
|
+
message = progname
|
26
|
+
progname = @progname
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@logdev.puts(
|
30
|
+
format_message(format_severity(severity), Time.now, progname, message))
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
# Log a +WARN+ message
|
35
|
+
def warn(progname = nil, &block)
|
36
|
+
add(WARN, nil, progname.yellow, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Log an +ERROR+ message
|
40
|
+
def error(progname = nil, &block)
|
41
|
+
add(ERROR, nil, progname.red, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def close
|
45
|
+
# No LogDevice in use
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def set_logdevice(severity)
|
51
|
+
if severity > INFO
|
52
|
+
$stderr
|
53
|
+
else
|
54
|
+
$stdout
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Bunto
|
2
|
+
module Tags
|
3
|
+
class HighlightBlock < Liquid::Block
|
4
|
+
include Liquid::StandardFilters
|
5
|
+
|
6
|
+
# The regular expression syntax checker. Start with the language specifier.
|
7
|
+
# Follow that by zero or more space separated options that take one of three
|
8
|
+
# forms: name, name=value, or name="<quoted list>"
|
9
|
+
#
|
10
|
+
# <quoted list> is a space-separated list of numbers
|
11
|
+
SYNTAX = /^([a-zA-Z0-9.+#-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$/
|
12
|
+
|
13
|
+
def initialize(tag_name, markup, tokens)
|
14
|
+
super
|
15
|
+
if markup.strip =~ SYNTAX
|
16
|
+
@lang = Regexp.last_match(1).downcase
|
17
|
+
@highlight_options = {}
|
18
|
+
if defined?(Regexp.last_match(2)) && Regexp.last_match(2) != ''
|
19
|
+
# Split along 3 possible forms -- key="<quoted list>", key=value, or key
|
20
|
+
Regexp.last_match(2).scan(/(?:\w="[^"]*"|\w=\w|\w)+/) do |opt|
|
21
|
+
key, value = opt.split('=')
|
22
|
+
# If a quoted list, convert to array
|
23
|
+
if value && value.include?("\"")
|
24
|
+
value.delete!('"')
|
25
|
+
value = value.split
|
26
|
+
end
|
27
|
+
@highlight_options[key.to_sym] = value || true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@highlight_options[:linenos] = "inline" if @highlight_options.key?(:linenos) && @highlight_options[:linenos] == true
|
31
|
+
else
|
32
|
+
raise SyntaxError.new <<-eos
|
33
|
+
Syntax Error in tag 'highlight' while parsing the following markup:
|
34
|
+
|
35
|
+
#{markup}
|
36
|
+
|
37
|
+
Valid syntax: highlight <lang> [linenos]
|
38
|
+
eos
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def render(context)
|
43
|
+
prefix = context["highlighter_prefix"] || ""
|
44
|
+
suffix = context["highlighter_suffix"] || ""
|
45
|
+
code = super.to_s.gsub(/\A(\n|\r)+|(\n|\r)+\z/, '')
|
46
|
+
|
47
|
+
is_safe = !!context.registers[:site].safe
|
48
|
+
|
49
|
+
output =
|
50
|
+
case context.registers[:site].highlighter
|
51
|
+
when 'pygments'
|
52
|
+
render_pygments(code, is_safe)
|
53
|
+
when 'rouge'
|
54
|
+
render_rouge(code)
|
55
|
+
else
|
56
|
+
render_codehighlighter(code)
|
57
|
+
end
|
58
|
+
|
59
|
+
rendered_output = add_code_tag(output)
|
60
|
+
prefix + rendered_output + suffix
|
61
|
+
end
|
62
|
+
|
63
|
+
def sanitized_opts(opts, is_safe)
|
64
|
+
if is_safe
|
65
|
+
Hash[[
|
66
|
+
[:startinline, opts.fetch(:startinline, nil)],
|
67
|
+
[:hl_lines, opts.fetch(:hl_lines, nil)],
|
68
|
+
[:linenos, opts.fetch(:linenos, nil)],
|
69
|
+
[:encoding, opts.fetch(:encoding, 'utf-8')],
|
70
|
+
[:cssclass, opts.fetch(:cssclass, nil)]
|
71
|
+
].reject { |f| f.last.nil? }]
|
72
|
+
else
|
73
|
+
opts
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def render_pygments(code, is_safe)
|
78
|
+
Bunto::External.require_with_graceful_fail('pygments')
|
79
|
+
|
80
|
+
highlighted_code = Pygments.highlight(
|
81
|
+
code,
|
82
|
+
:lexer => @lang,
|
83
|
+
:options => sanitized_opts(@highlight_options, is_safe)
|
84
|
+
)
|
85
|
+
|
86
|
+
if highlighted_code.nil?
|
87
|
+
Bunto.logger.error "There was an error highlighting your code:"
|
88
|
+
puts
|
89
|
+
Bunto.logger.error code
|
90
|
+
puts
|
91
|
+
Bunto.logger.error "While attempting to convert the above code, Pygments.rb" \
|
92
|
+
" returned an unacceptable value."
|
93
|
+
Bunto.logger.error "This is usually a timeout problem solved by running `bunto build` again."
|
94
|
+
raise ArgumentError.new("Pygments.rb returned an unacceptable value when attempting to highlight some code.")
|
95
|
+
end
|
96
|
+
|
97
|
+
highlighted_code.sub('<div class="highlight"><pre>', '').sub('</pre></div>', '')
|
98
|
+
end
|
99
|
+
|
100
|
+
def render_rouge(code)
|
101
|
+
Bunto::External.require_with_graceful_fail('rouge')
|
102
|
+
formatter = Rouge::Formatters::HTML.new(:line_numbers => @highlight_options[:linenos], :wrap => false)
|
103
|
+
lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText
|
104
|
+
formatter.format(lexer.lex(code))
|
105
|
+
end
|
106
|
+
|
107
|
+
def render_codehighlighter(code)
|
108
|
+
h(code).strip
|
109
|
+
end
|
110
|
+
|
111
|
+
def add_code_tag(code)
|
112
|
+
code_attributes = [
|
113
|
+
"class=\"language-#{@lang.to_s.tr('+', '-')}\"",
|
114
|
+
"data-lang=\"#{@lang}\""
|
115
|
+
].join(" ")
|
116
|
+
"<figure class=\"highlight\"><pre><code #{code_attributes}>#{code.chomp}</code></pre></figure>"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
Liquid::Template.register_tag('highlight', Bunto::Tags::HighlightBlock)
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Bunto
|
4
|
+
module Tags
|
5
|
+
class IncludeTagError < StandardError
|
6
|
+
attr_accessor :path
|
7
|
+
|
8
|
+
def initialize(msg, path)
|
9
|
+
super(msg)
|
10
|
+
@path = path
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class IncludeTag < Liquid::Tag
|
15
|
+
attr_reader :includes_dir
|
16
|
+
|
17
|
+
VALID_SYNTAX = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
|
18
|
+
VARIABLE_SYNTAX = /(?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)(?<params>.*)/
|
19
|
+
|
20
|
+
def initialize(tag_name, markup, tokens)
|
21
|
+
super
|
22
|
+
matched = markup.strip.match(VARIABLE_SYNTAX)
|
23
|
+
if matched
|
24
|
+
@file = matched['variable'].strip
|
25
|
+
@params = matched['params'].strip
|
26
|
+
else
|
27
|
+
@file, @params = markup.strip.split(' ', 2)
|
28
|
+
end
|
29
|
+
validate_params if @params
|
30
|
+
@tag_name = tag_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def syntax_example
|
34
|
+
"{% #{@tag_name} file.ext param='value' param2='value' %}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_params(context)
|
38
|
+
params = {}
|
39
|
+
markup = @params
|
40
|
+
|
41
|
+
while match = VALID_SYNTAX.match(markup) do
|
42
|
+
markup = markup[match.end(0)..-1]
|
43
|
+
|
44
|
+
value = if match[2]
|
45
|
+
match[2].gsub(/\\"/, '"')
|
46
|
+
elsif match[3]
|
47
|
+
match[3].gsub(/\\'/, "'")
|
48
|
+
elsif match[4]
|
49
|
+
context[match[4]]
|
50
|
+
end
|
51
|
+
|
52
|
+
params[match[1]] = value
|
53
|
+
end
|
54
|
+
params
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_file_name(file)
|
58
|
+
if file !~ /^[a-zA-Z0-9_\/\.-]+$/ || file =~ /\.\// || file =~ /\/\./
|
59
|
+
raise ArgumentError.new <<-eos
|
60
|
+
Invalid syntax for include tag. File contains invalid characters or sequences:
|
61
|
+
|
62
|
+
#{file}
|
63
|
+
|
64
|
+
Valid syntax:
|
65
|
+
|
66
|
+
#{syntax_example}
|
67
|
+
|
68
|
+
eos
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def validate_params
|
73
|
+
full_valid_syntax = Regexp.compile('\A\s*(?:' + VALID_SYNTAX.to_s + '(?=\s|\z)\s*)*\z')
|
74
|
+
unless @params =~ full_valid_syntax
|
75
|
+
raise ArgumentError.new <<-eos
|
76
|
+
Invalid syntax for include tag:
|
77
|
+
|
78
|
+
#{@params}
|
79
|
+
|
80
|
+
Valid syntax:
|
81
|
+
|
82
|
+
#{syntax_example}
|
83
|
+
|
84
|
+
eos
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Grab file read opts in the context
|
89
|
+
def file_read_opts(context)
|
90
|
+
context.registers[:site].file_read_opts
|
91
|
+
end
|
92
|
+
|
93
|
+
# Render the variable if required
|
94
|
+
def render_variable(context)
|
95
|
+
if @file.match(VARIABLE_SYNTAX)
|
96
|
+
partial = context.registers[:site].liquid_renderer.file("(variable)").parse(@file)
|
97
|
+
partial.render!(context)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def tag_includes_dir(context)
|
102
|
+
context.registers[:site].config['includes_dir'].freeze
|
103
|
+
end
|
104
|
+
|
105
|
+
def render(context)
|
106
|
+
site = context.registers[:site]
|
107
|
+
@includes_dir = tag_includes_dir(context)
|
108
|
+
dir = resolved_includes_dir(context)
|
109
|
+
|
110
|
+
file = render_variable(context) || @file
|
111
|
+
validate_file_name(file)
|
112
|
+
|
113
|
+
path = File.join(dir, file)
|
114
|
+
validate_path(path, dir, site.safe)
|
115
|
+
|
116
|
+
# Add include to dependency tree
|
117
|
+
if context.registers[:page] && context.registers[:page].key?("path")
|
118
|
+
site.regenerator.add_dependency(
|
119
|
+
site.in_source_dir(context.registers[:page]["path"]),
|
120
|
+
path
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
begin
|
125
|
+
partial = load_cached_partial(path, context)
|
126
|
+
|
127
|
+
context.stack do
|
128
|
+
context['include'] = parse_params(context) if @params
|
129
|
+
partial.render!(context)
|
130
|
+
end
|
131
|
+
rescue => e
|
132
|
+
raise IncludeTagError.new e.message, File.join(@includes_dir, @file)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def load_cached_partial(path, context)
|
137
|
+
context.registers[:cached_partials] ||= {}
|
138
|
+
cached_partial = context.registers[:cached_partials]
|
139
|
+
|
140
|
+
if cached_partial.key?(path)
|
141
|
+
cached_partial[path]
|
142
|
+
else
|
143
|
+
cached_partial[path] = context.registers[:site].liquid_renderer.file(path).parse(read_file(path, context))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def resolved_includes_dir(context)
|
148
|
+
context.registers[:site].in_source_dir(@includes_dir)
|
149
|
+
end
|
150
|
+
|
151
|
+
def validate_path(path, dir, safe)
|
152
|
+
if safe && !realpath_prefixed_with?(path, dir)
|
153
|
+
raise IOError.new "The included file '#{path}' should exist and should not be a symlink"
|
154
|
+
elsif !File.exist?(path)
|
155
|
+
raise IOError.new "Included file '#{path_relative_to_source(dir, path)}' not found"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def path_relative_to_source(dir, path)
|
160
|
+
File.join(@includes_dir, path.sub(Regexp.new("^#{dir}"), ""))
|
161
|
+
end
|
162
|
+
|
163
|
+
def realpath_prefixed_with?(path, dir)
|
164
|
+
File.exist?(path) && File.realpath(path).start_with?(dir)
|
165
|
+
end
|
166
|
+
|
167
|
+
# This method allows to modify the file content by inheriting from the class.
|
168
|
+
def read_file(file, context)
|
169
|
+
File.read(file, file_read_opts(context))
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class IncludeRelativeTag < IncludeTag
|
174
|
+
def tag_includes_dir(context)
|
175
|
+
'.'.freeze
|
176
|
+
end
|
177
|
+
|
178
|
+
def page_path(context)
|
179
|
+
context.registers[:page].nil? ? includes_dir : File.dirname(context.registers[:page]["path"])
|
180
|
+
end
|
181
|
+
|
182
|
+
def resolved_includes_dir(context)
|
183
|
+
context.registers[:site].in_source_dir(page_path(context))
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
Liquid::Template.register_tag('include', Bunto::Tags::IncludeTag)
|
190
|
+
Liquid::Template.register_tag('include_relative', Bunto::Tags::IncludeRelativeTag)
|