bunto 2.0.0.pre → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|