feed-abstract 0.0.1 → 0.0.2
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.
- data/README.rdoc +3 -3
- data/feed-abstract.gemspec +1 -1
- data/lib/feed-abstract/channel/atom.rb +30 -32
- data/lib/feed-abstract/channel/rdf.rb +47 -49
- data/lib/feed-abstract/channel/rss.rb +69 -71
- data/lib/feed-abstract/feed.rb +58 -61
- data/lib/feed-abstract/item/atom.rb +41 -43
- data/lib/feed-abstract/item/rdf.rb +38 -40
- data/lib/feed-abstract/item/rss.rb +77 -79
- data/lib/feed-abstract/items/atom.rb +11 -13
- data/lib/feed-abstract/items/rdf.rb +10 -12
- data/lib/feed-abstract/items/rss.rb +10 -12
- data/lib/feed-abstract/mixins.rb +47 -49
- data/lib/feed-abstract/version.rb +2 -4
- data/spec/feed_abstract_channel_spec.rb +1 -1
- data/spec/feed_abstract_item_spec.rb +1 -1
- data/spec/feed_abstract_spec.rb +1 -1
- metadata +2 -2
    
        data/README.rdoc
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 | 
            -
            =  | 
| 1 | 
            +
            = FeedAbstract
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            FeedAbstract creates a common object graph for RSS, Atom, and RDF feeds using the classes returned by RSS::Parser 
         | 
| 4 4 |  | 
| 5 5 | 
             
            == Installation
         | 
| 6 6 |  | 
| @@ -8,7 +8,7 @@ Feed::Abstract creates a common object graph for RSS, Atom, and RDF feeds using | |
| 8 8 |  | 
| 9 9 | 
             
            == Usage 
         | 
| 10 10 |  | 
| 11 | 
            -
            See  | 
| 11 | 
            +
            See FeedAbstract::Feed for basic examples. Also see the FeedAbstract::Channel and FeedAbstract::Item namespaces.
         | 
| 12 12 |  | 
| 13 13 | 
             
            == Author
         | 
| 14 14 |  | 
    
        data/feed-abstract.gemspec
    CHANGED
    
    | @@ -4,7 +4,7 @@ require "feed-abstract/version" | |
| 4 4 |  | 
| 5 5 | 
             
            Gem::Specification.new do |s|
         | 
| 6 6 | 
             
              s.name        = "feed-abstract"
         | 
| 7 | 
            -
              s.version     =  | 
| 7 | 
            +
              s.version     = FeedAbstract::VERSION
         | 
| 8 8 | 
             
              s.platform    = Gem::Platform::RUBY
         | 
| 9 9 | 
             
              s.authors     = ["Daniel Collis-Puro"]
         | 
| 10 10 | 
             
              s.email       = ["djcp@cyber.law.harvard.edu"]
         | 
| @@ -1,47 +1,45 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class Abstract
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 5 4 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 5 | 
            +
              # You don't want this class. You want FeedAbstract::Channel::Atom, FeedAbstract::Channel::RSS or FeedAbstract::Channel::RDF.
         | 
| 6 | 
            +
              class Channel
         | 
| 8 7 |  | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 8 | 
            +
                # See FeedAbstractMixins::Atom for more instance methods.
         | 
| 9 | 
            +
                class Atom
         | 
| 10 | 
            +
                  include FeedAbstractMixins::Atom
         | 
| 12 11 |  | 
| 13 | 
            -
             | 
| 12 | 
            +
                  attr_reader :feed, :source
         | 
| 14 13 |  | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
                    def description
         | 
| 20 | 
            -
                      @feed.subtitle.content
         | 
| 21 | 
            -
                    end
         | 
| 22 | 
            -
                    alias :subtitle :description
         | 
| 14 | 
            +
                  def initialize(feed)
         | 
| 15 | 
            +
                    @feed = @source = feed
         | 
| 16 | 
            +
                  end
         | 
| 23 17 |  | 
| 24 | 
            -
             | 
| 25 | 
            -
                     | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
                    end
         | 
| 18 | 
            +
                  def description
         | 
| 19 | 
            +
                    @feed.subtitle.content
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                  alias :subtitle :description
         | 
| 29 22 |  | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 23 | 
            +
                  # A string representing the application that created this feed.
         | 
| 24 | 
            +
                  def generator
         | 
| 25 | 
            +
                    return '' if @feed.generator.nil?
         | 
| 26 | 
            +
                    @feed.generator.content
         | 
| 27 | 
            +
                  end
         | 
| 35 28 |  | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 29 | 
            +
                  # A URL (perhaps with domain, depending on input) representing an icon for the feed.
         | 
| 30 | 
            +
                  def icon
         | 
| 31 | 
            +
                    return '' if @feed.icon.nil?
         | 
| 32 | 
            +
                    @feed.icon.content
         | 
| 33 | 
            +
                  end
         | 
| 41 34 |  | 
| 35 | 
            +
                  # A URL (perhaps with domain, depending on input) representing a logo for the feed.
         | 
| 36 | 
            +
                  def logo
         | 
| 37 | 
            +
                    return '' if @feed.logo.nil?
         | 
| 38 | 
            +
                    @feed.logo.content
         | 
| 42 39 | 
             
                  end
         | 
| 40 | 
            +
             | 
| 43 41 | 
             
                end
         | 
| 42 | 
            +
              end
         | 
| 44 43 |  | 
| 45 44 |  | 
| 46 | 
            -
              end
         | 
