nanoc 4.1.6 → 4.2.0b1
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 +1 -0
- data/Gemfile.lock +2 -1
- data/NEWS.md +11 -4
- data/lib/nanoc/base/checksummer.rb +135 -46
- data/lib/nanoc/base/compilation/compiler.rb +18 -28
- data/lib/nanoc/base/compilation/dependency_tracker.rb +22 -32
- data/lib/nanoc/base/compilation/filter.rb +2 -4
- data/lib/nanoc/base/entities.rb +1 -0
- data/lib/nanoc/base/entities/content.rb +14 -3
- data/lib/nanoc/base/entities/document.rb +14 -6
- data/lib/nanoc/base/entities/item.rb +0 -31
- data/lib/nanoc/base/entities/item_rep.rb +1 -1
- data/lib/nanoc/base/entities/lazy_value.rb +36 -0
- data/lib/nanoc/base/entities/pattern.rb +3 -2
- data/lib/nanoc/base/entities/site.rb +2 -0
- data/lib/nanoc/base/memoization.rb +17 -10
- data/lib/nanoc/base/repos/compiled_content_cache.rb +1 -1
- data/lib/nanoc/base/repos/data_source.rb +10 -6
- data/lib/nanoc/base/services/executor.rb +22 -22
- data/lib/nanoc/base/services/item_rep_router.rb +4 -5
- data/lib/nanoc/base/views.rb +0 -1
- data/lib/nanoc/base/views/item_rep_view.rb +3 -9
- data/lib/nanoc/base/views/mixins/document_view_mixin.rb +4 -11
- data/lib/nanoc/base/views/view.rb +1 -0
- data/lib/nanoc/base/views/view_context.rb +5 -1
- data/lib/nanoc/cli/commands/compile.rb +0 -6
- data/lib/nanoc/data_sources.rb +5 -5
- data/lib/nanoc/data_sources/filesystem.rb +219 -90
- data/lib/nanoc/extra/checking/check.rb +1 -2
- data/lib/nanoc/extra/checking/checks.rb +2 -0
- data/lib/nanoc/extra/checking/checks/css.rb +6 -14
- data/lib/nanoc/extra/checking/checks/html.rb +6 -14
- data/lib/nanoc/extra/checking/checks/internal_links.rb +14 -3
- data/lib/nanoc/extra/checking/checks/w3c_validator.rb +28 -0
- data/lib/nanoc/extra/deployers/fog.rb +134 -78
- data/lib/nanoc/extra/link_collector.rb +14 -18
- data/lib/nanoc/filters/sass.rb +3 -3
- data/lib/nanoc/helpers.rb +1 -0
- data/lib/nanoc/helpers/capturing.rb +16 -58
- data/lib/nanoc/helpers/child_parent.rb +51 -0
- data/lib/nanoc/helpers/filtering.rb +0 -1
- data/lib/nanoc/helpers/html_escape.rb +5 -0
- data/lib/nanoc/helpers/link_to.rb +2 -0
- data/lib/nanoc/helpers/rendering.rb +3 -4
- data/lib/nanoc/rule_dsl/action_provider.rb +20 -4
- data/lib/nanoc/rule_dsl/recording_executor.rb +3 -1
- data/lib/nanoc/rule_dsl/rule_context.rb +0 -1
- data/lib/nanoc/rule_dsl/rule_memory_calculator.rb +4 -1
- data/lib/nanoc/spec.rb +217 -0
- data/lib/nanoc/version.rb +1 -1
- data/test/base/test_data_source.rb +4 -2
- data/test/base/test_dependency_tracker.rb +5 -11
- data/test/data_sources/test_filesystem.rb +605 -69
- data/test/extra/checking/checks/test_internal_links.rb +25 -0
- data/test/extra/deployers/test_fog.rb +0 -177
- data/test/filters/test_less.rb +9 -4
- data/test/helpers/test_capturing.rb +38 -212
- data/test/helpers/test_link_to.rb +0 -205
- data/test/helpers/test_xml_sitemap.rb +2 -1
- metadata +7 -12
- data/lib/nanoc/base/views/site_view.rb +0 -14
- data/lib/nanoc/data_sources/filesystem_unified.rb +0 -101
- data/test/data_sources/test_filesystem_unified.rb +0 -559
- data/test/helpers/test_breadcrumbs.rb +0 -60
- data/test/helpers/test_filtering.rb +0 -112
- data/test/helpers/test_html_escape.rb +0 -26
- data/test/helpers/test_rendering.rb +0 -147
- data/test/helpers/test_tagging.rb +0 -92
- data/test/helpers/test_text.rb +0 -18
@@ -32,24 +32,19 @@ module Nanoc
|
|
32
32
|
|
33
33
|
# @see Hash#[]
|
34
34
|
def [](key)
|
35
|
-
|
36
|
-
Nanoc::Int::NotificationCenter.post(:visit_ended, unwrap)
|
37
|
-
|
35
|
+
@context.dependency_tracker.bounce(unwrap)
|
38
36
|
unwrap.attributes[key]
|
39
37
|
end
|
40
38
|
|
41
39
|
# @return [Hash]
|
42
40
|
def attributes
|
43
|
-
|
44
|
-
Nanoc::Int::NotificationCenter.post(:visit_ended, unwrap)
|
45
|
-
|
41
|
+
@context.dependency_tracker.bounce(unwrap)
|
46
42
|
unwrap.attributes
|
47
43
|
end
|
48
44
|
|
49
45
|
# @see Hash#fetch
|
50
46
|
def fetch(key, fallback = NONE, &_block)
|
51
|
-
|
52
|
-
Nanoc::Int::NotificationCenter.post(:visit_ended, unwrap)
|
47
|
+
@context.dependency_tracker.bounce(unwrap)
|
53
48
|
|
54
49
|
if unwrap.attributes.key?(key)
|
55
50
|
unwrap.attributes[key]
|
@@ -64,9 +59,7 @@ module Nanoc
|
|
64
59
|
|
65
60
|
# @see Hash#key?
|
66
61
|
def key?(key)
|
67
|
-
|
68
|
-
Nanoc::Int::NotificationCenter.post(:visit_ended, unwrap)
|
69
|
-
|
62
|
+
@context.dependency_tracker.bounce(unwrap)
|
70
63
|
unwrap.attributes.key?(key)
|
71
64
|
end
|
72
65
|
|
@@ -3,10 +3,14 @@ module Nanoc
|
|
3
3
|
class ViewContext
|
4
4
|
attr_reader :reps
|
5
5
|
attr_reader :items
|
6
|
+
attr_reader :dependency_tracker
|
7
|
+
attr_reader :compiler
|
6
8
|
|
7
|
-
def initialize(reps:, items:)
|
9
|
+
def initialize(reps:, items:, dependency_tracker:, compiler:)
|
8
10
|
@reps = reps
|
9
11
|
@items = items
|
12
|
+
@dependency_tracker = dependency_tracker
|
13
|
+
@compiler = compiler
|
10
14
|
end
|
11
15
|
end
|
12
16
|
end
|
@@ -298,12 +298,6 @@ module Nanoc::CLI::Commands
|
|
298
298
|
Nanoc::Int::NotificationCenter.on(:filtering_ended) do |rep, filter_name|
|
299
299
|
puts "*** Ended filtering #{rep.inspect} with #{filter_name}"
|
300
300
|
end
|
301
|
-
Nanoc::Int::NotificationCenter.on(:visit_started) do |item|
|
302
|
-
puts "*** Started visiting #{item.inspect}"
|
303
|
-
end
|
304
|
-
Nanoc::Int::NotificationCenter.on(:visit_ended) do |item|
|
305
|
-
puts "*** Ended visiting #{item.inspect}"
|
306
|
-
end
|
307
301
|
Nanoc::Int::NotificationCenter.on(:dependency_created) do |src, dst|
|
308
302
|
puts "*** Dependency created from #{src.inspect} onto #{dst.inspect}"
|
309
303
|
end
|
data/lib/nanoc/data_sources.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# @api private
|
2
2
|
module Nanoc::DataSources
|
3
|
-
autoload 'Filesystem', 'nanoc/data_sources/filesystem'
|
4
|
-
autoload 'FilesystemUnified', 'nanoc/data_sources/filesystem_unified'
|
5
|
-
|
6
|
-
Nanoc::DataSource.register '::Nanoc::DataSources::FilesystemUnified', :filesystem_unified
|
7
|
-
Nanoc::DataSource.register '::Nanoc::DataSources::FilesystemUnified', :filesystem
|
8
3
|
end
|
4
|
+
|
5
|
+
require_relative 'data_sources/filesystem'
|
6
|
+
|
7
|
+
Nanoc::DataSource.register ::Nanoc::DataSources::Filesystem, :filesystem
|
8
|
+
Nanoc::DataSource.register ::Nanoc::DataSources::Filesystem, :filesystem_unified
|
@@ -1,8 +1,51 @@
|
|
1
1
|
module Nanoc::DataSources
|
2
|
-
#
|
2
|
+
# The filesystem data source stores its items and layouts in nested
|
3
|
+
# directories. Items and layouts are represented by one or two files; if it
|
4
|
+
# is represented using one file, the metadata can be contained in this file.
|
5
|
+
#
|
6
|
+
# The default root directory for items is the `content` directory; for
|
7
|
+
# layouts, this is the `layouts` directory. This can be overridden
|
8
|
+
# in the data source configuration:
|
9
|
+
#
|
10
|
+
# data_sources:
|
11
|
+
# - type: filesystem
|
12
|
+
# content_dir: items
|
13
|
+
# layouts_dir: layouts
|
14
|
+
#
|
15
|
+
# The metadata for items and layouts can be stored in a separate file with
|
16
|
+
# the same base name but with the `.yaml` extension. If such a file is
|
17
|
+
# found, metadata is read from that file. Alternatively, the content file
|
18
|
+
# itself can start with a metadata section: it can be stored at the top of
|
19
|
+
# the file, between `---` (three dashes) separators. For example:
|
20
|
+
#
|
21
|
+
# ---
|
22
|
+
# title: "Moo!"
|
23
|
+
# ---
|
24
|
+
# h1. Hello!
|
25
|
+
#
|
26
|
+
# The metadata section can be omitted. If the file does not start with
|
27
|
+
# three or five dashes, the entire file will be considered as content.
|
28
|
+
#
|
29
|
+
# The identifier of items and layouts is the filename itself, without the
|
30
|
+
# root directory (as determined by the `content_dir` or `layouts_dir`
|
31
|
+
# configuration attribute, for items resp. layouts). For example:
|
32
|
+
#
|
33
|
+
# foo/bar/index.html → /foo/bar/index.html
|
34
|
+
# foo/bar.html → /foo/bar.html
|
35
|
+
#
|
36
|
+
# Note that each item must have an unique identifier. Nanoc will display an
|
37
|
+
# error if two items with the same identifier are found.
|
38
|
+
#
|
39
|
+
# The file extension does not determine the filters to run on items; the
|
40
|
+
# Rules file is used to specify processing instructors for each item.
|
41
|
+
#
|
42
|
+
# It is possible to set an explicit encoding that should be used when reading
|
43
|
+
# files. In the data source configuration, set `encoding` to an encoding
|
44
|
+
# understood by Ruby’s `Encoding`. If no encoding is set in the configuration,
|
45
|
+
# one will be inferred from the environment.
|
3
46
|
#
|
4
47
|
# @api private
|
5
|
-
|
48
|
+
class Filesystem < Nanoc::DataSource
|
6
49
|
# See {Nanoc::DataSource#up}.
|
7
50
|
def up
|
8
51
|
end
|
@@ -21,16 +64,72 @@ module Nanoc::DataSources
|
|
21
64
|
|
22
65
|
# See {Nanoc::DataSource#items}.
|
23
66
|
def items
|
24
|
-
load_objects(content_dir_name,
|
67
|
+
load_objects(content_dir_name, Nanoc::Int::Item)
|
25
68
|
end
|
26
69
|
|
27
70
|
# See {Nanoc::DataSource#layouts}.
|
28
71
|
def layouts
|
29
|
-
load_objects(layouts_dir_name,
|
72
|
+
load_objects(layouts_dir_name, Nanoc::Int::Layout)
|
30
73
|
end
|
31
74
|
|
32
75
|
protected
|
33
76
|
|
77
|
+
class ProtoDocument
|
78
|
+
attr_reader :attributes
|
79
|
+
attr_reader :checksum_data
|
80
|
+
attr_reader :is_binary
|
81
|
+
alias binary? is_binary
|
82
|
+
|
83
|
+
def initialize(is_binary:, content: nil, filename: nil, attributes:, checksum_data: nil)
|
84
|
+
if content.nil? && filename.nil?
|
85
|
+
raise ArgumentError, '#initialize needs at least content or filename'
|
86
|
+
end
|
87
|
+
|
88
|
+
@is_binary = is_binary
|
89
|
+
@content = content
|
90
|
+
@filename = filename
|
91
|
+
@attributes = attributes
|
92
|
+
@checksum_data = checksum_data
|
93
|
+
end
|
94
|
+
|
95
|
+
def content
|
96
|
+
if binary?
|
97
|
+
raise ArgumentError, 'cannot fetch content of binary item'
|
98
|
+
else
|
99
|
+
@content
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def filename
|
104
|
+
if binary?
|
105
|
+
@filename
|
106
|
+
else
|
107
|
+
raise ArgumentError, 'cannot fetch filename of non-binary item'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def read_proto_document(content_filename, meta_filename, klass)
|
113
|
+
is_binary = content_filename && !@site_config[:text_extensions].include?(File.extname(content_filename)[1..-1])
|
114
|
+
|
115
|
+
if is_binary && klass == Nanoc::Int::Item
|
116
|
+
meta = (meta_filename && YAML.load_file(meta_filename)) || {}
|
117
|
+
|
118
|
+
ProtoDocument.new(is_binary: true, filename: content_filename, attributes: meta)
|
119
|
+
elsif is_binary && klass == Nanoc::Int::Layout
|
120
|
+
raise "The layout file '#{content_filename}' is a binary file, but layouts can only be textual"
|
121
|
+
else
|
122
|
+
parse_result = parse(content_filename, meta_filename)
|
123
|
+
|
124
|
+
ProtoDocument.new(
|
125
|
+
is_binary: false,
|
126
|
+
content: parse_result.content,
|
127
|
+
attributes: parse_result.attributes,
|
128
|
+
checksum_data: "content=#{parse_result.content},meta=#{parse_result.attributes_data}",
|
129
|
+
)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
34
133
|
# Creates instances of klass corresponding to the files in dir_name. The
|
35
134
|
# kind attribute indicates the kind of object that is being loaded and is
|
36
135
|
# used solely for debugging purposes.
|
@@ -42,76 +141,75 @@ module Nanoc::DataSources
|
|
42
141
|
# metadata section.
|
43
142
|
#
|
44
143
|
# @see Nanoc::DataSources::Filesystem#load_objects
|
45
|
-
def load_objects(dir_name,
|
144
|
+
def load_objects(dir_name, klass)
|
46
145
|
res = []
|
47
146
|
|
48
147
|
return [] if dir_name.nil?
|
49
148
|
|
50
149
|
all_split_files_in(dir_name).each do |base_filename, (meta_ext, content_exts)|
|
51
150
|
content_exts.each do |content_ext|
|
52
|
-
# Get filenames
|
53
151
|
meta_filename = filename_for(base_filename, meta_ext)
|
54
152
|
content_filename = filename_for(base_filename, content_ext)
|
55
153
|
|
56
|
-
|
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
|
154
|
+
proto_doc = read_proto_document(content_filename, meta_filename, klass)
|
66
155
|
|
67
|
-
|
68
|
-
attributes =
|
69
|
-
|
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 content_filename
|
77
|
-
identifier = identifier_for_filename(content_filename[dir_name.length..-1])
|
78
|
-
elsif meta_filename
|
79
|
-
identifier = identifier_for_filename(meta_filename[dir_name.length..-1])
|
80
|
-
else
|
81
|
-
raise 'meta_filename and content_filename are both nil'
|
82
|
-
end
|
156
|
+
content = content_for(proto_doc, content_filename)
|
157
|
+
attributes = attributes_for(proto_doc, content_filename, meta_filename)
|
158
|
+
identifier = identifier_for(content_filename, meta_filename, dir_name)
|
83
159
|
|
84
|
-
|
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
|
-
attributes[:mtime] = mtime
|
97
|
-
|
98
|
-
# Create content
|
99
|
-
full_content_filename = content_filename && File.expand_path(content_filename)
|
100
|
-
content =
|
101
|
-
if is_binary
|
102
|
-
Nanoc::Int::BinaryContent.new(full_content_filename)
|
103
|
-
else
|
104
|
-
Nanoc::Int::TextualContent.new(content_or_filename, filename: full_content_filename)
|
105
|
-
end
|
106
|
-
|
107
|
-
# Create object
|
108
|
-
res << klass.new(content, attributes, identifier)
|
160
|
+
res << klass.new(content, attributes, identifier, checksum_data: proto_doc.checksum_data)
|
109
161
|
end
|
110
162
|
end
|
111
163
|
|
112
164
|
res
|
113
165
|
end
|
114
166
|
|
167
|
+
def attributes_for(proto_doc, content_filename, meta_filename)
|
168
|
+
extra_attributes = {
|
169
|
+
filename: content_filename,
|
170
|
+
content_filename: content_filename,
|
171
|
+
meta_filename: meta_filename,
|
172
|
+
extension: content_filename ? ext_of(content_filename)[1..-1] : nil,
|
173
|
+
mtime: mtime_of(content_filename, meta_filename),
|
174
|
+
}
|
175
|
+
|
176
|
+
extra_attributes.merge(proto_doc.attributes)
|
177
|
+
end
|
178
|
+
|
179
|
+
def identifier_for(content_filename, meta_filename, dir_name)
|
180
|
+
if content_filename
|
181
|
+
identifier_for_filename(content_filename[dir_name.length..-1])
|
182
|
+
elsif meta_filename
|
183
|
+
identifier_for_filename(meta_filename[dir_name.length..-1])
|
184
|
+
else
|
185
|
+
raise 'meta_filename and content_filename are both nil'
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def content_for(proto_doc, content_filename)
|
190
|
+
full_content_filename = content_filename && File.expand_path(content_filename)
|
191
|
+
|
192
|
+
if proto_doc.binary?
|
193
|
+
Nanoc::Int::BinaryContent.new(full_content_filename)
|
194
|
+
else
|
195
|
+
Nanoc::Int::TextualContent.new(proto_doc.content, filename: full_content_filename)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def mtime_of(content_filename, meta_filename)
|
200
|
+
meta_mtime = meta_filename ? File.stat(meta_filename).mtime : nil
|
201
|
+
content_mtime = content_filename ? File.stat(content_filename).mtime : nil
|
202
|
+
if meta_mtime && content_mtime
|
203
|
+
meta_mtime > content_mtime ? meta_mtime : content_mtime
|
204
|
+
elsif meta_mtime
|
205
|
+
meta_mtime
|
206
|
+
elsif content_mtime
|
207
|
+
content_mtime
|
208
|
+
else
|
209
|
+
raise 'meta_mtime and content_mtime are both nil'
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
115
213
|
# e.g.
|
116
214
|
#
|
117
215
|
# {
|
@@ -167,18 +265,30 @@ module Nanoc::DataSources
|
|
167
265
|
# data sources may prefer to implement this differently (for example,
|
168
266
|
# {Nanoc::DataSources::FilesystemVerbose} doubles the last part of the
|
169
267
|
# basename before concatenating it with a period and the extension).
|
170
|
-
def filename_for(
|
171
|
-
|
172
|
-
|
173
|
-
|
268
|
+
def filename_for(base_filename, ext)
|
269
|
+
if ext.nil?
|
270
|
+
nil
|
271
|
+
elsif ext.empty?
|
272
|
+
base_filename
|
273
|
+
else
|
274
|
+
base_filename + '.' + ext
|
275
|
+
end
|
174
276
|
end
|
175
277
|
|
176
278
|
# Returns the identifier that corresponds with the given filename, which
|
177
279
|
# can be the content filename or the meta filename.
|
178
|
-
def identifier_for_filename(
|
179
|
-
|
180
|
-
|
181
|
-
|
280
|
+
def identifier_for_filename(filename)
|
281
|
+
if config[:identifier_type] == 'full'
|
282
|
+
return Nanoc::Identifier.new(filename)
|
283
|
+
end
|
284
|
+
|
285
|
+
regex =
|
286
|
+
if filename =~ /(^|\/)index(\.[^\/]+)?$/
|
287
|
+
@config && @config[:allow_periods_in_identifiers] ? /\/?(index)?(\.[^\/\.]+)?$/ : /\/?index(\.[^\/]+)?$/
|
288
|
+
else
|
289
|
+
@config && @config[:allow_periods_in_identifiers] ? /\.[^\/\.]+$/ : /\.[^\/]+$/
|
290
|
+
end
|
291
|
+
Nanoc::Identifier.new(filename.sub(regex, ''), type: :legacy)
|
182
292
|
end
|
183
293
|
|
184
294
|
# Returns the base name of filename, i.e. filename with the first or all
|
@@ -198,6 +308,8 @@ module Nanoc::DataSources
|
|
198
308
|
# Returns a regex that is used for determining the extension of a file
|
199
309
|
# name. The first match group will be the entire extension, including the
|
200
310
|
# leading period.
|
311
|
+
#
|
312
|
+
# @return [Regex]
|
201
313
|
def extension_regex
|
202
314
|
if @config && @config[:allow_periods_in_identifiers]
|
203
315
|
/(\.[^\/\.]+$)/
|
@@ -206,32 +318,31 @@ module Nanoc::DataSources
|
|
206
318
|
end
|
207
319
|
end
|
208
320
|
|
209
|
-
#
|
210
|
-
|
211
|
-
# file content itself.
|
212
|
-
def parse(content_filename, meta_filename, _kind)
|
213
|
-
# Read content and metadata from separate files
|
321
|
+
# @return [ParseResult]
|
322
|
+
def parse(content_filename, meta_filename)
|
214
323
|
if meta_filename
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
meta = YAML.load(meta_raw) || {}
|
219
|
-
rescue Exception => e
|
220
|
-
raise "Could not parse YAML for #{meta_filename}: #{e.message}"
|
221
|
-
end
|
222
|
-
verify_meta(meta, meta_filename)
|
223
|
-
return [meta, content]
|
324
|
+
parse_with_separate_meta_filename(content_filename, meta_filename)
|
325
|
+
else
|
326
|
+
parse_with_frontmatter(content_filename)
|
224
327
|
end
|
328
|
+
end
|
329
|
+
|
330
|
+
# @return [ParseResult]
|
331
|
+
def parse_with_separate_meta_filename(content_filename, meta_filename)
|
332
|
+
content = content_filename ? read(content_filename) : ''
|
333
|
+
meta_raw = read(meta_filename)
|
334
|
+
meta = parse_metadata(meta_raw, meta_filename)
|
335
|
+
ParseResult.new(content: content, attributes: meta, attributes_data: meta_raw)
|
336
|
+
end
|
225
337
|
|
226
|
-
|
338
|
+
# @return [ParseResult]
|
339
|
+
def parse_with_frontmatter(content_filename)
|
227
340
|
data = read(content_filename)
|
228
341
|
|
229
|
-
# Check presence of metadata section
|
230
342
|
if data !~ /\A-{3,5}\s*$/
|
231
|
-
return
|
343
|
+
return ParseResult.new(content: data, attributes: {}, attributes_data: '')
|
232
344
|
end
|
233
345
|
|
234
|
-
# Split data
|
235
346
|
pieces = data.split(/^(-{5}|-{3})[ \t]*\r?\n?/, 3)
|
236
347
|
if pieces.size < 4
|
237
348
|
raise RuntimeError.new(
|
@@ -239,17 +350,35 @@ module Nanoc::DataSources
|
|
239
350
|
)
|
240
351
|
end
|
241
352
|
|
242
|
-
|
353
|
+
meta = parse_metadata(pieces[2], content_filename)
|
354
|
+
content = pieces[4]
|
355
|
+
|
356
|
+
ParseResult.new(content: content, attributes: meta, attributes_data: pieces[2])
|
357
|
+
end
|
358
|
+
|
359
|
+
# @return [Hash]
|
360
|
+
def parse_metadata(data, filename)
|
243
361
|
begin
|
244
|
-
meta = YAML.load(
|
362
|
+
meta = YAML.load(data) || {}
|
245
363
|
rescue Exception => e
|
246
|
-
raise "Could not parse YAML for #{
|
364
|
+
raise "Could not parse YAML for #{filename}: #{e.message}"
|
247
365
|
end
|
248
|
-
verify_meta(meta, content_filename)
|
249
|
-
content = pieces[4]
|
250
366
|
|
251
|
-
|
252
|
-
|
367
|
+
verify_meta(meta, filename)
|
368
|
+
|
369
|
+
meta
|
370
|
+
end
|
371
|
+
|
372
|
+
class ParseResult
|
373
|
+
attr_reader :content
|
374
|
+
attr_reader :attributes
|
375
|
+
attr_reader :attributes_data
|
376
|
+
|
377
|
+
def initialize(content:, attributes:, attributes_data:)
|
378
|
+
@content = content
|
379
|
+
@attributes = attributes
|
380
|
+
@attributes_data = attributes_data
|
381
|
+
end
|
253
382
|
end
|
254
383
|
|
255
384
|
class InvalidMetadataError < Nanoc::Error
|