nanoc3 3.2.0a1 → 3.2.0a2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/ChangeLog +2 -2
  2. data/NEWS.md +14 -0
  3. data/README.md +20 -12
  4. data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
  5. data/lib/nanoc3/base/compilation/checksum_store.rb +130 -0
  6. data/lib/nanoc3/base/compilation/checksummer.rb +68 -0
  7. data/lib/nanoc3/base/compilation/compiled_content_cache.rb +57 -0
  8. data/lib/nanoc3/base/{compiler.rb → compilation/compiler.rb} +255 -55
  9. data/lib/nanoc3/base/{compiler_dsl.rb → compilation/compiler_dsl.rb} +11 -6
  10. data/lib/nanoc3/base/{dependency_tracker.rb → compilation/dependency_tracker.rb} +62 -92
  11. data/lib/nanoc3/base/{filter.rb → compilation/filter.rb} +0 -0
  12. data/lib/nanoc3/base/compilation/item_rep_proxy.rb +87 -0
  13. data/lib/nanoc3/base/compilation/outdatedness_checker.rb +86 -0
  14. data/lib/nanoc3/base/compilation/outdatedness_reasons.rb +43 -0
  15. data/lib/nanoc3/base/{rule.rb → compilation/rule.rb} +8 -2
  16. data/lib/nanoc3/base/{rule_context.rb → compilation/rule_context.rb} +17 -14
  17. data/lib/nanoc3/base/directed_graph.rb +8 -0
  18. data/lib/nanoc3/base/errors.rb +9 -17
  19. data/lib/nanoc3/base/plugin_registry.rb +1 -1
  20. data/lib/nanoc3/base/result_data/item_rep.rb +447 -0
  21. data/lib/nanoc3/base/{code_snippet.rb → source_data/code_snippet.rb} +7 -22
  22. data/lib/nanoc3/base/{data_source.rb → source_data/data_source.rb} +0 -0
  23. data/lib/nanoc3/base/{item.rb → source_data/item.rb} +20 -30
  24. data/lib/nanoc3/base/{layout.rb → source_data/layout.rb} +7 -26
  25. data/lib/nanoc3/base/source_data/site.rb +314 -0
  26. data/lib/nanoc3/base/store.rb +126 -0
  27. data/lib/nanoc3/base.rb +26 -15
  28. data/lib/nanoc3/cli/base.rb +2 -1
  29. data/lib/nanoc3/cli/commands/compile.rb +116 -48
  30. data/lib/nanoc3/cli/commands/create_item.rb +0 -1
  31. data/lib/nanoc3/cli/commands/create_layout.rb +0 -1
  32. data/lib/nanoc3/cli/commands/create_site.rb +11 -1
  33. data/lib/nanoc3/cli/commands/debug.rb +11 -6
  34. data/lib/nanoc3/cli/commands/info.rb +1 -2
  35. data/lib/nanoc3/cli/commands/update.rb +0 -1
  36. data/lib/nanoc3/cli/commands/watch.rb +27 -32
  37. data/lib/nanoc3/cli/logger.rb +2 -2
  38. data/lib/nanoc3/data_sources/filesystem.rb +1 -6
  39. data/lib/nanoc3/extra/auto_compiler.rb +2 -3
  40. data/lib/nanoc3/extra/deployers/rsync.rb +1 -0
  41. data/lib/nanoc3/extra/validators/links.rb +45 -26
  42. data/lib/nanoc3/filters/asciidoc.rb +58 -0
  43. data/lib/nanoc3/filters/colorize_syntax.rb +47 -9
  44. data/lib/nanoc3/filters/less.rb +6 -0
  45. data/lib/nanoc3/filters/sass.rb +8 -5
  46. data/lib/nanoc3/filters.rb +2 -0
  47. data/lib/nanoc3/helpers/blogging.rb +8 -0
  48. data/lib/nanoc3/helpers/html_escape.rb +37 -7
  49. data/lib/nanoc3/helpers/link_to.rb +15 -4
  50. data/lib/nanoc3/helpers/rendering.rb +6 -2
  51. data/lib/nanoc3/tasks/clean.rb +0 -4
  52. data/lib/nanoc3.rb +1 -1
  53. data/nanoc3.gemspec +42 -0
  54. metadata +35 -19
  55. data/lib/nanoc3/base/checksummer.rb +0 -40
  56. data/lib/nanoc3/base/compiled_content_cache.rb +0 -86
  57. data/lib/nanoc3/base/item_rep.rb +0 -537
  58. data/lib/nanoc3/base/site.rb +0 -490
