nanoc 2.0.4 → 2.1

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 (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
@@ -0,0 +1,44 @@
1
+ module Nanoc
2
+
3
+ # Nanoc::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 (Nanoc::AssetRep)
11
+ # that should be compiled by this filter.
12
+ #
13
+ # +asset+:: A proxy for the asset (Nanoc::Asset) for which +asset_rep+ is
14
+ # the representation.
15
+ #
16
+ # +site+:: The site (Nanoc::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("Nanoc::BinaryFilter subclasses must implement #run")
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,41 @@
1
+ module Nanoc
2
+
3
+ # Nanoc::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 Nanoc::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
@@ -1,54 +1,66 @@
1
1
  module Nanoc
2
+
3
+ # Nanoc::Compiler is responsible for compiling a site's page and asset
4
+ # representations.
2
5
  class Compiler
3
6
 
4
7
  attr_reader :stack
5
8
 
9
+ # Creates a new compiler for the given site.
6
10
  def initialize(site)
7
- @site = site
11
+ @site = site
12
+ @stack = []
8
13
  end
9
14
 
10
- def run(page=nil)
11
- # Give feedback
12
- log(:high, "Compiling #{page.nil? ? 'site' : 'page'}...")
13
- time_before = Time.now
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
14
42
 
15
- # Get the data we need
43
+ # Load data
16
44
  @site.load_data
17
- eval(@site.code, $nanoc_binding)
18
45
 
19
46
  # Create output directory if necessary
20
47
  FileUtils.mkdir_p(@site.config[:output_dir])
21
48
 
22
- # Compile
49
+ # Initialize
23
50
  @stack = []
24
- pages = (page.nil? ? @site.pages : [ page ])
25
- pages.each do |current_page|
26
- begin
27
- current_page.compile
28
- rescue => exception
29
- handle_exception(exception, current_page, !page.nil?)
30
- end
31
- end
32
51
 
33
- # Give feedback
34
- log(:high, "No pages were modified.") unless pages.any? { |page| page.modified? }
35
- log(:high, "#{page.nil? ? 'Site' : 'Pages'} compiled in #{format('%.2f', Time.now - time_before)}s.")
36
- end
52
+ # Get pages and asset reps
53
+ objects = @site.pages + @site.assets if objects.nil?
54
+ reps = objects.map { |o| o.reps }.flatten
37
55
 
38
- def handle_exception(exception, page, single_page)
39
- raise exception if single_page
40
-
41
- log(:high, "ERROR: An exception occured while compiling page #{page.path}.", $stderr)
42
- log(:high, "", $stderr)
43
- log(:high, "If you think this is a bug in nanoc, please do report it at", $stderr)
44
- log(:high, "<http://nanoc.stoneship.org/trac/newticket> -- thanks!", $stderr)
45
- log(:high, "", $stderr)
46
- log(:high, 'Message:', $stderr)
47
- log(:high, ' ' + exception.message, $stderr)
48
- log(:high, 'Backtrace:', $stderr)
49
- log(:high, exception.backtrace.map { |t| ' - ' + t }.join("\n"), $stderr)
50
-
51
- exit(1)
56
+ # Compile everything
57
+ reps.each do |rep|
58
+ if rep.is_a?(Nanoc::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
52
64
  end
53
65
 
54
66
  end
@@ -5,18 +5,38 @@ class Hash
5
5
  # Cleans up the hash and returns the result. It performs the following
6
6
  # operations:
7
7
  #
8
- # * Values with keys ending in _at and _on are converted into Times and
9
- # Dates, respectively
8
+ # * Values with keys ending in +_at+ and +_on+ are converted into +Time+ and
9
+ # and +Date+ objects, respectively
10
10
  # * All keys are converted to symbols
11
- # * Value strings 'true', 'false', and 'none' are converted into
12
- # true, false, and nil, respectively
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
+ # }
13
32
  def clean
14
33
  inject({}) do |hash, (key, value)|
15
34
  real_key = key.to_s
16
- if real_key =~ /_on$/
35
+
36
+ if real_key =~ /_on$/ and value.is_a?(String)
17
37
  hash.merge(key.to_sym => Date.parse(value))
18
- elsif real_key =~ /_at$/
19
- hash.merge(key.to_sym => Time.parse(value))
38
+ elsif real_key =~ /_at$/ and value.is_a?(String)
39
+ hash.merge(key.to_sym => Time.parse(value.to_s))
20
40
  elsif value == 'true'
21
41
  hash.merge(key.to_sym => true)
22
42
  elsif value == 'false'
@@ -31,4 +51,28 @@ class Hash
31
51
  end
32
52
  end
33
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
+
34
78
  end
@@ -0,0 +1,8 @@
1
+ class String
2
+
3
+ # Transforms string into an actual path
4
+ def cleaned_path
5
+ "/#{self}/".gsub(/^\/+|\/+$/, '/')
6
+ end
7
+
8
+ end
@@ -1,15 +1,31 @@
1
1
  module Nanoc
2
- class DataSource < Plugin
3
2
 
4
- attr_reader :config
3
+ # Nanoc::DataSource is responsible for loading data. It is the (abstract)
4
+ # superclass for all data sources. Subclasses must at least implement the
5
+ # data reading methods (+pages+, +page_defaults+, +layouts+, +templates+,
6
+ # and +code+); all other methods involving data manipulation are optional.
7
+ #
8
+ # Apart from the methods for loading and storing data, there are the +up+
9
+ # and +down+ methods for bringing up and tearing down the connection to the
10
+ # data source. These should be overridden in subclasses. The +loading+
11
+ # method wraps +up+ and +down+.
12
+ #
13
+ # The +setup+ method is used for setting up a site's data source for the
14
+ # first time. This method should be overridden in subclasses.
15
+ class DataSource < Plugin
5
16
 
17
+ # Creates a new data source for the given site.
6
18
  def initialize(site)
7
19
  @site = site
8
20
  @references = 0
9
21
  end
10
22
 
11
- # Preparation
12
-
23
+ # Loads the data source when necessary (calling +up+), yields, and unloads
24
+ # the data source when it is not being used elsewhere. All data source
25
+ # queries and data manipulations should be wrapped in a +loading+ block;
26
+ # it ensures that the data source is loaded when necessary and makes sure
27
+ # the data source does not get unloaded while it is still being used
28
+ # elsewhere.
13
29
  def loading
14
30
  # Load if necessary
15
31
  up if @references == 0
@@ -22,31 +38,248 @@ module Nanoc
22
38
  down if @references == 0
23
39
  end
24
40
 
25
- def up ; end
26
- def down ; end
41
+ ########## Loading and unloading
42
+
43
+ # Brings up the connection to the data. This is an abstract method
44
+ # implemented by the subclass. Depending on the way data is stored, this
45
+ # may not be necessary. This is the ideal place to connect to the
46
+ # database, for example.
47
+ #
48
+ # Subclasses may implement this method.
49
+ def up
50
+ end
51
+
52
+ # Brings down the connection to the data. This is an abstract method
53
+ # implemented by the subclass. This method should undo the effects of
54
+ # +up+.
55
+ #
56
+ # Subclasses may implement this method.
57
+ def down
58
+ end
59
+
60
+ ########## Creating/updating
61
+
62
+ # Creates the bare minimum essentials for this data source to work. This
63
+ # action will likely be destructive. This method should not create sample
64
+ # data such as a default home page, a default layout, etc. For example, if
65
+ # you're using a database, this is where you should create the necessary
66
+ # tables for the data source to function properly.
67
+ #
68
+ # Subclasses must implement this method.
69
+ def setup
70
+ not_implemented('setup')
71
+ end
72
+
73
+ # Removes all data stored by this data source. This method undoes the
74
+ # effects of the +setup+ method.
75
+ #
76
+ # Subclasses must implement this method.
77
+ def destroy
78
+ not_implemented('destroy')
79
+ end
80
+
81
+ # Updated the content stored in this site to a newer version. A newer
82
+ # version of a data source may store content in a different format, and
83
+ # this method will update the stored content to this newer format.
84
+ #
85
+ # Subclasses may implement this method.
86
+ def update
87
+ end
88
+
89
+ ########## Pages
90
+
91
+ # Returns the list of pages (represented by Nanoc::Page) in this site.
92
+ # This is an abstract method implemented by the subclass.
93
+ #
94
+ # Subclasses must implement this method.
95
+ def pages
96
+ not_implemented('pages')
97
+ end
98
+
99
+ # Saves the given page in the data source, creating it if it doesn't exist
100
+ # yet and updating the existing copy otherwise.
101
+ #
102
+ # Subclasses must implement this method.
103
+ def save_page(page)
104
+ not_implemented('save_page')
105
+ end
106
+
107
+ # Changes the path of the given page to the given new path. When changing
108
+ # a page's path, this method must be used (save_page will not work).
109
+ #
110
+ # Subclasses must implement this method.
111
+ def move_page(page, new_path)
112
+ not_implemented('move_page')
113
+ end
114
+
115
+ # Removes the given page from the data source.
116
+ #
117
+ # Subclasses must implement this method.
118
+ def delete_page(page)
119
+ not_implemented('delete_page')
120
+ end
121
+
122
+ ########## Assets
123
+
124
+ # Returns the list of assets (represented by Nanoc::Asset) in this site.
125
+ # This is an abstract method implemented by the subclass.
126
+ #
127
+ # Subclasses must implement this method.
128
+ def assets
129
+ not_implemented('assets')
130
+ end
131
+
132
+ # Saves the given asset in the data source, creating it if it doesn't
133
+ # exist yet and updating the existing copy otherwise.
134
+ #
135
+ # Subclasses must implement this method.
136
+ def save_asset(asset)
137
+ not_implemented('save_asset')
138
+ end
139
+
140
+ # Changes the path of the given asset to the given new path. When changing
141
+ # a asset's path, this method must be used (save_asset will not work).
142
+ #
143
+ # Subclasses must implement this method.
144
+ def move_asset(asset, new_path)
145
+ not_implemented('move_asset')
146
+ end
147
+
148
+ # Removes the given asset from the data source.
149
+ #
150
+ # Subclasses must implement this method.
151
+ def delete_asset(asset)
152
+ not_implemented('delete_asset')
153
+ end
154
+
155
+ ########## Page defaults
27
156
 
28
- def setup ; end
157
+ # Returns the page defaults (represented by Nanoc::PageDefaults) of this
158
+ # site. This is an abstract method implemented by the subclass.
159
+ #
160
+ # Subclasses must implement this method.
161
+ def page_defaults
162
+ not_implemented('page_defaults')
163
+ end
29
164
 
30
- # Loading data
165
+ # Saves the given page defaults in the data source.
166
+ #
167
+ # Subclasses must implement this method.
168
+ def save_page_defaults(page_defaults)
169
+ not_implemented('save_page_defaults')
170
+ end
31
171
 
32
- def pages ; error 'DataSource#pages must be overridden' ; end
33
- def page_defaults ; error 'DataSource#page_defaults must be overridden' ; end
34
- def layouts ; error 'DataSource#layouts must be overridden' ; end
35
- def templates ; error 'DataSource#templates must be overridden' ; end
36
- def code ; error 'DataSource#code must be overridden' ; end
172
+ ########## Asset defaults
37
173
 
38
- # Creating data
174
+ # Returns the asset defaults (represented by Nanoc::AssetDefaults) of this
175
+ # site. This is an abstract method implemented by the subclass.
176
+ #
177
+ # Subclasses must implement this method.
178
+ def asset_defaults
179
+ not_implemented('asset_defaults')
180
+ end
39
181
 
40
- def create_page(name, template)
41
- error 'DataSource#create_page must be overridden'
182
+ # Saves the given asset defaults in the data source.
183
+ #
184
+ # Subclasses must implement this method.
185
+ def save_asset_defaults(asset_defaults)
186
+ not_implemented('save_asset_defaults')
42
187
  end
43
188
 
44
- def create_layout(name)
45
- error 'DataSource#create_layout must be overridden'
189
+ ########## Layouts
190
+
191
+ # Returns the list of layouts (represented by Nanoc::Layout) in this site.
192
+ # This is an abstract method implemented by the subclass.
193
+ #
194
+ # Subclasses must implement this method.
195
+ def layouts
196
+ not_implemented('layouts')
46
197
  end
47
198
 
48
- def create_template(name)
49
- error 'DataSource#create_template must be overridden'
199
+ # Saves the given layout in the data source, creating it if it doesn't
200
+ # exist yet and updating the existing copy otherwise.
201
+ #
202
+ # Subclasses must implement this method.
203
+ def save_layout(layout)
204
+ not_implemented('save_layout')
205
+ end
206
+
207
+ # Changes the path of the given layout to the given new path. When
208
+ # changing a layout's path, this method must be used (save_layout will not
209
+ # work).
210
+ #
211
+ # Subclasses must implement this method.
212
+ def move_layout(layout, new_path)
213
+ not_implemented('move_layout')
214
+ end
215
+
216
+ # Removes the given layout from the data source.
217
+ #
218
+ # Subclasses must implement this method.
219
+ def delete_layout(layout)
220
+ not_implemented('delete_layout')
221
+ end
222
+
223
+ ########## Templates
224
+
225
+ # Returns the list of templates (represented by Nanoc::Template) in this
226
+ # site. This is an abstract method implemented by the subclass.
227
+ #
228
+ # Subclasses must implement this method.
229
+ def templates
230
+ not_implemented('templates')
231
+ end
232
+
233
+ # Saves the given template in the data source, creating it if it doesn't
234
+ # exist yet and updating the existing copy otherwise.
235
+ #
236
+ # Subclasses must implement this method.
237
+ def save_template(template)
238
+ not_implemented('save_template')
239
+ end
240
+
241
+ # Changes the name of the given template to the given new name. When
242
+ # changing a template's name, this method must be used (save_template will
243
+ # not work).
244
+ #
245
+ # Subclasses must implement this method.
246
+ def move_template(template, new_name)
247
+ not_implemented('move_template')
248
+ end
249
+
250
+ # Removes the given template from the data source.
251
+ #
252
+ # Subclasses must implement this method.
253
+ def delete_template(template)
254
+ not_implemented('delete_template')
255
+ end
256
+
257
+ ########## Code
258
+
259
+ # Returns the custom code (represented by Nanoc::Code) for this site.
260
+ # This is an abstract method implemented by the subclass. This can be code
261
+ # for custom filters, routers, and more, but pretty much any code can
262
+ # be put in there (global helper functions are very useful).
263
+ #
264
+ # Subclasses must implement this method.
265
+ def code
266
+ not_implemented('code')
267
+ end
268
+
269
+ # Saves the given code in the data source.
270
+ #
271
+ # Subclasses must implement this method.
272
+ def save_code(code)
273
+ not_implemented('save_code')
274
+ end
275
+
276
+ private
277
+
278
+ def not_implemented(name)
279
+ raise NotImplementedError.new(
280
+ "#{self.class} does not override ##{name}, which is required for " +
281
+ "this data source to be used."
282
+ )
50
283
  end
51
284
 
52
285
  end