lib/nanoc/base/data_source.rb in nanoc-2.0.4 vs lib/nanoc/base/data_source.rb in nanoc-2.1
- old
+ new
@@ -1,17 +1,33 @@
module Nanoc
+
+ # Nanoc::DataSource is responsible for loading data. It is the (abstract)
+ # superclass for all data sources. Subclasses must at least implement the
+ # data reading methods (+pages+, +page_defaults+, +layouts+, +templates+,
+ # and +code+); all other methods involving data manipulation are optional.
+ #
+ # Apart from the methods for loading and storing data, there are the +up+
+ # and +down+ methods for bringing up and tearing down the connection to the
+ # data source. These should be overridden in subclasses. The +loading+
+ # method wraps +up+ and +down+.
+ #
+ # The +setup+ method is used for setting up a site's data source for the
+ # first time. This method should be overridden in subclasses.
class DataSource < Plugin
- attr_reader :config
-
+ # Creates a new data source for the given site.
def initialize(site)
@site = site
@references = 0
end
- # Preparation
-
+ # Loads the data source when necessary (calling +up+), yields, and unloads
+ # the data source when it is not being used elsewhere. All data source
+ # queries and data manipulations should be wrapped in a +loading+ block;
+ # it ensures that the data source is loaded when necessary and makes sure
+ # the data source does not get unloaded while it is still being used
+ # elsewhere.
def loading
# Load if necessary
up if @references == 0
@references += 1
@@ -20,34 +36,251 @@
# Unload if necessary
@references -= 1
down if @references == 0
end
- def up ; end
- def down ; end
+ ########## Loading and unloading
- def setup ; end
+ # Brings up the connection to the data. This is an abstract method
+ # implemented by the subclass. Depending on the way data is stored, this
+ # may not be necessary. This is the ideal place to connect to the
+ # database, for example.
+ #
+ # Subclasses may implement this method.
+ def up
+ end
- # Loading data
+ # Brings down the connection to the data. This is an abstract method
+ # implemented by the subclass. This method should undo the effects of
+ # +up+.
+ #
+ # Subclasses may implement this method.
+ def down
+ end
- def pages ; error 'DataSource#pages must be overridden' ; end
- def page_defaults ; error 'DataSource#page_defaults must be overridden' ; end
- def layouts ; error 'DataSource#layouts must be overridden' ; end
- def templates ; error 'DataSource#templates must be overridden' ; end
- def code ; error 'DataSource#code must be overridden' ; end
+ ########## Creating/updating
- # Creating data
+ # Creates the bare minimum essentials for this data source to work. This
+ # action will likely be destructive. This method should not create sample
+ # data such as a default home page, a default layout, etc. For example, if
+ # you're using a database, this is where you should create the necessary
+ # tables for the data source to function properly.
+ #
+ # Subclasses must implement this method.
+ def setup
+ not_implemented('setup')
+ end
- def create_page(name, template)
- error 'DataSource#create_page must be overridden'
+ # Removes all data stored by this data source. This method undoes the
+ # effects of the +setup+ method.
+ #
+ # Subclasses must implement this method.
+ def destroy
+ not_implemented('destroy')
end
- def create_layout(name)
- error 'DataSource#create_layout must be overridden'
+ # Updated the content stored in this site to a newer version. A newer
+ # version of a data source may store content in a different format, and
+ # this method will update the stored content to this newer format.
+ #
+ # Subclasses may implement this method.
+ def update
end
- def create_template(name)
- error 'DataSource#create_template must be overridden'
+ ########## Pages
+
+ # Returns the list of pages (represented by Nanoc::Page) in this site.
+ # This is an abstract method implemented by the subclass.
+ #
+ # Subclasses must implement this method.
+ def pages
+ not_implemented('pages')
+ end
+
+ # Saves the given page in the data source, creating it if it doesn't exist
+ # yet and updating the existing copy otherwise.
+ #
+ # Subclasses must implement this method.
+ def save_page(page)
+ not_implemented('save_page')
+ end
+
+ # Changes the path of the given page to the given new path. When changing
+ # a page's path, this method must be used (save_page will not work).
+ #
+ # Subclasses must implement this method.
+ def move_page(page, new_path)
+ not_implemented('move_page')
+ end
+
+ # Removes the given page from the data source.
+ #
+ # Subclasses must implement this method.
+ def delete_page(page)
+ not_implemented('delete_page')
+ end
+
+ ########## Assets
+
+ # Returns the list of assets (represented by Nanoc::Asset) in this site.
+ # This is an abstract method implemented by the subclass.
+ #
+ # Subclasses must implement this method.
+ def assets
+ not_implemented('assets')
+ end
+
+ # Saves the given asset in the data source, creating it if it doesn't
+ # exist yet and updating the existing copy otherwise.
+ #
+ # Subclasses must implement this method.
+ def save_asset(asset)
+ not_implemented('save_asset')
+ end
+
+ # Changes the path of the given asset to the given new path. When changing
+ # a asset's path, this method must be used (save_asset will not work).
+ #
+ # Subclasses must implement this method.
+ def move_asset(asset, new_path)
+ not_implemented('move_asset')
+ end
+
+ # Removes the given asset from the data source.
+ #
+ # Subclasses must implement this method.
+ def delete_asset(asset)
+ not_implemented('delete_asset')
+ end
+
+ ########## Page defaults
+
+ # Returns the page defaults (represented by Nanoc::PageDefaults) of this
+ # site. This is an abstract method implemented by the subclass.
+ #
+ # Subclasses must implement this method.
+ def page_defaults
+ not_implemented('page_defaults')
+ end
+
+ # Saves the given page defaults in the data source.
+ #
+ # Subclasses must implement this method.
+ def save_page_defaults(page_defaults)
+ not_implemented('save_page_defaults')
+ end
+
+ ########## Asset defaults
+
+ # Returns the asset defaults (represented by Nanoc::AssetDefaults) of this
+ # site. This is an abstract method implemented by the subclass.
+ #
+ # Subclasses must implement this method.
+ def asset_defaults
+ not_implemented('asset_defaults')
+ end
+
+ # Saves the given asset defaults in the data source.
+ #
+ # Subclasses must implement this method.
+ def save_asset_defaults(asset_defaults)
+ not_implemented('save_asset_defaults')
+ end
+
+ ########## Layouts
+
+ # Returns the list of layouts (represented by Nanoc::Layout) in this site.
+ # This is an abstract method implemented by the subclass.
+ #
+ # Subclasses must implement this method.
+ def layouts
+ not_implemented('layouts')
+ end
+
+ # Saves the given layout in the data source, creating it if it doesn't
+ # exist yet and updating the existing copy otherwise.
+ #
+ # Subclasses must implement this method.
+ def save_layout(layout)
+ not_implemented('save_layout')
+ end
+
+ # Changes the path of the given layout to the given new path. When
+ # changing a layout's path, this method must be used (save_layout will not
+ # work).
+ #
+ # Subclasses must implement this method.
+ def move_layout(layout, new_path)
+ not_implemented('move_layout')
+ end
+
+ # Removes the given layout from the data source.
+ #
+ # Subclasses must implement this method.
+ def delete_layout(layout)
+ not_implemented('delete_layout')
+ end
+
+ ########## Templates
+
+ # Returns the list of templates (represented by Nanoc::Template) in this
+ # site. This is an abstract method implemented by the subclass.
+ #
+ # Subclasses must implement this method.
+ def templates
+ not_implemented('templates')
+ end
+
+ # Saves the given template in the data source, creating it if it doesn't
+ # exist yet and updating the existing copy otherwise.
+ #
+ # Subclasses must implement this method.
+ def save_template(template)
+ not_implemented('save_template')
+ end
+
+ # Changes the name of the given template to the given new name. When
+ # changing a template's name, this method must be used (save_template will
+ # not work).
+ #
+ # Subclasses must implement this method.
+ def move_template(template, new_name)
+ not_implemented('move_template')
+ end
+
+ # Removes the given template from the data source.
+ #
+ # Subclasses must implement this method.
+ def delete_template(template)
+ not_implemented('delete_template')
+ end
+
+ ########## Code
+
+ # Returns the custom code (represented by Nanoc::Code) for this site.
+ # This is an abstract method implemented by the subclass. This can be code
+ # for custom filters, routers, and more, but pretty much any code can
+ # be put in there (global helper functions are very useful).
+ #
+ # Subclasses must implement this method.
+ def code
+ not_implemented('code')
+ end
+
+ # Saves the given code in the data source.
+ #
+ # Subclasses must implement this method.
+ def save_code(code)
+ not_implemented('save_code')
+ end
+
+ private
+
+ def not_implemented(name)
+ raise NotImplementedError.new(
+ "#{self.class} does not override ##{name}, which is required for " +
+ "this data source to be used."
+ )
end
end
end