| 47 45 | 
             
            end
         | 
| @@ -1,63 +1,61 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class  | 
| 5 | 
            -
                class  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
                     | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
                    end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                    # The authors list as a string, joined with a comma. 
         | 
| 15 | 
            -
                    def author
         | 
| 16 | 
            -
                      return '' if self.authors.empty?
         | 
| 17 | 
            -
                      self.authors.join(', ')
         | 
| 18 | 
            -
                    end
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 4 | 
            +
              class Channel
         | 
| 5 | 
            +
                class RDF < RSS
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  # The authors list as an array.
         | 
| 8 | 
            +
                  def authors
         | 
| 9 | 
            +
                    return [] if @feed.channel.dc_publishers.empty?
         | 
| 10 | 
            +
                    @feed.channel.dc_publishers
         | 
| 11 | 
            +
                  end
         | 
| 19 12 |  | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                      end
         | 
| 26 | 
            -
                      ''
         | 
| 27 | 
            -
                    end
         | 
| 13 | 
            +
                  # The authors list as a string, joined with a comma. 
         | 
| 14 | 
            +
                  def author
         | 
| 15 | 
            +
                    return '' if self.authors.empty?
         | 
| 16 | 
            +
                    self.authors.join(', ')
         | 
| 17 | 
            +
                  end
         | 
| 28 18 |  | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 19 | 
            +
                  # The generator of this feed.
         | 
| 20 | 
            +
                  def generator
         | 
| 21 | 
            +
                    return '' unless @feed.channel.respond_to?(:about)
         | 
| 22 | 
            +
                    if @feed.channel.about.match(/connotea/i)
         | 
| 23 | 
            +
                      return 'Connotea'
         | 
| 33 24 | 
             
                    end
         | 
| 25 | 
            +
                    ''
         | 
| 26 | 
            +
                  end
         | 
| 34 27 |  | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 28 | 
            +
                  # The category list as an array.
         | 
| 29 | 
            +
                  def categories
         | 
| 30 | 
            +
                    return [] if @feed.channel.dc_subjects.empty?
         | 
| 31 | 
            +
                    @feed.channel.dc_subjects.collect{|c| c.content}
         | 
| 32 | 
            +
                  end
         | 
| 40 33 |  | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
                    alias :logo :icon 
         | 
| 34 | 
            +
                  # The category list as a string, joined with a comma.
         | 
| 35 | 
            +
                  def category
         | 
| 36 | 
            +
                    return '' if self.categories.empty?
         | 
| 37 | 
            +
                    self.categories.join(', ')
         | 
| 38 | 
            +
                  end
         | 
| 47 39 |  | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 40 | 
            +
                  # A URL (with or without domain depending on input) to a icon representing this feed.
         | 
| 41 | 
            +
                  def icon
         | 
| 42 | 
            +
                    return '' if @feed.channel.image.nil?
         | 
| 43 | 
            +
                    @feed.channel.image.resource
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                  alias :logo :icon 
         | 
| 53 46 |  | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 47 | 
            +
                  # Copyright info.
         | 
| 48 | 
            +
                  def rights
         | 
| 49 | 
            +
                    return '' if @feed.channel.dc_rights.nil?
         | 
| 50 | 
            +
                    @feed.channel.dc_rights
         | 
| 51 | 
            +
                  end
         | 
| 59 52 |  | 
| 53 | 
            +
                  # A Time object representing when this feed was updated, or at least "dated" according to the RDF spec.
         | 
| 54 | 
            +
                  def updated
         | 
| 55 | 
            +
                    return '' if @feed.channel.dc_date.nil?
         | 
| 56 | 
            +
                    @feed.channel.dc_date
         | 
| 60 57 | 
             
                  end
         | 
| 58 | 
            +
             | 
| 61 59 | 
             
                end
         | 
| 62 60 | 
             
              end
         | 
| 63 61 | 
             
            end
         | 
| @@ -1,91 +1,89 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class  | 
| 5 | 
            -
                class  | 
| 6 | 
            -
                   | 
| 7 | 
            -
             | 
| 8 | 
            -
                    attr_reader :feed, :source
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 4 | 
            +
              class Channel
         | 
| 5 | 
            +
                class RSS
         | 
| 6 | 
            +
                  include FeedAbstractMixins::RSS
         | 
| 7 | 
            +
                  attr_reader :feed, :source
         | 
| 9 8 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
                    def title
         | 
| 15 | 
            -
                      @feed.channel.title
         | 
| 16 | 
            -
                    end
         | 
| 9 | 
            +
                  def initialize(feed)
         | 
| 10 | 
            +
                    @feed = @source = feed
         | 
| 11 | 
            +
                  end
         | 
| 17 12 |  | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
                    alias :subtitle :description
         | 
| 13 | 
            +
                  def title
         | 
| 14 | 
            +
                    @feed.channel.title
         | 
| 15 | 
            +
                  end
         | 
| 22 16 |  | 
| 23 | 
            -
             | 
| 24 | 
            -
                     | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
                      elsif @feed.channel.link.match(/www\.delicious\.com/i)
         | 
| 28 | 
            -
                        return 'Delicious'
         | 
| 29 | 
            -
                      end
         | 
| 30 | 
            -
                      return '' if @feed.channel.generator.nil?
         | 
| 31 | 
            -
                      @feed.channel.generator
         | 
| 32 | 
            -
                    end
         | 
| 17 | 
            +
                  def description
         | 
