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,56 @@
1
+ module Bunto
2
+ class RelatedPosts
3
+ class << self
4
+ attr_accessor :lsi
5
+ end
6
+
7
+ attr_reader :post, :site
8
+
9
+ def initialize(post)
10
+ @post = post
11
+ @site = post.site
12
+ Bunto::External.require_with_graceful_fail('classifier-reborn') if site.lsi
13
+ end
14
+
15
+ def build
16
+ return [] unless site.posts.docs.size > 1
17
+
18
+ if site.lsi
19
+ build_index
20
+ lsi_related_posts
21
+ else
22
+ most_recent_posts
23
+ end
24
+ end
25
+
26
+ def build_index
27
+ self.class.lsi ||= begin
28
+ lsi = ClassifierReborn::LSI.new(:auto_rebuild => false)
29
+ display("Populating LSI...")
30
+
31
+ site.posts.docs.each do |x|
32
+ lsi.add_item(x)
33
+ end
34
+
35
+ display("Rebuilding index...")
36
+ lsi.build_index
37
+ display("")
38
+ lsi
39
+ end
40
+ end
41
+
42
+ def lsi_related_posts
43
+ self.class.lsi.find_related(post, 11)
44
+ end
45
+
46
+ def most_recent_posts
47
+ @most_recent_posts ||= (site.posts.docs.reverse - [post]).first(10)
48
+ end
49
+
50
+ def display(output)
51
+ $stdout.print("\n")
52
+ $stdout.print(Bunto.logger.formatted_topic(output))
53
+ $stdout.flush
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,191 @@
1
+ # encoding: UTF-8
2
+
3
+ module Bunto
4
+ class Renderer
5
+ attr_reader :document, :site, :payload
6
+
7
+ def initialize(site, document, site_payload = nil)
8
+ @site = site
9
+ @document = document
10
+ @payload = site_payload || site.site_payload
11
+ end
12
+
13
+ # Determine which converters to use based on this document's
14
+ # extension.
15
+ #
16
+ # Returns an array of Converter instances.
17
+ def converters
18
+ @converters ||= site.converters.select { |c| c.matches(document.extname) }
19
+ end
20
+
21
+ # Determine the extname the outputted file should have
22
+ #
23
+ # Returns the output extname including the leading period.
24
+ def output_ext
25
+ @output_ext ||= (permalink_ext || converter_output_ext)
26
+ end
27
+
28
+ ######################
29
+ ## DAT RENDER THO
30
+ ######################
31
+
32
+ def run
33
+ Bunto.logger.debug "Rendering:", document.relative_path
34
+
35
+ payload["page"] = document.to_liquid
36
+
37
+ if document.respond_to? :pager
38
+ payload["paginator"] = document.pager.to_liquid
39
+ end
40
+
41
+ if document.is_a?(Document) && document.collection.label == 'posts'
42
+ payload['site']['related_posts'] = document.related_posts
43
+ end
44
+
45
+ # render and transform content (this becomes the final content of the object)
46
+ payload['highlighter_prefix'] = converters.first.highlighter_prefix
47
+ payload['highlighter_suffix'] = converters.first.highlighter_suffix
48
+
49
+ Bunto.logger.debug "Pre-Render Hooks:", document.relative_path
50
+ document.trigger_hooks(:pre_render, payload)
51
+
52
+ info = {
53
+ :filters => [Bunto::Filters],
54
+ :registers => { :site => site, :page => payload['page'] }
55
+ }
56
+
57
+ output = document.content
58
+
59
+ if document.render_with_liquid?
60
+ Bunto.logger.debug "Rendering Liquid:", document.relative_path
61
+ output = render_liquid(output, payload, info, document.path)
62
+ end
63
+
64
+ Bunto.logger.debug "Rendering Markup:", document.relative_path
65
+ output = convert(output)
66
+ document.content = output
67
+
68
+ if document.place_in_layout?
69
+ Bunto.logger.debug "Rendering Layout:", document.relative_path
70
+ place_in_layouts(
71
+ output,
72
+ payload,
73
+ info
74
+ )
75
+ else
76
+ output
77
+ end
78
+ end
79
+
80
+ # Convert the given content using the converters which match this renderer's document.
81
+ #
82
+ # content - the raw, unconverted content
83
+ #
84
+ # Returns the converted content.
85
+ def convert(content)
86
+ converters.reduce(content) do |output, converter|
87
+ begin
88
+ converter.convert output
89
+ rescue => e
90
+ Bunto.logger.error "Conversion error:", "#{converter.class} encountered an error while converting '#{document.relative_path}':"
91
+ Bunto.logger.error("", e.to_s)
92
+ raise e
93
+ end
94
+ end
95
+ end
96
+
97
+ # Render the given content with the payload and info
98
+ #
99
+ # content -
100
+ # payload -
101
+ # info -
102
+ # path - (optional) the path to the file, for use in ex
103
+ #
104
+ # Returns the content, rendered by Liquid.
105
+ def render_liquid(content, payload, info, path = nil)
106
+ site.liquid_renderer.file(path).parse(content).render!(payload, info)
107
+ rescue Tags::IncludeTagError => e
108
+ Bunto.logger.error "Liquid Exception:", "#{e.message} in #{e.path}, included in #{path || document.relative_path}"
109
+ raise e
110
+ rescue Exception => e
111
+ Bunto.logger.error "Liquid Exception:", "#{e.message} in #{path || document.relative_path}"
112
+ raise e
113
+ end
114
+
115
+ # Checks if the layout specified in the document actually exists
116
+ #
117
+ # layout - the layout to check
118
+ #
119
+ # Returns true if the layout is invalid, false if otherwise
120
+ def invalid_layout?(layout)
121
+ !document.data["layout"].nil? && layout.nil?
122
+ end
123
+
124
+ # Render layouts and place given content inside.
125
+ #
126
+ # content - the content to be placed in the layout
127
+ #
128
+ #
129
+ # Returns the content placed in the Liquid-rendered layouts
130
+ def place_in_layouts(content, payload, info)
131
+ output = content.dup
132
+ layout = site.layouts[document.data["layout"]]
133
+
134
+ Bunto.logger.warn("Build Warning:", "Layout '#{document.data["layout"]}' requested in #{document.relative_path} does not exist.") if invalid_layout? layout
135
+
136
+ used = Set.new([layout])
137
+
138
+ while layout
139
+ payload['content'] = output
140
+ payload['page'] = document.to_liquid
141
+ payload['layout'] = Utils.deep_merge_hashes(payload['layout'] || {}, layout.data)
142
+
143
+ output = render_liquid(
144
+ layout.content,
145
+ payload,
146
+ info,
147
+ File.join(site.config['layouts_dir'], layout.name)
148
+ )
149
+
150
+ # Add layout to dependency tree
151
+ site.regenerator.add_dependency(
152
+ site.in_source_dir(document.path),
153
+ site.in_source_dir(layout.path)
154
+ ) if document.write?
155
+
156
+ if layout = site.layouts[layout.data["layout"]]
157
+ if used.include?(layout)
158
+ layout = nil # avoid recursive chain
159
+ else
160
+ used << layout
161
+ end
162
+ end
163
+ end
164
+
165
+ output
166
+ end
167
+
168
+ private
169
+
170
+ def permalink_ext
171
+ if document.permalink && !document.permalink.end_with?("/")
172
+ permalink_ext = File.extname(document.permalink)
173
+ permalink_ext unless permalink_ext.empty?
174
+ end
175
+ end
176
+
177
+ def converter_output_ext
178
+ if output_exts.size == 1
179
+ output_exts.last
180
+ else
181
+ output_exts[-2]
182
+ end
183
+ end
184
+
185
+ def output_exts
186
+ @output_exts ||= converters.map do |c|
187
+ c.output_ext(document.extname)
188
+ end.compact
189
+ end
190
+ end
191
+ end
data/lib/bunto/site.rb ADDED
@@ -0,0 +1,391 @@
1
+ # encoding: UTF-8
2
+ require 'csv'
3
+
4
+ module Bunto
5
+ class Site
6
+ attr_reader :source, :dest, :config
7
+ attr_accessor :layouts, :pages, :static_files, :drafts,
8
+ :exclude, :include, :lsi, :highlighter, :permalink_style,
9
+ :time, :future, :unpublished, :safe, :plugins, :limit_posts,
10
+ :show_drafts, :keep_files, :baseurl, :data, :file_read_opts,
11
+ :gems, :plugin_manager
12
+
13
+ attr_accessor :converters, :generators, :reader
14
+ attr_reader :regenerator, :liquid_renderer
15
+
16
+ # Public: Initialize a new Site.
17
+ #
18
+ # config - A Hash containing site configuration details.
19
+ def initialize(config)
20
+ @config = config.clone
21
+
22
+ %w(safe lsi highlighter baseurl exclude include future unpublished
23
+ show_drafts limit_posts keep_files gems).each do |opt|
24
+ self.send("#{opt}=", config[opt])
25
+ end
26
+
27
+ # Source and destination may not be changed after the site has been created.
28
+ @source = File.expand_path(config['source']).freeze
29
+ @dest = File.expand_path(config['destination']).freeze
30
+
31
+ @reader = Bunto::Reader.new(self)
32
+
33
+ # Initialize incremental regenerator
34
+ @regenerator = Regenerator.new(self)
35
+
36
+ @liquid_renderer = LiquidRenderer.new(self)
37
+
38
+ self.plugin_manager = Bunto::PluginManager.new(self)
39
+ self.plugins = plugin_manager.plugins_path
40
+
41
+ self.file_read_opts = {}
42
+ self.file_read_opts[:encoding] = config['encoding'] if config['encoding']
43
+
44
+ self.permalink_style = config['permalink'].to_sym
45
+
46
+ Bunto.sites << self
47
+
48
+ reset
49
+ setup
50
+ end
51
+
52
+ # Public: Read, process, and write this Site to output.
53
+ #
54
+ # Returns nothing.
55
+ def process
56
+ reset
57
+ read
58
+ generate
59
+ render
60
+ cleanup
61
+ write
62
+ print_stats
63
+ end
64
+
65
+ def print_stats
66
+ if @config['profile']
67
+ puts @liquid_renderer.stats_table
68
+ end
69
+ end
70
+
71
+ # Reset Site details.
72
+ #
73
+ # Returns nothing
74
+ def reset
75
+ self.time = (config['time'] ? Utils.parse_date(config['time'].to_s, "Invalid time in _config.yml.") : Time.now)
76
+ self.layouts = {}
77
+ self.pages = []
78
+ self.static_files = []
79
+ self.data = {}
80
+ @collections = nil
81
+ @regenerator.clear_cache
82
+ @liquid_renderer.reset
83
+
84
+ if limit_posts < 0
85
+ raise ArgumentError, "limit_posts must be a non-negative number"
86
+ end
87
+
88
+ Bunto::Hooks.trigger :site, :after_reset, self
89
+ end
90
+
91
+ # Load necessary libraries, plugins, converters, and generators.
92
+ #
93
+ # Returns nothing.
94
+ def setup
95
+ ensure_not_in_dest
96
+
97
+ plugin_manager.conscientious_require
98
+
99
+ self.converters = instantiate_subclasses(Bunto::Converter)
100
+ self.generators = instantiate_subclasses(Bunto::Generator)
101
+ end
102
+
103
+ # Check that the destination dir isn't the source dir or a directory
104
+ # parent to the source dir.
105
+ def ensure_not_in_dest
106
+ dest_pathname = Pathname.new(dest)
107
+ Pathname.new(source).ascend do |path|
108
+ if path == dest_pathname
109
+ raise Errors::FatalException.new "Destination directory cannot be or contain the Source directory."
110
+ end
111
+ end
112
+ end
113
+
114
+ # The list of collections and their corresponding Bunto::Collection instances.
115
+ # If config['collections'] is set, a new instance is created for each item in the collection.
116
+ # If config['collections'] is not set, a new hash is returned.
117
+ #
118
+ # Returns a Hash containing collection name-to-instance pairs.
119
+ def collections
120
+ @collections ||= Hash[collection_names.map { |coll| [coll, Bunto::Collection.new(self, coll)] } ]
121
+ end
122
+
123
+ # The list of collection names.
124
+ #
125
+ # Returns an array of collection names from the configuration,
126
+ # or an empty array if the `collections` key is not set.
127
+ def collection_names
128
+ case config['collections']
129
+ when Hash
130
+ config['collections'].keys
131
+ when Array
132
+ config['collections']
133
+ when nil
134
+ []
135
+ else
136
+ raise ArgumentError, "Your `collections` key must be a hash or an array."
137
+ end
138
+ end
139
+
140
+ # Read Site data from disk and load it into internal data structures.
141
+ #
142
+ # Returns nothing.
143
+ def read
144
+ reader.read
145
+ limit_posts!
146
+ Bunto::Hooks.trigger :site, :post_read, self
147
+ end
148
+
149
+ # Run each of the Generators.
150
+ #
151
+ # Returns nothing.
152
+ def generate
153
+ generators.each do |generator|
154
+ generator.generate(self)
155
+ end
156
+ end
157
+
158
+ # Render the site to the destination.
159
+ #
160
+ # Returns nothing.
161
+ def render
162
+ relative_permalinks_are_deprecated
163
+
164
+ payload = site_payload
165
+
166
+ Bunto::Hooks.trigger :site, :pre_render, self, payload
167
+
168
+ collections.each do |_, collection|
169
+ collection.docs.each do |document|
170
+ if regenerator.regenerate?(document)
171
+ document.output = Bunto::Renderer.new(self, document, payload).run
172
+ document.trigger_hooks(:post_render)
173
+ end
174
+ end
175
+ end
176
+
177
+ pages.flatten.each do |page|
178
+ if regenerator.regenerate?(page)
179
+ page.output = Bunto::Renderer.new(self, page, payload).run
180
+ page.trigger_hooks(:post_render)
181
+ end
182
+ end
183
+
184
+ Bunto::Hooks.trigger :site, :post_render, self, payload
185
+ rescue Errno::ENOENT
186
+ # ignore missing layout dir
187
+ end
188
+
189
+ # Remove orphaned files and empty directories in destination.
190
+ #
191
+ # Returns nothing.
192
+ def cleanup
193
+ site_cleaner.cleanup!
194
+ end
195
+
196
+ # Write static files, pages, and posts.
197
+ #
198
+ # Returns nothing.
199
+ def write
200
+ each_site_file do |item|
201
+ item.write(dest) if regenerator.regenerate?(item)
202
+ end
203
+ regenerator.write_metadata
204
+ Bunto::Hooks.trigger :site, :post_write, self
205
+ end
206
+
207
+ def posts
208
+ collections['posts'] ||= Collection.new(self, 'posts')
209
+ end
210
+
211
+ # Construct a Hash of Posts indexed by the specified Post attribute.
212
+ #
213
+ # post_attr - The String name of the Post attribute.
214
+ #
215
+ # Examples
216
+ #
217
+ # post_attr_hash('categories')
218
+ # # => { 'tech' => [<Post A>, <Post B>],
219
+ # # 'ruby' => [<Post B>] }
220
+ #
221
+ # Returns the Hash: { attr => posts } where
222
+ # attr - One of the values for the requested attribute.
223
+ # posts - The Array of Posts with the given attr value.
224
+ def post_attr_hash(post_attr)
225
+ # Build a hash map based on the specified post attribute ( post attr =>
226
+ # array of posts ) then sort each array in reverse order.
227
+ hash = Hash.new { |h, key| h[key] = [] }
228
+ posts.docs.each { |p| p.data[post_attr].each { |t| hash[t] << p } if p.data[post_attr] }
229
+ hash.values.each { |posts| posts.sort!.reverse! }
230
+ hash
231
+ end
232
+
233
+ def tags
234
+ post_attr_hash('tags')
235
+ end
236
+
237
+ def categories
238
+ post_attr_hash('categories')
239
+ end
240
+
241
+ # Prepare site data for site payload. The method maintains backward compatibility
242
+ # if the key 'data' is already used in _config.yml.
243
+ #
244
+ # Returns the Hash to be hooked to site.data.
245
+ def site_data
246
+ config['data'] || data
247
+ end
248
+
249
+ # The Hash payload containing site-wide data.
250
+ #
251
+ # Returns the Hash: { "site" => data } where data is a Hash with keys:
252
+ # "time" - The Time as specified in the configuration or the
253
+ # current time if none was specified.
254
+ # "posts" - The Array of Posts, sorted chronologically by post date
255
+ # and then title.
256
+ # "pages" - The Array of all Pages.
257
+ # "html_pages" - The Array of HTML Pages.
258
+ # "categories" - The Hash of category values and Posts.
259
+ # See Site#post_attr_hash for type info.
260
+ # "tags" - The Hash of tag values and Posts.
261
+ # See Site#post_attr_hash for type info.
262
+ def site_payload
263
+ Drops::UnifiedPayloadDrop.new self
264
+ end
265
+
266
+ # Get the implementation class for the given Converter.
267
+ # Returns the Converter instance implementing the given Converter.
268
+ # klass - The Class of the Converter to fetch.
269
+
270
+ def find_converter_instance(klass)
271
+ converters.find { |klass_| klass_.instance_of?(klass) } || \
272
+ raise("No Converters found for #{klass}")
273
+ end
274
+
275
+ # klass - class or module containing the subclasses.
276
+ # Returns array of instances of subclasses of parameter.
277
+ # Create array of instances of the subclasses of the class or module
278
+ # passed in as argument.
279
+
280
+ def instantiate_subclasses(klass)
281
+ klass.descendants.select { |c| !safe || c.safe }.sort.map do |c|
282
+ c.new(config)
283
+ end
284
+ end
285
+
286
+ # Warns the user if permanent links are relative to the parent
287
+ # directory. As this is a deprecated function of Bunto.
288
+ #
289
+ # Returns
290
+ def relative_permalinks_are_deprecated
291
+ if config['relative_permalinks']
292
+ Bunto.logger.abort_with "Since v3.0, permalinks for pages" \
293
+ " in subfolders must be relative to the" \
294
+ " site source directory, not the parent" \
295
+ " directory. Check http://bunto.github.io/docs/upgrading/"\
296
+ " for more info."
297
+ end
298
+ end
299
+
300
+ # Get the to be written documents
301
+ #
302
+ # Returns an Array of Documents which should be written
303
+ def docs_to_write
304
+ documents.select(&:write?)
305
+ end
306
+
307
+ # Get all the documents
308
+ #
309
+ # Returns an Array of all Documents
310
+ def documents
311
+ collections.reduce(Set.new) do |docs, (_, collection)|
312
+ docs + collection.docs + collection.files
313
+ end.to_a
314
+ end
315
+
316
+ def each_site_file
317
+ %w(pages static_files docs_to_write).each do |type|
318
+ send(type).each do |item|
319
+ yield item
320
+ end
321
+ end
322
+ end
323
+
324
+ # Returns the FrontmatterDefaults or creates a new FrontmatterDefaults
325
+ # if it doesn't already exist.
326
+ #
327
+ # Returns The FrontmatterDefaults
328
+ def frontmatter_defaults
329
+ @frontmatter_defaults ||= FrontmatterDefaults.new(self)
330
+ end
331
+
332
+ # Whether to perform a full rebuild without incremental regeneration
333
+ #
334
+ # Returns a Boolean: true for a full rebuild, false for normal build
335
+ def incremental?(override = {})
336
+ override['incremental'] || config['incremental']
337
+ end
338
+
339
+ # Returns the publisher or creates a new publisher if it doesn't
340
+ # already exist.
341
+ #
342
+ # Returns The Publisher
343
+ def publisher
344
+ @publisher ||= Publisher.new(self)
345
+ end
346
+
347
+ # Public: Prefix a given path with the source directory.
348
+ #
349
+ # paths - (optional) path elements to a file or directory within the
350
+ # source directory
351
+ #
352
+ # Returns a path which is prefixed with the source directory.
353
+ def in_source_dir(*paths)
354
+ paths.reduce(source) do |base, path|
355
+ Bunto.sanitized_path(base, path)
356
+ end
357
+ end
358
+
359
+ # Public: Prefix a given path with the destination directory.
360
+ #
361
+ # paths - (optional) path elements to a file or directory within the
362
+ # destination directory
363
+ #
364
+ # Returns a path which is prefixed with the destination directory.
365
+ def in_dest_dir(*paths)
366
+ paths.reduce(dest) do |base, path|
367
+ Bunto.sanitized_path(base, path)
368
+ end
369
+ end
370
+
371
+ private
372
+
373
+ # Limits the current posts; removes the posts which exceed the limit_posts
374
+ #
375
+ # Returns nothing
376
+ def limit_posts!
377
+ if limit_posts > 0
378
+ limit = posts.docs.length < limit_posts ? posts.docs.length : limit_posts
379
+ self.posts.docs = posts.docs[-limit, limit]
380
+ end
381
+ end
382
+
383
+ # Returns the Cleaner or creates a new Cleaner if it doesn't
384
+ # already exist.
385
+ #
386
+ # Returns The Cleaner
387
+ def site_cleaner
388
+ @site_cleaner ||= Cleaner.new(self)
389
+ end
390
+ end
391
+ end