urss 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gemrc ADDED
@@ -0,0 +1 @@
1
+ :ssl_verify_mode: 0
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.gpairrc ADDED
@@ -0,0 +1 @@
1
+ alone for github
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use 1.9.3@urss > /dev/null
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - ruby-head
3
+ - jruby
4
+ - 1.9.3
5
+ - 1.8.7
6
+ - 1.9.2
7
+ - ree
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in urss.gemspec
4
+ gemspec
5
+
6
+ gem "rake"
7
+ gem "rspec"
8
+ gem "webmock"
9
+ gem "simplecov"
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 zedtux
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Urss [![Build Status](https://secure.travis-ci.org/zedtux/urss.png)](http://travis-ci.org/zedtux/urss) [![Dependency Status](https://gemnasium.com/zedtux/urss.png)](http://gemnasium.com/zedtux/urss)
2
+
3
+ URSS or Ultra RSS is another ruby library to parse Feed RSS that has been created because there was no existing one that support multiple media:content or media:thumbnail.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'urss'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install urss
18
+
19
+ ## Usage
20
+
21
+ ````ruby
22
+ rss = Urss.at("http://www.ruby-lang.org/en/feeds/news.rss")
23
+ rss.title
24
+ #=> "Ruby News"
25
+ rss.url
26
+ #=> "http://www.ruby-lang.org/en/feeds/news.rss/"
27
+ rss.description
28
+ #=> "The latest news from Ruby-Lang.org."
29
+ rss.updated_at
30
+ #=> ""
31
+ rss.entries.size
32
+ #=> 10
33
+ rss.entries.first.title
34
+ #=> "Ruby 1.9.3-p194 is released"
35
+ rss.entries.first.created_at
36
+ #=> "Fri, 20 Apr 2012 03:19:04 GMT"
37
+ rss.entries.first.url
38
+ #=> "http://www.ruby-lang.org/en/news/2012/04/20/ruby-1-9-3-p194-is-released/"
39
+ ````
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new("spec")
7
+
8
+ task :default => :spec
data/lib/urss.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "urss/version"
2
+ require "open-uri"
3
+ require "nokogiri"
4
+
5
+ require "urss/rss"
6
+ require "urss/feed"
7
+ require "urss/feed/entry"
8
+ require "urss/feed/atom"
9
+ require "urss/feed/atom_entry"
10
+ require "urss/feed/rss"
11
+ require "urss/feed/rss_entry"
12
+ require "urss/media"
13
+
14
+ module Urss
15
+ class NotANokogiriInstance < StandardError; end
16
+
17
+ def self.at(url)
18
+ raise ArgumentError if url.nil? || !url.is_a?(String) || url.empty?
19
+
20
+ Rss.build(Nokogiri::XML(open(url)))
21
+ end
22
+
23
+ end
data/lib/urss/feed.rb ADDED
@@ -0,0 +1,17 @@
1
+ class Urss::Feed
2
+
3
+ # ~~~~ Attributes ~~~~
4
+ attr_accessor :title, :url, :description, :updated_at, :entries
5
+
6
+ # ~~~~ Class methods ~~~~
7
+
8
+ # ~~~~ Instance methods ~~~~
9
+ def initialize
10
+ self.title = nil
11
+ self.url = nil
12
+ self.description = nil
13
+ self.updated_at = nil
14
+ self.entries = []
15
+ end
16
+
17
+ end
@@ -0,0 +1,20 @@
1
+ class Urss::Feed::Atom < Urss::Feed
2
+
3
+ # ~~~~ Attributes ~~~~
4
+
5
+ # ~~~~ Class methods ~~~~
6
+ def self.build(nokogiri_instance, namespace, root_node)
7
+ raise Urss::NotANokogiriInstance unless nokogiri_instance.is_a?(Nokogiri::XML::NodeSet)
8
+ feed_rss = self.new
9
+ feed_rss.title = nokogiri_instance.xpath("//#{namespace}#{root_node}/title").text
10
+ feed_rss.url = nokogiri_instance.xpath("//#{namespace}#{root_node}/#{namespace}link[@rel='self']").attr("href").value
11
+ feed_rss.description = nokogiri_instance.xpath("//#{namespace}#{root_node}/#{namespace}subtitle").text.strip
12
+ feed_rss.updated_at = nokogiri_instance.xpath("//#{namespace}#{root_node}/#{namespace}updated").text
13
+ nokogiri_instance.xpath("//#{namespace}entry").each {|item| feed_rss.entries << Urss::Feed::Atom::Entry.build(item, namespace)}
14
+
15
+ feed_rss
16
+ end
17
+
18
+ # ~~~~ Instance methods ~~~~
19
+
20
+ end
@@ -0,0 +1,44 @@
1
+ class Urss::Feed::Atom::Entry < Urss::Feed::Entry
2
+
3
+ # ~~~~ Attributes ~~~~
4
+
5
+ # ~~~~ Class methods ~~~~
6
+ def self.build(nokogiri_instance, namespace=nil)
7
+ raise Urss::NotANokogiriInstance unless nokogiri_instance.is_a?(Nokogiri::XML::Element)
8
+
9
+ entry = self.new
10
+ entry.title = nokogiri_instance.xpath("./#{namespace}title").text
11
+ entry.url = nokogiri_instance.xpath("./#{namespace}link[@rel='alternate']").attr("href").value
12
+ entry.created_at = nokogiri_instance.xpath("./#{namespace}published").text
13
+ entry.author = nokogiri_instance.xpath("./#{namespace}author/#{namespace}name").text
14
+ entry.content = nokogiri_instance.xpath("./description").text
15
+
16
+ begin
17
+ # When having only one media:content then all media:* nodes are used to create one Urss::Media
18
+ # Otherwise each media:* are different Urss::Media
19
+ single_media = nokogiri_instance.xpath("./media:content").size == 1
20
+ media = nil
21
+ nokogiri_instance.xpath("./media:*").each do |media_attributes|
22
+ if single_media
23
+ media = Urss::Media.new if media.nil?
24
+ media.update(media_attributes)
25
+ else
26
+ media = Urss::Media.new
27
+ media.update(media_attributes)
28
+ media_attributes.children.select{|child| child.class == Nokogiri::XML::Element}.each do |element|
29
+ media.update(element)
30
+ end
31
+ entry.medias << media
32
+ end
33
+ end
34
+ entry.medias << media if single_media
35
+ rescue Nokogiri::XML::XPath::SyntaxError
36
+ # No media element
37
+ end
38
+
39
+ entry
40
+ end
41
+
42
+ # ~~~~ Instance methods ~~~~
43
+
44
+ end
@@ -0,0 +1,20 @@
1
+ class Urss::Feed::Entry
2
+
3
+ # ~~~~ Attributes ~~~~
4
+ attr_accessor :title, :url, :comments_url, :created_at, :author, :categories, :content, :medias
5
+
6
+ # ~~~~ Class methods ~~~~
7
+
8
+ # ~~~~ Instance methods ~~~~
9
+ def initialize
10
+ self.title = nil
11
+ self.url = nil
12
+ self.comments_url = nil
13
+ self.created_at = nil
14
+ self.author = nil
15
+ self.categories = []
16
+ self.content = nil
17
+ self.medias = []
18
+ end
19
+
20
+ end
@@ -0,0 +1,27 @@
1
+ class Urss::Feed::Rss < Urss::Feed
2
+
3
+ # ~~~~ Attributes ~~~~
4
+
5
+ # ~~~~ Class methods ~~~~
6
+ def self.build(nokogiri_instance, namespace, root_node)
7
+ raise Urss::NotANokogiriInstance unless nokogiri_instance.is_a?(Nokogiri::XML::NodeSet)
8
+ feed_rss = self.new
9
+ feed_rss.title = nokogiri_instance.xpath("//#{namespace}#{root_node}/#{namespace}title").text
10
+ feed_rss.url = nokogiri_instance.xpath("//#{namespace}#{root_node}/#{namespace}link").text
11
+ feed_rss.description = nokogiri_instance.xpath("//#{namespace}#{root_node}/#{namespace}description").text
12
+ feed_rss.updated_at = nokogiri_instance.xpath("//#{namespace}#{root_node}/#{namespace}pubDate").text
13
+ if feed_rss.updated_at.nil? || feed_rss.updated_at.empty?
14
+ begin
15
+ feed_rss.updated_at = nokogiri_instance.xpath("//#{namespace}#{root_node}/dc:date").text
16
+ rescue Nokogiri::XML::XPath::SyntaxError
17
+ # No pubDate or date field
18
+ end
19
+ end
20
+ nokogiri_instance.xpath("//#{namespace}item").each {|item| feed_rss.entries << Urss::Feed::Rss::Entry.build(item, namespace)}
21
+
22
+ feed_rss
23
+ end
24
+
25
+ # ~~~~ Instance methods ~~~~
26
+
27
+ end
@@ -0,0 +1,49 @@
1
+ class Urss::Feed::Rss::Entry < Urss::Feed::Entry
2
+
3
+ # ~~~~ Attributes ~~~~
4
+
5
+ # ~~~~ Class methods ~~~~
6
+ def self.build(nokogiri_instance, namespace=nil)
7
+ raise Urss::NotANokogiriInstance unless nokogiri_instance.is_a?(Nokogiri::XML::Element)
8
+
9
+ entry = self.new
10
+ entry.title = nokogiri_instance.xpath("./#{namespace}title").text
11
+ entry.url = nokogiri_instance.xpath("./#{namespace}link").text
12
+ entry.comments_url = nokogiri_instance.xpath("./comments").text
13
+ entry.created_at = nokogiri_instance.xpath("./pubDate").text
14
+ if entry.created_at.nil? || entry.created_at.empty?
15
+ entry.created_at = nokogiri_instance.xpath("./dc:date").text
16
+ end
17
+ entry.author = nokogiri_instance.xpath("./dc:creator", nokogiri_instance.namespaces).text
18
+ entry.categories = nokogiri_instance.search("category").collect(&:text).join(", ")
19
+ entry.content = nokogiri_instance.xpath("./description").text
20
+
21
+ begin
22
+ # When having only one media:content then all media:* nodes are used to create one Urss::Media
23
+ # Otherwise each media:* are different Urss::Media
24
+ single_media = nokogiri_instance.xpath("./media:content").size == 1
25
+ media = nil
26
+ nokogiri_instance.xpath("./media:*").each do |media_attributes|
27
+ if single_media
28
+ media = Urss::Media.new if media.nil?
29
+ media.update(media_attributes)
30
+ else
31
+ media = Urss::Media.new
32
+ media.update(media_attributes)
33
+ media_attributes.children.select{|child| child.class == Nokogiri::XML::Element}.each do |element|
34
+ media.update(element)
35
+ end
36
+ entry.medias << media
37
+ end
38
+ end
39
+ entry.medias << media if single_media
40
+ rescue Nokogiri::XML::XPath::SyntaxError
41
+ # No media element
42
+ end
43
+
44
+ entry
45
+ end
46
+
47
+ # ~~~~ Instance methods ~~~~
48
+
49
+ end
data/lib/urss/media.rb ADDED
@@ -0,0 +1,31 @@
1
+ class Urss::Media
2
+
3
+ # ~~~~ Attributes ~~~~
4
+ attr_accessor :content_url, :title, :thumbnail_url
5
+
6
+ # ~~~~ Class methods ~~~~
7
+
8
+ # ~~~~ Instance methods ~~~~
9
+ def initialize
10
+ self.content_url = nil
11
+ self.title = nil
12
+ self.thumbnail_url = nil
13
+ end
14
+
15
+ def update(nokogiri_instance)
16
+ raise Urss::NotANokogiriInstance unless nokogiri_instance.is_a?(Nokogiri::XML::Element)
17
+
18
+ if nokogiri_instance.attributes["url"]
19
+ if nokogiri_instance.name == "thumbnail"
20
+ self.thumbnail_url = nokogiri_instance.attributes["url"].value
21
+ else
22
+ self.content_url = nokogiri_instance.attributes["url"].value
23
+ end
24
+ else
25
+ if nokogiri_instance.name == "title"
26
+ self.title = nokogiri_instance.text
27
+ end
28
+ end
29
+ end
30
+
31
+ end
data/lib/urss/rss.rb ADDED
@@ -0,0 +1,28 @@
1
+ class Urss::Rss
2
+
3
+ # ~~~~ Attributes ~~~~
4
+
5
+ # ~~~~ Class methods ~~~~
6
+ def self.build(nokogiri_instance)
7
+ raise Urss::NotANokogiriInstance unless nokogiri_instance.is_a?(Nokogiri::XML::Document)
8
+
9
+ namespace = nokogiri_instance.namespaces["xmlns"] ? "xmlns:" : nil
10
+
11
+ # Factory
12
+ ["channel", "feed"].each do |root|
13
+ unless (root_instance = nokogiri_instance.xpath("//#{namespace}#{root}")).empty?
14
+ rss_object = case root
15
+ when "channel"
16
+ Urss::Feed::Rss
17
+ when "feed"
18
+ Urss::Feed::Atom
19
+ end.build(root_instance, namespace, root)
20
+ return rss_object
21
+ break
22
+ end
23
+ end
24
+ end
25
+
26
+ # ~~~~ Instance methods ~~~~
27
+
28
+ end
@@ -0,0 +1,3 @@
1
+ module Urss
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,17 @@
1
+ require "simplecov"
2
+ SimpleCov.start
3
+
4
+ require "rubygems"
5
+ require "bundler/setup"
6
+
7
+ # require "webmock/rspec" is not working. So:
8
+ require "webmock"
9
+ include WebMock::API
10
+
11
+ require "support/webmocks"
12
+
13
+ require "urss"
14
+
15
+ RSpec.configure do |config|
16
+
17
+ end
@@ -0,0 +1,45 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom">
3
+ <rss:title type="text">dive into mark</title>
4
+ <subtitle type="html">
5
+ A &lt;em&gt;lot&lt;/em&gt; of effort
6
+ went into making this effortless
7
+ </subtitle>
8
+ <updated>2005-07-31T12:29:29Z</updated>
9
+ <id>tag:example.org,2003:3</id>
10
+ <link rel="alternate" type="text/html"
11
+ hreflang="en" href="http://example.org/"/>
12
+ <link rel="self" type="application/atom+xml"
13
+ href="http://example.org/feed.atom"/>
14
+ <rights>Copyright (c) 2003, Mark Pilgrim</rights>
15
+ <generator uri="http://www.example.com/" version="1.0">
16
+ Example Toolkit
17
+ </generator>
18
+ <entry>
19
+ <title>Atom draft-07 snapshot</title>
20
+ <link rel="alternate" type="text/html"
21
+ href="http://example.org/2005/04/02/atom"/>
22
+ <link rel="enclosure" type="audio/mpeg" length="1337"
23
+ href="http://example.org/audio/ph34r_my_podcast.mp3"/>
24
+ <id>tag:example.org,2003:3.2397</id>
25
+ <updated>2005-07-31T12:29:29Z</updated>
26
+ <published>2003-12-13T08:29:29-04:00</published>
27
+ <author>
28
+ <name>Mark Pilgrim</name>
29
+ <uri>http://example.org/</uri>
30
+ <email>f8dy@example.com</email>
31
+ </author>
32
+ <contributor>
33
+ <name>Sam Ruby</name>
34
+ </contributor>
35
+ <contributor>
36
+ <name>Joe Gregorio</name>
37
+ </contributor>
38
+ <content type="xhtml" xml:lang="en"
39
+ xml:base="http://diveintomark.org/">
40
+ <div xmlns="http://www.w3.org/1999/xhtml">
41
+ <p><i>[Update: The Atom draft is finished.]</i></p>
42
+ </div>
43
+ </content>
44
+ </entry>
45
+ </feed>