bunto 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.markdown +59 -0
  4. data/bin/bunto +51 -0
  5. data/lib/bunto.rb +179 -0
  6. data/lib/bunto/cleaner.rb +105 -0
  7. data/lib/bunto/collection.rb +205 -0
  8. data/lib/bunto/command.rb +65 -0
  9. data/lib/bunto/commands/build.rb +77 -0
  10. data/lib/bunto/commands/clean.rb +42 -0
  11. data/lib/bunto/commands/doctor.rb +114 -0
  12. data/lib/bunto/commands/help.rb +31 -0
  13. data/lib/bunto/commands/new.rb +82 -0
  14. data/lib/bunto/commands/serve.rb +204 -0
  15. data/lib/bunto/commands/serve/servlet.rb +61 -0
  16. data/lib/bunto/configuration.rb +323 -0
  17. data/lib/bunto/converter.rb +48 -0
  18. data/lib/bunto/converters/identity.rb +21 -0
  19. data/lib/bunto/converters/markdown.rb +92 -0
  20. data/lib/bunto/converters/markdown/kramdown_parser.rb +117 -0
  21. data/lib/bunto/converters/markdown/rdiscount_parser.rb +33 -0
  22. data/lib/bunto/converters/markdown/redcarpet_parser.rb +102 -0
  23. data/lib/bunto/converters/smartypants.rb +34 -0
  24. data/lib/bunto/convertible.rb +297 -0
  25. data/lib/bunto/deprecator.rb +46 -0
  26. data/lib/bunto/document.rb +444 -0
  27. data/lib/bunto/drops/bunto_drop.rb +21 -0
  28. data/lib/bunto/drops/collection_drop.rb +22 -0
  29. data/lib/bunto/drops/document_drop.rb +27 -0
  30. data/lib/bunto/drops/drop.rb +176 -0
  31. data/lib/bunto/drops/site_drop.rb +38 -0
  32. data/lib/bunto/drops/unified_payload_drop.rb +25 -0
  33. data/lib/bunto/drops/url_drop.rb +83 -0
  34. data/lib/bunto/entry_filter.rb +72 -0
  35. data/lib/bunto/errors.rb +10 -0
  36. data/lib/bunto/excerpt.rb +127 -0
  37. data/lib/bunto/external.rb +59 -0
  38. data/lib/bunto/filters.rb +367 -0
  39. data/lib/bunto/frontmatter_defaults.rb +188 -0
  40. data/lib/bunto/generator.rb +3 -0
  41. data/lib/bunto/hooks.rb +101 -0
  42. data/lib/bunto/layout.rb +49 -0
  43. data/lib/bunto/liquid_extensions.rb +22 -0
  44. data/lib/bunto/liquid_renderer.rb +39 -0
  45. data/lib/bunto/liquid_renderer/file.rb +50 -0
  46. data/lib/bunto/liquid_renderer/table.rb +94 -0
  47. data/lib/bunto/log_adapter.rb +115 -0
  48. data/lib/bunto/mime.types +800 -0
  49. data/lib/bunto/page.rb +180 -0
  50. data/lib/bunto/plugin.rb +96 -0
  51. data/lib/bunto/plugin_manager.rb +95 -0
  52. data/lib/bunto/post.rb +329 -0
  53. data/lib/bunto/publisher.rb +21 -0
  54. data/lib/bunto/reader.rb +126 -0
  55. data/lib/bunto/readers/collection_reader.rb +20 -0
  56. data/lib/bunto/readers/data_reader.rb +69 -0
  57. data/lib/bunto/readers/layout_reader.rb +53 -0
  58. data/lib/bunto/readers/page_reader.rb +21 -0
  59. data/lib/bunto/readers/post_reader.rb +62 -0
  60. data/lib/bunto/readers/static_file_reader.rb +21 -0
  61. data/lib/bunto/regenerator.rb +175 -0
  62. data/lib/bunto/related_posts.rb +56 -0
  63. data/lib/bunto/renderer.rb +191 -0
  64. data/lib/bunto/site.rb +391 -0
  65. data/lib/bunto/static_file.rb +141 -0
  66. data/lib/bunto/stevenson.rb +58 -0
  67. data/lib/bunto/tags/highlight.rb +122 -0
  68. data/lib/bunto/tags/include.rb +190 -0
  69. data/lib/bunto/tags/post_url.rb +88 -0
  70. data/lib/bunto/url.rb +136 -0
  71. data/lib/bunto/utils.rb +287 -0
  72. data/lib/bunto/utils/ansi.rb +59 -0
  73. data/lib/bunto/utils/platforms.rb +30 -0
  74. data/lib/bunto/version.rb +3 -0
  75. data/lib/site_template/.gitignore +3 -0
  76. data/lib/site_template/_config.yml +21 -0
  77. data/lib/site_template/_includes/footer.html +38 -0
  78. data/lib/site_template/_includes/head.html +12 -0
  79. data/lib/site_template/_includes/header.html +27 -0
  80. data/lib/site_template/_includes/icon-github.html +1 -0
  81. data/lib/site_template/_includes/icon-github.svg +1 -0
  82. data/lib/site_template/_includes/icon-twitter.html +1 -0
  83. data/lib/site_template/_includes/icon-twitter.svg +1 -0
  84. data/lib/site_template/_layouts/default.html +20 -0
  85. data/lib/site_template/_layouts/page.html +14 -0
  86. data/lib/site_template/_layouts/post.html +15 -0
  87. data/lib/site_template/_posts/0000-00-00-welcome-to-bunto.markdown.erb +25 -0
  88. data/lib/site_template/_sass/_base.scss +206 -0
  89. data/lib/site_template/_sass/_layout.scss +242 -0
  90. data/lib/site_template/_sass/_syntax-highlighting.scss +71 -0
  91. data/lib/site_template/about.md +15 -0
  92. data/lib/site_template/css/main.scss +53 -0
  93. data/lib/site_template/feed.xml +30 -0
  94. data/lib/site_template/index.html +23 -0
  95. 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