| 18 | 
            +
                    @feed.channel.description
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                  alias :subtitle :description
         | 
| 33 21 |  | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 22 | 
            +
                  # The generator of this feed as a string. Sometimes a URL, sometimes a string (e.g. the application name).
         | 
| 23 | 
            +
                  def generator
         | 
| 24 | 
            +
                    if ! @feed.channel.generator.nil? && @feed.channel.generator.match(/wordpress\.org/i)
         | 
| 25 | 
            +
                      return 'WordPress'
         | 
| 26 | 
            +
                    elsif @feed.channel.link.match(/www\.delicious\.com/i)
         | 
| 27 | 
            +
                      return 'Delicious'
         | 
| 37 28 | 
             
                    end
         | 
| 29 | 
            +
                    return '' if @feed.channel.generator.nil?
         | 
| 30 | 
            +
                    @feed.channel.generator
         | 
| 31 | 
            +
                  end
         | 
| 38 32 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
                     | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
                    end
         | 
| 33 | 
            +
                  def link
         | 
| 34 | 
            +
                    return '' if @feed.channel.link.nil?
         | 
| 35 | 
            +
                    @feed.channel.link
         | 
| 36 | 
            +
                  end
         | 
| 44 37 |  | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 38 | 
            +
                  # Copyright info.
         | 
| 39 | 
            +
                  def rights
         | 
| 40 | 
            +
                    return '' if @feed.channel.copyright.nil? && @feed.channel.dc_rights.nil?
         | 
| 41 | 
            +
                    [@feed.channel.copyright,@feed.channel.dc_rights].compact.join(' ')
         | 
| 42 | 
            +
                  end
         | 
| 50 43 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 44 | 
            +
                  # A Time object.
         | 
| 45 | 
            +
                  def updated
         | 
| 46 | 
            +
                    return '' if @feed.channel.lastBuildDate.nil?
         | 
| 47 | 
            +
                    @feed.channel.lastBuildDate
         | 
| 48 | 
            +
                  end
         | 
| 56 49 |  | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 50 | 
            +
                  # A globally unique ID for this feed. A URL in this case.
         | 
| 51 | 
            +
                  def guid
         | 
| 52 | 
            +
                    return '' if @feed.channel.link.nil?
         | 
| 53 | 
            +
                    @feed.channel.link
         | 
| 54 | 
            +
                  end
         | 
| 62 55 |  | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 56 | 
            +
                  # The authors (a merge of the RSS managingEditor and dc:publisher elements) as an array.
         | 
| 57 | 
            +
                  def authors
         | 
| 58 | 
            +
                    return [] if @feed.channel.managingEditor.nil? && @feed.channel.dc_publishers.empty?
         | 
| 59 | 
            +
                    [@feed.channel.managingEditor, @feed.channel.dc_publishers].flatten.uniq
         | 
| 60 | 
            +
                  end
         | 
| 68 61 |  | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 62 | 
            +
                  # The author list joined with a comma.
         | 
| 63 | 
            +
                  def author
         | 
| 64 | 
            +
                    return '' if self.authors.empty?
         | 
| 65 | 
            +
                    self.authors.join(', ')
         | 
| 66 | 
            +
                  end
         | 
| 74 67 |  | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 68 | 
            +
                  # The category list (a merge of the RSS category and dc:subject elements) as an array. 
         | 
| 69 | 
            +
                  def categories
         | 
| 70 | 
            +
                    return [] if @feed.channel.categories.empty? && @feed.channel.dc_subjects.empty?
         | 
| 71 | 
            +
                    [@feed.channel.categories, @feed.channel.dc_subjects].flatten.uniq.collect{|c| c.content}
         | 
| 72 | 
            +
                  end
         | 
| 80 73 |  | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
                    alias :logo :icon 
         | 
| 74 | 
            +
                  # The category list as a string, joined with a comma.
         | 
| 75 | 
            +
                  def category
         | 
| 76 | 
            +
                    return '' if @feed.channel.categories.empty?
         | 
| 77 | 
            +
                    @feed.channel.categories.collect{|c| c.content}.join(', ')
         | 
| 78 | 
            +
                  end
         | 
| 87 79 |  | 
| 80 | 
            +
                  # A URL to an icon representing this feed.
         | 
| 81 | 
            +
                  def icon
         | 
| 82 | 
            +
                    return '' if @feed.channel.image.nil?
         | 
| 83 | 
            +
                    @feed.channel.image.url
         | 
| 88 84 | 
             
                  end
         | 
| 85 | 
            +
                  alias :logo :icon 
         | 
| 86 | 
            +
             | 
| 89 87 | 
             
                end
         | 
| 90 88 | 
             
              end
         | 
| 91 89 | 
             
            end
         | 
    
        data/lib/feed-abstract/feed.rb
    CHANGED
    
    | @@ -1,74 +1,71 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 3 | 
            +
            module FeedAbstract
         | 
| 4 4 | 
             
              class ParserError < Exception
         | 
| 5 5 | 
             
              end
         | 
| 6 6 |  | 
| 7 | 
            -
              class  | 
| 7 | 
            +
              # FeedAbstract:::Feed is the main class. It invokes RSS::Parser and negotiates which of the FeedAbstract::Channel and FeedAbstract::Item classes get dispatched to normalize the object graph of the feed you're parsing. 
         | 
| 8 | 
            +
              class Feed
         | 
| 9 | 
            +
                attr_reader :channel, :raw_feed, :items
         | 
