nanoc2 2.2.3

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.
Files changed (100) hide show
  1. data/ChangeLog +3 -0
  2. data/LICENSE +19 -0
  3. data/README +75 -0
  4. data/Rakefile +76 -0
  5. data/bin/nanoc2 +26 -0
  6. data/lib/nanoc2.rb +73 -0
  7. data/lib/nanoc2/base.rb +26 -0
  8. data/lib/nanoc2/base/asset.rb +117 -0
  9. data/lib/nanoc2/base/asset_defaults.rb +21 -0
  10. data/lib/nanoc2/base/asset_rep.rb +282 -0
  11. data/lib/nanoc2/base/binary_filter.rb +44 -0
  12. data/lib/nanoc2/base/code.rb +41 -0
  13. data/lib/nanoc2/base/compiler.rb +67 -0
  14. data/lib/nanoc2/base/core_ext.rb +2 -0
  15. data/lib/nanoc2/base/core_ext/hash.rb +78 -0
  16. data/lib/nanoc2/base/core_ext/string.rb +8 -0
  17. data/lib/nanoc2/base/data_source.rb +286 -0
  18. data/lib/nanoc2/base/defaults.rb +30 -0
  19. data/lib/nanoc2/base/filter.rb +93 -0
  20. data/lib/nanoc2/base/layout.rb +91 -0
  21. data/lib/nanoc2/base/notification_center.rb +66 -0
  22. data/lib/nanoc2/base/page.rb +132 -0
  23. data/lib/nanoc2/base/page_defaults.rb +20 -0
  24. data/lib/nanoc2/base/page_rep.rb +324 -0
  25. data/lib/nanoc2/base/plugin.rb +71 -0
  26. data/lib/nanoc2/base/proxies.rb +5 -0
  27. data/lib/nanoc2/base/proxies/asset_proxy.rb +29 -0
  28. data/lib/nanoc2/base/proxies/asset_rep_proxy.rb +26 -0
  29. data/lib/nanoc2/base/proxies/layout_proxy.rb +25 -0
  30. data/lib/nanoc2/base/proxies/page_proxy.rb +35 -0
  31. data/lib/nanoc2/base/proxies/page_rep_proxy.rb +28 -0
  32. data/lib/nanoc2/base/proxy.rb +37 -0
  33. data/lib/nanoc2/base/router.rb +72 -0
  34. data/lib/nanoc2/base/site.rb +274 -0
  35. data/lib/nanoc2/base/template.rb +64 -0
  36. data/lib/nanoc2/binary_filters.rb +1 -0
  37. data/lib/nanoc2/binary_filters/image_science_thumbnail.rb +28 -0
  38. data/lib/nanoc2/cli.rb +9 -0
  39. data/lib/nanoc2/cli/base.rb +132 -0
  40. data/lib/nanoc2/cli/commands.rb +10 -0
  41. data/lib/nanoc2/cli/commands/autocompile.rb +80 -0
  42. data/lib/nanoc2/cli/commands/compile.rb +312 -0
  43. data/lib/nanoc2/cli/commands/create_layout.rb +85 -0
  44. data/lib/nanoc2/cli/commands/create_page.rb +85 -0
  45. data/lib/nanoc2/cli/commands/create_site.rb +323 -0
  46. data/lib/nanoc2/cli/commands/create_template.rb +76 -0
  47. data/lib/nanoc2/cli/commands/help.rb +69 -0
  48. data/lib/nanoc2/cli/commands/info.rb +125 -0
  49. data/lib/nanoc2/cli/commands/switch.rb +141 -0
  50. data/lib/nanoc2/cli/commands/update.rb +91 -0
  51. data/lib/nanoc2/cli/logger.rb +72 -0
  52. data/lib/nanoc2/data_sources.rb +2 -0
  53. data/lib/nanoc2/data_sources/filesystem.rb +707 -0
  54. data/lib/nanoc2/data_sources/filesystem_combined.rb +495 -0
  55. data/lib/nanoc2/extra.rb +6 -0
  56. data/lib/nanoc2/extra/auto_compiler.rb +285 -0
  57. data/lib/nanoc2/extra/context.rb +22 -0
  58. data/lib/nanoc2/extra/core_ext.rb +2 -0
  59. data/lib/nanoc2/extra/core_ext/hash.rb +54 -0
  60. data/lib/nanoc2/extra/core_ext/time.rb +13 -0
  61. data/lib/nanoc2/extra/file_proxy.rb +29 -0
  62. data/lib/nanoc2/extra/vcs.rb +48 -0
  63. data/lib/nanoc2/extra/vcses.rb +5 -0
  64. data/lib/nanoc2/extra/vcses/bazaar.rb +21 -0
  65. data/lib/nanoc2/extra/vcses/dummy.rb +20 -0
  66. data/lib/nanoc2/extra/vcses/git.rb +21 -0
  67. data/lib/nanoc2/extra/vcses/mercurial.rb +21 -0
  68. data/lib/nanoc2/extra/vcses/subversion.rb +21 -0
  69. data/lib/nanoc2/filters.rb +16 -0
  70. data/lib/nanoc2/filters/bluecloth.rb +13 -0
  71. data/lib/nanoc2/filters/erb.rb +19 -0
  72. data/lib/nanoc2/filters/erubis.rb +14 -0
  73. data/lib/nanoc2/filters/haml.rb +21 -0
  74. data/lib/nanoc2/filters/markaby.rb +14 -0
  75. data/lib/nanoc2/filters/maruku.rb +14 -0
  76. data/lib/nanoc2/filters/old.rb +19 -0
  77. data/lib/nanoc2/filters/rainpress.rb +13 -0
  78. data/lib/nanoc2/filters/rdiscount.rb +13 -0
  79. data/lib/nanoc2/filters/rdoc.rb +23 -0
  80. data/lib/nanoc2/filters/redcloth.rb +14 -0
  81. data/lib/nanoc2/filters/relativize_paths.rb +16 -0
  82. data/lib/nanoc2/filters/relativize_paths_in_css.rb +16 -0
  83. data/lib/nanoc2/filters/relativize_paths_in_html.rb +16 -0
  84. data/lib/nanoc2/filters/rubypants.rb +14 -0
  85. data/lib/nanoc2/filters/sass.rb +18 -0
  86. data/lib/nanoc2/helpers.rb +9 -0
  87. data/lib/nanoc2/helpers/blogging.rb +217 -0
  88. data/lib/nanoc2/helpers/capturing.rb +63 -0
  89. data/lib/nanoc2/helpers/filtering.rb +54 -0
  90. data/lib/nanoc2/helpers/html_escape.rb +25 -0
  91. data/lib/nanoc2/helpers/link_to.rb +113 -0
  92. data/lib/nanoc2/helpers/render.rb +49 -0
  93. data/lib/nanoc2/helpers/tagging.rb +56 -0
  94. data/lib/nanoc2/helpers/text.rb +38 -0
  95. data/lib/nanoc2/helpers/xml_sitemap.rb +63 -0
  96. data/lib/nanoc2/routers.rb +3 -0
  97. data/lib/nanoc2/routers/default.rb +54 -0
  98. data/lib/nanoc2/routers/no_dirs.rb +66 -0
  99. data/lib/nanoc2/routers/versioned.rb +79 -0
  100. metadata +185 -0
