bunto 2.0.0.pre → 3.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 +4 -4
- data/.rubocop.yml +80 -0
- data/README.markdown +15 -19
- data/bin/bunto +1 -1
- data/lib/bunto.rb +7 -5
- data/lib/bunto/cleaner.rb +3 -2
- data/lib/bunto/collection.rb +3 -3
- data/lib/bunto/commands/clean.rb +10 -12
- data/lib/bunto/commands/doctor.rb +1 -1
- data/lib/bunto/commands/new.rb +29 -0
- data/lib/bunto/commands/serve.rb +17 -15
- data/lib/bunto/configuration.rb +4 -3
- data/lib/bunto/converter.rb +6 -2
- data/lib/bunto/converters/markdown.rb +1 -1
- data/lib/bunto/converters/markdown/kramdown_parser.rb +1 -0
- data/lib/bunto/convertible.rb +5 -5
- data/lib/bunto/deprecator.rb +1 -1
- data/lib/bunto/document.rb +11 -4
- data/lib/bunto/drops/document_drop.rb +7 -0
- data/lib/bunto/entry_filter.rb +6 -2
- data/lib/bunto/errors.rb +4 -0
- data/lib/bunto/external.rb +1 -1
- data/lib/bunto/filters.rb +49 -8
- data/lib/bunto/frontmatter_defaults.rb +2 -2
- data/lib/bunto/hooks.rb +1 -0
- data/lib/bunto/layout.rb +16 -1
- data/lib/bunto/mime.types +1 -1
- data/lib/bunto/page.rb +1 -0
- data/lib/bunto/plugin.rb +1 -1
- data/lib/bunto/plugin_manager.rb +4 -4
- data/lib/bunto/publisher.rb +4 -4
- data/lib/bunto/readers/data_reader.rb +3 -2
- data/lib/bunto/readers/layout_reader.rb +19 -3
- data/lib/bunto/readers/post_reader.rb +5 -1
- data/lib/bunto/regenerator.rb +5 -3
- data/lib/bunto/renderer.rb +3 -2
- data/lib/bunto/site.rb +47 -17
- data/lib/bunto/static_file.rb +5 -1
- data/lib/bunto/tags/include.rb +33 -31
- data/lib/bunto/tags/link.rb +26 -0
- data/lib/bunto/tags/post_url.rb +18 -8
- data/lib/bunto/theme.rb +56 -0
- data/lib/bunto/utils.rb +3 -2
- data/lib/bunto/version.rb +1 -1
- data/lib/site_template/_config.yml +8 -2
- data/lib/site_template/_includes/footer.html +3 -3
- data/lib/site_template/_includes/head.html +2 -2
- data/lib/site_template/_includes/header.html +3 -3
- data/lib/site_template/_layouts/default.html +2 -2
- data/lib/site_template/_layouts/page.html +1 -1
- data/lib/site_template/_layouts/post.html +1 -1
- data/lib/site_template/_posts/0000-00-00-welcome-to-bunto.markdown.erb +1 -1
- data/lib/site_template/_sass/_base.scss +11 -17
- data/lib/site_template/about.md +5 -1
- data/lib/site_template/index.html +1 -1
- metadata +32 -29
data/lib/bunto/converter.rb
CHANGED
@@ -8,7 +8,9 @@ module Bunto
|
|
8
8
|
#
|
9
9
|
# Returns the String prefix.
|
10
10
|
def self.highlighter_prefix(highlighter_prefix = nil)
|
11
|
-
@highlighter_prefix
|
11
|
+
if !defined?(@highlighter_prefix) || !highlighter_prefix.nil?
|
12
|
+
@highlighter_prefix = highlighter_prefix
|
13
|
+
end
|
12
14
|
@highlighter_prefix
|
13
15
|
end
|
14
16
|
|
@@ -20,7 +22,9 @@ module Bunto
|
|
20
22
|
#
|
21
23
|
# Returns the String suffix.
|
22
24
|
def self.highlighter_suffix(highlighter_suffix = nil)
|
23
|
-
@highlighter_suffix
|
25
|
+
if !defined?(@highlighter_suffix) || !highlighter_suffix.nil?
|
26
|
+
@highlighter_suffix = highlighter_suffix
|
27
|
+
end
|
24
28
|
@highlighter_suffix
|
25
29
|
end
|
26
30
|
|
@@ -6,7 +6,7 @@ module Bunto
|
|
6
6
|
safe true
|
7
7
|
|
8
8
|
def setup
|
9
|
-
return if @setup
|
9
|
+
return if @setup ||= false
|
10
10
|
unless (@parser = get_processor)
|
11
11
|
Bunto.logger.error "Invalid Markdown processor given:", @config["markdown"]
|
12
12
|
Bunto.logger.info "", "Custom processors are not loaded in safe mode" if @config["safe"]
|
data/lib/bunto/convertible.rb
CHANGED
@@ -39,9 +39,9 @@ module Bunto
|
|
39
39
|
filename = File.join(base, name)
|
40
40
|
|
41
41
|
begin
|
42
|
-
self.content = File.read(site.in_source_dir(base, name),
|
42
|
+
self.content = File.read(@path || site.in_source_dir(base, name),
|
43
43
|
Utils.merged_file_read_opts(site, opts))
|
44
|
-
if content =~
|
44
|
+
if content =~ Document::YAML_FRONT_MATTER_REGEXP
|
45
45
|
self.content = $POSTMATCH
|
46
46
|
self.data = SafeYAML.load(Regexp.last_match(1))
|
47
47
|
end
|
@@ -215,9 +215,9 @@ module Bunto
|
|
215
215
|
payload["layout"] = Utils.deep_merge_hashes(payload["layout"] || {}, layout.data)
|
216
216
|
|
217
217
|
self.output = render_liquid(layout.content,
|
218
|
-
|
219
|
-
|
220
|
-
|
218
|
+
payload,
|
219
|
+
info,
|
220
|
+
layout.relative_path)
|
221
221
|
|
222
222
|
# Add layout to dependency tree
|
223
223
|
site.regenerator.add_dependency(
|
data/lib/bunto/deprecator.rb
CHANGED
@@ -22,7 +22,7 @@ module Bunto
|
|
22
22
|
|
23
23
|
def no_subcommand(args)
|
24
24
|
if args.size > 0 && args.first =~ /^--/ && !%w(--help --version).include?(args.first)
|
25
|
-
deprecation_message "Bunto now uses subcommands instead of just switches. Run `bunto
|
25
|
+
deprecation_message "Bunto now uses subcommands instead of just switches. Run `bunto help` to find out more."
|
26
26
|
abort
|
27
27
|
end
|
28
28
|
end
|
data/lib/bunto/document.rb
CHANGED
@@ -68,7 +68,11 @@ module Bunto
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def date
|
71
|
-
data['date'] ||= site.time
|
71
|
+
data['date'] ||= (draft? ? source_file_mtime : site.time)
|
72
|
+
end
|
73
|
+
|
74
|
+
def source_file_mtime
|
75
|
+
@source_file_mtime ||= File.mtime(path)
|
72
76
|
end
|
73
77
|
|
74
78
|
# Returns whether the document is a draft. This is only the case if
|
@@ -217,8 +221,11 @@ module Bunto
|
|
217
221
|
def destination(base_directory)
|
218
222
|
dest = site.in_dest_dir(base_directory)
|
219
223
|
path = site.in_dest_dir(dest, URL.unescape_path(url))
|
220
|
-
|
221
|
-
|
224
|
+
if url.end_with? "/"
|
225
|
+
path = File.join(path, "index.html")
|
226
|
+
else
|
227
|
+
path << output_ext unless path.end_with? output_ext
|
228
|
+
end
|
222
229
|
path
|
223
230
|
end
|
224
231
|
|
@@ -256,7 +263,7 @@ module Bunto
|
|
256
263
|
@data = SafeYAML.load_file(path)
|
257
264
|
else
|
258
265
|
begin
|
259
|
-
defaults = @site.frontmatter_defaults.all(
|
266
|
+
defaults = @site.frontmatter_defaults.all(relative_path, collection.label.to_sym)
|
260
267
|
merge_data!(defaults, source: "front matter defaults") unless defaults.empty?
|
261
268
|
|
262
269
|
self.content = File.read(path, Utils.merged_file_read_opts(site, opts))
|
@@ -20,6 +20,13 @@ module Bunto
|
|
20
20
|
fallback_data['excerpt'].to_s
|
21
21
|
end
|
22
22
|
|
23
|
+
def <=>(other)
|
24
|
+
return nil unless other.is_a? DocumentDrop
|
25
|
+
cmp = self['date'] <=> other['date']
|
26
|
+
cmp = self['path'] <=> other['path'] if cmp.nil? || cmp == 0
|
27
|
+
cmp
|
28
|
+
end
|
29
|
+
|
23
30
|
private
|
24
31
|
def_delegator :@obj, :data, :fallback_data
|
25
32
|
end
|
data/lib/bunto/entry_filter.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Bunto
|
2
2
|
class EntryFilter
|
3
|
-
SPECIAL_LEADING_CHARACTERS = ['.', '_', '#'].freeze
|
3
|
+
SPECIAL_LEADING_CHARACTERS = ['.', '_', '#', '~'].freeze
|
4
4
|
|
5
5
|
attr_reader :site
|
6
6
|
|
@@ -52,7 +52,11 @@ module Bunto
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def symlink?(entry)
|
55
|
-
File.symlink?(entry) &&
|
55
|
+
site.safe && File.symlink?(entry) && symlink_outside_site_source?(entry)
|
56
|
+
end
|
57
|
+
|
58
|
+
def symlink_outside_site_source?(entry)
|
59
|
+
! File.realpath(entry).start_with?(File.realpath(@site.source))
|
56
60
|
end
|
57
61
|
|
58
62
|
def ensure_leading_slash(path)
|
data/lib/bunto/errors.rb
CHANGED
@@ -6,5 +6,9 @@ module Bunto
|
|
6
6
|
InvalidPermalinkError = Class.new(FatalException)
|
7
7
|
InvalidYAMLFrontMatterError = Class.new(FatalException)
|
8
8
|
MissingDependencyException = Class.new(FatalException)
|
9
|
+
|
10
|
+
InvalidDateError = Class.new(FatalException)
|
11
|
+
InvalidPostNameError = Class.new(FatalException)
|
12
|
+
PostURLError = Class.new(FatalException)
|
9
13
|
end
|
10
14
|
end
|
data/lib/bunto/external.rb
CHANGED
@@ -48,7 +48,7 @@ In order to use Bunto as currently configured, you'll need to install this gem.
|
|
48
48
|
|
49
49
|
The full error message from Ruby is: '#{e.message}'
|
50
50
|
|
51
|
-
If you run into trouble, you can find helpful resources at
|
51
|
+
If you run into trouble, you can find helpful resources at http://bunto.github.io/help/!
|
52
52
|
MSG
|
53
53
|
raise Bunto::Errors::MissingDependencyException.new(name)
|
54
54
|
end
|
data/lib/bunto/filters.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'json'
|
3
3
|
require 'date'
|
4
|
+
require 'liquid'
|
4
5
|
|
5
6
|
module Bunto
|
6
7
|
module Filters
|
@@ -15,11 +16,11 @@ module Bunto
|
|
15
16
|
converter.convert(input)
|
16
17
|
end
|
17
18
|
|
18
|
-
# Convert
|
19
|
+
# Convert quotes into smart quotes.
|
19
20
|
#
|
20
|
-
# input - The
|
21
|
+
# input - The String to convert.
|
21
22
|
#
|
22
|
-
# Returns the
|
23
|
+
# Returns the smart-quotified String.
|
23
24
|
def smartify(input)
|
24
25
|
site = @context.registers[:site]
|
25
26
|
converter = site.find_converter_instance(Bunto::Converters::SmartyPants)
|
@@ -117,7 +118,7 @@ module Bunto
|
|
117
118
|
#
|
118
119
|
# Returns the escaped String.
|
119
120
|
def xml_escape(input)
|
120
|
-
|
121
|
+
input.to_s.encode(:xml => :attr).gsub(/\A"|"\Z/, "")
|
121
122
|
end
|
122
123
|
|
123
124
|
# CGI escape a string for use in a URL. Replaces any special characters
|
@@ -205,7 +206,7 @@ module Bunto
|
|
205
206
|
input.group_by do |item|
|
206
207
|
item_property(item, property).to_s
|
207
208
|
end.inject([]) do |memo, i|
|
208
|
-
memo << { "name" => i.first, "items" => i.last }
|
209
|
+
memo << { "name" => i.first, "items" => i.last, "size" => i.last.size }
|
209
210
|
end
|
210
211
|
else
|
211
212
|
input
|
@@ -222,7 +223,27 @@ module Bunto
|
|
222
223
|
def where(input, property, value)
|
223
224
|
return input unless input.is_a?(Enumerable)
|
224
225
|
input = input.values if input.is_a?(Hash)
|
225
|
-
input.select { |object| item_property(object, property).to_s
|
226
|
+
input.select { |object| Array(item_property(object, property)).map(&:to_s).include?(value.to_s) }
|
227
|
+
end
|
228
|
+
|
229
|
+
# Filters an array of objects against an expression
|
230
|
+
#
|
231
|
+
# input - the object array
|
232
|
+
# variable - the variable to assign each item to in the expression
|
233
|
+
# expression - a Liquid comparison expression passed in as a string
|
234
|
+
#
|
235
|
+
# Returns the filtered array of objects
|
236
|
+
def where_exp(input, variable, expression)
|
237
|
+
return input unless input.is_a?(Enumerable)
|
238
|
+
input = input.values if input.is_a?(Hash) # FIXME
|
239
|
+
|
240
|
+
condition = parse_condition(expression)
|
241
|
+
@context.stack do
|
242
|
+
input.select do |object|
|
243
|
+
@context[variable] = object
|
244
|
+
condition.evaluate(@context)
|
245
|
+
end
|
246
|
+
end
|
226
247
|
end
|
227
248
|
|
228
249
|
# Sort an array of objects
|
@@ -308,14 +329,14 @@ module Bunto
|
|
308
329
|
#
|
309
330
|
# Returns a String representation of the object.
|
310
331
|
def inspect(input)
|
311
|
-
|
332
|
+
xml_escape(input.inspect)
|
312
333
|
end
|
313
334
|
|
314
335
|
private
|
315
336
|
def time(input)
|
316
337
|
case input
|
317
338
|
when Time
|
318
|
-
input
|
339
|
+
input.clone
|
319
340
|
when Date
|
320
341
|
input.to_time
|
321
342
|
when String
|
@@ -363,5 +384,25 @@ module Bunto
|
|
363
384
|
end
|
364
385
|
end
|
365
386
|
end
|
387
|
+
|
388
|
+
# Parse a string to a Liquid Condition
|
389
|
+
def parse_condition(exp)
|
390
|
+
parser = Liquid::Parser.new(exp)
|
391
|
+
left_expr = parser.expression
|
392
|
+
operator = parser.consume?(:comparison)
|
393
|
+
condition =
|
394
|
+
if operator
|
395
|
+
Liquid::Condition.new(left_expr, operator, parser.expression)
|
396
|
+
else
|
397
|
+
Liquid::Condition.new(left_expr)
|
398
|
+
end
|
399
|
+
parser.consume(:end_of_string)
|
400
|
+
|
401
|
+
condition
|
402
|
+
end
|
366
403
|
end
|
367
404
|
end
|
405
|
+
|
406
|
+
Liquid::Template.register_filter(
|
407
|
+
Bunto::Filters
|
408
|
+
)
|
@@ -94,8 +94,8 @@ module Bunto
|
|
94
94
|
return true if !scope.key?('path') || scope['path'].empty?
|
95
95
|
|
96
96
|
scope_path = Pathname.new(scope['path'])
|
97
|
-
Pathname.new(sanitize_path(path)).ascend do |
|
98
|
-
if
|
97
|
+
Pathname.new(sanitize_path(path)).ascend do |ascended_path|
|
98
|
+
if ascended_path.to_s == scope_path.to_s
|
99
99
|
return true
|
100
100
|
end
|
101
101
|
end
|
data/lib/bunto/hooks.rb
CHANGED
data/lib/bunto/layout.rb
CHANGED
@@ -29,7 +29,14 @@ module Bunto
|
|
29
29
|
@site = site
|
30
30
|
@base = base
|
31
31
|
@name = name
|
32
|
-
|
32
|
+
|
33
|
+
if site.theme && site.theme.layouts_path.eql?(base)
|
34
|
+
@base_dir = site.theme.root
|
35
|
+
@path = site.in_theme_dir(base, name)
|
36
|
+
else
|
37
|
+
@base_dir = site.source
|
38
|
+
@path = site.in_source_dir(base, name)
|
39
|
+
end
|
33
40
|
|
34
41
|
self.data = {}
|
35
42
|
|
@@ -45,5 +52,13 @@ module Bunto
|
|
45
52
|
def process(name)
|
46
53
|
self.ext = File.extname(name)
|
47
54
|
end
|
55
|
+
|
56
|
+
# The path to the layout, relative to the site source.
|
57
|
+
#
|
58
|
+
# Returns a String path which represents the relative path
|
59
|
+
# from the site source to this layout
|
60
|
+
def relative_path
|
61
|
+
@relative_path ||= Pathname.new(path).relative_path_from(Pathname.new(@base_dir)).to_s
|
62
|
+
end
|
48
63
|
end
|
49
64
|
end
|
data/lib/bunto/mime.types
CHANGED
data/lib/bunto/page.rb
CHANGED
data/lib/bunto/plugin.rb
CHANGED
data/lib/bunto/plugin_manager.rb
CHANGED
@@ -30,16 +30,16 @@ module Bunto
|
|
30
30
|
def self.require_from_bundler
|
31
31
|
if !ENV["BUNTO_NO_BUNDLER_REQUIRE"] && File.file?("Gemfile")
|
32
32
|
require "bundler"
|
33
|
-
|
34
|
-
|
33
|
+
|
34
|
+
Bundler.setup
|
35
|
+
required_gems = Bundler.require(:bunto_plugins)
|
35
36
|
Bunto.logger.debug("PluginManager:", "Required #{required_gems.map(&:name).join(', ')}")
|
36
37
|
ENV["BUNTO_NO_BUNDLER_REQUIRE"] = "true"
|
38
|
+
|
37
39
|
true
|
38
40
|
else
|
39
41
|
false
|
40
42
|
end
|
41
|
-
rescue LoadError, Bundler::GemfileNotFound
|
42
|
-
false
|
43
43
|
end
|
44
44
|
|
45
45
|
# Check whether a gem plugin is allowed to be used during this build.
|
data/lib/bunto/publisher.rb
CHANGED
@@ -8,14 +8,14 @@ module Bunto
|
|
8
8
|
can_be_published?(thing) && !hidden_in_the_future?(thing)
|
9
9
|
end
|
10
10
|
|
11
|
+
def hidden_in_the_future?(thing)
|
12
|
+
thing.respond_to?(:date) && !@site.future && thing.date.to_i > @site.time.to_i
|
13
|
+
end
|
14
|
+
|
11
15
|
private
|
12
16
|
|
13
17
|
def can_be_published?(thing)
|
14
18
|
thing.data.fetch('published', true) || @site.unpublished
|
15
19
|
end
|
16
|
-
|
17
|
-
def hidden_in_the_future?(thing)
|
18
|
-
thing.respond_to?(:date) && !@site.future && thing.date.to_i > @site.time.to_i
|
19
|
-
end
|
20
20
|
end
|
21
21
|
end
|
@@ -4,6 +4,7 @@ module Bunto
|
|
4
4
|
def initialize(site)
|
5
5
|
@site = site
|
6
6
|
@content = {}
|
7
|
+
@entry_filter = EntryFilter.new(site)
|
7
8
|
end
|
8
9
|
|
9
10
|
# Read all the files in <source>/<dir>/_drafts and create a new Draft
|
@@ -26,7 +27,7 @@ module Bunto
|
|
26
27
|
#
|
27
28
|
# Returns nothing
|
28
29
|
def read_data_to(dir, data)
|
29
|
-
return unless File.directory?(dir) &&
|
30
|
+
return unless File.directory?(dir) && !@entry_filter.symlink?(dir)
|
30
31
|
|
31
32
|
entries = Dir.chdir(dir) do
|
32
33
|
Dir['*.{yaml,yml,json,csv}'] + Dir['*'].select { |fn| File.directory?(fn) }
|
@@ -34,7 +35,7 @@ module Bunto
|
|
34
35
|
|
35
36
|
entries.each do |entry|
|
36
37
|
path = @site.in_source_dir(dir, entry)
|
37
|
-
next if
|
38
|
+
next if @entry_filter.symlink?(path)
|
38
39
|
|
39
40
|
key = sanitize_filename(File.basename(entry, '.*'))
|
40
41
|
if File.directory?(path)
|
@@ -7,8 +7,12 @@ module Bunto
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def read
|
10
|
-
layout_entries.each do |
|
11
|
-
@layouts[layout_name(
|
10
|
+
layout_entries.each do |layout_file|
|
11
|
+
@layouts[layout_name(layout_file)] = Layout.new(site, layout_directory, layout_file)
|
12
|
+
end
|
13
|
+
|
14
|
+
theme_layout_entries.each do |layout_file|
|
15
|
+
@layouts[layout_name(layout_file)] ||= Layout.new(site, theme_layout_directory, layout_file)
|
12
16
|
end
|
13
17
|
|
14
18
|
@layouts
|
@@ -18,11 +22,23 @@ module Bunto
|
|
18
22
|
@layout_directory ||= (layout_directory_in_cwd || layout_directory_inside_source)
|
19
23
|
end
|
20
24
|
|
25
|
+
def theme_layout_directory
|
26
|
+
@theme_layout_directory ||= site.theme.layouts_path if site.theme
|
27
|
+
end
|
28
|
+
|
21
29
|
private
|
22
30
|
|
23
31
|
def layout_entries
|
32
|
+
entries_in layout_directory
|
33
|
+
end
|
34
|
+
|
35
|
+
def theme_layout_entries
|
36
|
+
theme_layout_directory ? entries_in(theme_layout_directory) : []
|
37
|
+
end
|
38
|
+
|
39
|
+
def entries_in(dir)
|
24
40
|
entries = []
|
25
|
-
within(
|
41
|
+
within(dir) do
|
26
42
|
entries = EntryFilter.new(site).filter(Dir['**/*.*'])
|
27
43
|
end
|
28
44
|
entries
|