| 8 10 |  | 
| 9 | 
            -
                #  | 
| 10 | 
            -
                 | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
                   | 
| 45 | 
            -
                   | 
| 46 | 
            -
                   | 
| 47 | 
            -
             | 
| 48 | 
            -
                    input = (xml.respond_to?(:read)) ? xml.read : xml
         | 
| 49 | 
            -
                    @raw_feed = RSS::Parser.parse(input,options[:do_validate], options[:ignore_unknown_element])
         | 
| 50 | 
            -
                    if @raw_feed == nil
         | 
| 51 | 
            -
                      raise Feed::ParserError
         | 
| 52 | 
            -
                    end
         | 
| 53 | 
            -
                    negotiate_channel_class
         | 
| 11 | 
            +
                # === Parameters
         | 
| 12 | 
            +
                # * xml - a string or object instance that responds to <b>read</b>
         | 
| 13 | 
            +
                # * :do_validate - whether or not the feed should be validated. Passed through to RSS::Parser
         | 
| 14 | 
            +
                # * :ignore_unknown_element - passed through to RSS::Parser
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # === Returns
         | 
| 17 | 
            +
                # An object with three attributes:
         | 
| 18 | 
            +
                # * channel - an instance of FeedAbstract::Channel matching the type of feed we recognized
         | 
| 19 | 
            +
                # * items - an array of items matching the type of feed we recognized.
         | 
| 20 | 
            +
                # * raw_feed - the raw feed object returned by RSS::Parser, which might include RSS::Atom::Feed, RSS::RDF, or RSS::Rss
         | 
| 21 | 
            +
                # You will most likely be using the <b>channel</b> and <b>items</b> attributes.
         | 
| 22 | 
            +
                #
         | 
| 23 | 
            +
                # === Notes
         | 
| 24 | 
            +
                # If a feed can't be parsed, we'll throw a FeedAbstract::ParserError.
         | 
| 25 | 
            +
                #
         | 
| 26 | 
            +
                # == Examples
         | 
| 27 | 
            +
                #
         | 
| 28 | 
            +
                #  f = FeedAbstract::Feed.new(File.open('/home/foo/xml/feed.rss2'))
         | 
| 29 | 
            +
                #  puts f.channel.title
         | 
| 30 | 
            +
                #  puts f.channel.description
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                #  f.items.each do|item|
         | 
| 33 | 
            +
                #   puts item.title
         | 
| 34 | 
            +
                #   puts item.link
         | 
| 35 | 
            +
                #  end
         | 
| 36 | 
            +
                #
         | 
| 37 | 
            +
                #  f = FeedAbstract::Feed.new(File.open('/home/foo/xml/feed.atom'))
         | 
| 38 | 
            +
                #  puts f.channel.generator
         | 
| 39 | 
            +
                #
         | 
| 40 | 
            +
                #  puts "All tags / categories / subjects in this feed: " + f.items.collect{|i| i.categories}.flatten.uniq.sort.join(', ')
         | 
| 41 | 
            +
                #  
         | 
| 42 | 
            +
                #  f = FeedAbstract::Feed.new(Net::HTTP.get(URI.parse('http://rss.slashdot.org/Slashdot/slashdot')))
         | 
| 43 | 
            +
                #  puts f.items.collect{|i| i.link}
         | 
| 44 | 
            +
                #   
         | 
| 45 | 
            +
                def initialize(xml = nil, options = {:do_validate => false, :ignore_unknown_element => true})
         | 
| 46 | 
            +
                  input = (xml.respond_to?(:read)) ? xml.read : xml
         | 
| 47 | 
            +
                  @raw_feed = RSS::Parser.parse(input,options[:do_validate], options[:ignore_unknown_element])
         | 
| 48 | 
            +
                  if @raw_feed == nil
         | 
| 49 | 
            +
                    raise FeedAbstract::ParserError
         | 
| 54 50 | 
             
                  end
         | 
| 51 | 
            +
                  negotiate_channel_class
         | 
| 52 | 
            +
                end
         | 
| 55 53 |  | 
| 56 | 
            -
             | 
| 54 | 
            +
                private 
         | 
| 57 55 |  | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
                    end
         | 
| 56 | 
            +
                #Here's an easy extension point for custom parsers.
         | 
| 57 | 
            +
                def negotiate_channel_class
         | 
| 58 | 
            +
                  if @raw_feed.class == RSS::Atom::Feed
         | 
| 59 | 
            +
                    @channel = Channel::Atom.new(@raw_feed)
         | 
| 60 | 
            +
                    @items = Items::Atom.new(@raw_feed)
         | 
| 61 | 
            +
                  elsif @raw_feed.class == RSS::RDF
         | 
| 62 | 
            +
                    @channel = Channel::RDF.new(@raw_feed)
         | 
| 63 | 
            +
                    @items = Items::RDF.new(@raw_feed)
         | 
| 64 | 
            +
                  else
         | 
| 65 | 
            +
                    @channel = Channel::RSS.new(@raw_feed)
         | 
| 66 | 
            +
                    @items = Items::RSS.new(@raw_feed)
         | 
| 70 67 | 
             
                  end
         | 
| 71 | 
            -
             | 
| 72 68 | 
             
                end
         | 
| 69 | 
            +
             | 
| 73 70 | 
             
              end
         | 
| 74 71 | 
             
            end
         | 
