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
@@ -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