lib/nanoc3/base/data_source.rb in nanoc3-3.0.9 vs lib/nanoc3/base/data_source.rb in nanoc3-3.1.0a1

- old
+ new

@@ -1,188 +1,224 @@ # encoding: utf-8 module Nanoc3 - # Nanoc3::DataSource is responsible for loading data. It is the (abstract) - # superclass for all data sources. Subclasses must at least implement the - # data reading methods (+items+, +layouts+, and +code_snippets+); all other - # methods involving data manipulation are optional. + # Responsible for loading site data. It is the (abstract) superclass for all + # data sources. Subclasses must at least implement the data reading methods + # ({#items} and {#layouts}); 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+. + # 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}. {#loading} is a convenience method for the + # more low-level methods {#use} and {#unuse}, which respectively increment + # and decrement the reference count; when the reference count goes from 0 to + # 1, the data source will be loaded ({#up} will be called) and when the + # reference count goes from 1 to 0, the data source will be unloaded + # ({#down} will be called). # - # 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 + # The {#setup} method is used for setting up a site's data source for the + # first time. + # + # @abstract Subclasses should at least implement {#items} and {#layouts}. If + # the data source should support creating items and layouts using the + # `create_item` and `create_layout` CLI commands, the {#setup}, + # {#create_item} and {#create_layout} methods should be implemented as well. + class DataSource - # A string containing the root where items returned by this data source - # should be mounted. + # @return [String] The root path where items returned by this data source + # should be mounted. attr_reader :items_root - # A string containing the root where layouts returned by this data source - # should be mounted. + # @return [String] The root path where layouts returned by this data + # source should be mounted. attr_reader :layouts_root - # A hash containing the configuration for this data source. For example, - # online data sources could contain authentication details. + # @return [Hash] The configuration for this data source. For example, + # online data sources could contain authentication details. attr_reader :config + extend Nanoc3::PluginRegistry::PluginMethods + # Creates a new data source for the given site. # - # +site+:: The site this data source belongs to. - # +items_root+:: The prefix that should be given to all items returned by - # the #items method (comparable to mount points for - # filesystems in Unix-ish OSes). - # +layouts_root+:: The prefix that should be given to all layouts returned - # by the #layouts method (comparable to mount points for - # filesystems in Unix-ish OSes). - # +config+:: The configuration for this data source. + # @param [Nanoc3::Site] site The site this data source belongs to. + # + # @param [String] items_root The prefix that should be given to all items + # returned by the #items method (comparable to mount points for + # filesystems in Unix-ish OSes). + # + # @param [String] layouts_root The prefix that should be given to all + # layouts returned by the #layouts method (comparable to mount points + # for filesystems in Unix-ish OSes). + # + # @param [Hash] config The configuration for this data source. def initialize(site, items_root, layouts_root, config) @site = site @items_root = items_root @layouts_root = layouts_root @config = config @references = 0 end - # Sets the identifiers for this data source. - def self.identifiers(*identifiers) - Nanoc3::DataSource.register(self, *identifiers) - end - - # Sets the identifier for this data source. - def self.identifier(identifier) - Nanoc3::DataSource.register(self, identifier) - end - - # Registers the given class as a data source with the given identifier. - def self.register(class_or_name, *identifiers) - Nanoc3::Plugin.register(Nanoc3::DataSource, class_or_name, *identifiers) - end - - # 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. + # Loads the data source when necessary (calling {#up}), yields, and + # unloads (using {#down}) 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. + # + # @return [void] def loading use yield ensure unuse end # Marks the data source as used by the caller. # # Calling this method increases the internal reference count. When the - # data source is used for the first time (first #use call), the data - # source will be loaded (#up will be called). Similarly, when the - # reference count reaches zero, the data source will be unloaded (#down - # will be called). + # data source is used for the first time (first {#use} call), the data + # source will be loaded ({#up} will be called). + # + # @return [void] def use up if @references == 0 @references += 1 end # Marks the data source as unused by the caller. # - # Calling this method increases the internal reference count. When the - # data source is used for the first time (first #use call), the data - # source will be loaded (#up will be called). Similarly, when the - # reference count reaches zero, the data source will be unloaded (#down - # will be called). + # Calling this method decreases the internal reference count. When the + # reference count reaches zero, i.e. when the data source is not used any + # more, the data soruce will be unloaded ({#down} will be called). + # + # @return [void] def unuse @references -= 1 down if @references == 0 end - ########## Loading and unloading - - # 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. + # Brings up the connection to the data. 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. + # Subclasses may override this method, but are not required to do so; the + # default implementation simply does nothing. + # + # @return [void] def up end - # Brings down the connection to the data. This is an abstract method - # implemented by the subclass. This method should undo the effects of - # +up+. + # Brings down the connection to the data. This method should undo the + # effects of the {#up} method. For example, a database connection + # established in {#up} should be closed in this method. # - # Subclasses may implement this method. + # Subclasses may override this method, but are not required to do so; the + # default implementation simply does nothing. + # + # @return [void] def down end - ########## Creating/updating - # 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 + # data such as a default home page, a default layout, etc. For example, + # when using a database, this is where you should create the necessary # tables for the data source to function properly. # - # Subclasses must implement this method. + # @abstract + # + # @return [void] def setup not_implemented('setup') end # 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. + # Subclasses may override this method, but are not required to do so; the + # default implementation simply does nothing. + # + # @return [void] def update end - ########## Loading data - - # Returns the list of items (represented by Nanoc3::Item) in this site. + # Returns the list of items (represented by {Nanoc3::Item}) in this site. # The default implementation simply returns an empty array. # - # Subclasses should not prepend items_root to the item's identifiers, as + # Subclasses should not prepend `items_root` to the item's identifiers, as # this will be done automatically. # - # Subclasses may implement this method. + # Subclasses may override this method, but are not required to do so; the + # default implementation simply does nothing. + # + # @return [Array<Nanoc3::Item>] A list of items def items [] end - # Returns the list of layouts (represented by Nanoc3::Layout) in this + # Returns the list of layouts (represented by {Nanoc3::Layout}) in this # site. The default implementation simply returns an empty array. # - # Subclasses should prepend layout_root to the layout's identifiers, since - # this is not done automatically. + # Subclasses should prepend `layout_root` to the layout's identifiers, + # since this is not done automatically. # - # Subclasses may implement this method. + # Subclasses may override this method, but are not required to do so; the + # default implementation simply does nothing. + # + # @return [Array<Nanoc3::Layout>] A list of layouts def layouts [] end - # Returns the custom code snippets (represented by Nanoc3::CodeSnippet) - # for this site. The default implementation simply returns an empty array. - # This can be code for custom filters and more, but pretty much any code - # can be put in there (global helper functions are very useful). + # Creates a new item with the given content, attributes and identifier. No + # instance of {Nanoc3::Item} will be created; this method creates the item + # in the data source so that it can be loaded and turned into a + # {Nanoc3::Item} instance by the {#items} method. # - # Subclasses may implement this method. - def code_snippets - [] - end - - ########## Creating data - - # Creates a new item with the given content, attributes and identifier. - def create_item(content, attributes, identifier) + # @abstract + # + # @param [String] content + # + # @param [Hash] attributes + # + # @param [String] identifier + # + # @param [Hash] params Extra parameters to give to the data source. This + # can be used to influence the way items are stored. For example, + # filesystem data sources could use this to pass the extension of the + # files that should be generated. + # + # @return [void] + def create_item(content, attributes, identifier, params={}) not_implemented('create_item') end # Creates a new layout with the given content, attributes and identifier. - def create_layout(content, attributes, identifier) + # No instance of {Nanoc3::Layout} will be created; this method creates the + # layout in the data source so that it can be loaded and turned into a + # {Nanoc3::Layout} instance by the {#layouts} method. + # + # @abstract + # + # @param [String] content + # + # @param [Hash] attributes + # + # @param [String] identifier + # + # @param [Hash] params Extra parameters to give to the data source. This + # can be used to influence the way items are stored. For example, + # filesystem data sources could use this to pass the extension of the + # files that should be generated. + # + # @return [void] + def create_layout(content, attributes, identifier, params={}) not_implemented('create_layout') end private