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.
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