| @@ -1,50 +1,48 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class Abstract
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                # You don't want this class. You want Feed::Abstract::Item::Atom, Feed::Abstract::Item::RSS or  Feed::Abstract::Item::RDF.
         | 
| 7 | 
            -
                class Item
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                  # See Feed::AbstractMixins::Atom for more instance methods.
         | 
| 10 | 
            -
                  class Atom
         | 
| 11 | 
            -
                    include Feed::AbstractMixins::Atom
         | 
| 12 | 
            -
                    attr_reader :item, :source
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                    def initialize(item)
         | 
| 15 | 
            -
                      @item = @source = item
         | 
| 16 | 
            -
                    end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                    # The full content of the item, most likely html.
         | 
| 19 | 
            -
                    def content
         | 
| 20 | 
            -
                      return '' if @item.content.nil?
         | 
| 21 | 
            -
                      @item.content.content
         | 
| 22 | 
            -
                    end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                    # The contributor list as an array.
         | 
| 25 | 
            -
                    def contributors
         | 
| 26 | 
            -
                      return [] if @item.contributors.empty?
         | 
| 27 | 
            -
                      @item.contributors.collect{|c| c.name.content}
         | 
| 28 | 
            -
                    end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                    #The contributor list as a strong joined with a comma.
         | 
| 31 | 
            -
                    def contributor
         | 
| 32 | 
            -
                      return '' if @item.contributors.empty?
         | 
| 33 | 
            -
                      @item.contributors.collect{|c| c.name.content}.join(', ')
         | 
| 34 | 
            -
                    end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                    def summary
         | 
| 37 | 
            -
                      return '' if @item.summary.nil?
         | 
| 38 | 
            -
                      @item.summary.content
         | 
| 39 | 
            -
                    end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                    # A Time object
         | 
| 42 | 
            -
                    def published
         | 
| 43 | 
            -
                      return '' if @item.published.nil?
         | 
| 44 | 
            -
                      @item.published.content
         | 
| 45 | 
            -
                    end
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 46 4 |  | 
| 5 | 
            +
              # You don't want this class. You want FeedAbstract::Item::Atom, FeedAbstract::Item::RSS or  FeedAbstract::Item::RDF.
         | 
| 6 | 
            +
              class Item
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                # See FeedAbstractMixins::Atom for more instance methods.
         | 
| 9 | 
            +
                class Atom
         | 
| 10 | 
            +
                  include FeedAbstractMixins::Atom
         | 
| 11 | 
            +
                  attr_reader :item, :source
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def initialize(item)
         | 
| 14 | 
            +
                    @item = @source = item
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # The full content of the item, most likely html.
         | 
| 18 | 
            +
                  def content
         | 
| 19 | 
            +
                    return '' if @item.content.nil?
         | 
| 20 | 
            +
                    @item.content.content
         | 
| 47 21 | 
             
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  # The contributor list as an array.
         | 
| 24 | 
            +
                  def contributors
         | 
| 25 | 
            +
                    return [] if @item.contributors.empty?
         | 
| 26 | 
            +
                    @item.contributors.collect{|c| c.name.content}
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  #The contributor list as a strong joined with a comma.
         | 
| 30 | 
            +
                  def contributor
         | 
| 31 | 
            +
                    return '' if @item.contributors.empty?
         | 
| 32 | 
            +
                    @item.contributors.collect{|c| c.name.content}.join(', ')
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def summary
         | 
| 36 | 
            +
                    return '' if @item.summary.nil?
         | 
| 37 | 
            +
                    @item.summary.content
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  # A Time object
         | 
| 41 | 
            +
                  def published
         | 
| 42 | 
            +
                    return '' if @item.published.nil?
         | 
| 43 | 
            +
                    @item.published.content
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 48 46 | 
             
                end
         | 
| 49 47 | 
             
              end
         | 
| 50 48 | 
             
            end
         | 
| @@ -1,48 +1,46 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class  | 
| 5 | 
            -
                class  | 
| 6 | 
            -
                  class RDF < RSS
         | 
| 7 | 
            -
             | 
| 8 | 
            -
                    # The author list (from the dc:creator element) as an array.
         | 
| 9 | 
            -
                    def authors
         | 
| 10 | 
            -
                      (@item.dc_creators.empty?) ? [] : @item.dc_creators.collect{|c| c.content}
         | 
| 11 | 
            -
                    end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                    # The author list as a string, joined with a comma.
         | 
| 14 | 
            -
                    def author
         | 
| 15 | 
            -
                      return '' if self.authors.empty?
         | 
| 16 | 
            -
                      self.authors.join(', ')
         | 
| 17 | 
            -
                    end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                    # The category list (parsed from the dc:subject element) as an array.
         | 
| 20 | 
            -
                    def categories
         | 
| 21 | 
            -
                      return [] if @item.dc_subjects.empty?
         | 
| 22 | 
            -
                      @item.dc_subjects.collect{|c| c.content}
         | 
| 23 | 
            -
                    end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                    # The category list as a string, joined with a comma.
         | 
| 26 | 
            -
                    def category
         | 
| 27 | 
            -
                      return '' if self.categories.empty?
         | 
| 28 | 
            -
                      self.categories.join(', ')
         | 
| 29 | 
            -
                    end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                    # A Time object.
         | 
| 32 | 
            -
                    def updated
         | 
| 33 | 
            -
                      return '' if @item.dc_date.nil?
         | 
| 34 | 
            -
                      @item.dc_date
         | 
| 35 | 
            -
                    end
         | 
