nanoc3 3.2.0a1 → 3.2.0a2

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 (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',