nanoc 2.0.4 → 2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/ChangeLog +31 -1
  2. data/LICENSE +1 -1
  3. data/README +63 -3
  4. data/Rakefile +59 -12
  5. data/bin/nanoc +7 -199
  6. data/lib/nanoc.rb +83 -12
  7. data/lib/nanoc/base/asset.rb +113 -0
  8. data/lib/nanoc/base/asset_defaults.rb +21 -0
  9. data/lib/nanoc/base/asset_rep.rb +277 -0
  10. data/lib/nanoc/base/binary_filter.rb +44 -0
  11. data/lib/nanoc/base/code.rb +41 -0
  12. data/lib/nanoc/base/compiler.rb +46 -34
  13. data/lib/nanoc/base/core_ext/hash.rb +51 -7
  14. data/lib/nanoc/base/core_ext/string.rb +8 -0
  15. data/lib/nanoc/base/data_source.rb +253 -20
  16. data/lib/nanoc/base/defaults.rb +30 -0
  17. data/lib/nanoc/base/enhancements.rb +9 -84
  18. data/lib/nanoc/base/filter.rb +109 -6
  19. data/lib/nanoc/base/layout.rb +91 -0
  20. data/lib/nanoc/base/notification_center.rb +66 -0
  21. data/lib/nanoc/base/page.rb +94 -126
  22. data/lib/nanoc/base/page_defaults.rb +20 -0
  23. data/lib/nanoc/base/page_rep.rb +318 -0
  24. data/lib/nanoc/base/plugin.rb +57 -9
  25. data/lib/nanoc/base/proxies/asset_proxy.rb +29 -0
  26. data/lib/nanoc/base/proxies/asset_rep_proxy.rb +26 -0
  27. data/lib/nanoc/base/proxies/layout_proxy.rb +25 -0
  28. data/lib/nanoc/base/proxies/page_proxy.rb +35 -0
  29. data/lib/nanoc/base/proxies/page_rep_proxy.rb +28 -0
  30. data/lib/nanoc/base/proxy.rb +37 -0
  31. data/lib/nanoc/base/router.rb +72 -0
  32. data/lib/nanoc/base/site.rb +219 -88
  33. data/lib/nanoc/base/template.rb +64 -0
  34. data/lib/nanoc/binary_filters/image_science_thumbnail.rb +28 -0
  35. data/lib/nanoc/cli.rb +1 -0
  36. data/lib/nanoc/cli/base.rb +219 -0
  37. data/lib/nanoc/cli/cli.rb +16 -0
  38. data/lib/nanoc/cli/command.rb +105 -0
  39. data/lib/nanoc/cli/commands/autocompile.rb +80 -0
  40. data/lib/nanoc/cli/commands/compile.rb +273 -0
  41. data/lib/nanoc/cli/commands/create_layout.rb +85 -0
  42. data/lib/nanoc/cli/commands/create_page.rb +85 -0
  43. data/lib/nanoc/cli/commands/create_site.rb +327 -0
  44. data/lib/nanoc/cli/commands/create_template.rb +76 -0
  45. data/lib/nanoc/cli/commands/help.rb +69 -0
  46. data/lib/nanoc/cli/commands/info.rb +114 -0
  47. data/lib/nanoc/cli/commands/switch.rb +141 -0
  48. data/lib/nanoc/cli/commands/update.rb +91 -0
  49. data/lib/nanoc/cli/ext.rb +37 -0
  50. data/lib/nanoc/cli/logger.rb +66 -0
  51. data/lib/nanoc/cli/option_parser.rb +168 -0
  52. data/lib/nanoc/data_sources/filesystem.rb +645 -224
  53. data/lib/nanoc/data_sources/filesystem_combined.rb +495 -0
  54. data/lib/nanoc/extra/auto_compiler.rb +265 -0
  55. data/lib/nanoc/extra/context.rb +22 -0
  56. data/lib/nanoc/extra/core_ext/hash.rb +54 -0
  57. data/lib/nanoc/extra/core_ext/time.rb +13 -0
  58. data/lib/nanoc/extra/file_proxy.rb +29 -0
  59. data/lib/nanoc/extra/vcs.rb +48 -0
  60. data/lib/nanoc/extra/vcses/bazaar.rb +21 -0
  61. data/lib/nanoc/extra/vcses/dummy.rb +20 -0
  62. data/lib/nanoc/extra/vcses/git.rb +21 -0
  63. data/lib/nanoc/extra/vcses/mercurial.rb +21 -0
  64. data/lib/nanoc/extra/vcses/subversion.rb +21 -0
  65. data/lib/nanoc/filters/bluecloth.rb +13 -0
  66. data/lib/nanoc/filters/erb.rb +6 -22
  67. data/lib/nanoc/filters/erubis.rb +14 -0
  68. data/lib/nanoc/filters/haml.rb +7 -23
  69. data/lib/nanoc/filters/markaby.rb +5 -5
  70. data/lib/nanoc/filters/maruku.rb +14 -0
  71. data/lib/nanoc/filters/old.rb +19 -0
  72. data/lib/nanoc/filters/rdiscount.rb +13 -0
  73. data/lib/nanoc/filters/rdoc.rb +5 -4
  74. data/lib/nanoc/filters/redcloth.rb +14 -0
  75. data/lib/nanoc/filters/rubypants.rb +14 -0
  76. data/lib/nanoc/filters/sass.rb +13 -0
  77. data/lib/nanoc/helpers/blogging.rb +170 -0
  78. data/lib/nanoc/helpers/capturing.rb +59 -0
  79. data/lib/nanoc/helpers/html_escape.rb +23 -0
  80. data/lib/nanoc/helpers/link_to.rb +69 -0
  81. data/lib/nanoc/helpers/render.rb +47 -0
  82. data/lib/nanoc/helpers/tagging.rb +52 -0
  83. data/lib/nanoc/helpers/xml_sitemap.rb +58 -0
  84. data/lib/nanoc/routers/default.rb +54 -0
  85. data/lib/nanoc/routers/no_dirs.rb +66 -0
  86. data/lib/nanoc/routers/versioned.rb +79 -0
  87. metadata +112 -22
  88. data/lib/nanoc/base/auto_compiler.rb +0 -132
  89. data/lib/nanoc/base/layout_processor.rb +0 -33
  90. data/lib/nanoc/base/page_proxy.rb +0 -31
  91. data/lib/nanoc/base/plugin_manager.rb +0 -33
  92. data/lib/nanoc/data_sources/database.rb +0 -259
  93. data/lib/nanoc/data_sources/trivial.rb +0 -145
  94. data/lib/nanoc/filters/markdown.rb +0 -13
  95. data/lib/nanoc/filters/smartypants.rb +0 -13
  96. data/lib/nanoc/filters/textile.rb +0 -13
  97. data/lib/nanoc/layout_processors/erb.rb +0 -35
  98. data/lib/nanoc/layout_processors/haml.rb +0 -38
  99. data/lib/nanoc/layout_processors/markaby.rb +0 -16
