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.
- data/ChangeLog +3 -0
- data/LICENSE +19 -0
- data/README +75 -0
- data/Rakefile +76 -0
- data/bin/nanoc2 +26 -0
- data/lib/nanoc2.rb +73 -0
- data/lib/nanoc2/base.rb +26 -0
- data/lib/nanoc2/base/asset.rb +117 -0
- data/lib/nanoc2/base/asset_defaults.rb +21 -0
- data/lib/nanoc2/base/asset_rep.rb +282 -0
- data/lib/nanoc2/base/binary_filter.rb +44 -0
- data/lib/nanoc2/base/code.rb +41 -0
- data/lib/nanoc2/base/compiler.rb +67 -0
- data/lib/nanoc2/base/core_ext.rb +2 -0
- data/lib/nanoc2/base/core_ext/hash.rb +78 -0
- data/lib/nanoc2/base/core_ext/string.rb +8 -0
- data/lib/nanoc2/base/data_source.rb +286 -0
- data/lib/nanoc2/base/defaults.rb +30 -0
- data/lib/nanoc2/base/filter.rb +93 -0
- data/lib/nanoc2/base/layout.rb +91 -0
- data/lib/nanoc2/base/notification_center.rb +66 -0
- data/lib/nanoc2/base/page.rb +132 -0
- data/lib/nanoc2/base/page_defaults.rb +20 -0
- data/lib/nanoc2/base/page_rep.rb +324 -0
- data/lib/nanoc2/base/plugin.rb +71 -0
- data/lib/nanoc2/base/proxies.rb +5 -0
- data/lib/nanoc2/base/proxies/asset_proxy.rb +29 -0
- data/lib/nanoc2/base/proxies/asset_rep_proxy.rb +26 -0
- data/lib/nanoc2/base/proxies/layout_proxy.rb +25 -0
- data/lib/nanoc2/base/proxies/page_proxy.rb +35 -0
- data/lib/nanoc2/base/proxies/page_rep_proxy.rb +28 -0
- data/lib/nanoc2/base/proxy.rb +37 -0
- data/lib/nanoc2/base/router.rb +72 -0
- data/lib/nanoc2/base/site.rb +274 -0
- data/lib/nanoc2/base/template.rb +64 -0
- data/lib/nanoc2/binary_filters.rb +1 -0
- data/lib/nanoc2/binary_filters/image_science_thumbnail.rb +28 -0
- data/lib/nanoc2/cli.rb +9 -0
- data/lib/nanoc2/cli/base.rb +132 -0
- data/lib/nanoc2/cli/commands.rb +10 -0
- data/lib/nanoc2/cli/commands/autocompile.rb +80 -0
- data/lib/nanoc2/cli/commands/compile.rb +312 -0
- data/lib/nanoc2/cli/commands/create_layout.rb +85 -0
- data/lib/nanoc2/cli/commands/create_page.rb +85 -0
- data/lib/nanoc2/cli/commands/create_site.rb +323 -0
- data/lib/nanoc2/cli/commands/create_template.rb +76 -0
- data/lib/nanoc2/cli/commands/help.rb +69 -0
- data/lib/nanoc2/cli/commands/info.rb +125 -0
- data/lib/nanoc2/cli/commands/switch.rb +141 -0
- data/lib/nanoc2/cli/commands/update.rb +91 -0
- data/lib/nanoc2/cli/logger.rb +72 -0
- data/lib/nanoc2/data_sources.rb +2 -0
- data/lib/nanoc2/data_sources/filesystem.rb +707 -0
- data/lib/nanoc2/data_sources/filesystem_combined.rb +495 -0
- data/lib/nanoc2/extra.rb +6 -0
- data/lib/nanoc2/extra/auto_compiler.rb +285 -0
- data/lib/nanoc2/extra/context.rb +22 -0
- data/lib/nanoc2/extra/core_ext.rb +2 -0
- data/lib/nanoc2/extra/core_ext/hash.rb +54 -0
- data/lib/nanoc2/extra/core_ext/time.rb +13 -0
- data/lib/nanoc2/extra/file_proxy.rb +29 -0
- data/lib/nanoc2/extra/vcs.rb +48 -0
- data/lib/nanoc2/extra/vcses.rb +5 -0
- data/lib/nanoc2/extra/vcses/bazaar.rb +21 -0
- data/lib/nanoc2/extra/vcses/dummy.rb +20 -0
- data/lib/nanoc2/extra/vcses/git.rb +21 -0
- data/lib/nanoc2/extra/vcses/mercurial.rb +21 -0
- data/lib/nanoc2/extra/vcses/subversion.rb +21 -0
- data/lib/nanoc2/filters.rb +16 -0
- data/lib/nanoc2/filters/bluecloth.rb +13 -0
- data/lib/nanoc2/filters/erb.rb +19 -0
- data/lib/nanoc2/filters/erubis.rb +14 -0
- data/lib/nanoc2/filters/haml.rb +21 -0
- data/lib/nanoc2/filters/markaby.rb +14 -0
- data/lib/nanoc2/filters/maruku.rb +14 -0
- data/lib/nanoc2/filters/old.rb +19 -0
- data/lib/nanoc2/filters/rainpress.rb +13 -0
- data/lib/nanoc2/filters/rdiscount.rb +13 -0
- data/lib/nanoc2/filters/rdoc.rb +23 -0
- data/lib/nanoc2/filters/redcloth.rb +14 -0
- data/lib/nanoc2/filters/relativize_paths.rb +16 -0
- data/lib/nanoc2/filters/relativize_paths_in_css.rb +16 -0
- data/lib/nanoc2/filters/relativize_paths_in_html.rb +16 -0
- data/lib/nanoc2/filters/rubypants.rb +14 -0
- data/lib/nanoc2/filters/sass.rb +18 -0
- data/lib/nanoc2/helpers.rb +9 -0
- data/lib/nanoc2/helpers/blogging.rb +217 -0
- data/lib/nanoc2/helpers/capturing.rb +63 -0
- data/lib/nanoc2/helpers/filtering.rb +54 -0
- data/lib/nanoc2/helpers/html_escape.rb +25 -0
- data/lib/nanoc2/helpers/link_to.rb +113 -0
- data/lib/nanoc2/helpers/render.rb +49 -0
- data/lib/nanoc2/helpers/tagging.rb +56 -0
- data/lib/nanoc2/helpers/text.rb +38 -0
- data/lib/nanoc2/helpers/xml_sitemap.rb +63 -0
- data/lib/nanoc2/routers.rb +3 -0
- data/lib/nanoc2/routers/default.rb +54 -0
- data/lib/nanoc2/routers/no_dirs.rb +66 -0
- data/lib/nanoc2/routers/versioned.rb +79 -0
- metadata +185 -0
@@ -0,0 +1,282 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# A Nanoc2::AssetRep is a single representation (rep) of an asset
|
4
|
+
# (Nanoc2::Asset). An asset can have multiple representations. A
|
5
|
+
# representation has its own attributes and its own output file. A single
|
6
|
+
# asset can therefore have multiple output files, each run through a
|
7
|
+
# different set of filters with a different layout.
|
8
|
+
#
|
9
|
+
# An asset representation is observable. The following events will be
|
10
|
+
# notified:
|
11
|
+
#
|
12
|
+
# * :compilation_started
|
13
|
+
# * :compilation_ended
|
14
|
+
# * :filtering_started
|
15
|
+
# * :filtering_ended
|
16
|
+
#
|
17
|
+
# The compilation-related events have one parameters (the page
|
18
|
+
# representation); the filtering-related events have two (the page
|
19
|
+
# representation, and a symbol containing the filter class name).
|
20
|
+
class AssetRep
|
21
|
+
|
22
|
+
# The asset (Nanoc2::Asset) to which this representation belongs.
|
23
|
+
attr_reader :asset
|
24
|
+
|
25
|
+
# A hash containing this asset representation's attributes.
|
26
|
+
attr_accessor :attributes
|
27
|
+
|
28
|
+
# This asset representation's unique name.
|
29
|
+
attr_reader :name
|
30
|
+
|
31
|
+
# Creates a new asset representation for the given asset and with the
|
32
|
+
# given attributes.
|
33
|
+
#
|
34
|
+
# +asset+:: The asset (Nanoc2::Asset) to which the new representation will
|
35
|
+
# belong.
|
36
|
+
#
|
37
|
+
# +attributes+:: A hash containing the new asset representation's
|
38
|
+
# attributes. This hash must have been run through
|
39
|
+
# Hash#clean before using it here.
|
40
|
+
#
|
41
|
+
# +name+:: The unique name for the new asset representation.
|
42
|
+
def initialize(asset, attributes, name)
|
43
|
+
# Set primary attributes
|
44
|
+
@asset = asset
|
45
|
+
@attributes = attributes
|
46
|
+
@name = name
|
47
|
+
|
48
|
+
# Reset flags
|
49
|
+
@compiled = false
|
50
|
+
@modified = false
|
51
|
+
@created = false
|
52
|
+
|
53
|
+
# Reset stages
|
54
|
+
@filtered = false
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns a proxy (Nanoc2::AssetRepProxy) for this asset representation.
|
58
|
+
def to_proxy
|
59
|
+
@proxy ||= AssetRepProxy.new(self)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns true if this asset rep's output file was created during the last
|
63
|
+
# compilation session, or false if the output file did already exist.
|
64
|
+
def created?
|
65
|
+
@created
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns true if this asset rep's output file was modified during the
|
69
|
+
# last compilation session, or false if the output file wasn't changed.
|
70
|
+
def modified?
|
71
|
+
@modified
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns true if this page rep has been compiled, false otherwise.
|
75
|
+
def compiled?
|
76
|
+
@compiled
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the path to the output file, including the path to the output
|
80
|
+
# directory specified in the site configuration, and including the
|
81
|
+
# filename and extension.
|
82
|
+
def disk_path
|
83
|
+
@disk_path ||= @asset.site.router.disk_path_for(self)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns the path to the output file as it would be used in a web
|
87
|
+
# browser: starting with a slash (representing the web root), and only
|
88
|
+
# including the filename and extension if they cannot be ignored (i.e.
|
89
|
+
# they are not in the site configuration's list of index files).
|
90
|
+
def web_path
|
91
|
+
compile(false, false)
|
92
|
+
|
93
|
+
@web_path ||= @asset.site.router.web_path_for(self)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns true if this asset rep's output file is outdated and must be
|
97
|
+
# regenerated, false otherwise.
|
98
|
+
def outdated?
|
99
|
+
# Outdated if we don't know
|
100
|
+
return true if @asset.mtime.nil?
|
101
|
+
|
102
|
+
# Outdated if compiled file doesn't exist
|
103
|
+
return true if !File.file?(disk_path)
|
104
|
+
|
105
|
+
# Get compiled mtime
|
106
|
+
compiled_mtime = File.stat(disk_path).mtime
|
107
|
+
|
108
|
+
# Outdated if file too old
|
109
|
+
return true if @asset.mtime > compiled_mtime
|
110
|
+
|
111
|
+
# Outdated if asset defaults outdated
|
112
|
+
return true if @asset.site.asset_defaults.mtime.nil?
|
113
|
+
return true if @asset.site.asset_defaults.mtime > compiled_mtime
|
114
|
+
|
115
|
+
# Outdated if code outdated
|
116
|
+
return true if @asset.site.code.mtime.nil?
|
117
|
+
return true if @asset.site.code.mtime > compiled_mtime
|
118
|
+
|
119
|
+
return false
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns the attribute with the given name. This method will look in
|
123
|
+
# several places for the requested attribute:
|
124
|
+
#
|
125
|
+
# 1. This asset representation's attributes;
|
126
|
+
# 2. The attributes of this asset representation's asset;
|
127
|
+
# 3. The asset defaults' representation corresponding to this asset
|
128
|
+
# representation;
|
129
|
+
# 4. The asset defaults in general;
|
130
|
+
# 5. The hardcoded asset defaults, if everything else fails.
|
131
|
+
def attribute_named(name)
|
132
|
+
# Check in here
|
133
|
+
return @attributes[name] if @attributes.has_key?(name)
|
134
|
+
|
135
|
+
# Check in asset
|
136
|
+
return @asset.attributes[name] if @asset.attributes.has_key?(name)
|
137
|
+
|
138
|
+
# Check in asset defaults' asset rep
|
139
|
+
asset_default_reps = @asset.site.asset_defaults.attributes[:reps] || {}
|
140
|
+
asset_default_rep = asset_default_reps[@name] || {}
|
141
|
+
return asset_default_rep[name] if asset_default_rep.has_key?(name)
|
142
|
+
|
143
|
+
# Check in site defaults (global)
|
144
|
+
asset_defaults_attrs = @asset.site.asset_defaults.attributes
|
145
|
+
return asset_defaults_attrs[name] if asset_defaults_attrs.has_key?(name)
|
146
|
+
|
147
|
+
# Check in hardcoded defaults
|
148
|
+
return Nanoc2::Asset::DEFAULTS[name]
|
149
|
+
end
|
150
|
+
|
151
|
+
# Compiles the asset representation and writes the result to the disk.
|
152
|
+
# This method should not be called directly; please use
|
153
|
+
# Nanoc2::Compiler#run instead, and pass this asset representation's asset
|
154
|
+
# as its first argument.
|
155
|
+
#
|
156
|
+
# The asset representation will only be compiled if it wasn't compiled
|
157
|
+
# before yet. To force recompilation of the asset rep, forgetting any
|
158
|
+
# progress, set +from_scratch+ to true.
|
159
|
+
#
|
160
|
+
# +even_when_not_outdated+:: true if the asset rep should be compiled even
|
161
|
+
# if it is not outdated, false if not.
|
162
|
+
#
|
163
|
+
# +from_scratch+:: true if the asset rep should be filtered again even if
|
164
|
+
# it has already been filtered, false otherwise.
|
165
|
+
def compile(even_when_not_outdated, from_scratch)
|
166
|
+
# Don't compile if already compiled
|
167
|
+
return if @compiled and !from_scratch
|
168
|
+
|
169
|
+
# Skip unless outdated
|
170
|
+
unless outdated? or even_when_not_outdated
|
171
|
+
Nanoc2::NotificationCenter.post(:compilation_started, self)
|
172
|
+
Nanoc2::NotificationCenter.post(:compilation_ended, self)
|
173
|
+
return
|
174
|
+
end
|
175
|
+
|
176
|
+
# Reset flags
|
177
|
+
@compiled = false
|
178
|
+
@modified = false
|
179
|
+
@created = !File.file?(self.disk_path)
|
180
|
+
|
181
|
+
# Forget progress if requested
|
182
|
+
@filtered = false if from_scratch
|
183
|
+
|
184
|
+
# Start
|
185
|
+
@asset.site.compiler.stack.push(self)
|
186
|
+
Nanoc2::NotificationCenter.post(:compilation_started, self)
|
187
|
+
|
188
|
+
# Compile
|
189
|
+
unless @filtered
|
190
|
+
if attribute_named(:binary) == true
|
191
|
+
compile_binary
|
192
|
+
else
|
193
|
+
compile_textual
|
194
|
+
end
|
195
|
+
end
|
196
|
+
@compiled = true
|
197
|
+
|
198
|
+
# Stop
|
199
|
+
@asset.site.compiler.stack.pop
|
200
|
+
Nanoc2::NotificationCenter.post(:compilation_ended, self)
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
# Computes and returns the MD5 digest for the given file.
|
206
|
+
def digest(filename)
|
207
|
+
# Create hash
|
208
|
+
incr_digest = Digest::MD5.new()
|
209
|
+
|
210
|
+
# Collect data
|
211
|
+
File.open(filename, 'r') do |io|
|
212
|
+
incr_digest << io.read(1000) until io.eof?
|
213
|
+
end
|
214
|
+
|
215
|
+
# Calculate hex hash
|
216
|
+
incr_digest.hexdigest
|
217
|
+
end
|
218
|
+
|
219
|
+
# Compiles the asset rep, treating its contents as binary data.
|
220
|
+
def compile_binary
|
221
|
+
# Calculate digest before
|
222
|
+
digest_before = File.file?(disk_path) ? digest(disk_path) : nil
|
223
|
+
|
224
|
+
# Run filters
|
225
|
+
current_file = @asset.file
|
226
|
+
attribute_named(:filters).each do |filter_name|
|
227
|
+
# Free resources so that this filter won't fail
|
228
|
+
GC.start
|
229
|
+
|
230
|
+
# Create filter
|
231
|
+
klass = Nanoc2::BinaryFilter.named(filter_name)
|
232
|
+
raise Nanoc2::Errors::UnknownFilterError.new(filter_name) if klass.nil?
|
233
|
+
filter = klass.new(self.to_proxy, @asset.to_proxy, @asset.site)
|
234
|
+
|
235
|
+
# Run filter
|
236
|
+
Nanoc2::NotificationCenter.post(:filtering_started, self, klass.identifier)
|
237
|
+
current_file = filter.run(current_file)
|
238
|
+
Nanoc2::NotificationCenter.post(:filtering_ended, self, klass.identifier)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Write asset
|
242
|
+
FileUtils.mkdir_p(File.dirname(self.disk_path))
|
243
|
+
FileUtils.cp(current_file.path, disk_path)
|
244
|
+
|
245
|
+
# Calculate digest after
|
246
|
+
digest_after = digest(disk_path)
|
247
|
+
@modified = (digest_after != digest_before)
|
248
|
+
end
|
249
|
+
|
250
|
+
# Compiles the asset rep, treating its contents as textual data.
|
251
|
+
def compile_textual
|
252
|
+
# Get content
|
253
|
+
current_content = @asset.file.read
|
254
|
+
|
255
|
+
# Check modified
|
256
|
+
@modified = @created ? true : File.read(self.disk_path) != current_content
|
257
|
+
|
258
|
+
# Run filters
|
259
|
+
attribute_named(:filters).each do |filter_name|
|
260
|
+
# Create filter
|
261
|
+
klass = Nanoc2::Filter.named(filter_name)
|
262
|
+
raise Nanoc2::Errors::UnknownFilterError.new(filter_name) if klass.nil?
|
263
|
+
filter = klass.new(self)
|
264
|
+
|
265
|
+
# Run filter
|
266
|
+
Nanoc2::NotificationCenter.post(:filtering_started, self, klass.identifier)
|
267
|
+
current_content = filter.run(current_content)
|
268
|
+
Nanoc2::NotificationCenter.post(:filtering_ended, self, klass.identifier)
|
269
|
+
end
|
270
|
+
|
271
|
+
# Write asset
|
272
|
+
FileUtils.mkdir_p(File.dirname(self.disk_path))
|
273
|
+
File.open(self.disk_path, 'w') { |io| io.write(current_content) }
|
274
|
+
end
|
275
|
+
|
276
|
+
def inspect
|
277
|
+
"<#{self.class} name=#{self.name} asset.path=#{self.asset.path}>"
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
|
282
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::BinaryFilter is responsible for filtering binary assets. It is the
|
4
|
+
# (abstract) superclass for all binary filters. Subclasses should override
|
5
|
+
# the +run+ method.
|
6
|
+
class BinaryFilter < Plugin
|
7
|
+
|
8
|
+
# Creates a new binary filter for the given asset and site.
|
9
|
+
#
|
10
|
+
# +asset_rep+:: A proxy for the asset representation (Nanoc2::AssetRep)
|
11
|
+
# that should be compiled by this filter.
|
12
|
+
#
|
13
|
+
# +asset+:: A proxy for the asset (Nanoc2::Asset) for which +asset_rep+ is
|
14
|
+
# the representation.
|
15
|
+
#
|
16
|
+
# +site+:: The site (Nanoc2::Site) this filter belongs to.
|
17
|
+
#
|
18
|
+
# +other_assigns+:: A hash containing other variables that should be made
|
19
|
+
# available during filtering.
|
20
|
+
def initialize(asset_rep, asset, site, other_assigns={})
|
21
|
+
@asset_rep = asset_rep
|
22
|
+
@asset = asset
|
23
|
+
@pages = site.pages.map { |p| p.to_proxy }
|
24
|
+
@assets = site.assets.map { |a| a.to_proxy }
|
25
|
+
@layouts = site.layouts.map { |l| l.to_proxy }
|
26
|
+
@config = site.config
|
27
|
+
@site = site
|
28
|
+
@other_assigns = other_assigns
|
29
|
+
end
|
30
|
+
|
31
|
+
# Runs the filter. This method returns a File instance pointing to a new
|
32
|
+
# file, containing the filtered content.
|
33
|
+
#
|
34
|
+
# +file+:: A File instance representing the incoming file that should be
|
35
|
+
# filtered. This file should _not_ be modified.
|
36
|
+
#
|
37
|
+
# Subclasses must implement this method.
|
38
|
+
def run(file)
|
39
|
+
raise NotImplementedError.new("Nanoc2::BinaryFilter subclasses must implement #run")
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::Code represent the custom code of a nanoc site. It contains the
|
4
|
+
# textual source code as well as a mtime, which is used to speed up site
|
5
|
+
# compilation.
|
6
|
+
class Code
|
7
|
+
|
8
|
+
# The Nanoc2::Site this code belongs to.
|
9
|
+
attr_accessor :site
|
10
|
+
|
11
|
+
# The textual source code representation.
|
12
|
+
attr_reader :data
|
13
|
+
|
14
|
+
# The time where the code was last modified.
|
15
|
+
attr_reader :mtime
|
16
|
+
|
17
|
+
# Creates a new code object. +data+ is the raw source code, which will be
|
18
|
+
# executed before compilation. +mtime+ is the time when the code was last
|
19
|
+
# modified (optional).
|
20
|
+
def initialize(data, mtime=nil)
|
21
|
+
@data = data
|
22
|
+
@mtime = mtime
|
23
|
+
end
|
24
|
+
|
25
|
+
# Loads the code by executing it.
|
26
|
+
def load
|
27
|
+
eval(@data, TOPLEVEL_BINDING)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Saves the code in the database, creating it if it doesn't exist yet or
|
31
|
+
# updating it if it already exists. Tells the site's data source to save
|
32
|
+
# the code.
|
33
|
+
def save
|
34
|
+
@site.data_source.loading do
|
35
|
+
@site.data_source.save_code(self)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::Compiler is responsible for compiling a site's page and asset
|
4
|
+
# representations.
|
5
|
+
class Compiler
|
6
|
+
|
7
|
+
attr_reader :stack
|
8
|
+
|
9
|
+
# Creates a new compiler for the given site.
|
10
|
+
def initialize(site)
|
11
|
+
@site = site
|
12
|
+
@stack = []
|
13
|
+
end
|
14
|
+
|
15
|
+
# Compiles (part of) the site and writes out the compiled page and asset
|
16
|
+
# representations.
|
17
|
+
#
|
18
|
+
# +obj+:: The page or asset that should be compiled, along with their
|
19
|
+
# dependencies, or +nil+ if the entire site should be compiled.
|
20
|
+
#
|
21
|
+
# This method also accepts a few parameters:
|
22
|
+
#
|
23
|
+
# +:also_layout+:: true if the page rep should also be laid out and
|
24
|
+
# post-filtered, false if the page rep should only be
|
25
|
+
# pre-filtered. Only applicable to page reps, and not to
|
26
|
+
# asset reps. Defaults to true.
|
27
|
+
#
|
28
|
+
# +:even_when_not_outdated+:: true if the rep should be compiled even if
|
29
|
+
# it is not outdated, false if not. Defaults
|
30
|
+
# to false.
|
31
|
+
#
|
32
|
+
# +:from_scratch+:: true if all compilation stages (for page reps:
|
33
|
+
# pre-filter, layout, post-filter; for asset reps:
|
34
|
+
# filter) should be performed again even if they have
|
35
|
+
# already been performed, false otherwise. Defaults to
|
36
|
+
# false.
|
37
|
+
def run(objects=nil, params={})
|
38
|
+
# Parse params
|
39
|
+
also_layout = params[:also_layout] || true
|
40
|
+
even_when_not_outdated = params[:even_when_not_outdated] || false
|
41
|
+
from_scratch = params[:from_scratch] || false
|
42
|
+
|
43
|
+
# Load data
|
44
|
+
@site.load_data
|
45
|
+
|
46
|
+
# Create output directory if necessary
|
47
|
+
FileUtils.mkdir_p(@site.config[:output_dir])
|
48
|
+
|
49
|
+
# Initialize
|
50
|
+
@stack = []
|
51
|
+
|
52
|
+
# Get pages and asset reps
|
53
|
+
objects = @site.pages + @site.assets if objects.nil?
|
54
|
+
reps = objects.map { |o| o.reps }.flatten
|
55
|
+
|
56
|
+
# Compile everything
|
57
|
+
reps.each do |rep|
|
58
|
+
if rep.is_a?(Nanoc2::PageRep)
|
59
|
+
rep.compile(also_layout, even_when_not_outdated, from_scratch)
|
60
|
+
else
|
61
|
+
rep.compile(even_when_not_outdated, from_scratch)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
|
5
|
+
# Cleans up the hash and returns the result. It performs the following
|
6
|
+
# operations:
|
7
|
+
#
|
8
|
+
# * Values with keys ending in +_at+ and +_on+ are converted into +Time+ and
|
9
|
+
# and +Date+ objects, respectively
|
10
|
+
# * All keys are converted to symbols
|
11
|
+
# * Value strings 'true', 'false' and 'none' are converted into +true+,
|
12
|
+
# +false+ and +nil+, respectively
|
13
|
+
#
|
14
|
+
# Hashes are cleaned recursively, so the value of a hash pair will also be
|
15
|
+
# cleaned if the value is a hash.
|
16
|
+
#
|
17
|
+
# For example, the following hash:
|
18
|
+
#
|
19
|
+
# {
|
20
|
+
# 'foo' => 'bar',
|
21
|
+
# :created_on => '2008-05-19',
|
22
|
+
# :layout => 'none'
|
23
|
+
# }
|
24
|
+
#
|
25
|
+
# will be converted into:
|
26
|
+
#
|
27
|
+
# {
|
28
|
+
# :foo => 'bar',
|
29
|
+
# :created_on => Date.parse('2008-05-19'),
|
30
|
+
# :layout => nil
|
31
|
+
# }
|
32
|
+
def clean
|
33
|
+
inject({}) do |hash, (key, value)|
|
34
|
+
real_key = key.to_s
|
35
|
+
|
36
|
+
if real_key =~ /_on$/ and value.is_a?(String)
|
37
|
+
hash.merge(key.to_sym => Date.parse(value))
|
38
|
+
elsif real_key =~ /_at$/ and value.is_a?(String)
|
39
|
+
hash.merge(key.to_sym => Time.parse(value.to_s))
|
40
|
+
elsif value == 'true'
|
41
|
+
hash.merge(key.to_sym => true)
|
42
|
+
elsif value == 'false'
|
43
|
+
hash.merge(key.to_sym => false)
|
44
|
+
elsif value == 'none'
|
45
|
+
hash.merge(key.to_sym => nil)
|
46
|
+
elsif value.is_a?(Hash)
|
47
|
+
hash.merge(key.to_sym => value.clean)
|
48
|
+
else
|
49
|
+
hash.merge(key.to_sym => value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the hash where all keys are converted to strings. Hash keys are
|
55
|
+
# converted to strings recursively, so the keys of a value of a hash pair
|
56
|
+
# will also be converted to strings if the value is a hash.
|
57
|
+
#
|
58
|
+
# For example, the following hash:
|
59
|
+
#
|
60
|
+
# {
|
61
|
+
# 'foo' => 'bar',
|
62
|
+
# :baz => 'quux'
|
63
|
+
# }
|
64
|
+
#
|
65
|
+
# will be converted into:
|
66
|
+
#
|
67
|
+
# {
|
68
|
+
# :foo => 'bar',
|
69
|
+
# :baz => 'quux'
|
70
|
+
# }
|
71
|
+
#
|
72
|
+
def stringify_keys
|
73
|
+
inject({}) do |hash, (key, value)|
|
74
|
+
hash.merge(key.to_s => value.is_a?(Hash) ? value.stringify_keys : value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|