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,92 @@
|
|
1
|
+
module Bunto
|
2
|
+
module Converters
|
3
|
+
class Markdown < Converter
|
4
|
+
highlighter_prefix "\n"
|
5
|
+
highlighter_suffix "\n"
|
6
|
+
safe true
|
7
|
+
|
8
|
+
def setup
|
9
|
+
return if @setup
|
10
|
+
unless (@parser = get_processor)
|
11
|
+
Bunto.logger.error "Invalid Markdown processor given:", @config["markdown"]
|
12
|
+
Bunto.logger.info "", "Custom processors are not loaded in safe mode" if @config["safe"]
|
13
|
+
Bunto.logger.error "", "Available processors are: #{valid_processors.join(", ")}"
|
14
|
+
raise Errors::FatalException, "Bailing out; invalid Markdown processor."
|
15
|
+
end
|
16
|
+
|
17
|
+
@setup = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_processor
|
21
|
+
case @config["markdown"].downcase
|
22
|
+
when "redcarpet" then return RedcarpetParser.new(@config)
|
23
|
+
when "kramdown" then return KramdownParser.new(@config)
|
24
|
+
when "rdiscount" then return RDiscountParser.new(@config)
|
25
|
+
else
|
26
|
+
get_custom_processor
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Public: Provides you with a list of processors, the ones we
|
31
|
+
# support internally and the ones that you have provided to us (if you
|
32
|
+
# are not in safe mode.)
|
33
|
+
|
34
|
+
def valid_processors
|
35
|
+
%W(rdiscount kramdown redcarpet) + third_party_processors
|
36
|
+
end
|
37
|
+
|
38
|
+
# Public: A list of processors that you provide via plugins.
|
39
|
+
# This is really only available if you are not in safe mode, if you are
|
40
|
+
# in safe mode (re: GitHub) then there will be none.
|
41
|
+
|
42
|
+
def third_party_processors
|
43
|
+
self.class.constants - \
|
44
|
+
%w(KramdownParser RDiscountParser RedcarpetParser PRIORITIES).map(
|
45
|
+
&:to_sym
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def extname_list
|
50
|
+
@extname_list ||= @config['markdown_ext'].split(',').map do |e|
|
51
|
+
".#{e.downcase}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def matches(ext)
|
56
|
+
extname_list.include?(ext.downcase)
|
57
|
+
end
|
58
|
+
|
59
|
+
def output_ext(_ext)
|
60
|
+
".html"
|
61
|
+
end
|
62
|
+
|
63
|
+
def convert(content)
|
64
|
+
setup
|
65
|
+
@parser.convert(content)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def get_custom_processor
|
70
|
+
converter_name = @config["markdown"]
|
71
|
+
if custom_class_allowed?(converter_name)
|
72
|
+
self.class.const_get(converter_name).new(@config)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Private: Determine whether a class name is an allowed custom
|
77
|
+
# markdown class name.
|
78
|
+
#
|
79
|
+
# parser_name - the name of the parser class
|
80
|
+
#
|
81
|
+
# Returns true if the parser name contains only alphanumeric
|
82
|
+
# characters and is defined within Bunto::Converters::Markdown
|
83
|
+
|
84
|
+
private
|
85
|
+
def custom_class_allowed?(parser_name)
|
86
|
+
parser_name !~ /[^A-Za-z0-9_]/ && self.class.constants.include?(
|
87
|
+
parser_name.to_sym
|
88
|
+
)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# Frozen-string-literal: true
|
2
|
+
# Encoding: utf-8
|
3
|
+
|
4
|
+
module Bunto
|
5
|
+
module Converters
|
6
|
+
class Markdown
|
7
|
+
class KramdownParser
|
8
|
+
CODERAY_DEFAULTS = {
|
9
|
+
"css" => "style",
|
10
|
+
"bold_every" => 10,
|
11
|
+
"line_numbers" => "inline",
|
12
|
+
"line_number_start" => 1,
|
13
|
+
"tab_width" => 4,
|
14
|
+
"wrap" => "div"
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
def initialize(config)
|
18
|
+
Bunto::External.require_with_graceful_fail "kramdown"
|
19
|
+
@main_fallback_highlighter = config["highlighter"] || "rouge"
|
20
|
+
@config = config["kramdown"] || {}
|
21
|
+
setup
|
22
|
+
end
|
23
|
+
|
24
|
+
# Setup and normalize the configuration:
|
25
|
+
# * Create Kramdown if it doesn't exist.
|
26
|
+
# * Set syntax_highlighter, detecting enable_coderay and merging highlighter if none.
|
27
|
+
# * Merge kramdown[coderay] into syntax_highlighter_opts stripping coderay_.
|
28
|
+
# * Make sure `syntax_highlighter_opts` exists.
|
29
|
+
|
30
|
+
def setup
|
31
|
+
@config["syntax_highlighter"] ||= highlighter
|
32
|
+
@config["syntax_highlighter_opts"] ||= {}
|
33
|
+
@config["coderay"] ||= {} # XXX: Legacy.
|
34
|
+
modernize_coderay_config
|
35
|
+
make_accessible
|
36
|
+
end
|
37
|
+
|
38
|
+
def convert(content)
|
39
|
+
Kramdown::Document.new(content, @config).to_html
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def make_accessible(hash = @config)
|
44
|
+
proc_ = proc { |hash_, key| hash_[key.to_s] if key.is_a?(Symbol) }
|
45
|
+
hash.default_proc = proc_
|
46
|
+
|
47
|
+
hash.each do |_, val|
|
48
|
+
make_accessible val if val.is_a?(
|
49
|
+
Hash
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# config[kramdown][syntax_higlighter] > config[kramdown][enable_coderay] > config[highlighter]
|
55
|
+
# Where `enable_coderay` is now deprecated because Kramdown
|
56
|
+
# supports Rouge now too.
|
57
|
+
|
58
|
+
private
|
59
|
+
def highlighter
|
60
|
+
return @highlighter if @highlighter
|
61
|
+
|
62
|
+
if @config["syntax_highlighter"]
|
63
|
+
return @highlighter = @config[
|
64
|
+
"syntax_highlighter"
|
65
|
+
]
|
66
|
+
end
|
67
|
+
|
68
|
+
@highlighter = begin
|
69
|
+
if @config.key?("enable_coderay") && @config["enable_coderay"]
|
70
|
+
Bunto::Deprecator.deprecation_message "You are using 'enable_coderay', " \
|
71
|
+
"use syntax_highlighter: coderay in your configuration file."
|
72
|
+
|
73
|
+
"coderay"
|
74
|
+
else
|
75
|
+
@main_fallback_highlighter
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def strip_coderay_prefix(hash)
|
82
|
+
hash.each_with_object({}) do |(key, val), hsh|
|
83
|
+
cleaned_key = key.gsub(/\Acoderay_/, "")
|
84
|
+
|
85
|
+
if key != cleaned_key
|
86
|
+
Bunto::Deprecator.deprecation_message(
|
87
|
+
"You are using '#{key}'. Normalizing to #{cleaned_key}."
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
hsh[cleaned_key] = val
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# If our highlighter is CodeRay we go in to merge the CodeRay defaults
|
96
|
+
# with your "coderay" key if it's there, deprecating it in the
|
97
|
+
# process of you using it.
|
98
|
+
|
99
|
+
private
|
100
|
+
def modernize_coderay_config
|
101
|
+
if highlighter == "coderay"
|
102
|
+
Bunto::Deprecator.deprecation_message "You are using 'kramdown.coderay' in your configuration, " \
|
103
|
+
"please use 'syntax_highlighter_opts' instead."
|
104
|
+
|
105
|
+
@config["syntax_highlighter_opts"] = begin
|
106
|
+
strip_coderay_prefix(
|
107
|
+
@config["syntax_highlighter_opts"] \
|
108
|
+
.merge(CODERAY_DEFAULTS) \
|
109
|
+
.merge(@config["coderay"])
|
110
|
+
)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Bunto
|
2
|
+
module Converters
|
3
|
+
class Markdown
|
4
|
+
class RDiscountParser
|
5
|
+
def initialize(config)
|
6
|
+
Bunto::External.require_with_graceful_fail "rdiscount"
|
7
|
+
@config = config
|
8
|
+
@rdiscount_extensions = @config['rdiscount']['extensions'].map(&:to_sym)
|
9
|
+
end
|
10
|
+
|
11
|
+
def convert(content)
|
12
|
+
rd = RDiscount.new(content, *@rdiscount_extensions)
|
13
|
+
html = rd.to_html
|
14
|
+
if @config['rdiscount']['toc_token']
|
15
|
+
html = replace_generated_toc(rd, html, @config['rdiscount']['toc_token'])
|
16
|
+
end
|
17
|
+
html
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def replace_generated_toc(rd, html, toc_token)
|
22
|
+
if rd.generate_toc && html.include?(toc_token)
|
23
|
+
utf8_toc = rd.toc_content
|
24
|
+
utf8_toc.force_encoding('utf-8') if utf8_toc.respond_to?(:force_encoding)
|
25
|
+
html.gsub(toc_token, utf8_toc)
|
26
|
+
else
|
27
|
+
html
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Bunto
|
2
|
+
module Converters
|
3
|
+
class Markdown
|
4
|
+
class RedcarpetParser
|
5
|
+
module CommonMethods
|
6
|
+
def add_code_tags(code, lang)
|
7
|
+
code = code.to_s
|
8
|
+
code = code.sub(/<pre>/, "<pre><code class=\"language-#{lang}\" data-lang=\"#{lang}\">")
|
9
|
+
code = code.sub(/<\/pre>/, "</code></pre>")
|
10
|
+
code
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module WithPygments
|
15
|
+
include CommonMethods
|
16
|
+
def block_code(code, lang)
|
17
|
+
Bunto::External.require_with_graceful_fail("pygments")
|
18
|
+
lang = lang && lang.split.first || "text"
|
19
|
+
add_code_tags(
|
20
|
+
Pygments.highlight(code, :lexer => lang, :options => { :encoding => 'utf-8' }),
|
21
|
+
lang
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module WithoutHighlighting
|
27
|
+
require 'cgi'
|
28
|
+
|
29
|
+
include CommonMethods
|
30
|
+
|
31
|
+
def code_wrap(code)
|
32
|
+
"<figure class=\"highlight\"><pre>#{CGI::escapeHTML(code)}</pre></figure>"
|
33
|
+
end
|
34
|
+
|
35
|
+
def block_code(code, lang)
|
36
|
+
lang = lang && lang.split.first || "text"
|
37
|
+
add_code_tags(code_wrap(code), lang)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module WithRouge
|
42
|
+
def block_code(code, lang)
|
43
|
+
code = "<pre>#{super}</pre>"
|
44
|
+
|
45
|
+
output = "<div class=\"highlight\">"
|
46
|
+
output << add_code_tags(code, lang)
|
47
|
+
output << "</div>"
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
def rouge_formatter(_lexer)
|
52
|
+
Rouge::Formatters::HTML.new(:wrap => false)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(config)
|
57
|
+
External.require_with_graceful_fail("redcarpet")
|
58
|
+
@config = config
|
59
|
+
@redcarpet_extensions = {}
|
60
|
+
@config['redcarpet']['extensions'].each { |e| @redcarpet_extensions[e.to_sym] = true }
|
61
|
+
|
62
|
+
@renderer ||= class_with_proper_highlighter(@config['highlighter'])
|
63
|
+
end
|
64
|
+
|
65
|
+
def class_with_proper_highlighter(highlighter)
|
66
|
+
case highlighter
|
67
|
+
when "pygments"
|
68
|
+
Class.new(Redcarpet::Render::HTML) do
|
69
|
+
include WithPygments
|
70
|
+
end
|
71
|
+
when "rouge"
|
72
|
+
Class.new(Redcarpet::Render::HTML) do
|
73
|
+
Bunto::External.require_with_graceful_fail(%w(
|
74
|
+
rouge
|
75
|
+
rouge/plugins/redcarpet
|
76
|
+
))
|
77
|
+
|
78
|
+
unless Gem::Version.new(Rouge.version) > Gem::Version.new("1.3.0")
|
79
|
+
abort "Please install Rouge 1.3.0 or greater and try running Bunto again."
|
80
|
+
end
|
81
|
+
|
82
|
+
include Rouge::Plugins::Redcarpet
|
83
|
+
include CommonMethods
|
84
|
+
include WithRouge
|
85
|
+
end
|
86
|
+
else
|
87
|
+
Class.new(Redcarpet::Render::HTML) do
|
88
|
+
include WithoutHighlighting
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def convert(content)
|
94
|
+
@redcarpet_extensions[:fenced_code_blocks] = !@redcarpet_extensions[:no_fenced_code_blocks]
|
95
|
+
@renderer.send :include, Redcarpet::Render::SmartyPants if @redcarpet_extensions[:smart]
|
96
|
+
markdown = Redcarpet::Markdown.new(@renderer.new(@redcarpet_extensions), @redcarpet_extensions)
|
97
|
+
markdown.render(content)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Kramdown::Parser::SmartyPants < Kramdown::Parser::Kramdown
|
2
|
+
def initialize(source, options)
|
3
|
+
super
|
4
|
+
@block_parsers = [:block_html]
|
5
|
+
@span_parsers = [:smart_quotes, :html_entity, :typographic_syms, :span_html]
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module Bunto
|
10
|
+
module Converters
|
11
|
+
class SmartyPants < Converter
|
12
|
+
safe true
|
13
|
+
priority :low
|
14
|
+
|
15
|
+
def initialize(config)
|
16
|
+
Bunto::External.require_with_graceful_fail "kramdown"
|
17
|
+
@config = config["kramdown"].dup || {}
|
18
|
+
@config[:input] = :SmartyPants
|
19
|
+
end
|
20
|
+
|
21
|
+
def matches(_)
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def output_ext(_)
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def convert(content)
|
30
|
+
Kramdown::Document.new(content, @config).to_html.chomp
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
# Convertible provides methods for converting a pagelike item
|
6
|
+
# from a certain type of markup into actual content
|
7
|
+
#
|
8
|
+
# Requires
|
9
|
+
# self.site -> Bunto::Site
|
10
|
+
# self.content
|
11
|
+
# self.content=
|
12
|
+
# self.data=
|
13
|
+
# self.ext=
|
14
|
+
# self.output=
|
15
|
+
# self.name
|
16
|
+
# self.path
|
17
|
+
# self.type -> :page, :post or :draft
|
18
|
+
|
19
|
+
module Bunto
|
20
|
+
module Convertible
|
21
|
+
# Returns the contents as a String.
|
22
|
+
def to_s
|
23
|
+
content || ''
|
24
|
+
end
|
25
|
+
|
26
|
+
# Whether the file is published or not, as indicated in YAML front-matter
|
27
|
+
def published?
|
28
|
+
!(data.key?('published') && data['published'] == false)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Read the YAML frontmatter.
|
32
|
+
#
|
33
|
+
# base - The String path to the dir containing the file.
|
34
|
+
# name - The String filename of the file.
|
35
|
+
# opts - optional parameter to File.read, default at site configs
|
36
|
+
#
|
37
|
+
# Returns nothing.
|
38
|
+
def read_yaml(base, name, opts = {})
|
39
|
+
filename = File.join(base, name)
|
40
|
+
|
41
|
+
begin
|
42
|
+
self.content = File.read(site.in_source_dir(base, name),
|
43
|
+
Utils.merged_file_read_opts(site, opts))
|
44
|
+
if content =~ /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
|
45
|
+
self.content = $POSTMATCH
|
46
|
+
self.data = SafeYAML.load(Regexp.last_match(1))
|
47
|
+
end
|
48
|
+
rescue SyntaxError => e
|
49
|
+
Bunto.logger.warn "YAML Exception reading #{filename}: #{e.message}"
|
50
|
+
rescue Exception => e
|
51
|
+
Bunto.logger.warn "Error reading file #{filename}: #{e.message}"
|
52
|
+
end
|
53
|
+
|
54
|
+
self.data ||= {}
|
55
|
+
|
56
|
+
validate_data! filename
|
57
|
+
validate_permalink! filename
|
58
|
+
|
59
|
+
self.data
|
60
|
+
end
|
61
|
+
|
62
|
+
def validate_data!(filename)
|
63
|
+
unless self.data.is_a?(Hash)
|
64
|
+
raise Errors::InvalidYAMLFrontMatterError, "Invalid YAML front matter in #{filename}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_permalink!(filename)
|
69
|
+
if self.data['permalink'] && self.data['permalink'].size == 0
|
70
|
+
raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Transform the contents based on the content type.
|
75
|
+
#
|
76
|
+
# Returns the transformed contents.
|
77
|
+
def transform
|
78
|
+
converters.reduce(content) do |output, converter|
|
79
|
+
begin
|
80
|
+
converter.convert output
|
81
|
+
rescue => e
|
82
|
+
Bunto.logger.error "Conversion error:", "#{converter.class} encountered an error while converting '#{path}':"
|
83
|
+
Bunto.logger.error("", e.to_s)
|
84
|
+
raise e
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Determine the extension depending on content_type.
|
90
|
+
#
|
91
|
+
# Returns the String extension for the output file.
|
92
|
+
# e.g. ".html" for an HTML output file.
|
93
|
+
def output_ext
|
94
|
+
Bunto::Renderer.new(site, self).output_ext
|
95
|
+
end
|
96
|
+
|
97
|
+
# Determine which converter to use based on this convertible's
|
98
|
+
# extension.
|
99
|
+
#
|
100
|
+
# Returns the Converter instance.
|
101
|
+
def converters
|
102
|
+
@converters ||= site.converters.select { |c| c.matches(ext) }.sort
|
103
|
+
end
|
104
|
+
|
105
|
+
# Render Liquid in the content
|
106
|
+
#
|
107
|
+
# content - the raw Liquid content to render
|
108
|
+
# payload - the payload for Liquid
|
109
|
+
# info - the info for Liquid
|
110
|
+
#
|
111
|
+
# Returns the converted content
|
112
|
+
def render_liquid(content, payload, info, path)
|
113
|
+
site.liquid_renderer.file(path).parse(content).render!(payload, info)
|
114
|
+
rescue Tags::IncludeTagError => e
|
115
|
+
Bunto.logger.error "Liquid Exception:", "#{e.message} in #{e.path}, included in #{path || self.path}"
|
116
|
+
raise e
|
117
|
+
rescue Exception => e
|
118
|
+
Bunto.logger.error "Liquid Exception:", "#{e.message} in #{path || self.path}"
|
119
|
+
raise e
|
120
|
+
end
|
121
|
+
|
122
|
+
# Convert this Convertible's data to a Hash suitable for use by Liquid.
|
123
|
+
#
|
124
|
+
# Returns the Hash representation of this Convertible.
|
125
|
+
def to_liquid(attrs = nil)
|
126
|
+
further_data = Hash[(attrs || self.class::ATTRIBUTES_FOR_LIQUID).map do |attribute|
|
127
|
+
[attribute, send(attribute)]
|
128
|
+
end]
|
129
|
+
|
130
|
+
defaults = site.frontmatter_defaults.all(relative_path, type)
|
131
|
+
Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
|
132
|
+
end
|
133
|
+
|
134
|
+
# The type of a document,
|
135
|
+
# i.e., its classname downcase'd and to_sym'd.
|
136
|
+
#
|
137
|
+
# Returns the type of self.
|
138
|
+
def type
|
139
|
+
if is_a?(Page)
|
140
|
+
:pages
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# returns the owner symbol for hook triggering
|
145
|
+
def hook_owner
|
146
|
+
if is_a?(Page)
|
147
|
+
:pages
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Determine whether the document is an asset file.
|
152
|
+
# Asset files include CoffeeScript files and Sass/SCSS files.
|
153
|
+
#
|
154
|
+
# Returns true if the extname belongs to the set of extensions
|
155
|
+
# that asset files use.
|
156
|
+
def asset_file?
|
157
|
+
sass_file? || coffeescript_file?
|
158
|
+
end
|
159
|
+
|
160
|
+
# Determine whether the document is a Sass file.
|
161
|
+
#
|
162
|
+
# Returns true if extname == .sass or .scss, false otherwise.
|
163
|
+
def sass_file?
|
164
|
+
%w(.sass .scss).include?(ext)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Determine whether the document is a CoffeeScript file.
|
168
|
+
#
|
169
|
+
# Returns true if extname == .coffee, false otherwise.
|
170
|
+
def coffeescript_file?
|
171
|
+
'.coffee'.eql?(ext)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Determine whether the file should be rendered with Liquid.
|
175
|
+
#
|
176
|
+
# Always returns true.
|
177
|
+
def render_with_liquid?
|
178
|
+
true
|
179
|
+
end
|
180
|
+
|
181
|
+
# Determine whether the file should be placed into layouts.
|
182
|
+
#
|
183
|
+
# Returns false if the document is an asset file.
|
184
|
+
def place_in_layout?
|
185
|
+
!asset_file?
|
186
|
+
end
|
187
|
+
|
188
|
+
# Checks if the layout specified in the document actually exists
|
189
|
+
#
|
190
|
+
# layout - the layout to check
|
191
|
+
#
|
192
|
+
# Returns true if the layout is invalid, false if otherwise
|
193
|
+
def invalid_layout?(layout)
|
194
|
+
!data["layout"].nil? && layout.nil? && !(self.is_a? Bunto::Excerpt)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Recursively render layouts
|
198
|
+
#
|
199
|
+
# layouts - a list of the layouts
|
200
|
+
# payload - the payload for Liquid
|
201
|
+
# info - the info for Liquid
|
202
|
+
#
|
203
|
+
# Returns nothing
|
204
|
+
def render_all_layouts(layouts, payload, info)
|
205
|
+
# recursively render layouts
|
206
|
+
layout = layouts[data["layout"]]
|
207
|
+
|
208
|
+
Bunto.logger.warn("Build Warning:", "Layout '#{data["layout"]}' requested in #{path} does not exist.") if invalid_layout? layout
|
209
|
+
|
210
|
+
used = Set.new([layout])
|
211
|
+
|
212
|
+
while layout
|
213
|
+
Bunto.logger.debug "Rendering Layout:", path
|
214
|
+
payload["content"] = output
|
215
|
+
payload["layout"] = Utils.deep_merge_hashes(payload["layout"] || {}, layout.data)
|
216
|
+
|
217
|
+
self.output = render_liquid(layout.content,
|
218
|
+
payload,
|
219
|
+
info,
|
220
|
+
File.join(site.config['layouts_dir'], layout.name))
|
221
|
+
|
222
|
+
# Add layout to dependency tree
|
223
|
+
site.regenerator.add_dependency(
|
224
|
+
site.in_source_dir(path),
|
225
|
+
site.in_source_dir(layout.path)
|
226
|
+
)
|
227
|
+
|
228
|
+
if layout = layouts[layout.data["layout"]]
|
229
|
+
if used.include?(layout)
|
230
|
+
layout = nil # avoid recursive chain
|
231
|
+
else
|
232
|
+
used << layout
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Add any necessary layouts to this convertible document.
|
239
|
+
#
|
240
|
+
# payload - The site payload Drop or Hash.
|
241
|
+
# layouts - A Hash of {"name" => "layout"}.
|
242
|
+
#
|
243
|
+
# Returns nothing.
|
244
|
+
def do_layout(payload, layouts)
|
245
|
+
Bunto.logger.debug "Rendering:", self.relative_path
|
246
|
+
|
247
|
+
Bunto.logger.debug "Pre-Render Hooks:", self.relative_path
|
248
|
+
Bunto::Hooks.trigger hook_owner, :pre_render, self, payload
|
249
|
+
info = { :filters => [Bunto::Filters], :registers => { :site => site, :page => payload["page"] } }
|
250
|
+
|
251
|
+
# render and transform content (this becomes the final content of the object)
|
252
|
+
payload["highlighter_prefix"] = converters.first.highlighter_prefix
|
253
|
+
payload["highlighter_suffix"] = converters.first.highlighter_suffix
|
254
|
+
|
255
|
+
if render_with_liquid?
|
256
|
+
Bunto.logger.debug "Rendering Liquid:", self.relative_path
|
257
|
+
self.content = render_liquid(content, payload, info, path)
|
258
|
+
end
|
259
|
+
Bunto.logger.debug "Rendering Markup:", self.relative_path
|
260
|
+
self.content = transform
|
261
|
+
|
262
|
+
# output keeps track of what will finally be written
|
263
|
+
self.output = content
|
264
|
+
|
265
|
+
render_all_layouts(layouts, payload, info) if place_in_layout?
|
266
|
+
Bunto.logger.debug "Post-Render Hooks:", self.relative_path
|
267
|
+
Bunto::Hooks.trigger hook_owner, :post_render, self
|
268
|
+
end
|
269
|
+
|
270
|
+
# Write the generated page file to the destination directory.
|
271
|
+
#
|
272
|
+
# dest - The String path to the destination dir.
|
273
|
+
#
|
274
|
+
# Returns nothing.
|
275
|
+
def write(dest)
|
276
|
+
path = destination(dest)
|
277
|
+
FileUtils.mkdir_p(File.dirname(path))
|
278
|
+
File.open(path, 'wb') do |f|
|
279
|
+
f.write(output)
|
280
|
+
end
|
281
|
+
Bunto::Hooks.trigger hook_owner, :post_write, self
|
282
|
+
end
|
283
|
+
|
284
|
+
# Accessor for data properties by Liquid.
|
285
|
+
#
|
286
|
+
# property - The String name of the property to retrieve.
|
287
|
+
#
|
288
|
+
# Returns the String value or nil if the property isn't included.
|
289
|
+
def [](property)
|
290
|
+
if self.class::ATTRIBUTES_FOR_LIQUID.include?(property)
|
291
|
+
send(property)
|
292
|
+
else
|
293
|
+
data[property]
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|