@@ -0,0 +1,314 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc3
4
+
5
+ # The in-memory representation of a nanoc site. It holds references to the
6
+ # following site data:
7
+ #
8
+ # * {#items} — the list of items ({Nanoc3::Item})
9
+ # * {#layouts} — the list of layouts ({Nanoc3::Layout})
10
+ # * {#code_snippets} — the list of code snippets ({Nanoc3::CodeSnippet})
11
+ # * {#data_sources} — the list of data sources ({Nanoc3::DataSource})
12
+ #
13
+ # In addition, each site has a {#config} hash which stores the site
14
+ # configuration.
15
+ #
16
+ # The physical representation of a {Nanoc3::Site} is usually a directory
17
+ # that contains a configuration file, site data, a rakefile, a rules file,
18
+ # etc. The way site data is stored depends on the data source.
19
+ class Site
20
+
21
+ # The default configuration for a data source. A data source's
22
+ # configuration overrides these options.
23
+ DEFAULT_DATA_SOURCE_CONFIG = {
24
+ :type => 'filesystem_unified',
25
+ :items_root => '/',
26
+ :layouts_root => '/',
27
+ :config => {}
28
+ }
29
+
30
+ # The default configuration for a site. A site's configuration overrides
31
+ # these options: when a {Nanoc3::Site} is created with a configuration
32
+ # that lacks some options, the default value will be taken from
33
+ # `DEFAULT_CONFIG`.
34
+ DEFAULT_CONFIG = {
35
+ :text_extensions => %w( css erb haml htm html js less markdown md php rb sass scss txt xhtml xml ),
36
+ :output_dir => 'output',
37
+ :data_sources => [ {} ],
38
+ :index_filenames => [ 'index.html' ],
39
+ :enable_output_diff => false
40
+ }
41
+
42
+ # Creates a site object for the site specified by the given
43
+ # `dir_or_config_hash` argument.
44
+ #
45
+ # @param [Hash, String] dir_or_config_hash If a string, contains the path
46
+ # to the site directory; if a hash, contains the site configuration.
47
+ def initialize(dir_or_config_hash)
48
+ build_config(dir_or_config_hash)
49
+ end
50
+
51
+ # Compiles the site.
52
+ #
53
+ # @return [void]
54
+ def compile
55
+ compiler.run
56
+ end
57
+
58
+ # Returns the compiler for this site. Will create a new compiler if none
59
+ # exists yet.
60
+ #
61
+ # @return [Nanoc3::Compiler] The compiler for this site
62
+ def compiler
63
+ @compiler ||= Compiler.new(self)
64
+ end
65
+
66
+ # Returns the data sources for this site. Will create a new data source if
67
+ # none exists yet.
68
+ #
69
+ # @return [Array<Nanoc3::DataSource>] The list of data sources for this
70
+ # site
71
+ #
72
+ # @raise [Nanoc3::Errors::UnknownDataSource] if the site configuration
73
+ # specifies an unknown data source
74
+ def data_sources
75
+ load_code_snippets
76
+
77
+ @data_sources ||= begin
78
+ @config[:data_sources].map do |data_source_hash|
79
+ # Get data source class
80
+ data_source_class = Nanoc3::DataSource.named(data_source_hash[:type])
81
+ raise Nanoc3::Errors::UnknownDataSource.new(data_source_hash[:type]) if data_source_class.nil?
82
+
83
+ # Warn about deprecated data sources
84
+ # TODO [in nanoc 4.0] remove me
85
+ case data_source_hash[:type]
86
+ when 'filesystem'
87
+ warn "Warning: the 'filesystem' data source has been renamed to 'filesystem_verbose'. Using 'filesystem' will work in nanoc 3.1.x, but it will likely not work anymore in a future release of nanoc. Please update your data source configuration and replace 'filesystem' with 'filesystem_verbose'."
88
+ when 'filesystem_combined', 'filesystem_compact'
89
+ warn "Warning: the 'filesystem_combined' and 'filesystem_compact' data source has been merged into the new 'filesystem_unified' data source. Using 'filesystem_combined' and 'filesystem_compact' will work in nanoc 3.1.x, but it will likely not work anymore in a future release of nanoc. Please update your data source configuration and replace 'filesystem_combined' and 'filesystem_compact with 'filesystem_unified'."
90
+ end
91
+
92
+ # Create data source
93
+ data_source_class.new(
94
+ self,
95
+ data_source_hash[:items_root],
96
+ data_source_hash[:layouts_root],
97
+ data_source_hash[:config] || {}
98
+ )
99
+ end
100
+ end
101
+ end
102
+
103
+ # Returns this site’s code snippets.
104
+ #
105
+ # @return [Array<Nanoc3::CodeSnippet>] The list of code snippets in this
106
+ # site
107
+ def code_snippets
108
+ load
109
+ @code_snippets
110
+ end
111
+
112
+ # Returns this site’s items.
113
+ #
114
+ # @return [Array<Nanoc3::Item>] The list of items in this site
115
+ def items
116
+ load
117
+ @items
118
+ end
119
+
120
+ # Returns this site’s layouts.
121
+ #
122
+ # @return [Array<Nanoc3::Layouts>] The list of layout in this site
123
+ def layouts
124
+ load
125
+ @layouts
126
+ end
127
+
128
+ # Returns the site configuration. It has the following keys:
129
+ #
130
+ # * `text_extensions` (`Array<String>`) - A list of file extensions that
131
+ # will cause nanoc to threat the file as textual instead of binary. When
132
+ # the data source finds a content file with an extension that is
133
+ # included in this list, it will be marked as textual.
134
+ #
135
+ # * `output_dir` (`String`) - The directory to which compiled items will
136
+ # be written. This path is relative to the current working directory,
137
+ # but can also be an absolute path.
138
+ #
139
+ # * `data_sources` (`Array<Hash>`) - A list of data sources for this site.
140
+ # See below for documentation on the structure of this list. By default,
141
+ # there is only one data source of the filesystem type mounted at `/`.
142
+ #
143
+ # * `index_filenames` (`Array<String>`) - A list of filenames that will be
144
+ # stripped off full item paths to create cleaner URLs. For example,
145
+ # `/about/` will be used instead of `/about/index.html`). The default
146
+ # value should be okay in most cases.
147
+ #
148
+ # * `enable_output_diff` (`Boolean`) - True when diffs should be generated
149
+ # for the compiled content of this site; false otherwise.
150
+ #
151
+ # The list of data sources consists of hashes with the following keys:
152
+ #
153
+ # * `:type` (`String`) - The type of data source, i.e. its identifier.
154
+ #
155
+ # * `:items_root` (`String`) - The prefix that should be given to all
156
+ # items returned by the {#items} method (comparable to mount points
157
+ # for filesystems in Unix-ish OSes).
158
+ #
159
+ # * `:layouts_root` (`String`) - The prefix that should be given to all
160
+ # layouts returned by the {#layouts} method (comparable to mount
161
+ # points for filesystems in Unix-ish OSes).
162
+ #
163
+ # * `:config` (`Hash`) - A hash containing the configuration for this data
164
+ # source. nanoc itself does not use this hash. This is especially
165
+ # useful for online data sources; for example, a Twitter data source
166
+ # would need the username of the account from which to fetch tweets.
167
+ #
168
+ # @return [Hash] The site configuration
169
+ def config
170
+ # Add reference to config if necessary
171
+ if !@config.respond_to?(:reference)
172
+ def @config.reference
173
+ :config
174
+ end
175
+ end
176
+
177
+ # Add data to config if necessary
178
+ if !@config.respond_to?(:data)
179
+ def @config.data
180
+ self.inspect
181
+ end
182
+ end
183
+
184
+ @config
185
+ end
186
+
187
+ # Fills each item's parent reference and children array with the
188
+ # appropriate items. It is probably not necessary to call this method
189
+ # manually; it will be called when appropriate.
190
+ #
191
+ # @return [void]
192
+ def setup_child_parent_links
193
+ # Clear all links
194
+ @items.each do |item|
195
+ item.parent = nil
196
+ item.children = []
197
+ end
198
+
199
+ @items.each do |item|
200
+ # Get parent
201
+ parent_identifier = item.identifier.sub(/[^\/]+\/$/, '')
202
+ parent = @items.find { |p| p.identifier == parent_identifier }
203
+ next if parent.nil? or item.identifier == '/'
204
+
205
+ # Link
206
+ item.parent = parent
207
+ parent.children << item
208
+ end
209
+ end
210
+
211
+ # TODO document
212
+ #
213
+ # @api private
214
+ def objects
215
+ # FIXME remove reference to rules
216
+ items + layouts + code_snippets + [ config, compiler.rules_with_reference ]
217
+ end
218
+
219
+ # @deprecated It is no longer necessary to explicitly load site data. It
220
+ # is safe to remove all {#load_data} calls.
221
+ def load_data(force=false)
222
+ warn 'It is no longer necessary to call Nanoc3::Site#load_data. This method no longer has any effect. All calls to this method can be safely removed.'
223
+ end
224
+
225
+ private
226
+
227
+ # Loads the site data. It is not necessary to call this method explicitly;
228
+ # it will be called when it is necessary.
229
+ def load
230
+ return if @data_loaded
231
+ @data_loaded = true
232
+
233
+ # Load all data
234
+ load_code_snippets
235
+ data_sources.each { |ds| ds.use }
236
+ load_items
237
+ load_layouts
238
+ data_sources.each { |ds| ds.unuse }
239
+ setup_child_parent_links
240
+
241
+ # Load compiler too
242
+ # FIXME this should not be necessary
243
+ compiler.load
244
+ end
245
+
246
+ # Loads this site’s code and executes it.
247
+ def load_code_snippets
248
+ @code_snippets_loaded ||= false
249
+ return if @code_snippets_loaded
250
+ @code_snippets_loaded = true
251
+
252
+ # Get code snippets
253
+ @code_snippets = Dir['lib/**/*.rb'].sort.map do |filename|
254
+ Nanoc3::CodeSnippet.new(
255
+ File.read(filename),
256
+ filename
257
+ )
258
+ end
259
+
260
+ # Execute code snippets
261
+ @code_snippets.each { |cs| cs.load }
262
+ end
263
+
264
+ # Loads this site’s items, sets up item child-parent relationships and
265
+ # builds each item's list of item representations.
266
+ def load_items
267
+ @items_loaded ||= false
268
+ return if @items_loaded
269
+ @items_loaded = true
270
+
271
+ # Get items
272
+ @items = []
273
+ data_sources.each do |ds|
274
+ items_in_ds = ds.items
275
+ items_in_ds.each { |i| i.identifier = File.join(ds.items_root, i.identifier) }
276
+ @items.concat(items_in_ds)
277
+ end
278
+ end
279
+
280
+ # Loads this site’s layouts.
281
+ def load_layouts
282
+ @layouts_loaded ||= false
283
+ return if @layouts_loaded
284
+ @layouts_loaded = true
285
+
286
+ # Get layouts
287
+ @layouts = []
288
+ data_sources.each do |ds|
289
+ layouts_in_ds = ds.layouts
290
+ layouts_in_ds.each { |i| i.identifier = File.join(ds.layouts_root, i.identifier) }
291
+ @layouts.concat(layouts_in_ds)
292
+ end
293
+ end
294
+
295
+ # Builds the configuration hash based on the given argument. Also see
296
+ # {#initialize} for details.
297
+ def build_config(dir_or_config_hash)
298
+ if dir_or_config_hash.is_a? String
299
+ # Read config from config.yaml in given dir
300
+ config_path = File.join(dir_or_config_hash, 'config.yaml')
301
+ @config = DEFAULT_CONFIG.merge(YAML.load_file(config_path).symbolize_keys)
302
+ @config[:data_sources].map! { |ds| ds.symbolize_keys }
303
+ else
304
+ # Use passed config hash
305
+ @config = DEFAULT_CONFIG.merge(dir_or_config_hash)
306
+ end
307
+
308
+ # Merge data sources with default data source config
309
+ @config[:data_sources].map! { |ds| DEFAULT_DATA_SOURCE_CONFIG.merge(ds) }
310
+ end
311
+
312
+ end
313
+
314
+ end
@@ -0,0 +1,126 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc3
4
+
5
+ # An abstract superclass for classes that need to store data to the
6
+ # filesystem, such as checksums, cached compiled content and dependency
7
+ # graphs.
8
+ #
9
+ # @abstract Subclasses must implement {#data} and {#data=}, and may
10
+ # implement {#no_data_found} and {#version_mismatch_detected}.
11
+ #
12
+ # @api private
13
+ class Store
14
+
15
+ # @return [String] The name of the file where data will be loaded from and
16
+ # stored to.
17
+ attr_reader :filename
18
+
19
+ # @return [Numeric] The version number corresponding to the file format
20
+ # the data is in. When the file format changes, the version number
21
+ # should be incremented.
22
+ attr_reader :version
23
+
24
+ # Creates a new store for the given filename.
25
+ #
26
+ # @param [String] filename The name of the file where data will be loaded
27
+ # from and stored to.
28
+ #
29
+ # @param [Numeric] version The version number corresponding to the file
30
+ # format the data is in. When the file format changes, the version
31
+ # number should be incremented.
32
+ def initialize(filename, version)
33
+ @filename = filename
34
+ @version = version
35
+ end
36
+
37
+ # @group Loading and storing data
38
+
39
+ # @return The data that should be written to the disk
40
+ #
41
+ # @abstract This method must be implemented by the subclass.
42
+ def data
43
+ raise NotImplementedError.new("Nanoc3::Store subclasses must implement #data and #data=")
44
+ end
45
+
46
+ # @param new_data The data that has been loaded from the disk
47
+ #
48
+ # @abstract This method must be implemented by the subclass.
49
+ #
50
+ # @return [void]
51
+ def data=(new_data)
52
+ raise NotImplementedError.new("Nanoc3::Store subclasses must implement #data and #data=")
53
+ end
54
+
55
+ # Loads the data from the filesystem into memory. This method will set the
56
+ # loaded data using the {#data=} method.
57
+ #
58
+ # @return [void]
59
+ def load
60
+ # Don’t load twice
61
+ if @loaded
62
+ return
63
+ end
64
+
65
+ # Check file existance
66
+ if !File.file?(self.filename)
67
+ no_data_found
68
+ @loaded = true
69
+ return
70
+ end
71
+
72
+ pstore.transaction do
73
+ # Check version
74
+ if pstore[:version] != self.version
75
+ version_mismatch_detected
76
+ @loaded = true
77
+ return
78
+ end
79
+
80
+ # Load
81
+ self.data = pstore[:data]
82
+ @loaded = true
83
+ end
84
+ end
85
+
86
+ # Stores the data contained in memory to the filesystem. This method will
87
+ # use the {#data} method to fetch the data that should be written.
88
+ #
89
+ # @return [void]
90
+ def store
91
+ FileUtils.mkdir_p(File.dirname(self.filename))
92
+
93
+ pstore.transaction do
94
+ pstore[:data] = self.data
95
+ pstore[:version] = self.version
96
+ end
97
+ end
98
+
99
+ # @group Callback methods
100
+
101
+ # Callback method that is called when no data file was found. By default,
102
+ # this implementation does nothing, but it should probably be overridden
103
+ # by the subclass.
104
+ #
105
+ # @return [void]
106
+ def no_data_found
107
+ end
108
+
109
+ # Callback method that is called when a version mismatch is detected. By
110
+ # default, this implementation does nothing, but it should probably be
111
+ # overridden by the subclass.
112
+ #
113
+ # @return [void]
114
+ def version_mismatch_detected
115
+ end
116
+
117
+ private
118
+
119
+ def pstore
120
+ require 'pstore'
121
+ @pstore ||= PStore.new(self.filename)
122
+ end
123
+
124
+ end
125
+
126
+ end
data/lib/nanoc3/base.rb CHANGED
@@ -5,26 +5,37 @@ module Nanoc3
5
5
  require 'nanoc3/base/core_ext'
