nanoc 4.1.6 → 4.2.0b1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|