data/lib/nanoc.rb CHANGED
@@ -1,24 +1,95 @@
1
1
  module Nanoc
2
2
 
3
- VERSION = '2.0.4'
3
+ # The current nanoc version.
4
+ VERSION = '2.1'
4
5
 
5
- def self.load_file(*path)
6
+ # Generic error. Superclass for all nanoc-specific errors.
7
+ class Error < RuntimeError ; end
8
+
9
+ module Errors # :nodoc:
10
+
11
+ # Error that is raised when a site is loaded that uses a data source with
12
+ # an unknown identifier.
13
+ class UnknownDataSourceError < Error ; end
14
+
15
+ # Error that is raised when a site is loaded that uses a data source with
16
+ # an unknown identifier.
17
+ class UnknownRouterError < Error ; end
18
+
19
+ # Error that is raised during site compilation when a page uses a layout
20
+ # that is not present in the site.
21
+ class UnknownLayoutError < Error ; end
22
+
23
+ # Error that is raised during site compilation when a page uses a filter
24
+ # that is not known.
25
+ class UnknownFilterError < Error ; end
26
+
27
+ # Error that is raised during site compilation when a layout is compiled
28
+ # for which the filter cannot be determined. This is similar to the
29
+ # UnknownFilterError, but specific for filters for layouts.
30
+ class CannotDetermineFilterError < Error ; end
31
+
32
+ # Error that is raised during site compilation when a page (directly or
33
+ # indirectly) includes its own page content, leading to endless recursion.
34
+ class RecursiveCompilationError < Error ; end
35
+
36
+ # Error that is raised when a certain function or feature is used that is
37
+ # no longer supported by nanoc.
38
+ class NoLongerSupportedError < Error ; end
39
+
40
+ end
41
+
42
+ module BinaryFilters # :nodoc:
43
+ end
44
+
45
+ module DataSources # :nodoc:
46
+ end
47
+
48
+ module Helpers # :nodoc:
49
+ end
50
+
51
+ module Extra # :nodoc:
52
+ end
53
+
54
+ module Filters # :nodoc:
55
+ end
56
+
57
+ module Routers # :nodoc:
58
+ end
59
+
60
+ # Requires the given Ruby files at the specified path.
61
+ #
62
+ # +path+:: An array containing path segments. This path is relative to the
63
+ # directory this file (nanoc.rb) is in. Can contain wildcards.
64
+ def self.load(*path)
6
65
  full_path = [ File.dirname(__FILE__), 'nanoc' ] + path
