nanoc 4.0.0a1 → 4.0.0a2
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/Gemfile.lock +9 -4
- data/NEWS.md +13 -0
- data/lib/nanoc/base.rb +2 -0
- data/lib/nanoc/base/compilation/compiler.rb +0 -1
- data/lib/nanoc/base/compilation/compiler_dsl.rb +21 -7
- data/lib/nanoc/base/compilation/item_rep_proxy.rb +10 -1
- data/lib/nanoc/base/compilation/rule.rb +10 -12
- data/lib/nanoc/base/compilation/rules_collection.rb +2 -2
- data/lib/nanoc/base/pattern.rb +63 -0
- data/lib/nanoc/base/source_data/data_source.rb +33 -18
- data/lib/nanoc/base/source_data/identifier.rb +65 -3
- data/lib/nanoc/base/source_data/item.rb +1 -1
- data/lib/nanoc/base/source_data/item_array.rb +17 -2
- data/lib/nanoc/base/source_data/layout.rb +1 -1
- data/lib/nanoc/base/source_data/site.rb +4 -3
- data/lib/nanoc/base/views/config.rb +22 -0
- data/lib/nanoc/base/views/item.rb +76 -0
- data/lib/nanoc/base/views/item_collection.rb +46 -4
- data/lib/nanoc/base/views/item_rep.rb +23 -0
- data/lib/nanoc/base/views/layout.rb +4 -0
- data/lib/nanoc/base/views/layout_collection.rb +7 -1
- data/lib/nanoc/base/views/mutable_config.rb +5 -0
- data/lib/nanoc/base/views/mutable_item.rb +15 -0
- data/lib/nanoc/base/views/mutable_item_collection.rb +25 -0
- data/lib/nanoc/base/views/mutable_layout.rb +5 -0
- data/lib/nanoc/base/views/mutable_layout_collection.rb +20 -2
- data/lib/nanoc/cli/cleaning_stream.rb +15 -0
- data/lib/nanoc/cli/commands/create-site.rb +17 -35
- data/lib/nanoc/cli/commands/shell.rb +7 -4
- data/lib/nanoc/data_sources.rb +0 -1
- data/lib/nanoc/data_sources/filesystem.rb +75 -76
- data/lib/nanoc/data_sources/filesystem_unified.rb +4 -27
- data/lib/nanoc/data_sources/filesystem_verbose.rb +4 -21
- data/lib/nanoc/version.rb +1 -1
- data/nanoc.gemspec +1 -1
- data/test/base/test_compiler.rb +35 -15
- data/test/base/test_compiler_dsl.rb +32 -30
- data/test/base/test_data_source.rb +2 -2
- data/test/base/test_item_array.rb +10 -1
- data/test/base/test_rule.rb +2 -2
- data/test/base/test_site.rb +32 -0
- data/test/cli/commands/test_create_site.rb +7 -1
- data/test/cli/commands/test_prune.rb +2 -2
- data/test/data_sources/test_filesystem.rb +29 -9
- data/test/data_sources/test_filesystem_unified.rb +48 -68
- data/test/helper.rb +1 -0
- data/test/helpers/test_breadcrumbs.rb +4 -4
- data/test/test_gem.rb +0 -1
- metadata +4 -5
- data/lib/nanoc/data_sources/static.rb +0 -62
- data/test/data_sources/test_static.rb +0 -93
@@ -7,12 +7,37 @@ module Nanoc
|
|
7
7
|
Nanoc::MutableItemView
|
8
8
|
end
|
9
9
|
|
10
|
+
# Creates a new item and adds it to the site’s collection of items.
|
11
|
+
#
|
12
|
+
# @param [String] content The uncompiled item content (if it is a textual
|
13
|
+
# item) or the path to the filename containing the content (if it is a
|
14
|
+
# binary item).
|
15
|
+
#
|
16
|
+
# @param [Hash] attributes A hash containing this item's attributes.
|
17
|
+
#
|
18
|
+
# @param [Nanoc::Identifier, String] identifier This item's identifier.
|
19
|
+
#
|
20
|
+
# @param [Hash] params Extra parameters.
|
21
|
+
#
|
22
|
+
# @option params [Symbol, nil] :binary (true) Whether or not this item is
|
23
|
+
# binary
|
24
|
+
#
|
25
|
+
# @return [self]
|
10
26
|
def create(content, attributes, identifier, params = {})
|
11
27
|
@items << Nanoc::Int::Item.new(content, attributes, identifier, params)
|
28
|
+
self
|
12
29
|
end
|
13
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]
|
14
38
|
def delete_if(&block)
|
15
39
|
@items.delete_if(&block)
|
40
|
+
self
|
16
41
|
end
|
17
42
|
end
|
18
43
|
end
|
@@ -7,12 +7,30 @@ module Nanoc
|
|
7
7
|
Nanoc::MutableLayoutView
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
# Creates a new layout and adds it to the site’s collection of layouts.
|
11
|
+
#
|
12
|
+
# @param [String] content The layout content.
|
13
|
+
#
|
14
|
+
# @param [Hash] attributes A hash containing this layout's attributes.
|
15
|
+
#
|
16
|
+
# @param [Nanoc::Identifier, String] identifier This layout's identifier.
|
17
|
+
#
|
18
|
+
# @return [self]
|
19
|
+
def create(content, attributes, identifier)
|
20
|
+
@layouts << Nanoc::Int::Layout.new(content, attributes, identifier)
|
21
|
+
self
|
12
22
|
end
|
13
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]
|
14
31
|
def delete_if(&block)
|
15
32
|
@layouts.delete_if(&block)
|
33
|
+
self
|
16
34
|
end
|
17
35
|
end
|
18
36
|
end
|
@@ -119,6 +119,21 @@ module Nanoc::CLI
|
|
119
119
|
@stream.winsize = (arg)
|
120
120
|
end
|
121
121
|
|
122
|
+
# @see IO.sync
|
123
|
+
def sync
|
124
|
+
@stream.sync
|
125
|
+
end
|
126
|
+
|
127
|
+
# @see IO.sync=
|
128
|
+
def sync=(arg)
|
129
|
+
@stream.sync = arg
|
130
|
+
end
|
131
|
+
|
132
|
+
# @see IO.sync=
|
133
|
+
def external_encoding
|
134
|
+
@stream.external_encoding
|
135
|
+
end
|
136
|
+
|
122
137
|
protected
|
123
138
|
|
124
139
|
def _nanoc_clean(s)
|
@@ -19,6 +19,11 @@ module Nanoc::CLI::Commands
|
|
19
19
|
end
|
20
20
|
|
21
21
|
DEFAULT_CONFIG = <<EOS unless defined? DEFAULT_CONFIG
|
22
|
+
# The syntax to use for patterns in the Rules file. Can be either `"glob"`
|
23
|
+
# (default) or `null`. The former will enable glob patterns, which behave like
|
24
|
+
# Ruby’s File.fnmatch. The latter will enable nanoc 3.x-style patterns.
|
25
|
+
pattern_syntax: glob
|
26
|
+
|
22
27
|
# A list of file extensions that nanoc will consider to be textual rather than
|
23
28
|
# binary. If an item with an extension not in this list is found, the file
|
24
29
|
# will be considered as binary.
|
@@ -83,6 +88,8 @@ data_sources:
|
|
83
88
|
# UTF-8 (which they should be!), change this.
|
84
89
|
encoding: utf-8
|
85
90
|
|
91
|
+
identifier_style: full
|
92
|
+
|
86
93
|
# Configuration for the “check” command, which run unit tests on the site.
|
87
94
|
checks:
|
88
95
|
# Configuration for the “internal_links” checker, which checks whether all
|
@@ -98,44 +105,19 @@ EOS
|
|
98
105
|
DEFAULT_RULES = <<EOS unless defined? DEFAULT_RULES
|
99
106
|
#!/usr/bin/env ruby
|
100
107
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
# identifiers--not for paths. Therefore, you can’t match on extension.
|
105
|
-
#
|
106
|
-
# * The order of rules is important: for each item, only the first matching
|
107
|
-
# rule is applied.
|
108
|
-
#
|
109
|
-
# * Item identifiers start and end with a slash (e.g. “/about/” for the file
|
110
|
-
# “content/about.html”). To select all children, grandchildren, … of an
|
111
|
-
# item, use the pattern “/about/*/”; “/about/*” will also select the parent,
|
112
|
-
# because “*” matches zero or more characters.
|
113
|
-
|
114
|
-
compile '*' do
|
115
|
-
if item[:extension] == 'css'
|
116
|
-
# don’t filter stylesheets
|
117
|
-
elsif item.binary?
|
118
|
-
# don’t filter binary items
|
119
|
-
else
|
120
|
-
filter :erb
|
121
|
-
layout 'default'
|
122
|
-
end
|
108
|
+
compile '/**/*.html' do
|
109
|
+
filter :erb
|
110
|
+
layout '/default.*'
|
123
111
|
end
|
124
112
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
# Write item with identifier /foo/ to /foo.ext
|
131
|
-
item.identifier.chop + (item[:extension] ? '.' + item[:extension] : '')
|
132
|
-
else
|
133
|
-
# Write item with identifier /foo/ to /foo/index.html
|
134
|
-
item.identifier + 'index.html'
|
135
|
-
end
|
113
|
+
compile '/**/*' do
|
114
|
+
end
|
115
|
+
|
116
|
+
route '/**/*' do
|
117
|
+
item.identifier.to_s
|
136
118
|
end
|
137
119
|
|
138
|
-
layout '
|
120
|
+
layout '/**/*', :erb
|
139
121
|
EOS
|
140
122
|
|
141
123
|
DEFAULT_ITEM = <<EOS unless defined? DEFAULT_ITEM
|
@@ -261,7 +243,7 @@ EOS
|
|
261
243
|
<head>
|
262
244
|
<meta charset="utf-8">
|
263
245
|
<title>A Brand New nanoc Site - <%= @item[:title] %></title>
|
264
|
-
<link rel="stylesheet" href="<%= @items['/stylesheet
|
246
|
+
<link rel="stylesheet" href="<%= @items['/stylesheet.*'].path %>">
|
265
247
|
|
266
248
|
<!-- you don't need to keep this, but it's cool for stats! -->
|
267
249
|
<meta name="generator" content="nanoc <%= Nanoc::VERSION %>">
|
@@ -20,11 +20,14 @@ module Nanoc::CLI::Commands
|
|
20
20
|
protected
|
21
21
|
|
22
22
|
def env
|
23
|
+
self.class.env_for_site(site)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.env_for(site)
|
23
27
|
{
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
config: site.config
|
28
|
+
items: Nanoc::ItemCollectionView.new(site.items),
|
29
|
+
layouts: Nanoc::LayoutCollectionView.new(site.layouts),
|
30
|
+
config: Nanoc::ConfigView.new(site.config),
|
28
31
|
}
|
29
32
|
end
|
30
33
|
end
|
data/lib/nanoc/data_sources.rb
CHANGED
@@ -5,7 +5,6 @@ module Nanoc::DataSources
|
|
5
5
|
autoload 'Filesystem', 'nanoc/data_sources/filesystem'
|
6
6
|
autoload 'FilesystemUnified', 'nanoc/data_sources/filesystem_unified'
|
7
7
|
autoload 'FilesystemVerbose', 'nanoc/data_sources/filesystem_verbose'
|
8
|
-
autoload 'Static', 'nanoc/data_sources/static'
|
9
8
|
|
10
9
|
Nanoc::DataSource.register '::Nanoc::DataSources::FilesystemVerbose', :filesystem_verbose
|
11
10
|
Nanoc::DataSource.register '::Nanoc::DataSources::FilesystemUnified', :filesystem_unified
|
@@ -33,15 +33,6 @@ module Nanoc::DataSources
|
|
33
33
|
|
34
34
|
protected
|
35
35
|
|
36
|
-
# Creates a new object (item or layout) on disk in dir_name according to
|
37
|
-
# the given identifier. The file will have its attributes taken from the
|
38
|
-
# attributes hash argument and its content from the content argument.
|
39
|
-
def create_object(_dir_name, _content, _attributes, _identifier, _params = {})
|
40
|
-
raise NotImplementedError.new(
|
41
|
-
"#{self.class} does not implement ##{name}"
|
42
|
-
)
|
43
|
-
end
|
44
|
-
|
45
36
|
# Creates instances of klass corresponding to the files in dir_name. The
|
46
37
|
# kind attribute indicates the kind of object that is being loaded and is
|
47
38
|
# used solely for debugging purposes.
|
@@ -54,96 +45,104 @@ module Nanoc::DataSources
|
|
54
45
|
#
|
55
46
|
# @see Nanoc::DataSources::Filesystem#load_objects
|
56
47
|
def load_objects(dir_name, kind, klass)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
48
|
+
res = []
|
49
|
+
|
50
|
+
all_split_files_in(dir_name).each do |base_filename, (meta_ext, content_exts)|
|
51
|
+
content_exts.each do |content_ext|
|
52
|
+
# Get filenames
|
53
|
+
meta_filename = filename_for(base_filename, meta_ext)
|
54
|
+
content_filename = filename_for(base_filename, content_ext)
|
55
|
+
|
56
|
+
# Read content and metadata
|
57
|
+
is_binary = content_filename && !@site.config[:text_extensions].include?(File.extname(content_filename)[1..-1])
|
58
|
+
if is_binary && klass == Nanoc::Int::Item
|
59
|
+
meta = (meta_filename && YAML.load_file(meta_filename)) || {}
|
60
|
+
content_or_filename = content_filename
|
61
|
+
elsif is_binary && klass == Nanoc::Int::Layout
|
62
|
+
raise "The layout file '#{content_filename}' is a binary file, but layouts can only be textual"
|
63
|
+
else
|
64
|
+
meta, content_or_filename = parse(content_filename, meta_filename, kind)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Get attributes
|
68
|
+
attributes = {
|
69
|
+
filename: content_filename,
|
70
|
+
content_filename: content_filename,
|
71
|
+
meta_filename: meta_filename,
|
72
|
+
extension: content_filename ? ext_of(content_filename)[1..-1] : nil,
|
73
|
+
}.merge(meta)
|
74
|
+
|
75
|
+
# Get identifier
|
76
|
+
if meta_filename
|
77
|
+
identifier = identifier_for_filename(meta_filename[dir_name.length..-1])
|
78
|
+
elsif content_filename
|
79
|
+
identifier = identifier_for_filename(content_filename[dir_name.length..-1])
|
80
|
+
else
|
81
|
+
raise 'meta_filename and content_filename are both nil'
|
82
|
+
end
|
83
|
+
|
84
|
+
# Get modification times
|
85
|
+
meta_mtime = meta_filename ? File.stat(meta_filename).mtime : nil
|
86
|
+
content_mtime = content_filename ? File.stat(content_filename).mtime : nil
|
87
|
+
if meta_mtime && content_mtime
|
88
|
+
mtime = meta_mtime > content_mtime ? meta_mtime : content_mtime
|
89
|
+
elsif meta_mtime
|
90
|
+
mtime = meta_mtime
|
91
|
+
elsif content_mtime
|
92
|
+
mtime = content_mtime
|
93
|
+
else
|
94
|
+
raise 'meta_mtime and content_mtime are both nil'
|
95
|
+
end
|
96
|
+
|
97
|
+
# Create layout object
|
98
|
+
res << klass.new(
|
99
|
+
content_or_filename, attributes, identifier,
|
100
|
+
binary: is_binary, mtime: mtime
|
101
|
+
)
|
88
102
|
end
|
89
|
-
|
90
|
-
# Get modification times
|
91
|
-
meta_mtime = meta_filename ? File.stat(meta_filename).mtime : nil
|
92
|
-
content_mtime = content_filename ? File.stat(content_filename).mtime : nil
|
93
|
-
if meta_mtime && content_mtime
|
94
|
-
mtime = meta_mtime > content_mtime ? meta_mtime : content_mtime
|
95
|
-
elsif meta_mtime
|
96
|
-
mtime = meta_mtime
|
97
|
-
elsif content_mtime
|
98
|
-
mtime = content_mtime
|
99
|
-
else
|
100
|
-
raise 'meta_mtime and content_mtime are both nil'
|
101
|
-
end
|
102
|
-
|
103
|
-
# Create layout object
|
104
|
-
klass.new(
|
105
|
-
content_or_filename, attributes, identifier,
|
106
|
-
binary: is_binary, mtime: mtime
|
107
|
-
)
|
108
103
|
end
|
104
|
+
|
105
|
+
res
|
109
106
|
end
|
110
107
|
|
111
|
-
#
|
112
|
-
# in which the keys are the file's dirname + basenames, and the values a
|
113
|
-
# pair consisting of the metafile extension and the content file
|
114
|
-
# extension. The meta file extension or the content file extension can be
|
115
|
-
# nil, but not both. Backup files are ignored. For example:
|
108
|
+
# e.g.
|
116
109
|
#
|
117
110
|
# {
|
118
|
-
# 'content/foo' => [ 'yaml', 'html' ],
|
119
|
-
# 'content/bar' => [ 'yaml', nil
|
120
|
-
# 'content/qux' => [ nil, 'html'
|
111
|
+
# 'content/foo' => [ 'yaml', ['html', 'md'] ],
|
112
|
+
# 'content/bar' => [ 'yaml', [nil] ],
|
113
|
+
# 'content/qux' => [ nil, ['html'] ]
|
121
114
|
# }
|
122
115
|
def all_split_files_in(dir_name)
|
123
|
-
|
116
|
+
by_basename =
|
124
117
|
all_files_in(dir_name)
|
125
118
|
.reject { |fn| fn =~ /(~|\.orig|\.rej|\.bak)$/ }
|
126
119
|
.group_by { |fn| basename_of(fn) }
|
127
120
|
|
128
|
-
|
121
|
+
all = {}
|
122
|
+
|
123
|
+
by_basename.each_pair do |basename, filenames|
|
129
124
|
# Divide
|
130
125
|
meta_filenames = filenames.select { |fn| ext_of(fn) == '.yaml' }
|
131
126
|
content_filenames = filenames.select { |fn| ext_of(fn) != '.yaml' }
|
132
127
|
|
133
128
|
# Check number of files per type
|
134
129
|
unless [0, 1].include?(meta_filenames.size)
|
135
|
-
raise "Found #{meta_filenames.size} meta files for #{
|
130
|
+
raise "Found #{meta_filenames.size} meta files for #{basename}; expected 0 or 1"
|
136
131
|
end
|
137
|
-
unless [
|
138
|
-
|
132
|
+
unless config[:identifier_style] == 'full'
|
133
|
+
unless [0, 1].include?(content_filenames.size)
|
134
|
+
raise "Found #{content_filenames.size} content files for #{basename}; expected 0 or 1"
|
135
|
+
end
|
139
136
|
end
|
140
137
|
|
141
|
-
|
142
|
-
|
143
|
-
|
138
|
+
all[basename] = []
|
139
|
+
all[basename][0] =
|
140
|
+
meta_filenames[0] ? 'yaml' : nil
|
141
|
+
all[basename][1] =
|
142
|
+
content_filenames.any? ? content_filenames.map { |fn| ext_of(fn)[1..-1] || '' } : [nil]
|
144
143
|
end
|
145
144
|
|
146
|
-
|
145
|
+
all
|
147
146
|
end
|
148
147
|
|
149
148
|
# Returns all files in the given directory and directories below it.
|
@@ -73,33 +73,6 @@ module Nanoc::DataSources
|
|
73
73
|
|
74
74
|
private
|
75
75
|
|
76
|
-
# See {Nanoc::DataSources::Filesystem#create_object}.
|
77
|
-
def create_object(dir_name, content, attributes, identifier, params = {})
|
78
|
-
# Check for periods
|
79
|
-
if (@config.nil? || !@config[:allow_periods_in_identifiers]) && identifier.include?('.')
|
80
|
-
raise "Attempted to create an object in #{dir_name} with identifier #{identifier} containing a period, but allow_periods_in_identifiers is not enabled in the site configuration. (Enabling allow_periods_in_identifiers may cause the site to break, though.)"
|
81
|
-
end
|
82
|
-
|
83
|
-
# Determine path
|
84
|
-
ext = params[:extension] || '.html'
|
85
|
-
path = dir_name + (identifier == '/' ? '/index.html' : identifier[0..-2] + ext)
|
86
|
-
parent_path = File.dirname(path)
|
87
|
-
|
88
|
-
# Notify
|
89
|
-
Nanoc::Int::NotificationCenter.post(:file_created, path)
|
90
|
-
|
91
|
-
# Write item
|
92
|
-
FileUtils.mkdir_p(parent_path)
|
93
|
-
File.open(path, 'w') do |io|
|
94
|
-
meta = attributes.__nanoc_stringify_keys_recursively
|
95
|
-
unless meta == {}
|
96
|
-
io.write(YAML.dump(meta).strip + "\n")
|
97
|
-
io.write("---\n")
|
98
|
-
end
|
99
|
-
io.write(content)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
76
|
# See {Nanoc::DataSources::Filesystem#filename_for}.
|
104
77
|
def filename_for(base_filename, ext)
|
105
78
|
if ext.nil?
|
@@ -114,6 +87,10 @@ module Nanoc::DataSources
|
|
114
87
|
# Returns the identifier derived from the given filename, first stripping
|
115
88
|
# the given directory name off the filename.
|
116
89
|
def identifier_for_filename(filename)
|
90
|
+
if config[:identifier_style] == 'full'
|
91
|
+
return Nanoc::Identifier.new(filename, style: :full)
|
92
|
+
end
|
93
|
+
|
117
94
|
if filename =~ /(^|\/)index(\.[^\/]+)?$/
|
118
95
|
regex = @config && @config[:allow_periods_in_identifiers] ? /\/?(index)?(\.[^\/\.]+)?$/ : /\/?index(\.[^\/]+)?$/
|
119
96
|
else
|