| 36 | 
            -
                    alias :published :updated
         | 
| 37 | 
            -
             | 
| 38 | 
            -
                    # A globally unique id, in this case probably a URL.
         | 
| 39 | 
            -
                    def guid
         | 
| 40 | 
            -
                      return '' if @item.about.nil?
         | 
| 41 | 
            -
                      @item.about
         | 
| 42 | 
            -
                    end
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 4 | 
            +
              class Item
         | 
| 5 | 
            +
                class RDF < RSS
         | 
| 43 6 |  | 
| 7 | 
            +
                  # The author list (from the dc:creator element) as an array.
         | 
| 8 | 
            +
                  def authors
         | 
| 9 | 
            +
                    (@item.dc_creators.empty?) ? [] : @item.dc_creators.collect{|c| c.content}
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  # The author list as a string, joined with a comma.
         | 
| 13 | 
            +
                  def author
         | 
| 14 | 
            +
                    return '' if self.authors.empty?
         | 
| 15 | 
            +
                    self.authors.join(', ')
         | 
| 16 | 
            +
                  end
         | 
| 44 17 |  | 
| 18 | 
            +
                  # The category list (parsed from the dc:subject element) as an array.
         | 
| 19 | 
            +
                  def categories
         | 
| 20 | 
            +
                    return [] if @item.dc_subjects.empty?
         | 
| 21 | 
            +
                    @item.dc_subjects.collect{|c| c.content}
         | 
| 45 22 | 
             
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # The category list as a string, joined with a comma.
         | 
| 25 | 
            +
                  def category
         | 
| 26 | 
            +
                    return '' if self.categories.empty?
         | 
| 27 | 
            +
                    self.categories.join(', ')
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  # A Time object.
         | 
| 31 | 
            +
                  def updated
         | 
| 32 | 
            +
                    return '' if @item.dc_date.nil?
         | 
| 33 | 
            +
                    @item.dc_date
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                  alias :published :updated
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # A globally unique id, in this case probably a URL.
         | 
| 38 | 
            +
                  def guid
         | 
| 39 | 
            +
                    return '' if @item.about.nil?
         | 
| 40 | 
            +
                    @item.about
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
             | 
| 46 44 | 
             
                end
         | 
| 47 45 | 
             
              end
         | 
| 48 46 | 
             
            end
         | 
| @@ -1,86 +1,84 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class  | 
| 5 | 
            -
                class  | 
| 6 | 
            -
                  class RSS
         | 
| 7 | 
            -
             | 
| 8 | 
            -
                    include Feed::AbstractMixins::RSS
         | 
| 9 | 
            -
                    attr_reader :item, :source
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                    def initialize(item)
         | 
| 12 | 
            -
                      @item = @source = item
         | 
| 13 | 
            -
                    end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                    def title
         | 
| 16 | 
            -
                      return '' if @item.title.nil?
         | 
| 17 | 
            -
                      @item.title
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                    
         | 
| 20 | 
            -
                    # The full content of this item, theoretically.
         | 
| 21 | 
            -
                    def content
         | 
| 22 | 
            -
                      return '' if @item.content_encoded.nil?
         | 
| 23 | 
            -
                      @item.content_encoded
         | 
| 24 | 
            -
                    end
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                    def summary
         | 
| 27 | 
            -
                      return '' if @item.description.nil?
         | 
| 28 | 
            -
                      @item.description
         | 
| 29 | 
            -
                    end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                    def link
         | 
| 32 | 
            -
                      @item.link
         | 
| 33 | 
            -
                    end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                    # The author list (a merge of the RSS author and dc:creator elements) as an array.
         | 
| 36 | 
            -
                    def authors
         | 
| 37 | 
            -
                      [@item.author, @item.dc_creators.collect{|c| c.content}].flatten.uniq.compact
         | 
| 38 | 
            -
                    end
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                    # The author list as a string, joined with a comma.
         | 
| 41 | 
            -
                    def author
         | 
| 42 | 
            -
                      (self.authors.empty?) ? '' : self.authors.join(', ')
         | 
| 43 | 
            -
                    end
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                    # The contributors (parsed from the dc:contributor element) as an array.
         | 
| 46 | 
            -
                    def contributors
         | 
| 47 | 
            -
                      (@item.dc_contributors.empty?) ? [] : @item.dc_contributors
         | 
| 48 | 
            -
                    end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                    # The contributor list as a string joined with a comma.
         | 
| 51 | 
            -
                    def contributor
         | 
| 52 | 
            -
                      (self.contributors.empty?) ? '' : self.contributors.join(', ')
         | 
| 53 | 
            -
                    end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                    # The category list as an array.
         | 
| 56 | 
            -
                    def categories
         | 
| 57 | 
            -
                      return [] if @item.categories.empty?
         | 
| 58 | 
            -
                      @item.categories.collect{|c| c.content}
         | 
| 59 | 
            -
                    end
         | 
| 60 | 
            -
             | 
| 61 | 
            -
                    # The category list as a string, joined with a comma.
         | 
| 62 | 
            -
                    def category
         | 
| 63 | 
            -
                      return '' if @item.categories.empty?
         | 
| 64 | 
            -
                      @item.categories.collect{|c| c.content}.join(', ')
         | 
| 65 | 
            -
                    end
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                    # Copyright info.
         | 
| 68 | 
            -
                    def rights
         | 
| 69 | 
            -
                      (@item.dc_rights.nil?) ? '' : @item.dc_rights
         | 