7
66
  Dir[File.join(full_path)].each { |f| require f }
8
67
  end
9
68
 
10
69
  end
11
70
 
71
+ # Load requirements
72
+ begin ; require 'rubygems' ; rescue LoadError ; end
73
+ require 'yaml'
74
+ require 'fileutils'
75
+
12
76
  # Load base
13
- Nanoc.load_file('base', 'enhancements.rb')
14
- Nanoc.load_file('base', 'core_ext', '*.rb')
15
- Nanoc.load_file('base', 'plugin.rb')
16
- Nanoc.load_file('base', '*.rb')
77
+ Nanoc.load('base', 'enhancements.rb')
78
+ Nanoc.load('base', 'defaults.rb')
79
+ Nanoc.load('base', 'proxy.rb')
80
+ Nanoc.load('base', 'proxies', '*.rb')
81
+ Nanoc.load('base', 'core_ext', '*.rb')
82
+ Nanoc.load('base', 'plugin.rb')
83
+ Nanoc.load('base', '*.rb')
17
84
 
18
- # Load plugins
19
- Nanoc.load_file('data_sources', '*.rb')
20
- Nanoc.load_file('filters', '*.rb')
21
- Nanoc.load_file('layout_processors', '*.rb')
85
+ # Load extra's
86
+ Nanoc.load('extra', 'core_ext', '*.rb')
87
+ Nanoc.load('extra', '*.rb')
88
+ Nanoc.load('extra', 'vcses', '*.rb')
22
89
 
