nanoc 4.0.0b1 → 4.0.0b2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/NEWS.md +26 -2
- data/README.md +1 -1
- data/lib/nanoc/base.rb +3 -1
- data/lib/nanoc/base/checksummer.rb +1 -3
- data/lib/nanoc/base/compilation/compiler.rb +3 -3
- data/lib/nanoc/base/compilation/compiler_dsl.rb +3 -3
- data/lib/nanoc/base/compilation/item_rep_proxy.rb +1 -1
- data/lib/nanoc/base/core_ext/array.rb +0 -11
- data/lib/nanoc/base/core_ext/hash.rb +0 -11
- data/lib/nanoc/base/identifiable_collection.rb +81 -0
- data/lib/nanoc/base/source_data/identifier.rb +9 -9
- data/lib/nanoc/base/source_data/site.rb +7 -5
- data/lib/nanoc/base/views/identifiable_collection.rb +78 -0
- data/lib/nanoc/base/views/item_collection.rb +1 -86
- data/lib/nanoc/base/views/layout_collection.rb +1 -57
- data/lib/nanoc/base/views/mutable_identifiable_collection.rb +17 -0
- data/lib/nanoc/base/views/mutable_item_collection.rb +2 -14
- data/lib/nanoc/base/views/mutable_layout_collection.rb +2 -14
- data/lib/nanoc/cli/commands/create-site.rb +44 -40
- data/lib/nanoc/data_sources/filesystem.rb +1 -1
- data/lib/nanoc/data_sources/filesystem_unified.rb +3 -3
- data/lib/nanoc/data_sources/filesystem_verbose.rb +3 -3
- data/lib/nanoc/filters/erb.rb +2 -2
- data/lib/nanoc/filters/rdiscount.rb +1 -1
- data/lib/nanoc/filters/redcarpet.rb +1 -1
- data/lib/nanoc/version.rb +1 -1
- data/tasks/test.rake +1 -0
- data/test/base/core_ext/array_spec.rb +0 -8
- data/test/base/core_ext/hash_spec.rb +0 -26
- data/test/base/test_compiler.rb +1 -1
- data/test/base/test_compiler_dsl.rb +13 -10
- data/test/base/test_item.rb +0 -6
- data/test/base/test_item_array.rb +8 -276
- data/test/base/test_layout.rb +1 -5
- data/test/base/test_outdatedness_checker.rb +9 -2
- data/test/base/test_site.rb +5 -5
- data/test/cli/commands/test_compile.rb +14 -0
- data/test/cli/commands/test_create_site.rb +40 -2
- data/test/cli/commands/test_prune.rb +19 -4
- data/test/data_sources/test_filesystem.rb +1 -1
- data/test/data_sources/test_filesystem_unified.rb +6 -6
- data/test/extra/checking/checks/test_stale.rb +2 -2
- data/test/helper.rb +8 -1
- data/test/helpers/test_blogging.rb +0 -235
- data/test/helpers/test_breadcrumbs.rb +31 -23
- data/test/helpers/test_xml_sitemap.rb +38 -29
- metadata +5 -3
- data/lib/nanoc/base/source_data/item_array.rb +0 -86
@@ -1,95 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Nanoc
|
4
|
-
class ItemCollectionView
|
5
|
-
include Enumerable
|
6
|
-
|
7
|
-
# @api private
|
8
|
-
def initialize(items)
|
9
|
-
@items = items
|
10
|
-
end
|
11
|
-
|
12
|
-
# @api private
|
13
|
-
def unwrap
|
14
|
-
@items
|
15
|
-
end
|
16
|
-
|
4
|
+
class ItemCollectionView < ::Nanoc::IdentifiableCollectionView
|
17
5
|
# @api private
|
18
6
|
def view_class
|
19
7
|
Nanoc::ItemView
|
20
8
|
end
|
21
|
-
|
22
|
-
# Calls the given block once for each item, passing that item as a parameter.
|
23
|
-
#
|
24
|
-
# @yieldparam [Nanoc::ItemView] item
|
25
|
-
#
|
26
|
-
# @yieldreturn [void]
|
27
|
-
#
|
28
|
-
# @return [self]
|
29
|
-
def each
|
30
|
-
@items.each { |i| yield view_class.new(i) }
|
31
|
-
self
|
32
|
-
end
|
33
|
-
|
34
|
-
# @return [Integer]
|
35
|
-
def size
|
36
|
-
@items.size
|
37
|
-
end
|
38
|
-
|
39
|
-
# @overload at(string)
|
40
|
-
#
|
41
|
-
# Finds the item whose identifier matches the given string.
|
42
|
-
#
|
43
|
-
# @param [String] string
|
44
|
-
#
|
45
|
-
# @return [nil] if no item matches the string
|
46
|
-
#
|
47
|
-
# @return [Nanoc::ItemView] if an item was found
|
48
|
-
def at(arg)
|
49
|
-
item = @items.at(arg)
|
50
|
-
item && view_class.new(item)
|
51
|
-
end
|
52
|
-
|
53
|
-
# Finds all items whose identifier matches the given argument.
|
54
|
-
#
|
55
|
-
# @param [String, Regex] arg
|
56
|
-
#
|
57
|
-
# @return [Enumerable<Nanoc::ItemView>]
|
58
|
-
def find_all(arg)
|
59
|
-
pat = Nanoc::Int::Pattern.from(arg)
|
60
|
-
@items.select { |i| pat.match?(i.identifier) }
|
61
|
-
end
|
62
|
-
|
63
|
-
# @overload [](string)
|
64
|
-
#
|
65
|
-
# Finds the item whose identifier matches the given string.
|
66
|
-
#
|
67
|
-
# If the glob syntax is enabled, the string can be a glob, in which case
|
68
|
-
# this method finds the first item that matches the given glob.
|
69
|
-
#
|
70
|
-
# @param [String] string
|
71
|
-
#
|
72
|
-
# @return [nil] if no item matches the string
|
73
|
-
#
|
74
|
-
# @return [Nanoc::ItemView] if an item was found
|
75
|
-
#
|
76
|
-
# @overload [](regex)
|
77
|
-
#
|
78
|
-
# Finds the item whose identifier matches the given regular expression.
|
79
|
-
#
|
80
|
-
# @param [Regex] regex
|
81
|
-
#
|
82
|
-
# @return [nil] if no item matches the regex
|
83
|
-
#
|
84
|
-
# @return [Nanoc::ItemView] if an item was found
|
85
|
-
def [](arg)
|
86
|
-
res = @items[arg]
|
87
|
-
case res
|
88
|
-
when nil
|
89
|
-
nil
|
90
|
-
else
|
91
|
-
view_class.new(res)
|
92
|
-
end
|
93
|
-
end
|
94
9
|
end
|
95
10
|
end
|
@@ -1,66 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Nanoc
|
4
|
-
class LayoutCollectionView
|
5
|
-
include Enumerable
|
6
|
-
|
7
|
-
# @api private
|
8
|
-
def initialize(layouts)
|
9
|
-
@layouts = layouts
|
10
|
-
end
|
11
|
-
|
12
|
-
# @api private
|
13
|
-
def unwrap
|
14
|
-
@layouts
|
15
|
-
end
|
16
|
-
|
4
|
+
class LayoutCollectionView < ::Nanoc::IdentifiableCollectionView
|
17
5
|
# @api private
|
18
6
|
def view_class
|
19
7
|
Nanoc::LayoutView
|
20
8
|
end
|
21
|
-
|
22
|
-
# Calls the given block once for each layout, passing that layout as a parameter.
|
23
|
-
#
|
24
|
-
# @yieldparam [Nanoc::LayoutView] layout
|
25
|
-
#
|
26
|
-
# @yieldreturn [void]
|
27
|
-
def each
|
28
|
-
@layouts.each { |l| yield view_class.new(l) }
|
29
|
-
self
|
30
|
-
end
|
31
|
-
|
32
|
-
# @overload [](string)
|
33
|
-
#
|
34
|
-
# Finds the item whose identifier matches the given string.
|
35
|
-
#
|
36
|
-
# If the glob syntax is enabled, the string can be a glob, in which case
|
37
|
-
# this method finds the first item that matches the given glob.
|
38
|
-
#
|
39
|
-
# @param [String] string
|
40
|
-
#
|
41
|
-
# @return [nil] if no item matches the string
|
42
|
-
#
|
43
|
-
# @return [Nanoc::ItemView] if an item was found
|
44
|
-
#
|
45
|
-
# @overload [](regex)
|
46
|
-
#
|
47
|
-
# Finds the item whose identifier matches the given regular expression.
|
48
|
-
#
|
49
|
-
# @param [Regex] regex
|
50
|
-
#
|
51
|
-
# @return [nil] if no item matches the regex
|
52
|
-
#
|
53
|
-
# @return [Nanoc::ItemView] if an item was found
|
54
|
-
def [](arg)
|
55
|
-
layout = @layouts.find { |l| l.identifier == arg }
|
56
|
-
return view_class.new(layout) if layout
|
57
|
-
|
58
|
-
# FIXME: this should only work if globs are enabled
|
59
|
-
pat = Nanoc::Int::Pattern.from(arg)
|
60
|
-
layout = @layouts.find { |l| pat.match?(l.identifier) }
|
61
|
-
return view_class.new(layout) if layout
|
62
|
-
|
63
|
-
nil
|
64
|
-
end
|
65
9
|
end
|
66
10
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc
|
4
|
+
class MutableIdentifiableCollectionView < Nanoc::IdentifiableCollectionView
|
5
|
+
# Deletes every object for which the block evaluates to true.
|
6
|
+
#
|
7
|
+
# @yieldparam [#identifier] object
|
8
|
+
#
|
9
|
+
# @yieldreturn [Boolean]
|
10
|
+
#
|
11
|
+
# @return [self]
|
12
|
+
def delete_if(&block)
|
13
|
+
@objects.delete_if { |o| yield(view_class.new(o)) }
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Nanoc
|
4
|
-
class MutableItemCollectionView < Nanoc::
|
4
|
+
class MutableItemCollectionView < Nanoc::MutableIdentifiableCollectionView
|
5
5
|
# @api private
|
6
6
|
def view_class
|
7
7
|
Nanoc::MutableItemView
|
@@ -24,19 +24,7 @@ module Nanoc
|
|
24
24
|
#
|
25
25
|
# @return [self]
|
26
26
|
def create(content, attributes, identifier, params = {})
|
27
|
-
@
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
|
-
# Deletes every item for which the block evaluates to true.
|
32
|
-
#
|
33
|
-
# @yieldparam [Nanoc::ItemView] item
|
34
|
-
#
|
35
|
-
# @yieldreturn [Boolean]
|
36
|
-
#
|
37
|
-
# @return [self]
|
38
|
-
def delete_if(&block)
|
39
|
-
@items.delete_if(&block)
|
27
|
+
@objects << Nanoc::Int::Item.new(content, attributes, identifier, params)
|
40
28
|
self
|
41
29
|
end
|
42
30
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Nanoc
|
4
|
-
class MutableLayoutCollectionView < Nanoc::
|
4
|
+
class MutableLayoutCollectionView < Nanoc::MutableIdentifiableCollectionView
|
5
5
|
# @api private
|
6
6
|
def view_class
|
7
7
|
Nanoc::MutableLayoutView
|
@@ -17,19 +17,7 @@ module Nanoc
|
|
17
17
|
#
|
18
18
|
# @return [self]
|
19
19
|
def create(content, attributes, identifier)
|
20
|
-
@
|
21
|
-
self
|
22
|
-
end
|
23
|
-
|
24
|
-
# Deletes every layout for which the block evaluates to true.
|
25
|
-
#
|
26
|
-
# @yieldparam [Nanoc::LayoutView] layout
|
27
|
-
#
|
28
|
-
# @yieldreturn [Boolean]
|
29
|
-
#
|
30
|
-
# @return [self]
|
31
|
-
def delete_if(&block)
|
32
|
-
@layouts.delete_if(&block)
|
20
|
+
@objects << Nanoc::Int::Layout.new(content, attributes, identifier)
|
33
21
|
self
|
34
22
|
end
|
35
23
|
end
|
@@ -6,6 +6,7 @@ summary 'create a site'
|
|
6
6
|
description "
|
7
7
|
Create a new site at the given path. The site will use the `filesystem_unified` data source by default, but this can be changed using the `--datasource` command-line option.
|
8
8
|
"
|
9
|
+
flag nil, :force, "Force creation of new site. Disregards previous existence of site in destination"
|
9
10
|
|
10
11
|
module Nanoc::CLI::Commands
|
11
12
|
class CreateSite < ::Nanoc::CLI::CommandRunner
|
@@ -20,9 +21,9 @@ module Nanoc::CLI::Commands
|
|
20
21
|
|
21
22
|
DEFAULT_CONFIG = <<EOS unless defined? DEFAULT_CONFIG
|
22
23
|
# The syntax to use for patterns in the Rules file. Can be either `"glob"`
|
23
|
-
# (default) or `
|
24
|
-
# Ruby’s File.fnmatch. The latter will enable nanoc 3.x-style patterns.
|
25
|
-
|
24
|
+
# (default) or `"legacy"`. The former will enable glob patterns, which behave
|
25
|
+
# like Ruby’s File.fnmatch. The latter will enable nanoc 3.x-style patterns.
|
26
|
+
string_pattern_type: glob
|
26
27
|
|
27
28
|
# A list of file extensions that nanoc will consider to be textual rather than
|
28
29
|
# binary. If an item with an extension not in this list is found, the file
|
@@ -47,8 +48,8 @@ enable_output_diff: false
|
|
47
48
|
|
48
49
|
prune:
|
49
50
|
# Whether to automatically remove files not managed by nanoc from the output
|
50
|
-
# directory.
|
51
|
-
auto_prune:
|
51
|
+
# directory.
|
52
|
+
auto_prune: true
|
52
53
|
|
53
54
|
# Which files and directories you want to exclude from pruning. If you version
|
54
55
|
# your output directory, you should probably exclude VCS directories such as
|
@@ -88,7 +89,7 @@ data_sources:
|
|
88
89
|
# UTF-8 (which they should be!), change this.
|
89
90
|
encoding: utf-8
|
90
91
|
|
91
|
-
|
92
|
+
identifier_type: full
|
92
93
|
|
93
94
|
# Configuration for the “check” command, which run unit tests on the site.
|
94
95
|
checks:
|
@@ -106,13 +107,29 @@ EOS
|
|
106
107
|
#!/usr/bin/env ruby
|
107
108
|
|
108
109
|
compile '/**/*.html' do
|
109
|
-
filter :erb
|
110
110
|
layout '/default.*'
|
111
111
|
end
|
112
112
|
|
113
|
+
# This is an example rule that matches Markdown (.md) files, and filters them
|
114
|
+
# using the :kramdown filter. It is commented out by default, because kramdown
|
115
|
+
# is not bundled with nanoc or Ruby.
|
116
|
+
#
|
117
|
+
#compile '/**/*.md' do
|
118
|
+
# filter :kramdown
|
119
|
+
# layout '/default.*'
|
120
|
+
#end
|
121
|
+
|
113
122
|
compile '/**/*' do
|
114
123
|
end
|
115
124
|
|
125
|
+
route '/**/*.{html,md}' do
|
126
|
+
if item.identifier =~ '/index.*'
|
127
|
+
'/index.html'
|
128
|
+
else
|
129
|
+
item.identifier.without_ext + '/index.html'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
116
133
|
route '/**/*' do
|
117
134
|
item.identifier.to_s
|
118
135
|
end
|
@@ -121,6 +138,10 @@ layout '/**/*', :erb
|
|
121
138
|
EOS
|
122
139
|
|
123
140
|
DEFAULT_ITEM = <<EOS unless defined? DEFAULT_ITEM
|
141
|
+
---
|
142
|
+
title: Home
|
143
|
+
---
|
144
|
+
|
124
145
|
<h1>A Brand New nanoc Site</h1>
|
125
146
|
|
126
147
|
<p>You’ve just created a new nanoc site. The page you are looking at right now is the home page for your site. To get started, consider replacing this default homepage with your own customized homepage. Some pointers on how to do so:</p>
|
@@ -280,8 +301,10 @@ EOS
|
|
280
301
|
data_source = options[:datasource] || 'filesystem_unified'
|
281
302
|
|
282
303
|
# Check whether site exists
|
283
|
-
if File.exist?(path) && (!File.directory?(path) || !(Dir.entries(path) - %w{ . .. }).empty?)
|
284
|
-
raise Nanoc::Int::Errors::GenericTrivial,
|
304
|
+
if File.exist?(path) && (!File.directory?(path) || !(Dir.entries(path) - %w{ . .. }).empty?) && !options[:force]
|
305
|
+
raise Nanoc::Int::Errors::GenericTrivial,
|
306
|
+
"The site was not created because '#{path}' already exists. " +
|
307
|
+
"Re-run the command using --force to create the site anyway."
|
285
308
|
end
|
286
309
|
|
287
310
|
# Check whether data source exists
|
@@ -302,41 +325,22 @@ EOS
|
|
302
325
|
FileUtils.mkdir_p('lib')
|
303
326
|
FileUtils.mkdir_p('output')
|
304
327
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
File.open('Rules', 'w') do |io|
|
311
|
-
io.write DEFAULT_RULES
|
312
|
-
end
|
313
|
-
Nanoc::Int::NotificationCenter.post(:file_created, 'Rules')
|
314
|
-
|
315
|
-
# Home page
|
316
|
-
File.open('content/index.html', 'w') do |io|
|
317
|
-
io << '---' << "\n"
|
318
|
-
io << 'title: Home' << "\n"
|
319
|
-
io << '---' << "\n"
|
320
|
-
io << "\n"
|
321
|
-
io << DEFAULT_ITEM
|
322
|
-
end
|
323
|
-
Nanoc::Int::NotificationCenter.post(:file_created, 'content/index.html')
|
324
|
-
|
325
|
-
# Style sheet
|
326
|
-
File.open('content/stylesheet.css', 'w') do |io|
|
327
|
-
io << DEFAULT_STYLESHEET
|
328
|
-
end
|
329
|
-
Nanoc::Int::NotificationCenter.post(:file_created, 'content/stylesheet.css')
|
330
|
-
|
331
|
-
# Layout
|
332
|
-
File.open('layouts/default.html', 'w') do |io|
|
333
|
-
io << DEFAULT_LAYOUT
|
334
|
-
end
|
335
|
-
Nanoc::Int::NotificationCenter.post(:file_created, 'layouts/default.html')
|
328
|
+
write('nanoc.yaml', DEFAULT_CONFIG)
|
329
|
+
write('Rules', DEFAULT_RULES)
|
330
|
+
write('content/index.html', DEFAULT_ITEM)
|
331
|
+
write('content/stylesheet.css', DEFAULT_STYLESHEET)
|
332
|
+
write('layouts/default.html', DEFAULT_LAYOUT)
|
336
333
|
end
|
337
334
|
|
338
335
|
puts "Created a blank nanoc site at '#{path}'. Enjoy!"
|
339
336
|
end
|
337
|
+
|
338
|
+
private
|
339
|
+
|
340
|
+
def write(filename, content)
|
341
|
+
File.write(filename, content)
|
342
|
+
Nanoc::Int::NotificationCenter.post(:file_created, filename)
|
343
|
+
end
|
340
344
|
end
|
341
345
|
end
|
342
346
|
|
@@ -129,7 +129,7 @@ module Nanoc::DataSources
|
|
129
129
|
unless [0, 1].include?(meta_filenames.size)
|
130
130
|
raise "Found #{meta_filenames.size} meta files for #{basename}; expected 0 or 1"
|
131
131
|
end
|
132
|
-
unless config[:
|
132
|
+
unless config[:identifier_type] == 'full'
|
133
133
|
unless [0, 1].include?(content_filenames.size)
|
134
134
|
raise "Found #{content_filenames.size} content files for #{basename}; expected 0 or 1"
|
135
135
|
end
|
@@ -87,8 +87,8 @@ module Nanoc::DataSources
|
|
87
87
|
# Returns the identifier derived from the given filename, first stripping
|
88
88
|
# the given directory name off the filename.
|
89
89
|
def identifier_for_filename(filename)
|
90
|
-
if config[:
|
91
|
-
return Nanoc::Identifier.new(filename
|
90
|
+
if config[:identifier_type] == 'full'
|
91
|
+
return Nanoc::Identifier.new(filename)
|
92
92
|
end
|
93
93
|
|
94
94
|
if filename =~ /(^|\/)index(\.[^\/]+)?$/
|
@@ -96,7 +96,7 @@ module Nanoc::DataSources
|
|
96
96
|
else
|
97
97
|
regex = @config && @config[:allow_periods_in_identifiers] ? /\.[^\/\.]+$/ : /\.[^\/]+$/
|
98
98
|
end
|
99
|
-
filename.sub(regex, '')
|
99
|
+
Nanoc::Identifier.new(filename.sub(regex, ''), type: :legacy)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
@@ -61,11 +61,11 @@ module Nanoc::DataSources
|
|
61
61
|
|
62
62
|
# See {Nanoc::DataSources::Filesystem#identifier_for_filename}.
|
63
63
|
def identifier_for_filename(filename)
|
64
|
-
if config[:
|
65
|
-
return Nanoc::Identifier.new(filename
|
64
|
+
if config[:identifier_type] == 'full'
|
65
|
+
return Nanoc::Identifier.new(filename)
|
66
66
|
end
|
67
67
|
|
68
|
-
filename.sub(/[^\/]+\.yaml$/, '')
|
68
|
+
Nanoc::Identifier.new(filename.sub(/[^\/]+\.yaml$/, ''), type: :legacy)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
data/lib/nanoc/filters/erb.rb
CHANGED
@@ -9,10 +9,10 @@ module Nanoc::Filters
|
|
9
9
|
#
|
10
10
|
# @param [String] content The content to filter
|
11
11
|
#
|
12
|
-
# @option params [Integer] safe_level (nil) The safe level (`$SAFE`) to
|
12
|
+
# @option params [Integer] :safe_level (nil) The safe level (`$SAFE`) to
|
13
13
|
# use while running this filter
|
14
14
|
#
|
15
|
-
# @option params [String] trim_mode (nil) The trim mode to use
|
15
|
+
# @option params [String] :trim_mode (nil) The trim mode to use
|
16
16
|
#
|
17
17
|
# @return [String] The filtered content
|
18
18
|
def run(content, params = {})
|