6
6
  require 'nanoc3/base/ordered_hash'
7
7
 
8
- autoload 'Checksummer', 'nanoc3/base/checksummer'
9
- autoload 'CodeSnippet', 'nanoc3/base/code_snippet'
10
- autoload 'CompiledContentCache', 'nanoc3/base/compiled_content_cache'
11
- autoload 'Compiler', 'nanoc3/base/compiler'
12
- autoload 'CompilerDSL', 'nanoc3/base/compiler_dsl'
13
- autoload 'Config', 'nanoc3/base/config'
8
+ # Load helper classes
14
9
  autoload 'Context', 'nanoc3/base/context'
15
- autoload 'DataSource', 'nanoc3/base/data_source'
16
- autoload 'DependencyTracker', 'nanoc3/base/dependency_tracker'
17
10
  autoload 'DirectedGraph', 'nanoc3/base/directed_graph'
18
11
  autoload 'Errors', 'nanoc3/base/errors'
19
- autoload 'Filter', 'nanoc3/base/filter'
20
- autoload 'Item', 'nanoc3/base/item'
21
- autoload 'ItemRep', 'nanoc3/base/item_rep'
22
- autoload 'Layout', 'nanoc3/base/layout'
23
12
  autoload 'NotificationCenter', 'nanoc3/base/notification_center'