@@ -0,0 +1,495 @@
1
+ module Nanoc2::DataSources
2
+
3
+ # = Pages
4
+ #
5
+ # The filesystem data source stores its pages in nested directories. A page
6
+ # is represented by a single file. The root directory is the 'content'
7
+ # directory.
8
+ #
9
+ # The metadata for a page is embedded into the file itself. It is stored at
10
+ # the top of the file, between '-----' (five dashes) separators. For
11
+ # example:
12
+ #
13
+ # -----
14
+ # filters_pre: [ 'redcloth' ]
15
+ # -----
16
+ # h1. Hello!
17
+ #
18
+ # The path of a page is determined as follows. A file with an 'index.*'
19
+ # filename, such as 'index.txt', will have the filesystem path with the
20
+ # 'index.*' part stripped as a path. For example, 'foo/bar/index.html' will
21
+ # have '/foo/bar/' as path.
22
+ #
23
+ # A file with a filename not starting with 'index.', such as 'foo.html',
24
+ # will have a path ending in 'foo/'. For example, 'foo/bar.html' will have
25
+ # '/foo/bar/' as path.
26
+ #
27
+ # Note that it is possible for two different, separate files to have the
28
+ # same path. It is therefore recommended to avoid such situations.
29
+ #
30
+ # Some more examples:
31
+ #
32
+ # content/index.html --> /
33
+ # content/foo.html --> /foo/
34
+ # content/foo/index.html --> /foo/
35
+ # content/foo/bar.html --> /foo/bar/
36
+ # content/foo/bar/index.html --> /foo/bar/
37
+ #
38
+ # File extensions are ignored by nanoc. The file extension does not
39
+ # determine the filters to run on it; the metadata in the file defines the
40
+ # list of filters.
41
+ #
42
+ # = Page defaults
43
+ #
44
+ # The page defaults are loaded from a YAML-formatted file named
45
+ # 'page_defaults.yaml' at the top level of the nanoc site directory. For
46
+ # backward compatibility, the file can also be named 'meta.yaml'.
47
+ #
48
+ # = Assets
49
+ #
50
+ # Assets are stored in a way similar to pages. The attributes are merged
51
+ # into the asset. This does mean, however, that only textual assets are
52
+ # supported, as there is no way to embed attributes in binary assets.
53
+ #
54
+ # = Asset defaults
55
+ #
56
+ # The asset defaults are stored similar to the way page defaults are stored,
57
+ # except that the asset defaults file is named 'asset_defaults.yaml'
58
+ # instead.
59
+ #
60
+ # = Layouts
61
+ #
62
+ # Layouts are stored as files in the 'layouts' directory. Similar to pages,
63
+ # each layout consists of a metadata part and a content part, separated by
64
+ # '-----'.
65
+ #
66
+ # = Templates
67
+ #
68
+ # Templates are located in the 'templates' directory. Templates are, just
69
+ # like pages, files consisting of a metadata part and a content part,
70
+ # separated by '-----'.
71
+ #
72
+ # = Code
73
+ #
74
+ # Code is stored in '.rb' files in the 'lib' directory. Code can reside in
75
+ # sub-directories.
76
+ class FilesystemCombined < Nanoc2::DataSource
77
+
78
+ PAGE_DEFAULTS_FILENAME = 'page_defaults.yaml'
79
+ PAGE_DEFAULTS_FILENAME_OLD = 'meta.yaml'
80
+ ASSET_DEFAULTS_FILENAME = 'asset_defaults.yaml'
81
+
82
+ ########## Attributes ##########
83
+
84
+ identifier :filesystem_combined
85
+
86
+ ########## VCSes ##########
87
+
88
+ attr_accessor :vcs
89
+
90
+ def vcs
91
+ @vcs ||= Nanoc2::Extra::VCSes::Dummy.new
92
+ end
93
+
94
+ ########## Preparation ##########
95
+
96
+ def up # :nodoc:
97
+ end
98
+
99
+ def down # :nodoc:
100
+ end
101
+
102
+ def setup # :nodoc:
103
+ # Create directories
104
+ %w( assets content templates layouts lib ).each do |dir|
105
+ FileUtils.mkdir_p(dir)
106
+ vcs.add(dir)
107
+ end
108
+ end
109
+
110
+ def destroy # :nodoc:
111
+ # Remove files
112
+ vcs.remove(ASSET_DEFAULTS_FILENAME) if File.file?(ASSET_DEFAULTS_FILENAME)
113
+ vcs.remove(PAGE_DEFAULTS_FILENAME) if File.file?(PAGE_DEFAULTS_FILENAME)
114
+ vcs.remove(PAGE_DEFAULTS_FILENAME_OLD) if File.file?(PAGE_DEFAULTS_FILENAME_OLD)
115
+
116
+ # Remove directories
117
+ vcs.remove('assets')
118
+ vcs.remove('content')
119
+ vcs.remove('templates')
120
+ vcs.remove('layouts')
121
+ vcs.remove('lib')
122
+ end
123
+
124
+ ########## Pages ##########
125
+
126
+ def pages # :nodoc:
127
+ files('content', true).map do |filename|
128
+ # Read and parse data
129
+ meta, content = *parse_file(filename, 'page')
130
+
131
+ # Skip drafts
132
+ return nil if meta[:is_draft]
133
+
134
+ # Get attributes
135
+ attributes = meta.merge(:file => Nanoc2::Extra::FileProxy.new(filename))
136
+
137
+ # Get actual path
138
+ if filename =~ /\/index\.[^\/]+$/
139
+ path = filename.sub(/^content/, '').sub(/index\.[^\/]+$/, '') + '/'
140
+ else
141
+ path = filename.sub(/^content/, '').sub(/\.[^\/]+$/, '') + '/'
142
+ end
143
+
144
+ # Get mtime
145
+ mtime = File.stat(filename).mtime
146
+
147
+ # Build page
148
+ Nanoc2::Page.new(content, attributes, path, mtime)
149
+ end.compact
150
+ end
151
+
152
+ def save_page(page) # :nodoc:
153
+ # Find page path
154
+ if page.path == '/'
155
+ paths = Dir['content/index.*']
156
+ path = paths[0] || 'content/index.html'
157
+ parent_path = '/'
158
+ else
159
+ last_path_component = page.path.split('/')[-1]
160
+ paths_best = Dir['content' + page.path[0..-2] + '.*']
161
+ paths_worst = Dir['content' + page.path + 'index.*']
162
+ path_default = 'content' + page.path[0..-2] + '.html'
163
+ path = paths_best[0] || paths_worst[0] || path_default
164
+ parent_path = '/' + File.join(page.path.split('/')[0..-2])
165
+ end
166
+
167
+ # Notify
168
+ if File.file?(path)
169
+ created = false
170
+ Nanoc2::NotificationCenter.post(:file_updated, path)
171
+ else
172
+ created = true
173
+ Nanoc2::NotificationCenter.post(:file_created, path)
174
+ end
175
+
176
+ # Write page
177
+ FileUtils.mkdir_p('content' + parent_path)
178
+ File.open(path, 'w') do |io|
179
+ io.write("-----\n")
180
+ io.write(page.attributes.to_split_yaml + "\n")
181
+ io.write("-----\n")
182
+ io.write(page.content)
183
+ end
184
+
185
+ # Add to working copy if possible
186
+ vcs.add(path) if created
187
+ end
188
+
189
+ def move_page(page, new_path) # :nodoc:
190
+ # TODO implement
191
+ end
192
+
193
+ def delete_page(page) # :nodoc:
194
+ # TODO implement
195
+ end
196
+
197
+ ########## Assets ##########
198
+
199
+ def assets # :nodoc:
200
+ files('assets', true).map do |filename|
201
+ # Read and parse data
202
+ meta, content = *parse_file(filename, 'asset')
203
+
204
+ # Skip drafts
205
+ return nil if meta[:is_draft]
206
+
207
+ # Get attributes
208
+ attributes = { 'extension' => File.extname(filename)[1..-1] }.merge(meta)
209
+
210
+ # Get actual path
211
+ if filename =~ /\/index\.[^\/]+$/
212
+ path = filename.sub(/^assets/, '').sub(/index\.[^\/]+$/, '') + '/'
213
+ else
214
+ path = filename.sub(/^assets/, '').sub(/\.[^\/]+$/, '') + '/'
215
+ end
216
+
217
+ # Get mtime
218
+ mtime = File.stat(filename).mtime
219
+
220
+ # Build asset
221
+ Nanoc2::Asset.new(StringIO.new(content), attributes, path, mtime)
222
+ end.compact
223
+ end
224
+
225
+ def save_asset(asset) # :nodoc:
226
+ # TODO implement
227
+ end
228
+
229
+ def move_asset(asset, new_path) # :nodoc:
230
+ # TODO implement
231
+ end
232
+
233
+ def delete_asset(asset) # :nodoc:
234
+ # TODO implement
235
+ end
236
+
237
+ ########## Page Defaults ##########
238
+
239
+ def page_defaults # :nodoc:
240
+ # Get attributes
241
+ filename = File.file?(PAGE_DEFAULTS_FILENAME) ? PAGE_DEFAULTS_FILENAME : PAGE_DEFAULTS_FILENAME_OLD
242
+ attributes = YAML.load_file(filename) || {}
243
+
244
+ # Get mtime
245
+ mtime = File.stat(filename).mtime
246
+
247
+ # Build page defaults
248
+ Nanoc2::PageDefaults.new(attributes, mtime)
249
+ end
250
+
251
+ def save_page_defaults(page_defaults) # :nodoc:
252
+ # Notify
253
+ if File.file?(PAGE_DEFAULTS_FILENAME)
254
+ filename = PAGE_DEFAULTS_FILENAME
255
+ created = false
256
+ Nanoc2::NotificationCenter.post(:file_updated, filename)
257
+ elsif File.file?(PAGE_DEFAULTS_FILENAME_OLD)
258
+ filename = PAGE_DEFAULTS_FILENAME_OLD
259
+ created = false
260
+ Nanoc2::NotificationCenter.post(:file_updated, filename)
261
+ else
262
+ filename = PAGE_DEFAULTS_FILENAME
263
+ created = true
264
+ Nanoc2::NotificationCenter.post(:file_created, filename)
265
+ end
266
+
267
+ # Write
268
+ File.open(filename, 'w') do |io|
269
+ io.write(page_defaults.attributes.to_split_yaml)
270
+ end
271
+
272
+ # Add to working copy if possible
273
+ vcs.add(filename) if created
274
+ end
275
+
276
+ ########## Asset defaults ##########
277
+
278
+ def asset_defaults # :nodoc:
279
+ if File.file?(ASSET_DEFAULTS_FILENAME)
280
+ # Get attributes
281
+ attributes = YAML.load_file(ASSET_DEFAULTS_FILENAME) || {}
282
+
283
+ # Get mtime
284
+ mtime = File.stat(ASSET_DEFAULTS_FILENAME).mtime
285
+
286
+ # Build asset defaults
287
+ Nanoc2::AssetDefaults.new(attributes, mtime)
288
+ else
289
+ Nanoc2::AssetDefaults.new({})
290
+ end
291
+ end
292
+
293
+ def save_asset_defaults(asset_defaults) # :nodoc:
294
+ # Notify
295
+ if File.file?(ASSET_DEFAULTS_FILENAME)
296
+ Nanoc2::NotificationCenter.post(:file_updated, ASSET_DEFAULTS_FILENAME)
297
+ created = false
298
+ else
299
+ Nanoc2::NotificationCenter.post(:file_created, ASSET_DEFAULTS_FILENAME)
300
+ created = true
301
+ end
302
+
303
+ # Write
304
+ File.open(ASSET_DEFAULTS_FILENAME, 'w') do |io|
305
+ io.write(asset_defaults.attributes.to_split_yaml)
306
+ end
307
+
308
+ # Add to working copy if possible
309
+ vcs.add(ASSET_DEFAULTS_FILENAME) if created
310
+ end
311
+
312
+ ########## Layouts ##########
313
+
314
+ def layouts # :nodoc:
315
+ files('layouts', true).map do |filename|
316
+ # Read and parse data
317
+ meta, content = *parse_file(filename, 'layout')
318
+
319
+ # Get actual path
320
+ if filename =~ /\/index\.[^\/]+$/
321
+ path = filename.sub(/^layouts/, '').sub(/index\.[^\/]+$/, '') + '/'
322
+ else
323
+ path = filename.sub(/^layouts/, '').sub(/\.[^\/]+$/, '') + '/'
324
+ end
325
+
326
+ # Get mtime
327
+ mtime = File.stat(filename).mtime
328
+
329
+ # Build layout
330
+ Nanoc2::Layout.new(content, meta, path, mtime)
331
+ end.compact
332
+ end
333
+
334
+ def save_layout(layout) # :nodoc:
335
+ # Find layout path
336
+ last_path_component = layout.path.split('/')[-1]
337
+ paths_best = Dir['layouts' + layout.path[0..-2] + '.*']
338
+ paths_worst = Dir['layouts' + layout.path + 'index.*']
339
+ path_default = 'layouts' + layout.path[0..-2] + '.html'
340
+ path = paths_best[0] || paths_worst[0] || path_default
341
+ parent_path = '/' + File.join(layout.path.split('/')[0..-2])
342
+
343
+ # Notify
344
+ if File.file?(path)
345
+ created = false
346
+ Nanoc2::NotificationCenter.post(:file_updated, path)
347
+ else
348
+ created = true
349
+ Nanoc2::NotificationCenter.post(:file_created, path)
350
+ end
351
+
352
+ # Write layout
353
+ FileUtils.mkdir_p('layouts' + parent_path)
354
+ File.open(path, 'w') do |io|
355
+ io.write("-----\n")
356
+ io.write(layout.attributes.to_split_yaml + "\n")
357
+ io.write("-----\n")
358
+ io.write(layout.content)
359
+ end
360
+
361
+ # Add to working copy if possible
362
+ vcs.add(path) if created
363
+ end
364
+
365
+ def move_layout(layout, new_path) # :nodoc:
366
+ # TODO implement
367
+ end
368
+
369
+ def delete_layout(layout) # :nodoc:
370
+ # TODO implement
371
+ end
372
+
373
+ ########## Templates ##########
374
+
375
+ def templates # :nodoc:
376
+ files('templates', false).map do |filename|
377
+ # Read and parse data
378
+ meta, content = *parse_file(filename, 'template')
379
+
380
+ # Get name
381
+ name = filename.sub(/^templates\//, '').sub(/\.[^\/]+$/, '')
382
+
383
+ # Build template
384
+ Nanoc2::Template.new(content, meta, name)
385
+ end.compact
386
+ end
387
+
388
+ def save_template(template) # :nodoc:
389
+ # Get template path
390
+ paths = Dir[File.join('templates', template.name) + '.*']
391
+ path_default = File.join('templates', template.name) + '.html'
392
+ path = paths[0] || path_default
393
+
394
+ # Notify
395
+ if File.file?(path)
396
+ created = false
397
+ Nanoc2::NotificationCenter.post(:file_updated, path)
398
+ else
399
+ created = true
400
+ Nanoc2::NotificationCenter.post(:file_created, path)
401
+ end
402
+
403
+ # Write template
404
+ File.open(path, 'w') do |io|
405
+ io.write("-----\n")
406
+ io.write(template.page_attributes.to_split_yaml + "\n")
407
+ io.write("-----\n")
408
+ io.write(template.page_content)
409
+ end
410
+
411
+ # Add to working copy if possible
412
+ vcs.add(path) if created
413
+ end
414
+
415
+ def move_template(template, new_name) # :nodoc:
416
+ # TODO implement
417
+ end
418
+
419
+ def delete_template(template) # :nodoc:
420
+ # TODO implement
421
+ end
422
+
423
+ ########## Code ##########
424
+
425
+ def code # :nodoc:
426
+ # Get data
427
+ data = Dir['lib/**/*.rb'].sort.map { |filename| File.read(filename) + "\n" }.join('')
428
+
429
+ # Get modification time
430
+ mtime = Dir['lib/**/*.rb'].map { |filename| File.stat(filename).mtime }.inject { |memo, mtime| memo > mtime ? mtime : memo}
431
+
432
+ # Build code
433
+ Nanoc2::Code.new(data, mtime)
434
+ end
435
+
436
+ def save_code(code) # :nodoc:
437
+ # Check whether code existed
438
+ existed = File.file?('lib/default.rb')
439
+
440
+ # Remove all existing code files
441
+ Dir['lib/**/*.rb'].each do |file|
442
+ vcs.remove(file) unless file == 'lib/default.rb'
443
+ end
444
+
445
+ # Notify
446
+ if existed
447
+ Nanoc2::NotificationCenter.post(:file_updated, 'lib/default.rb')
448
+ else
449
+ Nanoc2::NotificationCenter.post(:file_created, 'lib/default.rb')
450
+ end
451
+
452
+ # Write new code
453
+ File.open('lib/default.rb', 'w') do |io|
454
+ io.write(code.data)
455
+ end
456
+
457
+ # Add to working copy if possible
458
+ vcs.add('lib/default.rb') unless existed
459
+ end
460
+
461
+ private
462
+
463
+ # Returns a list of all files in +dir+, ignoring any unwanted files (files
464
+ # that end with '~', '.orig', '.rej' or '.bak').
465
+ #
466
+ # +recursively+:: When +true+, finds files in +dir+ as well as its
467
+ # subdirectories; when +false+, only searches +dir+
468
+ # itself.
469
+ def files(dir, recursively)
470
+ glob = File.join([dir] + (recursively ? [ '**', '*' ] : [ '*' ]))
471
+ Dir[glob].reject { |f| File.directory?(f) or f =~ /(~|\.orig|\.rej|\.bak)$/ }
472
+ end
473
+
474
+ # Parses the file named +filename+ and returns an array with its first
475
+ # element a hash with the file's metadata, and with its second element the
476
+ # file content itself.
477
+ def parse_file(filename, kind)
478
+ # Split file
479
+ pieces = File.read(filename).split(/^-----/)
480
+ if pieces.size < 3
481
+ raise RuntimeError.new(
482
+ "The file '#{filename}' does not seem to be a nanoc #{kind}"
483
+ )
484
+ end
485
+
486
+ # Parse
487
+ meta = YAML.load(pieces[1]) || {}
488
+ content = pieces[2..-1].join.strip
489
+
490
+ [ meta, content ]
491
+ end
492
+
493
+ end
494
+
495
+ end