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
@@ -35,7 +35,11 @@ module Bunto
|
|
35
35
|
read_content(dir, magic_dir, matcher).tap do |docs|
|
36
36
|
docs.each(&:read)
|
37
37
|
end.select do |doc|
|
38
|
-
site.publisher.publish?(doc)
|
38
|
+
site.publisher.publish?(doc).tap do |will_publish|
|
39
|
+
if !will_publish && site.publisher.hidden_in_the_future?(doc)
|
40
|
+
Bunto.logger.debug "Skipping:", "#{doc.relative_path} has a future date"
|
41
|
+
end
|
42
|
+
end
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
data/lib/bunto/regenerator.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Bunto
|
2
2
|
class Regenerator
|
3
3
|
attr_reader :site, :metadata, :cache
|
4
|
+
attr_accessor :disabled
|
5
|
+
private :disabled, :disabled=
|
4
6
|
|
5
7
|
def initialize(site)
|
6
8
|
@site = site
|
@@ -115,7 +117,7 @@ module Bunto
|
|
115
117
|
#
|
116
118
|
# Returns nothing.
|
117
119
|
def add_dependency(path, dependency)
|
118
|
-
return if metadata[path].nil? ||
|
120
|
+
return if metadata[path].nil? || disabled
|
119
121
|
|
120
122
|
unless metadata[path]["deps"].include? dependency
|
121
123
|
metadata[path]["deps"] << dependency
|
@@ -144,8 +146,8 @@ module Bunto
|
|
144
146
|
#
|
145
147
|
# Returns a Boolean (true for disabled, false for enabled).
|
146
148
|
def disabled?
|
147
|
-
|
148
|
-
|
149
|
+
self.disabled = !site.incremental? if disabled.nil?
|
150
|
+
disabled
|
149
151
|
end
|
150
152
|
|
151
153
|
private
|
data/lib/bunto/renderer.rb
CHANGED
@@ -40,6 +40,8 @@ module Bunto
|
|
40
40
|
|
41
41
|
if document.is_a?(Document) && document.collection.label == 'posts'
|
42
42
|
payload['site']['related_posts'] = document.related_posts
|
43
|
+
else
|
44
|
+
payload['site']['related_posts'] = nil
|
43
45
|
end
|
44
46
|
|
45
47
|
# render and transform content (this becomes the final content of the object)
|
@@ -50,7 +52,6 @@ module Bunto
|
|
50
52
|
document.trigger_hooks(:pre_render, payload)
|
51
53
|
|
52
54
|
info = {
|
53
|
-
:filters => [Bunto::Filters],
|
54
55
|
:registers => { :site => site, :page => payload['page'] }
|
55
56
|
}
|
56
57
|
|
@@ -144,7 +145,7 @@ module Bunto
|
|
144
145
|
layout.content,
|
145
146
|
payload,
|
146
147
|
info,
|
147
|
-
|
148
|
+
layout.relative_path
|
148
149
|
)
|
149
150
|
|
150
151
|
# Add layout to dependency tree
|
data/lib/bunto/site.rb
CHANGED
@@ -8,15 +8,40 @@ module Bunto
|
|
8
8
|
:exclude, :include, :lsi, :highlighter, :permalink_style,
|
9
9
|
:time, :future, :unpublished, :safe, :plugins, :limit_posts,
|
10
10
|
:show_drafts, :keep_files, :baseurl, :data, :file_read_opts,
|
11
|
-
:gems, :plugin_manager
|
11
|
+
:gems, :plugin_manager, :theme
|
12
12
|
|
13
13
|
attr_accessor :converters, :generators, :reader
|
14
|
-
attr_reader :regenerator, :liquid_renderer
|
14
|
+
attr_reader :regenerator, :liquid_renderer, :includes_load_paths
|
15
15
|
|
16
16
|
# Public: Initialize a new Site.
|
17
17
|
#
|
18
18
|
# config - A Hash containing site configuration details.
|
19
19
|
def initialize(config)
|
20
|
+
# Source and destination may not be changed after the site has been created.
|
21
|
+
@source = File.expand_path(config['source']).freeze
|
22
|
+
@dest = File.expand_path(config['destination']).freeze
|
23
|
+
|
24
|
+
self.config = config
|
25
|
+
|
26
|
+
@reader = Reader.new(self)
|
27
|
+
@regenerator = Regenerator.new(self)
|
28
|
+
@liquid_renderer = LiquidRenderer.new(self)
|
29
|
+
|
30
|
+
Bunto.sites << self
|
31
|
+
|
32
|
+
Bunto::Hooks.trigger :site, :after_init, self
|
33
|
+
|
34
|
+
reset
|
35
|
+
setup
|
36
|
+
end
|
37
|
+
|
38
|
+
# Public: Set the site's configuration. This handles side-effects caused by
|
39
|
+
# changing values in the configuration.
|
40
|
+
#
|
41
|
+
# config - a Bunto::Configuration, containing the new configuration.
|
42
|
+
#
|
43
|
+
# Returns the new configuration.
|
44
|
+
def config=(config)
|
20
45
|
@config = config.clone
|
21
46
|
|
22
47
|
%w(safe lsi highlighter baseurl exclude include future unpublished
|
@@ -24,29 +49,21 @@ module Bunto
|
|
24
49
|
self.send("#{opt}=", config[opt])
|
25
50
|
end
|
26
51
|
|
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
52
|
self.plugin_manager = Bunto::PluginManager.new(self)
|
39
53
|
self.plugins = plugin_manager.plugins_path
|
40
54
|
|
55
|
+
self.theme = nil
|
56
|
+
self.theme = Bunto::Theme.new(config["theme"]) if config["theme"]
|
57
|
+
|
58
|
+
@includes_load_paths = Array(in_source_dir(config["includes_dir"].to_s))
|
59
|
+
@includes_load_paths << theme.includes_path if self.theme
|
60
|
+
|
41
61
|
self.file_read_opts = {}
|
42
62
|
self.file_read_opts[:encoding] = config['encoding'] if config['encoding']
|
43
63
|
|
44
64
|
self.permalink_style = config['permalink'].to_sym
|
45
65
|
|
46
|
-
|
47
|
-
|
48
|
-
reset
|
49
|
-
setup
|
66
|
+
@config
|
50
67
|
end
|
51
68
|
|
52
69
|
# Public: Read, process, and write this Site to output.
|
@@ -356,6 +373,19 @@ module Bunto
|
|
356
373
|
end
|
357
374
|
end
|
358
375
|
|
376
|
+
# Public: Prefix a given path with the theme directory.
|
377
|
+
#
|
378
|
+
# paths - (optional) path elements to a file or directory within the
|
379
|
+
# theme directory
|
380
|
+
#
|
381
|
+
# Returns a path which is prefixed with the theme root directory.
|
382
|
+
def in_theme_dir(*paths)
|
383
|
+
return nil unless theme
|
384
|
+
paths.reduce(theme.root) do |base, path|
|
385
|
+
Bunto.sanitized_path(base, path)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
359
389
|
# Public: Prefix a given path with the destination directory.
|
360
390
|
#
|
361
391
|
# paths - (optional) path elements to a file or directory within the
|
data/lib/bunto/static_file.rb
CHANGED
@@ -80,7 +80,11 @@ module Bunto
|
|
80
80
|
|
81
81
|
FileUtils.mkdir_p(File.dirname(dest_path))
|
82
82
|
FileUtils.rm(dest_path) if File.exist?(dest_path)
|
83
|
-
|
83
|
+
if @site.safe || Bunto.env == "production"
|
84
|
+
FileUtils.cp(path, dest_path)
|
85
|
+
else
|
86
|
+
FileUtils.copy_entry(path, dest_path)
|
87
|
+
end
|
84
88
|
File.utime(@@mtimes[path], @@mtimes[path], dest_path)
|
85
89
|
|
86
90
|
true
|
data/lib/bunto/tags/include.rb
CHANGED
@@ -12,8 +12,6 @@ module Bunto
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class IncludeTag < Liquid::Tag
|
15
|
-
attr_reader :includes_dir
|
16
|
-
|
17
15
|
VALID_SYNTAX = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
|
18
16
|
VARIABLE_SYNTAX = /(?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)(?<params>.*)/
|
19
17
|
|
@@ -98,20 +96,29 @@ eos
|
|
98
96
|
end
|
99
97
|
end
|
100
98
|
|
101
|
-
def
|
102
|
-
context.registers[:site].
|
99
|
+
def tag_includes_dirs(context)
|
100
|
+
context.registers[:site].includes_load_paths.freeze
|
101
|
+
end
|
102
|
+
|
103
|
+
def locate_include_file(context, file, safe)
|
104
|
+
includes_dirs = tag_includes_dirs(context)
|
105
|
+
includes_dirs.each do |dir|
|
106
|
+
path = File.join(dir, file)
|
107
|
+
return path if valid_include_file?(path, dir, safe)
|
108
|
+
end
|
109
|
+
raise IOError, "Could not locate the included file '#{file}' in any of #{includes_dirs}." \
|
110
|
+
" Ensure it exists in one of those directories and, if it is a symlink, " \
|
111
|
+
"does not point outside your site source."
|
103
112
|
end
|
104
113
|
|
105
114
|
def render(context)
|
106
115
|
site = context.registers[:site]
|
107
|
-
@includes_dir = tag_includes_dir(context)
|
108
|
-
dir = resolved_includes_dir(context)
|
109
116
|
|
110
117
|
file = render_variable(context) || @file
|
111
118
|
validate_file_name(file)
|
112
119
|
|
113
|
-
path =
|
114
|
-
|
120
|
+
path = locate_include_file(context, file, site.safe)
|
121
|
+
return unless path
|
115
122
|
|
116
123
|
# Add include to dependency tree
|
117
124
|
if context.registers[:page] && context.registers[:page].key?("path")
|
@@ -121,16 +128,16 @@ eos
|
|
121
128
|
)
|
122
129
|
end
|
123
130
|
|
124
|
-
begin
|
131
|
+
#begin
|
125
132
|
partial = load_cached_partial(path, context)
|
126
133
|
|
127
134
|
context.stack do
|
128
135
|
context['include'] = parse_params(context) if @params
|
129
136
|
partial.render!(context)
|
130
137
|
end
|
131
|
-
|
132
|
-
raise IncludeTagError.new e.message,
|
133
|
-
|
138
|
+
#rescue => e
|
139
|
+
#raise IncludeTagError.new e.message, path
|
140
|
+
#end
|
134
141
|
end
|
135
142
|
|
136
143
|
def load_cached_partial(path, context)
|
@@ -144,24 +151,18 @@ eos
|
|
144
151
|
end
|
145
152
|
end
|
146
153
|
|
147
|
-
def
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
def validate_path(path, dir, safe)
|
152
|
-
if safe && !realpath_prefixed_with?(path, dir)
|
153
|
-
raise IOError.new "The included file '#{path}' should exist and should not be a symlink"
|
154
|
-
elsif !File.exist?(path)
|
155
|
-
raise IOError.new "Included file '#{path_relative_to_source(dir, path)}' not found"
|
156
|
-
end
|
154
|
+
def valid_include_file?(path, dir, safe)
|
155
|
+
!(outside_site_source?(path, dir, safe) || !File.exist?(path))
|
157
156
|
end
|
158
157
|
|
159
|
-
def
|
160
|
-
|
158
|
+
def outside_site_source?(path, dir, safe)
|
159
|
+
safe && !realpath_prefixed_with?(path, dir)
|
161
160
|
end
|
162
161
|
|
163
162
|
def realpath_prefixed_with?(path, dir)
|
164
163
|
File.exist?(path) && File.realpath(path).start_with?(dir)
|
164
|
+
rescue
|
165
|
+
false
|
165
166
|
end
|
166
167
|
|
167
168
|
# This method allows to modify the file content by inheriting from the class.
|
@@ -171,16 +172,17 @@ eos
|
|
171
172
|
end
|
172
173
|
|
173
174
|
class IncludeRelativeTag < IncludeTag
|
174
|
-
def
|
175
|
-
|
175
|
+
def tag_includes_dirs(context)
|
176
|
+
Array(page_path(context)).freeze
|
176
177
|
end
|
177
178
|
|
178
179
|
def page_path(context)
|
179
|
-
context.registers[:page].nil?
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
180
|
+
if context.registers[:page].nil?
|
181
|
+
context.registers[:site].source
|
182
|
+
else
|
183
|
+
current_doc_dir = File.dirname(context.registers[:page]["path"])
|
184
|
+
context.registers[:site].in_source_dir current_doc_dir
|
185
|
+
end
|
184
186
|
end
|
185
187
|
end
|
186
188
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Bunto
|
2
|
+
module Tags
|
3
|
+
class Link < Liquid::Tag
|
4
|
+
TagName = 'link'
|
5
|
+
|
6
|
+
def initialize(tag_name, relative_path, tokens)
|
7
|
+
super
|
8
|
+
|
9
|
+
@relative_path = relative_path.strip
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(context)
|
13
|
+
site = context.registers[:site]
|
14
|
+
|
15
|
+
site.docs_to_write.each do |document|
|
16
|
+
return document.url if document.relative_path == @relative_path
|
17
|
+
end
|
18
|
+
|
19
|
+
raise ArgumentError, "Could not find document '#{@relative_path}' in tag '#{TagName}'.\n\n" \
|
20
|
+
"Make sure the document exists and the path is correct."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Liquid::Template.register_tag(Bunto::Tags::Link::TagName, Bunto::Tags::Link)
|
data/lib/bunto/tags/post_url.rb
CHANGED
@@ -7,22 +7,30 @@ module Bunto
|
|
7
7
|
|
8
8
|
def initialize(name)
|
9
9
|
@name = name
|
10
|
+
|
10
11
|
all, @path, @date, @slug = *name.sub(/^\//, "").match(MATCHER)
|
11
|
-
|
12
|
+
unless all
|
13
|
+
raise Bunto::Errors::InvalidPostNameError,
|
14
|
+
"'#{name}' does not contain valid date and/or title."
|
15
|
+
end
|
12
16
|
|
13
17
|
@name_regex = /^#{path}#{date}-#{slug}\.[^.]+/
|
14
18
|
end
|
15
19
|
|
20
|
+
def post_date
|
21
|
+
@post_date ||= Utils.parse_date(date,
|
22
|
+
"\"#{date}\" does not contain valid date and/or title.")
|
23
|
+
end
|
24
|
+
|
16
25
|
def ==(other)
|
17
26
|
other.basename.match(@name_regex)
|
18
27
|
end
|
19
28
|
|
20
29
|
def deprecated_equality(other)
|
21
|
-
date = Utils.parse_date(name, "'#{name}' does not contain valid date and/or title.")
|
22
30
|
slug == post_slug(other) &&
|
23
|
-
|
24
|
-
|
25
|
-
|
31
|
+
post_date.year == other.date.year &&
|
32
|
+
post_date.month == other.date.month &&
|
33
|
+
post_date.day == other.date.day
|
26
34
|
end
|
27
35
|
|
28
36
|
private
|
@@ -47,11 +55,13 @@ module Bunto
|
|
47
55
|
@orig_post = post.strip
|
48
56
|
begin
|
49
57
|
@post = PostComparer.new(@orig_post)
|
50
|
-
rescue
|
51
|
-
raise
|
58
|
+
rescue => e
|
59
|
+
raise Bunto::Errors::PostURLError, <<-eos
|
52
60
|
Could not parse name of post "#{@orig_post}" in tag 'post_url'.
|
53
61
|
|
54
62
|
Make sure the post exists and the name is correct.
|
63
|
+
|
64
|
+
#{e.class}: #{e.message}
|
55
65
|
eos
|
56
66
|
end
|
57
67
|
end
|
@@ -75,7 +85,7 @@ eos
|
|
75
85
|
return p.url
|
76
86
|
end
|
77
87
|
|
78
|
-
raise
|
88
|
+
raise Bunto::Errors::PostURLError, <<-eos
|
79
89
|
Could not find post "#{@orig_post}" in tag 'post_url'.
|
80
90
|
|
81
91
|
Make sure the post exists and the name is correct.
|
data/lib/bunto/theme.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Bunto
|
2
|
+
class Theme
|
3
|
+
extend Forwardable
|
4
|
+
attr_reader :name
|
5
|
+
def_delegator :gemspec, :version, :version
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
@name = name.downcase.strip
|
9
|
+
configure_sass
|
10
|
+
end
|
11
|
+
|
12
|
+
def root
|
13
|
+
@root ||= gemspec.full_gem_path
|
14
|
+
end
|
15
|
+
|
16
|
+
def includes_path
|
17
|
+
path_for :includes
|
18
|
+
end
|
19
|
+
|
20
|
+
def layouts_path
|
21
|
+
path_for :layouts
|
22
|
+
end
|
23
|
+
|
24
|
+
def sass_path
|
25
|
+
path_for :sass
|
26
|
+
end
|
27
|
+
|
28
|
+
def configure_sass
|
29
|
+
return unless sass_path
|
30
|
+
require 'sass'
|
31
|
+
Sass.load_paths << sass_path
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def path_for(folder)
|
37
|
+
resolved_dir = realpath_for(folder)
|
38
|
+
return unless resolved_dir
|
39
|
+
|
40
|
+
path = Bunto.sanitized_path(root, resolved_dir)
|
41
|
+
path if Dir.exists?(path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def realpath_for(folder)
|
45
|
+
File.realpath(Bunto.sanitized_path(root, "_#{folder}"))
|
46
|
+
rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def gemspec
|
51
|
+
@gemspec ||= Gem::Specification.find_by_name(name)
|
52
|
+
rescue Gem::LoadError
|
53
|
+
raise Bunto::Errors::MissingDependencyException, "The #{name} theme could not be found."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/bunto/utils.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
module Bunto
|
2
3
|
module Utils
|
3
4
|
extend self
|
@@ -20,7 +21,7 @@ module Bunto
|
|
20
21
|
|
21
22
|
def titleize_slug(slug)
|
22
23
|
slug.split("-").map! do |val|
|
23
|
-
val.capitalize
|
24
|
+
val.capitalize
|
24
25
|
end.join(" ")
|
25
26
|
end
|
26
27
|
|
@@ -126,7 +127,7 @@ module Bunto
|
|
126
127
|
def parse_date(input, msg = "Input could not be parsed.")
|
127
128
|
Time.parse(input).localtime
|
128
129
|
rescue ArgumentError
|
129
|
-
raise Errors::
|
130
|
+
raise Errors::InvalidDateError, "Invalid date '#{input}': #{msg}"
|
130
131
|
end
|
131
132
|
|
132
133
|
# Determines whether a given file has
|