24
13
  autoload 'PluginRegistry', 'nanoc3/base/plugin_registry'
25
- autoload 'Rule', 'nanoc3/base/rule'
26
- autoload 'RuleContext', 'nanoc3/base/rule_context'
27
- autoload 'Site', 'nanoc3/base/site'
14
+ autoload 'Store', 'nanoc3/base/store'
15
+
16
+ # Load source data classes
17
+ autoload 'CodeSnippet', 'nanoc3/base/source_data/code_snippet'
18
+ autoload 'DataSource', 'nanoc3/base/source_data/data_source'
19
+ autoload 'Item', 'nanoc3/base/source_data/item'
20
+ autoload 'Layout', 'nanoc3/base/source_data/layout'
21
+ autoload 'Site', 'nanoc3/base/source_data/site'
22
+
23
+ # Load result data classes
24
+ autoload 'ItemRep', 'nanoc3/base/result_data/item_rep'
25
+
26
+ # Load compilation classes
27
+ autoload 'Checksummer', 'nanoc3/base/compilation/checksummer'
28
+ autoload 'ChecksumStore', 'nanoc3/base/compilation/checksum_store'
29
+ autoload 'CompiledContentCache', 'nanoc3/base/compilation/compiled_content_cache'
30
+ autoload 'Compiler', 'nanoc3/base/compilation/compiler'
31
+ autoload 'CompilerDSL', 'nanoc3/base/compilation/compiler_dsl'
32
+ autoload 'DependencyTracker', 'nanoc3/base/compilation/dependency_tracker'
33
+ autoload 'Filter', 'nanoc3/base/compilation/filter'
34
+ autoload 'ItemRepProxy', 'nanoc3/base/compilation/item_rep_proxy'
35
+ autoload 'OutdatednessChecker', 'nanoc3/base/compilation/outdatedness_checker'
36
+ autoload 'OutdatednessReasons', 'nanoc3/base/compilation/outdatedness_reasons'
37
+ autoload 'Rule', 'nanoc3/base/compilation/rule'
38
+ autoload 'RuleContext', 'nanoc3/base/compilation/rule_context'
28
39
 
29
40
  # Deprecated; use PluginRepository instead
30
41
  # TODO [in nanoc 4.0] remove me
@@ -5,7 +5,7 @@ module Nanoc3::CLI
5
5
  class Base < Cri::Base
6
6
 
7
7
  # A hash that contains the name of the gem for a given required file. If a
8
- # {#require} fails, the gem name is looked up in this hash.
8
+ # `#require` fails, the gem name is looked up in this hash.
9
9
  GEM_NAMES = {
10
10
  'adsf' => 'adsf',
11
11
  'bluecloth' => 'bluecloth',
@@ -13,6 +13,7 @@ module Nanoc3::CLI
13
13
  'coderay' => 'coderay',
14
14
  'cri' => 'cri',
15
15
  'erubis' => 'erubis',
16
+ 'escape' => 'escape',
16
17
  'fssm' => 'fssm',
17
18
  'haml' => 'haml',
18
19
  'json' => 'json',