lib/nanoc3/helpers/blogging.rb in nanoc3-3.0.9 vs lib/nanoc3/helpers/blogging.rb in nanoc3-3.1.0a1

- old
+ new

@@ -1,125 +1,137 @@ # encoding: utf-8 module Nanoc3::Helpers - # Nanoc3::Helpers::Blogging provides some functionality for building blogs, - # such as finding articles and constructing feeds. + # Provides functionality for building blogs, such as finding articles and + # constructing feeds. # # This helper has a few requirements. First, all blog articles should have # the following attributes: # - # * 'kind', set to 'article'. + # * `kind` — Set to `"article"` # - # * 'created_at', set to the creation timestamp. + # * `created_at` — The article’s publication timestamp. This timestamp can + # be in any format parseable by `Time.parse`. # - # Some functions in this blogging helper, such as the +atom_feed+ function, + # Some functions in this blogging helper, such as the {#atom_feed} function, # require additional attributes to be set; these attributes are described in # the documentation for these functions. # - # The two main functions are sorted_articles and atom_feed. - # - # To activate this helper, +include+ it, like this: - # - # include Nanoc3::Helpers::Blogging + # The two main functions are {#sorted_articles} and {#atom_feed}. module Blogging - # Returns an unsorted list of articles. + # Returns an unsorted list of articles, i.e. items where the `kind` + # attribute is set to `"article"`. + # + # @return [Array] An array containing all articles def articles @items.select { |item| item[:kind] == 'article' } end - # Returns a list of articles, sorted by descending creation date (so newer - # articles appear first). + # Returns a sorted list of articles, i.e. items where the `kind` + # attribute is set to `"article"`. Articles are sorted by descending + # creation date, so newer articles appear before older articles. + # + # @return [Array] A sorted array containing all articles def sorted_articles require 'time' - articles.sort_by do |a| - time = a[:created_at] - time.is_a?(String) ? Time.parse(time) : time - end.reverse + articles.sort_by { |a| t = a[:created_at] ; t.is_a?(String) ? Time.parse(t) : t }.reverse end # Returns a string representing the atom feed containing recent articles, - # sorted by descending creation date. +params+ is a hash where the - # following keys can be set: + # sorted by descending creation date. # - # +limit+:: The maximum number of articles to show. Defaults to 5. - # - # +articles+:: A list of articles to include in the feed. Defaults to the - # list of articles returned by the articles function. - # - # +content_proc+:: A proc that returns the content of the given article, - # passed as a parameter. By default, given the argument - # +article+, this proc will return - # +article.reps[0].content+. This function may not return - # nil. - # - # +excerpt_proc+:: A proc that returns the excerpt of the given article, - # passed as a parameter. By default, given the argument - # +article+, this proc will return +article.excerpt+. - # This function may return nil. - # # The following attributes must be set on blog articles: # - # * 'title', containing the title of the blog post. + # * `title` — The title of the blog post # - # * all other attributes mentioned above. + # * `kind` and `created_at` (described above) # # The following attributes can optionally be set on blog articles to # change the behaviour of the Atom feed: # - # * 'excerpt', containing an excerpt of the article, usually only a few + # * `excerpt` — An excerpt of the article, which is usually only a few # lines long. # - # * 'custom_path_in_feed', containing the path that will be used instead - # of the normal path in the feed. This can be useful when including + # * `custom_path_in_feed` — The path that will be used instead of the + # normal path in the feed. This can be useful when including # non-outputted items in a feed; such items could have their custom feed # path set to the blog path instead, for example. # # The feed will also include dates on which the articles were updated. # These are generated automatically; the way this happens depends on the # used data source (the filesystem data source checks the file mtimes, for # instance). # # The site configuration will need to have the following attributes: # - # * 'base_url', containing the URL to the site, without trailing slash. - # For example, if the site is at "http://example.com/", the base_url - # would be "http://example.com". + # * `base_url` — The URL to the site, without trailing slash. For + # example, if the site is at “http://example.com/”, the `base_url` + # would be “http://example.com”. # # The feed item will need to have the following attributes: # - # * 'title', containing the title of the feed, which is usually also the - # title of the blog. + # * `title` — The title of the feed, which is usually also the title of + # the blog. # - # * 'author_name', containing the name of the item's author. This will - # likely be a global attribute, unless the site is managed by several - # people/ + # * `author_name` — The name of the item’s author. # - # * 'author_uri', containing the URI for the item's author, such as the - # author's web site URL. This will also likely be a global attribute. + # * `author_uri` — The URI for the item’s author, such as the author’s + # web site URL. # # The feed item can have the following optional attributes: # - # * 'feed_url', containing the custom URL of the feed. This can be useful - # when the private feed URL shouldn't be exposed; for example, when - # using FeedBurner this would be set to the public FeedBurner URL. + # * `feed_url` — The custom URL of the feed. This can be useful when the + # private feed URL shouldn’t be exposed; for example, when using + # FeedBurner this would be set to the public FeedBurner URL. # - # To construct a feed, create a blank item with no layout, only the 'erb' - # (or 'erubis') filter, and an 'xml' extension. It may also be useful to - # set 'is_hidden' to true, so that helpers such as the sitemap helper will - # ignore the item. The content of the feed item should be: + # To construct a feed, create a new item and make sure that it is + # filtered with `:erb` or `:erubis`; it should not be laid out. Ensure + # that it is routed to the proper path, e.g. `/blog.xml`. It may also be + # useful to set the `is_hidden` attribute to true, so that helpers such + # as the sitemap helper will ignore the item. The content of the feed + # item should be `<%= atom_feed %>`. # - # <%= atom_feed %> + # @example Defining compilation and routing rules for a feed item + # + # compile '/blog/feed/' do + # filter :erb + # end + # + # route '/blog/feed/' do + # '/blog.xml' + # end + # + # @example Limiting the number of items in a feed + # + # <%= atom_feed :limit => 5 %> + # + # @option params [Number] :limit (5) The maximum number of articles to + # show + # + # @option params [Array] :articles (sorted_articles) A list of articles to + # include in the feed + # + # @option params [Proc] :content_proc (->{ |article| + # article.compiled_content(:snapshot => :pre) }) A proc that returns the + # content of the given article, which is passed as a parameter. This + # function may not return nil. + # + # @option params [proc] :excerpt_proc (->{ |article| article[:excerpt] }) + # A proc that returns the excerpt of the given article, passed as a + # parameter. This function should return nil if there is no excerpt. + # + # @return [String] The generated feed content def atom_feed(params={}) require 'builder' require 'time' # Extract parameters limit = params[:limit] || 5 relevant_articles = params[:articles] || articles || [] - content_proc = params[:content_proc] || lambda { |a| a.reps[0].content_at_snapshot(:pre) } + content_proc = params[:content_proc] || lambda { |a| a.compiled_content(:snapshot => :pre) } excerpt_proc = params[:excerpt_proc] || lambda { |a| a[:excerpt] } # Check config attributes if @site.config[:base_url].nil? raise RuntimeError.new('Cannot build Atom feed: site configuration has no base_url') @@ -143,14 +155,11 @@ if relevant_articles.any? { |a| a[:created_at].nil? } raise RuntimeError.new('Cannot build Atom feed: one or more articles lack created_at') end # Get sorted relevant articles - sorted_relevant_articles = relevant_articles.sort_by do |a| - time = a[:created_at] - time.is_a?(String) ? Time.parse(time) : time - end.reverse.first(limit) + sorted_relevant_articles = relevant_articles.sort_by { |a| Time.parse(a[:created_at]) }.reverse.first(limit) # Get most recent article last_article = sorted_relevant_articles.first # Create builder @@ -165,12 +174,11 @@ # Add primary attributes xml.id root_url xml.title @item[:title] # Add date - time = last_article[:created_at] - xml.updated((time.is_a?(String) ? Time.parse(time) : time).to_iso8601_time) + xml.updated Time.parse(last_article[:created_at]).to_iso8601_time # Add links xml.link(:rel => 'alternate', :href => root_url) xml.link(:rel => 'self', :href => feed_url) @@ -190,12 +198,11 @@ # Add primary attributes xml.id atom_tag_for(a) xml.title a[:title], :type => 'html' # Add dates - time = a[:created_at] - xml.published((time.is_a?(String) ? Time.parse(time) : time).to_iso8601_time) + xml.published Time.parse(a[:created_at]).to_iso8601_time xml.updated a.mtime.to_iso8601_time # Add link xml.link(:rel => 'alternate', :href => url) @@ -210,47 +217,56 @@ buffer end # Returns the URL for the given item. It will return the URL containing # the custom path in the feed if possible, otherwise the normal path. + # + # @param [Nanoc3::Item] item The item for which to fetch the URL. + # + # @return [String] The URL of the given item def url_for(item) # Check attributes if @site.config[:base_url].nil? raise RuntimeError.new('Cannot build Atom feed: site configuration has no base_url') end # Get path - path = item[:custom_path_in_feed] || item.reps[0].path + path = item[:custom_path_in_feed] || item.path return nil if path.nil? # Build URL @site.config[:base_url] + path end # Returns the URL of the feed. It will return the custom feed URL if set, # or otherwise the normal feed URL. + # + # @return [String] The URL of the feed def feed_url # Check attributes if @site.config[:base_url].nil? raise RuntimeError.new('Cannot build Atom feed: site configuration has no base_url') end - @item[:feed_url] || @site.config[:base_url] + @item.reps[0].path + @item[:feed_url] || @site.config[:base_url] + @item.path end # Returns an URI containing an unique ID for the given item. This will be # used in the Atom feed to uniquely identify articles. These IDs are - # created using a procedure suggested by Mark Pilgrim in this blog post: - # http://diveintomark.org/archives/2004/05/28/howto-atom-id. + # created using a procedure suggested by Mark Pilgrim and described in his + # [“How to make a good ID in Atom” blog post] + # (http://diveintomark.org/archives/2004/05/28/howto-atom-id). + # + # @param [Nanoc3::Item] item The item for which to create an atom tag + # + # @return [String] The atom tag for the given item def atom_tag_for(item) require 'time' hostname, base_dir = %r{^.+?://([^/]+)(.*)$}.match(@site.config[:base_url])[1..2] + formatted_date = Time.parse(item[:created_at]).to_iso8601_date - time = item[:created_at] - formatted_date = (time.is_a?(String) ? Time.parse(time) : time).to_iso8601_date - - 'tag:' + hostname + ',' + formatted_date + ':' + base_dir + (item.reps[0].path || item.identifier) + 'tag:' + hostname + ',' + formatted_date + ':' + base_dir + (item.path || item.identifier) end end end