23
- # Get global binding
24
- $nanoc_binding = binding
90
+ # Load plugins
91
+ Nanoc.load('data_sources', '*.rb')
92
+ Nanoc.load('filters', '*.rb')
93
+ Nanoc.load('binary_filters', '*.rb')
94
+ Nanoc.load('routers', '*.rb')
95
+ Nanoc.load('helpers', '*.rb')
@@ -0,0 +1,113 @@
1
+ module Nanoc
2
+
3
+ # A Nanoc::Asset represents an asset in a nanoc site. It has a file object
4
+ # (File instance) and attributes, as well as a path. It can also store the
5
+ # modification time to speed up compilation.
6
+ #
7
+ # Each asset has a list of asset representations or reps (Nanoc::AssetRep);
8
+ # compiling an asset actually compiles all of its assets.
9
+ class Asset
10
+
11
+ # Defaults values for assets.
12
+ DEFAULTS = {
13
+ :extension => 'dat',
14
+ :binary => true,
15
+ :filters => []
16
+ }
17
+
18
+ # The Nanoc::Site this asset belongs to.
19
+ attr_accessor :site
20
+
21
+ # This assets's file.
22
+ attr_reader :file
23
+
24
+ # A hash containing this asset's attributes.
25
+ attr_accessor :attributes
26
+
27
+ # This asset's path.
28
+ attr_reader :path
29
+
30
+ # The time when this asset was last modified.
31
+ attr_reader :mtime
32
+
33
+ # This asset's list of asset representations.
34
+ attr_reader :reps
35
+
36
+ # Creates a new asset.
37
+ #
38
+ # +file+:: An instance of File representing the uncompiled asset.
39
+ #
40
+ # +attributes+:: A hash containing this asset's attributes.
41
+ #
42
+ # +path+:: This asset's path.
43
+ #
44
+ # +mtime+:: The time when this asset was last modified.
45
+ def initialize(file, attributes, path, mtime=nil)
46
+ # Set primary attributes
47
+ @file = file
48
+ @attributes = attributes.clean
49
+ @path = path.cleaned_path
50
+ @mtime = mtime
51
+ end
52
+
53
+ # Builds the individual asset representations (Nanoc::AssetRep) for this
54
+ # asset.
55
+ def build_reps
56
+ # Get list of rep names
57
+ rep_names_default = (@site.asset_defaults.attributes[:reps] || {}).keys
58
+ rep_names_this = (@attributes[:reps] || {}).keys + [ :default ]
59
+ rep_names = rep_names_default | rep_names_this
60
+
61
+ # Get list of reps
62
+ reps = rep_names.inject({}) do |memo, rep_name|
63
+ rep = (@attributes[:reps] || {})[rep_name]
64
+ is_bad = (@attributes[:reps] || {}).has_key?(rep_name) && rep.nil?
65
+ is_bad ? memo : memo.merge(rep_name => rep || {})
66
+ end
67
+
68
+ # Build reps
69
+ @reps = []
70
+ reps.each_pair do |name, attrs|
71
+ @reps << AssetRep.new(self, attrs, name)
72
+ end
73
+ end
74
+
75
+ # Returns a proxy (Nanoc::AssetProxy) for this asset.
76
+ def to_proxy
77
+ @proxy ||= AssetProxy.new(self)
78
+ end
79
+
80
+ # Returns the attribute with the given name.
81
+ def attribute_named(name)
82
+ return @attributes[name] if @attributes.has_key?(name)
83
+ return @site.asset_defaults.attributes[name] if @site.asset_defaults.attributes.has_key?(name)
84
+ return DEFAULTS[name]
85
+ end
86
+
87
+ # Saves the asset in the database, creating it if it doesn't exist yet or
88
+ # updating it if it already exists. Tells the site's data source to save
89
+ # the asset.
90
+ def save
91
+ @site.data_source.loading do
92
+ @site.data_source.save_asset(self)
93
+ end
94
+ end
95
+
96
+ # Moves the asset to a new path. Tells the site's data source to move the
97
+ # asset.
98
+ def move_to(new_path)
99
+ @site.data_source.loading do
100
+ @site.data_source.move_asset(self, new_path)
101
+ end
102
+ end
103
+
104
+ # Deletes the asset. Tells the site's data source to delete the asset.
105
+ def delete
106
+ @site.data_source.loading do
107
+ @site.data_source.delete_asset(self)
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,21 @@
1
+ module Nanoc
2
+
3
+ # Nanoc::AssetDefaults represent the default attributes for all assets in
4
+ # the site. If a specific asset attribute is requested, but not found, then
5
+ # the asset defaults will be queried for this attribute. (If the attribute
6
+ # doesn't even exist in the asset defaults, hardcoded defaults will be
7
+ # used.)
8
+ class AssetDefaults < Defaults
9
+
10
+ # Saves the asset defaults in the database, creating it if it doesn't
11
+ # exist yet or updating it if it already exists. Tells the site's data
12
+ # source to save the asset defaults.
13
+ def save
14
+ @site.data_source.loading do
15
+ @site.data_source.save_asset_defaults(self)
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,277 @@
1
+ module Nanoc
2
+
3
+ # A Nanoc::AssetRep is a single representation (rep) of an asset
4
+ # (Nanoc::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 (Nanoc::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 (Nanoc::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 (Nanoc::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 Nanoc::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
+ # Nanoc::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
+ Nanoc::NotificationCenter.post(:compilation_started, self)
172
+ Nanoc::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
+ Nanoc::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
+ Nanoc::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(file)
207
+ # Create hash
208
+ incr_digest = Digest::MD5.new()
209
+
210
+ # Collect data
211
+ file.rewind
212
+ incr_digest << file.read(1000) until file.eof?
213
+
214
+ # Calculate hex hash
215
+ incr_digest.hexdigest
216
+ end
217
+
218
+ # Compiles the asset rep, treating its contents as binary data.
219
+ def compile_binary
220
+ # Calculate digest before
221
+ digest_before = File.file?(disk_path) ? digest(File.open(disk_path, 'r')) : nil
222
+
223
+ # Run filters
224
+ current_file = @asset.file
225
+ attribute_named(:filters).each do |filter_name|
226
+ # Free resources so that this filter won't fail
227
+ GC.start
228
+
229
+ # Create filter
230
+ klass = Nanoc::BinaryFilter.named(filter_name)
231
+ raise Nanoc::Errors::UnknownFilterError.new(filter_name) if klass.nil?
232
+ filter = klass.new(self.to_proxy, @asset.to_proxy, @asset.site)
233
+
234
+ # Run filter
235
+ Nanoc::NotificationCenter.post(:filtering_started, self, klass.identifier)
236
+ current_file = filter.run(current_file)
237
+ Nanoc::NotificationCenter.post(:filtering_ended, self, klass.identifier)
238
+ end
239
+
240
+ # Write asset
241
+ FileUtils.mkdir_p(File.dirname(self.disk_path))
242
+ FileUtils.cp(current_file.path, disk_path)
243
+
244
+ # Calculate digest after
245
+ digest_after = digest(current_file)
246
+ @modified = (digest_after != digest_before)
247
+ end
248
+
249
+ # Compiles the asset rep, treating its contents as textual data.
250
+ def compile_textual
251
+ # Get content
252
+ current_content = @asset.file.read
253
+
254
+ # Check modified
255
+ @modified = @created ? true : File.read(self.disk_path) != current_content
256
+
257
+ # Run filters
258
+ attribute_named(:filters).each do |filter_name|
259
+ # Create filter
260
+ klass = Nanoc::Filter.named(filter_name)
261
+ raise Nanoc::Errors::UnknownFilterError.new(filter_name) if klass.nil?
262
+ filter = klass.new(self)
263
+
264
+ # Run filter
265
+ Nanoc::NotificationCenter.post(:filtering_started, self, klass.identifier)
266
+ current_content = filter.run(current_content)
267
+ Nanoc::NotificationCenter.post(:filtering_ended, self, klass.identifier)
268
+ end
269
+
270
+ # Write asset
271
+ FileUtils.mkdir_p(File.dirname(self.disk_path))
272
+ File.open(self.disk_path, 'w') { |io| io.write(current_content) }
273
+ end
274
+
275
+ end
276
+
277
+ end