| 70 | 
            -
                    end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                    def updated
         | 
| 73 | 
            -
                      (@item.pubDate.nil?) ? '' : @item.pubDate
         | 
| 74 | 
            -
                    end
         | 
| 75 | 
            -
                    alias :published :updated
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                    # A globally unique id.
         | 
| 78 | 
            -
                    def guid
         | 
| 79 | 
            -
                      return '' if @item.guid.nil?
         | 
| 80 | 
            -
                      @item.guid.content
         | 
| 81 | 
            -
                    end
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 4 | 
            +
              class Item
         | 
| 5 | 
            +
                class RSS
         | 
| 82 6 |  | 
| 7 | 
            +
                  include FeedAbstractMixins::RSS
         | 
| 8 | 
            +
                  attr_reader :item, :source
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def initialize(item)
         | 
| 11 | 
            +
                    @item = @source = item
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def title
         | 
| 15 | 
            +
                    return '' if @item.title.nil?
         | 
| 16 | 
            +
                    @item.title
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  # The full content of this item, theoretically.
         | 
| 20 | 
            +
                  def content
         | 
| 21 | 
            +
                    return '' if @item.content_encoded.nil?
         | 
| 22 | 
            +
                    @item.content_encoded
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def summary
         | 
| 26 | 
            +
                    return '' if @item.description.nil?
         | 
| 27 | 
            +
                    @item.description
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def link
         | 
| 31 | 
            +
                    @item.link
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  # The author list (a merge of the RSS author and dc:creator elements) as an array.
         | 
| 35 | 
            +
                  def authors
         | 
| 36 | 
            +
                    [@item.author, @item.dc_creators.collect{|c| c.content}].flatten.uniq.compact
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  # The author list as a string, joined with a comma.
         | 
| 40 | 
            +
                  def author
         | 
| 41 | 
            +
                    (self.authors.empty?) ? '' : self.authors.join(', ')
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  # The contributors (parsed from the dc:contributor element) as an array.
         | 
| 45 | 
            +
                  def contributors
         | 
| 46 | 
            +
                    (@item.dc_contributors.empty?) ? [] : @item.dc_contributors
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  # The contributor list as a string joined with a comma.
         | 
| 50 | 
            +
                  def contributor
         | 
| 51 | 
            +
                    (self.contributors.empty?) ? '' : self.contributors.join(', ')
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  # The category list as an array.
         | 
| 55 | 
            +
                  def categories
         | 
| 56 | 
            +
                    return [] if @item.categories.empty?
         | 
| 57 | 
            +
                    @item.categories.collect{|c| c.content}
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  # The category list as a string, joined with a comma.
         | 
| 61 | 
            +
                  def category
         | 
| 62 | 
            +
                    return '' if @item.categories.empty?
         | 
| 63 | 
            +
                    @item.categories.collect{|c| c.content}.join(', ')
         | 
| 83 64 | 
             
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  # Copyright info.
         | 
| 67 | 
            +
                  def rights
         | 
| 68 | 
            +
                    (@item.dc_rights.nil?) ? '' : @item.dc_rights
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def updated
         | 
| 72 | 
            +
                    (@item.pubDate.nil?) ? '' : @item.pubDate
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                  alias :published :updated
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  # A globally unique id.
         | 
| 77 | 
            +
                  def guid
         | 
| 78 | 
            +
                    return '' if @item.guid.nil?
         | 
| 79 | 
            +
                    @item.guid.content
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
             | 
| 84 82 | 
             
                end
         | 
| 85 83 | 
             
              end
         | 
| 86 84 | 
             
            end
         | 
| @@ -1,22 +1,20 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class Abstract
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 5 4 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 5 | 
            +
              #Nothing interesting. The classes in this namespace map the RSS::Parser object entries/items to the proper FeedAbstract::Item classes. Perhap item-level transformations could be supported through this class in the future.
         | 
| 6 | 
            +
              class Items
         | 
| 7 | 
            +
                class Atom < Array
         | 
| 8 | 
            +
                  attr_reader :feed, :items
         | 
| 10 9 |  | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
                      end
         | 
| 10 | 
            +
                  def initialize(feed)
         | 
| 11 | 
            +
                    @feed = feed
         | 
| 12 | 
            +
                    return [] if @feed.items.empty?
         | 
| 13 | 
            +
                    @feed.items.each do|item|
         | 
| 14 | 
            +
                      self << ::FeedAbstract::Item::Atom.new(item)
         | 
| 17 15 | 
             
                    end
         | 
| 18 | 
            -
             | 
| 19 16 | 
             
                  end
         | 
| 17 | 
            +
             | 
| 20 18 | 
             
                end
         | 
| 21 19 | 
             
              end
         | 
| 22 20 | 
             
            end
         | 
| @@ -1,20 +1,18 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class  | 
| 5 | 
            -
                class  | 
| 6 | 
            -
                   | 
| 7 | 
            -
                    attr_reader :feed, :items
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 4 | 
            +
              class Items
         | 
| 5 | 
            +
                class RDF < Array
         | 
| 6 | 
            +
                  attr_reader :feed, :items
         | 
| 8 7 |  | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
                      end
         | 
| 8 | 
            +
                  def initialize(feed)
         | 
| 9 | 
            +
                    @feed = feed
         | 
| 10 | 
            +
                    return [] if @feed.items.empty?
         | 
| 11 | 
            +
                    @feed.items.each do|item|
         | 
