nanoc3 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +3 -0
- data/LICENSE +19 -0
- data/NEWS.rdoc +262 -0
- data/README.rdoc +80 -0
- data/Rakefile +11 -0
- data/bin/nanoc3 +16 -0
- data/lib/nanoc3/base/code_snippet.rb +42 -0
- data/lib/nanoc3/base/compiler.rb +225 -0
- data/lib/nanoc3/base/compiler_dsl.rb +110 -0
- data/lib/nanoc3/base/core_ext/array.rb +21 -0
- data/lib/nanoc3/base/core_ext/hash.rb +23 -0
- data/lib/nanoc3/base/core_ext/string.rb +14 -0
- data/lib/nanoc3/base/core_ext.rb +5 -0
- data/lib/nanoc3/base/data_source.rb +197 -0
- data/lib/nanoc3/base/dependency_tracker.rb +291 -0
- data/lib/nanoc3/base/errors.rb +95 -0
- data/lib/nanoc3/base/filter.rb +60 -0
- data/lib/nanoc3/base/item.rb +87 -0
- data/lib/nanoc3/base/item_rep.rb +236 -0
- data/lib/nanoc3/base/layout.rb +53 -0
- data/lib/nanoc3/base/notification_center.rb +68 -0
- data/lib/nanoc3/base/plugin.rb +88 -0
- data/lib/nanoc3/base/preprocessor_context.rb +37 -0
- data/lib/nanoc3/base/rule.rb +37 -0
- data/lib/nanoc3/base/rule_context.rb +68 -0
- data/lib/nanoc3/base/site.rb +334 -0
- data/lib/nanoc3/base.rb +25 -0
- data/lib/nanoc3/cli/base.rb +151 -0
- data/lib/nanoc3/cli/commands/autocompile.rb +89 -0
- data/lib/nanoc3/cli/commands/compile.rb +279 -0
- data/lib/nanoc3/cli/commands/create_item.rb +79 -0
- data/lib/nanoc3/cli/commands/create_layout.rb +94 -0
- data/lib/nanoc3/cli/commands/create_site.rb +320 -0
- data/lib/nanoc3/cli/commands/help.rb +71 -0
- data/lib/nanoc3/cli/commands/info.rb +114 -0
- data/lib/nanoc3/cli/commands/update.rb +96 -0
- data/lib/nanoc3/cli/commands.rb +13 -0
- data/lib/nanoc3/cli/logger.rb +73 -0
- data/lib/nanoc3/cli.rb +16 -0
- data/lib/nanoc3/data_sources/delicious.rb +66 -0
- data/lib/nanoc3/data_sources/filesystem.rb +231 -0
- data/lib/nanoc3/data_sources/filesystem_combined.rb +202 -0
- data/lib/nanoc3/data_sources/filesystem_common.rb +22 -0
- data/lib/nanoc3/data_sources/filesystem_compact.rb +232 -0
- data/lib/nanoc3/data_sources/last_fm.rb +103 -0
- data/lib/nanoc3/data_sources/twitter.rb +53 -0
- data/lib/nanoc3/data_sources.rb +20 -0
- data/lib/nanoc3/extra/auto_compiler.rb +97 -0
- data/lib/nanoc3/extra/chick.rb +119 -0
- data/lib/nanoc3/extra/context.rb +24 -0
- data/lib/nanoc3/extra/core_ext/time.rb +19 -0
- data/lib/nanoc3/extra/core_ext.rb +3 -0
- data/lib/nanoc3/extra/deployers/rsync.rb +64 -0
- data/lib/nanoc3/extra/deployers.rb +12 -0
- data/lib/nanoc3/extra/file_proxy.rb +31 -0
- data/lib/nanoc3/extra/validators/links.rb +0 -0
- data/lib/nanoc3/extra/validators/w3c.rb +71 -0
- data/lib/nanoc3/extra/validators.rb +12 -0
- data/lib/nanoc3/extra/vcs.rb +65 -0
- data/lib/nanoc3/extra/vcses/bazaar.rb +21 -0
- data/lib/nanoc3/extra/vcses/dummy.rb +20 -0
- data/lib/nanoc3/extra/vcses/git.rb +21 -0
- data/lib/nanoc3/extra/vcses/mercurial.rb +21 -0
- data/lib/nanoc3/extra/vcses/subversion.rb +21 -0
- data/lib/nanoc3/extra/vcses.rb +17 -0
- data/lib/nanoc3/extra.rb +16 -0
- data/lib/nanoc3/filters/bluecloth.rb +13 -0
- data/lib/nanoc3/filters/coderay.rb +17 -0
- data/lib/nanoc3/filters/erb.rb +19 -0
- data/lib/nanoc3/filters/erubis.rb +17 -0
- data/lib/nanoc3/filters/haml.rb +20 -0
- data/lib/nanoc3/filters/less.rb +13 -0
- data/lib/nanoc3/filters/markaby.rb +14 -0
- data/lib/nanoc3/filters/maruku.rb +14 -0
- data/lib/nanoc3/filters/rainpress.rb +13 -0
- data/lib/nanoc3/filters/rdiscount.rb +13 -0
- data/lib/nanoc3/filters/rdoc.rb +23 -0
- data/lib/nanoc3/filters/redcloth.rb +14 -0
- data/lib/nanoc3/filters/relativize_paths.rb +32 -0
- data/lib/nanoc3/filters/rubypants.rb +14 -0
- data/lib/nanoc3/filters/sass.rb +17 -0
- data/lib/nanoc3/filters.rb +37 -0
- data/lib/nanoc3/helpers/blogging.rb +226 -0
- data/lib/nanoc3/helpers/breadcrumbs.rb +25 -0
- data/lib/nanoc3/helpers/capturing.rb +71 -0
- data/lib/nanoc3/helpers/filtering.rb +46 -0
- data/lib/nanoc3/helpers/html_escape.rb +22 -0
- data/lib/nanoc3/helpers/link_to.rb +120 -0
- data/lib/nanoc3/helpers/rendering.rb +76 -0
- data/lib/nanoc3/helpers/tagging.rb +58 -0
- data/lib/nanoc3/helpers/text.rb +40 -0
- data/lib/nanoc3/helpers/xml_sitemap.rb +69 -0
- data/lib/nanoc3/helpers.rb +16 -0
- data/lib/nanoc3/package.rb +106 -0
- data/lib/nanoc3/tasks/clean.rake +16 -0
- data/lib/nanoc3/tasks/clean.rb +33 -0
- data/lib/nanoc3/tasks/deploy/rsync.rake +11 -0
- data/lib/nanoc3/tasks/validate.rake +35 -0
- data/lib/nanoc3/tasks.rb +9 -0
- data/lib/nanoc3.rb +19 -0
- data/vendor/cri/ChangeLog +0 -0
- data/vendor/cri/LICENSE +19 -0
- data/vendor/cri/NEWS +0 -0
- data/vendor/cri/README +4 -0
- data/vendor/cri/Rakefile +25 -0
- data/vendor/cri/lib/cri/base.rb +153 -0
- data/vendor/cri/lib/cri/command.rb +105 -0
- data/vendor/cri/lib/cri/core_ext/string.rb +41 -0
- data/vendor/cri/lib/cri/core_ext.rb +8 -0
- data/vendor/cri/lib/cri/option_parser.rb +186 -0
- data/vendor/cri/lib/cri.rb +12 -0
- data/vendor/cri/test/test_base.rb +6 -0
- data/vendor/cri/test/test_command.rb +6 -0
- data/vendor/cri/test/test_core_ext.rb +21 -0
- data/vendor/cri/test/test_option_parser.rb +279 -0
- metadata +225 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::DataSources
|
4
|
+
|
5
|
+
# Nanoc3::DataSources::Delicious provides for a delicious.com bookmarks from
|
6
|
+
# a single user as items (Nanoc3::Item instances).
|
7
|
+
#
|
8
|
+
# The configuration must have a "username" attribute containing the username
|
9
|
+
# of the account from which to fetch the bookmarks.
|
10
|
+
#
|
11
|
+
# The items returned by this data source will be mounted at {root}/{id},
|
12
|
+
# where +id+ is a sequence number that is not necessarily unique for this
|
13
|
+
# bookmark (because delicious.com unfortunately does not provide unique IDs
|
14
|
+
# for each bookmark).
|
15
|
+
#
|
16
|
+
# The items returned by this data source will have the following attributes:
|
17
|
+
#
|
18
|
+
# +:url+:: The URL the bookmark leads to.
|
19
|
+
#
|
20
|
+
# +:description+:: The description (title, usually) of the bookmark.
|
21
|
+
#
|
22
|
+
# +:tags+:: An array of tags (strings) for this bookmark.
|
23
|
+
#
|
24
|
+
# +:date+:: The timestamp when this bookmark was created (a Time object).
|
25
|
+
#
|
26
|
+
# +:note+:: The personal note for this bookmark (can be nil).
|
27
|
+
#
|
28
|
+
# +:author+:: The username of the person storing the bookmark.
|
29
|
+
class Delicious < Nanoc3::DataSource
|
30
|
+
|
31
|
+
def items
|
32
|
+
@items ||= begin
|
33
|
+
require 'json'
|
34
|
+
require 'time'
|
35
|
+
|
36
|
+
# Get data
|
37
|
+
@http_client ||= Nanoc3::Extra::CHiCk::Client.new
|
38
|
+
status, headers, data = *@http_client.get("http://feeds.delicious.com/v2/json/#{self.config[:username]}")
|
39
|
+
|
40
|
+
# Parse as JSON
|
41
|
+
raw_items = JSON.parse(data)
|
42
|
+
|
43
|
+
# Convert to items
|
44
|
+
raw_items.enum_with_index.map do |raw_item, i|
|
45
|
+
# Get data
|
46
|
+
content = raw_item['n']
|
47
|
+
attributes = {
|
48
|
+
:url => raw_item['u'],
|
49
|
+
:description => raw_item['d'],
|
50
|
+
:tags => raw_item['t'],
|
51
|
+
:date => Time.parse(raw_item['dt']),
|
52
|
+
:note => raw_item['n'],
|
53
|
+
:author => raw_item['a']
|
54
|
+
}
|
55
|
+
identifier = "/#{i}/"
|
56
|
+
mtime = nil
|
57
|
+
|
58
|
+
# Build item
|
59
|
+
Nanoc3::Item.new(content, attributes, identifier, mtime)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::DataSources
|
4
|
+
|
5
|
+
# The filesystem data source is the default data source for a new nanoc
|
6
|
+
# site. It stores all data as files on the hard disk.
|
7
|
+
#
|
8
|
+
# None of the methods are documented in this file. See Nanoc3::DataSource
|
9
|
+
# for documentation on the overridden methods instead.
|
10
|
+
#
|
11
|
+
# = Items
|
12
|
+
#
|
13
|
+
# The filesystem data source stores its items in nested directories. Each
|
14
|
+
# directory represents a single item. The root directory is the 'content'
|
15
|
+
# directory.
|
16
|
+
#
|
17
|
+
# Every directory has a content file and a meta file. The content file
|
18
|
+
# contains the actual item content, while the meta file contains the item's
|
19
|
+
# metadata, formatted as YAML.
|
20
|
+
#
|
21
|
+
# Both content files and meta files are named after its parent directory
|
22
|
+
# (i.e. item). For example, a item named 'foo' will have a directory named
|
23
|
+
# 'foo', with e.g. a 'foo.markdown' content file and a 'foo.yaml' meta file.
|
24
|
+
#
|
25
|
+
# Content file extensions are not used for determining the filter that
|
26
|
+
# should be run; the meta file defines the list of filters. The meta file
|
27
|
+
# extension must always be 'yaml', though.
|
28
|
+
#
|
29
|
+
# Content files can also have the 'index' basename. Similarly, meta files
|
30
|
+
# can have the 'meta' basename. For example, a parent directory named 'foo'
|
31
|
+
# can have an 'index.txt' content file and a 'meta.yaml' meta file. This is
|
32
|
+
# to preserve backward compatibility.
|
33
|
+
#
|
34
|
+
# = Layouts
|
35
|
+
#
|
36
|
+
# Layouts are stored as directories in the 'layouts' directory. Each layout
|
37
|
+
# contains a content file and a meta file. The content file contain the
|
38
|
+
# actual layout, and the meta file describes how the item should be handled
|
39
|
+
# (contains the filter that should be used).
|
40
|
+
#
|
41
|
+
# For backward compatibility, a layout can also be a single file in the
|
42
|
+
# 'layouts' directory. Such a layout cannot have any metadata; the filter
|
43
|
+
# used for this layout is determined from the file extension.
|
44
|
+
#
|
45
|
+
# = Code Snippets
|
46
|
+
#
|
47
|
+
# Code snippets are stored in '.rb' files in the 'lib' directory. Code
|
48
|
+
# snippets can reside in sub-directories.
|
49
|
+
class Filesystem < Nanoc3::DataSource
|
50
|
+
|
51
|
+
include Nanoc3::DataSources::FilesystemCommon
|
52
|
+
|
53
|
+
########## VCSes ##########
|
54
|
+
|
55
|
+
attr_accessor :vcs
|
56
|
+
|
57
|
+
def vcs
|
58
|
+
@vcs ||= Nanoc3::Extra::VCSes::Dummy.new
|
59
|
+
end
|
60
|
+
|
61
|
+
########## Preparation ##########
|
62
|
+
|
63
|
+
def up
|
64
|
+
end
|
65
|
+
|
66
|
+
def down
|
67
|
+
end
|
68
|
+
|
69
|
+
def setup
|
70
|
+
# Create directories
|
71
|
+
%w( content layouts lib ).each do |dir|
|
72
|
+
FileUtils.mkdir_p(dir)
|
73
|
+
vcs.add(dir)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
########## Loading data ##########
|
78
|
+
|
79
|
+
def items
|
80
|
+
meta_filenames('content').map do |meta_filename|
|
81
|
+
# Read metadata
|
82
|
+
meta = YAML.load_file(meta_filename) || {}
|
83
|
+
|
84
|
+
# Get content
|
85
|
+
content_filename = content_filename_for_dir(File.dirname(meta_filename))
|
86
|
+
content = File.read(content_filename)
|
87
|
+
|
88
|
+
# Get attributes
|
89
|
+
attributes = meta.merge(:file => Nanoc3::Extra::FileProxy.new(content_filename))
|
90
|
+
|
91
|
+
# Get identifier
|
92
|
+
identifier = meta_filename.sub(/^content/, '').sub(/[^\/]+\.yaml$/, '')
|
93
|
+
|
94
|
+
# Get modification times
|
95
|
+
meta_mtime = File.stat(meta_filename).mtime
|
96
|
+
content_mtime = File.stat(content_filename).mtime
|
97
|
+
mtime = meta_mtime > content_mtime ? meta_mtime : content_mtime
|
98
|
+
|
99
|
+
# Create item object
|
100
|
+
Nanoc3::Item.new(content, attributes, identifier, mtime)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def layouts
|
105
|
+
meta_filenames('layouts').map do |meta_filename|
|
106
|
+
# Get content
|
107
|
+
content_filename = content_filename_for_dir(File.dirname(meta_filename))
|
108
|
+
content = File.read(content_filename)
|
109
|
+
|
110
|
+
# Get attributes
|
111
|
+
attributes = YAML.load_file(meta_filename) || {}
|
112
|
+
|
113
|
+
# Get identifier
|
114
|
+
identifier = meta_filename.sub(/^layouts\//, '').sub(/\/[^\/]+\.yaml$/, '')
|
115
|
+
|
116
|
+
# Get modification times
|
117
|
+
meta_mtime = File.stat(meta_filename).mtime
|
118
|
+
content_mtime = File.stat(content_filename).mtime
|
119
|
+
mtime = meta_mtime > content_mtime ? meta_mtime : content_mtime
|
120
|
+
|
121
|
+
# Create layout object
|
122
|
+
Nanoc3::Layout.new(content, attributes, identifier, mtime)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
########## Creating data ##########
|
127
|
+
|
128
|
+
# Creates a new item with the given content, attributes and identifier.
|
129
|
+
def create_item(content, attributes, identifier)
|
130
|
+
# Determine base path
|
131
|
+
last_component = identifier.split('/')[-1] || 'content'
|
132
|
+
base_path = 'content' + identifier + last_component
|
133
|
+
|
134
|
+
# Get filenames
|
135
|
+
dir_path = 'content' + identifier
|
136
|
+
meta_filename = 'content' + identifier + last_component + '.yaml'
|
137
|
+
content_filename = 'content' + identifier + last_component + '.html'
|
138
|
+
|
139
|
+
# Notify
|
140
|
+
Nanoc3::NotificationCenter.post(:file_created, meta_filename)
|
141
|
+
Nanoc3::NotificationCenter.post(:file_created, content_filename)
|
142
|
+
|
143
|
+
# Create files
|
144
|
+
FileUtils.mkdir_p(dir_path)
|
145
|
+
File.open(meta_filename, 'w') { |io| io.write(YAML.dump(attributes.stringify_keys)) }
|
146
|
+
File.open(content_filename, 'w') { |io| io.write(content) }
|
147
|
+
end
|
148
|
+
|
149
|
+
# Creates a new layout with the given content, attributes and identifier.
|
150
|
+
def create_layout(content, attributes, identifier)
|
151
|
+
# Determine base path
|
152
|
+
last_component = identifier.split('/')[-1]
|
153
|
+
base_path = 'layouts' + identifier + last_component
|
154
|
+
|
155
|
+
# Get filenames
|
156
|
+
dir_path = 'layouts' + identifier
|
157
|
+
meta_filename = 'layouts' + identifier + last_component + '.yaml'
|
158
|
+
content_filename = 'layouts' + identifier + last_component + '.html'
|
159
|
+
|
160
|
+
# Notify
|
161
|
+
Nanoc3::NotificationCenter.post(:file_created, meta_filename)
|
162
|
+
Nanoc3::NotificationCenter.post(:file_created, content_filename)
|
163
|
+
|
164
|
+
# Create files
|
165
|
+
FileUtils.mkdir_p(dir_path)
|
166
|
+
File.open(meta_filename, 'w') { |io| io.write(YAML.dump(attributes.stringify_keys)) }
|
167
|
+
File.open(content_filename, 'w') { |io| io.write(content) }
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
########## Custom functions ##########
|
173
|
+
|
174
|
+
# Returns the list of all meta files in the given base directory as well
|
175
|
+
# as its subdirectories.
|
176
|
+
def meta_filenames(base)
|
177
|
+
# Find all possible meta file names
|
178
|
+
filenames = Dir[base + '/**/*.yaml']
|
179
|
+
|
180
|
+
# Filter out invalid meta files
|
181
|
+
good_filenames = []
|
182
|
+
bad_filenames = []
|
183
|
+
filenames.each do |filename|
|
184
|
+
if filename =~ /meta\.yaml$/ or filename =~ /([^\/]+)\/\1\.yaml$/
|
185
|
+
good_filenames << filename
|
186
|
+
else
|
187
|
+
bad_filenames << filename
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Warn about bad filenames
|
192
|
+
unless bad_filenames.empty?
|
193
|
+
raise RuntimeError.new(
|
194
|
+
"The following files appear to be meta files, " +
|
195
|
+
"but have an invalid name:\n - " +
|
196
|
+
bad_filenames.join("\n - ")
|
197
|
+
)
|
198
|
+
end
|
199
|
+
|
200
|
+
good_filenames
|
201
|
+
end
|
202
|
+
|
203
|
+
# Returns the filename of the content file in the given directory,
|
204
|
+
# ignoring any unwanted files (files that end with '~', '.orig', '.rej' or
|
205
|
+
# '.bak')
|
206
|
+
def content_filename_for_dir(dir)
|
207
|
+
# Find all files
|
208
|
+
filename_glob_1 = dir.sub(/([^\/]+)$/, '\1/\1.*')
|
209
|
+
filename_glob_2 = dir.sub(/([^\/]+)$/, '\1/index.*')
|
210
|
+
filenames = (Dir[filename_glob_1] + Dir[filename_glob_2]).uniq
|
211
|
+
|
212
|
+
# Reject meta files
|
213
|
+
filenames.reject! { |f| f =~ /\.yaml$/ }
|
214
|
+
|
215
|
+
# Reject backups
|
216
|
+
filenames.reject! { |f| f =~ /(~|\.orig|\.rej|\.bak)$/ }
|
217
|
+
|
218
|
+
# Make sure there is only one content file
|
219
|
+
if filenames.size != 1
|
220
|
+
raise RuntimeError.new(
|
221
|
+
"Expected 1 content file in #{dir} but found #{filenames.size}"
|
222
|
+
)
|
223
|
+
end
|
224
|
+
|
225
|
+
# Return content filename
|
226
|
+
filenames.first
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::DataSources
|
4
|
+
|
5
|
+
# = Items
|
6
|
+
#
|
7
|
+
# The filesystem data source stores its items in nested directories. A item
|
8
|
+
# is represented by a single file. The root directory is the 'content'
|
9
|
+
# directory.
|
10
|
+
#
|
11
|
+
# The metadata for a item is embedded into the file itself. It is stored at
|
12
|
+
# the top of the file, between '---' (three dashes) separators. For example:
|
13
|
+
#
|
14
|
+
# ---
|
15
|
+
# title: "Moo!"
|
16
|
+
# ---
|
17
|
+
# h1. Hello!
|
18
|
+
#
|
19
|
+
# The identifier of a item is determined as follows. A file with an
|
20
|
+
# 'index.*' filename, such as 'index.txt', will have the filesystem path
|
21
|
+
# with the 'index.*' part stripped as a identifier. For example,
|
22
|
+
# 'foo/bar/index.html' will have '/foo/bar/' as identifier.
|
23
|
+
#
|
24
|
+
# A file with a filename not starting with 'index.', such as 'foo.html',
|
25
|
+
# will have an identifier ending in 'foo/'. For example, 'foo/bar.html' will
|
26
|
+
# have '/foo/bar/' as identifier.
|
27
|
+
#
|
28
|
+
# Note that it is possible for two different, separate files to have the
|
29
|
+
# same identifier. It is therefore recommended to avoid such situations.
|
30
|
+
#
|
31
|
+
# Some more examples:
|
32
|
+
#
|
33
|
+
# content/index.html --> /
|
34
|
+
# content/foo.html --> /foo/
|
35
|
+
# content/foo/index.html --> /foo/
|
36
|
+
# content/foo/bar.html --> /foo/bar/
|
37
|
+
# content/foo/bar/index.html --> /foo/bar/
|
38
|
+
#
|
39
|
+
# File extensions are ignored by nanoc. The file extension does not
|
40
|
+
# determine the filters to run on it; the metadata in the file defines the
|
41
|
+
# list of filters.
|
42
|
+
#
|
43
|
+
# = Layouts
|
44
|
+
#
|
45
|
+
# Layouts are stored as files in the 'layouts' directory. Similar to items,
|
46
|
+
# each layout consists of a metadata part and a content part, separated by
|
47
|
+
# '---' (three dashes).
|
48
|
+
#
|
49
|
+
# = Code Snippets
|
50
|
+
#
|
51
|
+
# Code snippets are stored in '.rb' files in the 'lib' directory. Code
|
52
|
+
# snippets can reside in sub-directories.
|
53
|
+
class FilesystemCombined < Nanoc3::DataSource
|
54
|
+
|
55
|
+
include Nanoc3::DataSources::FilesystemCommon
|
56
|
+
|
57
|
+
########## VCSes ##########
|
58
|
+
|
59
|
+
attr_accessor :vcs
|
60
|
+
|
61
|
+
def vcs
|
62
|
+
@vcs ||= Nanoc3::Extra::VCSes::Dummy.new
|
63
|
+
end
|
64
|
+
|
65
|
+
########## Preparation ##########
|
66
|
+
|
67
|
+
def up
|
68
|
+
end
|
69
|
+
|
70
|
+
def down
|
71
|
+
end
|
72
|
+
|
73
|
+
def setup
|
74
|
+
# Create directories
|
75
|
+
%w( content layouts lib ).each do |dir|
|
76
|
+
FileUtils.mkdir_p(dir)
|
77
|
+
vcs.add(dir)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
########## Loading data ##########
|
82
|
+
|
83
|
+
def items
|
84
|
+
files('content', true).map do |filename|
|
85
|
+
# Read and parse data
|
86
|
+
meta, content = *parse_file(filename, 'item')
|
87
|
+
|
88
|
+
# Get attributes
|
89
|
+
attributes = meta.merge(:file => Nanoc3::Extra::FileProxy.new(filename))
|
90
|
+
|
91
|
+
# Get actual identifier
|
92
|
+
if filename =~ /\/index\.[^\/]+$/
|
93
|
+
identifier = filename.sub(/^content/, '').sub(/index\.[^\/]+$/, '') + '/'
|
94
|
+
else
|
95
|
+
identifier = filename.sub(/^content/, '').sub(/\.[^\/]+$/, '') + '/'
|
96
|
+
end
|
97
|
+
|
98
|
+
# Get mtime
|
99
|
+
mtime = File.stat(filename).mtime
|
100
|
+
|
101
|
+
# Build item
|
102
|
+
Nanoc3::Item.new(content, attributes, identifier, mtime)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def layouts
|
107
|
+
files('layouts', true).map do |filename|
|
108
|
+
# Read and parse data
|
109
|
+
meta, content = *parse_file(filename, 'layout')
|
110
|
+
|
111
|
+
# Get actual identifier
|
112
|
+
if filename =~ /\/index\.[^\/]+$/
|
113
|
+
identifier = filename.sub(/^layouts/, '').sub(/index\.[^\/]+$/, '') + '/'
|
114
|
+
else
|
115
|
+
identifier = filename.sub(/^layouts/, '').sub(/\.[^\/]+$/, '') + '/'
|
116
|
+
end
|
117
|
+
|
118
|
+
# Get mtime
|
119
|
+
mtime = File.stat(filename).mtime
|
120
|
+
|
121
|
+
# Build layout
|
122
|
+
Nanoc3::Layout.new(content, meta, identifier, mtime)
|
123
|
+
end.compact
|
124
|
+
end
|
125
|
+
|
126
|
+
########## Creating data ##########
|
127
|
+
|
128
|
+
# Creates a new item with the given content, attributes and identifier.
|
129
|
+
def create_item(content, attributes, identifier)
|
130
|
+
# Determine path
|
131
|
+
if identifier == '/'
|
132
|
+
path = 'content/index.html'
|
133
|
+
else
|
134
|
+
path = 'content' + identifier[0..-2] + '.html'
|
135
|
+
end
|
136
|
+
parent_path = File.dirname(path)
|
137
|
+
|
138
|
+
# Notify
|
139
|
+
Nanoc3::NotificationCenter.post(:file_created, path)
|
140
|
+
|
141
|
+
# Write item
|
142
|
+
FileUtils.mkdir_p(parent_path)
|
143
|
+
File.open(path, 'w') do |io|
|
144
|
+
io.write(YAML.dump(attributes.stringify_keys) + "\n")
|
145
|
+
io.write("---\n")
|
146
|
+
io.write(content)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Creates a new layout with the given content, attributes and identifier.
|
151
|
+
def create_layout(content, attributes, identifier)
|
152
|
+
# Determine path
|
153
|
+
path = 'layouts' + identifier[0..-2] + '.html'
|
154
|
+
parent_path = File.dirname(path)
|
155
|
+
|
156
|
+
# Notify
|
157
|
+
Nanoc3::NotificationCenter.post(:file_created, path)
|
158
|
+
|
159
|
+
# Write layout
|
160
|
+
FileUtils.mkdir_p(parent_path)
|
161
|
+
File.open(path, 'w') do |io|
|
162
|
+
io.write(YAML.dump(attributes.stringify_keys) + "\n")
|
163
|
+
io.write("---\n")
|
164
|
+
io.write(content)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
# Returns a list of all files in +dir+, ignoring any unwanted files (files
|
171
|
+
# that end with '~', '.orig', '.rej' or '.bak').
|
172
|
+
#
|
173
|
+
# +recursively+:: When +true+, finds files in +dir+ as well as its
|
174
|
+
# subdirectories; when +false+, only searches +dir+
|
175
|
+
# itself.
|
176
|
+
def files(dir, recursively)
|
177
|
+
glob = File.join([dir] + (recursively ? [ '**', '*' ] : [ '*' ]))
|
178
|
+
Dir[glob].reject { |f| File.directory?(f) or f =~ /(~|\.orig|\.rej|\.bak)$/ }
|
179
|
+
end
|
180
|
+
|
181
|
+
# Parses the file named +filename+ and returns an array with its first
|
182
|
+
# element a hash with the file's metadata, and with its second element the
|
183
|
+
# file content itself.
|
184
|
+
def parse_file(filename, kind)
|
185
|
+
# Split file
|
186
|
+
pieces = File.read(filename).split(/^(-{5}|-{3})/).compact
|
187
|
+
if pieces.size < 3
|
188
|
+
raise RuntimeError.new(
|
189
|
+
"The file '#{filename}' does not seem to be a nanoc #{kind}"
|
190
|
+
)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Parse
|
194
|
+
meta = YAML.load(pieces[2]) || {}
|
195
|
+
content = pieces[4..-1].join.strip
|
196
|
+
|
197
|
+
[ meta, content ]
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::DataSources
|
4
|
+
|
5
|
+
# The Nanoc3::DataSources::FilesystemCommon module provides code
|
6
|
+
# snippet-loading and rule-loading methods that are used by both the
|
7
|
+
# filesystem and the filesystem_combined data sources.
|
8
|
+
module FilesystemCommon
|
9
|
+
|
10
|
+
def code_snippets
|
11
|
+
Dir['lib/**/*.rb'].sort.map do |filename|
|
12
|
+
Nanoc3::CodeSnippet.new(
|
13
|
+
File.read(filename),
|
14
|
+
filename.sub(/^lib\//, ''),
|
15
|
+
File.stat(filename).mtime
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|