| 12 | 
            +
                      self << ::FeedAbstract::Item::RDF.new(item)
         | 
| 15 13 | 
             
                    end
         | 
| 16 | 
            -
             | 
| 17 14 | 
             
                  end
         | 
| 15 | 
            +
             | 
| 18 16 | 
             
                end
         | 
| 19 17 | 
             
              end
         | 
| 20 18 | 
             
            end
         | 
| @@ -1,20 +1,18 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              class  | 
| 5 | 
            -
                class  | 
| 6 | 
            -
                   | 
| 7 | 
            -
                    attr_reader :feed, :items
         | 
| 3 | 
            +
            module FeedAbstract
         | 
| 4 | 
            +
              class Items
         | 
| 5 | 
            +
                class RSS < Array
         | 
| 6 | 
            +
                  attr_reader :feed, :items
         | 
| 8 7 |  | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
                      end
         | 
| 8 | 
            +
                  def initialize(feed)
         | 
| 9 | 
            +
                    @feed = feed
         | 
| 10 | 
            +
                    return [] if @feed.items.empty?
         | 
| 11 | 
            +
                    @feed.items.each do|item|
         | 
| 12 | 
            +
                      self << ::FeedAbstract::Item::RSS.new(item)
         | 
| 15 13 | 
             
                    end
         | 
| 16 | 
            -
             | 
| 17 14 | 
             
                  end
         | 
| 15 | 
            +
             | 
| 18 16 | 
             
                end
         | 
| 19 17 | 
             
              end
         | 
| 20 18 | 
             
            end
         | 
    
        data/lib/feed-abstract/mixins.rb
    CHANGED
    
    | @@ -1,66 +1,64 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 2 |  | 
| 3 | 
            -
            module  | 
| 4 | 
            -
              module AbstractMixins
         | 
| 3 | 
            +
            module FeedAbstractMixins
         | 
| 5 4 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
                # Instance methods shared between Feed::Abstract::Channel::Atom and Feed::Abstract::Item::Atom
         | 
| 10 | 
            -
                module Atom
         | 
| 5 | 
            +
              module RSS
         | 
| 6 | 
            +
              end
         | 
| 11 7 |  | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
                  end
         | 
| 8 | 
            +
              # Instance methods shared between FeedAbstract::Channel::Atom and FeedAbstract::Item::Atom
         | 
| 9 | 
            +
              module Atom
         | 
| 15 10 |  | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
                  end
         | 
| 11 | 
            +
                def title
         | 
| 12 | 
            +
                  @source.title.content
         | 
| 13 | 
            +
                end
         | 
| 20 14 |  | 
| 21 | 
            -
             | 
| 22 | 
            -
                   | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                  end
         | 
| 15 | 
            +
                def link
         | 
| 16 | 
            +
                  return '' if @source.link.nil?
         | 
| 17 | 
            +
                  @source.link.href
         | 
| 18 | 
            +
                end
         | 
| 26 19 |  | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 20 | 
            +
                # A globally unique ID to this resource, usually (but not always) a URL.
         | 
| 21 | 
            +
                def guid
         | 
| 22 | 
            +
                  return '' if @source.id.nil?
         | 
| 23 | 
            +
                  @source.id.content
         | 
| 24 | 
            +
                end
         | 
| 32 25 |  | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 26 | 
            +
                # A Time object representing when resource was updated.
         | 
| 27 | 
            +
                def updated
         | 
| 28 | 
            +
                  return '' if @source.updated.nil?
         | 
| 29 | 
            +
                  @source.updated.content
         | 
| 30 | 
            +
                end
         | 
| 38 31 |  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 32 | 
            +
                # Copyright info.
         | 
| 33 | 
            +
                def rights
         | 
| 34 | 
            +
                  return '' if @source.rights.nil?
         | 
| 35 | 
            +
                  @source.rights.content
         | 
| 36 | 
            +
                end
         | 
| 44 37 |  | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 38 | 
            +
                # An array of author names
         | 
| 39 | 
            +
                def authors
         | 
| 40 | 
            +
                  return [] if @source.authors.empty?
         | 
| 41 | 
            +
                  @source.authors.collect{|au| au.name.content}
         | 
| 42 | 
            +
                end
         | 
| 50 43 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 44 | 
            +
                # The authors list as a string, joined with a comma.
         | 
| 45 | 
            +
                def author
         | 
| 46 | 
            +
                  return '' if self.authors.empty?
         | 
| 47 | 
            +
                  self.authors.join(', ')
         | 
| 48 | 
            +
                end
         | 
| 56 49 |  | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 50 | 
            +
                # The categories list as an array.
         | 
| 51 | 
            +
                def categories
         | 
| 52 | 
            +
                  return [] if @source.categories.empty?
         | 
| 53 | 
            +
                  @source.categories.collect{|c| c.term}
         | 
| 54 | 
            +
                end
         | 
| 62 55 |  | 
| 56 | 
            +
                # The categories list as a string joined with a comma.
         | 
| 57 | 
            +
                def category
         | 
| 58 | 
            +
                  return '' if self.categories.empty?
         | 
| 59 | 
            +
                  self.categories.join(', ')
         | 
| 63 60 | 
             
                end
         | 
| 64 61 |  | 
| 65 62 | 
             
              end
         | 
| 63 | 
            +
             | 
| 66 64 | 
             
            end
         | 
    
        data/spec/feed_abstract_spec.rb
    CHANGED