moxie-columbus 0.1.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://gems.gemfury.com/qsNMqt3pW3Ar1QaNqsdX/'
2
+ source "http://rubygems.org"
3
+
4
+ # Specify your gem's dependencies in firehose.gemspec
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,86 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ moxie-columbus (0.1.2.1)
5
+ moxie-columbus
6
+
7
+ GEM
8
+ remote: https://gems.gemfury.com/qsNMqt3pW3Ar1QaNqsdX/
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ activesupport (4.0.2)
12
+ i18n (~> 0.6, >= 0.6.4)
13
+ minitest (~> 4.2)
14
+ multi_json (~> 1.3)
15
+ thread_safe (~> 0.1)
16
+ tzinfo (~> 0.3.37)
17
+ addressable (2.3.5)
18
+ atomic (1.1.14)
19
+ builder (3.2.2)
20
+ descendants_tracker (0.0.3)
21
+ fakeweb (1.3.0)
22
+ faraday (0.8.8)
23
+ multipart-post (~> 1.2.0)
24
+ git (1.2.6)
25
+ github_api (0.11.1)
26
+ addressable (~> 2.3)
27
+ descendants_tracker (~> 0.0.1)
28
+ faraday (~> 0.8, < 0.10)
29
+ hashie (>= 1.2)
30
+ multi_json (>= 1.7.5, < 2.0)
31
+ nokogiri (~> 1.6.0)
32
+ oauth2
33
+ hashie (2.0.5)
34
+ highline (1.6.20)
35
+ httpauth (0.2.0)
36
+ i18n (0.6.9)
37
+ jeweler (2.0.0)
38
+ builder
39
+ bundler (>= 1.0)
40
+ git (>= 1.2.5)
41
+ github_api
42
+ highline (>= 1.6.15)
43
+ nokogiri (>= 1.5.10)
44
+ rake
45
+ rdoc
46
+ jnunemaker-matchy (0.4.0)
47
+ json (1.8.1)
48
+ jwt (0.1.8)
49
+ multi_json (>= 1.5)
50
+ mini_portile (0.5.2)
51
+ minitest (4.7.5)
52
+ multi_json (1.8.2)
53
+ multi_xml (0.5.5)
54
+ multipart-post (1.2.0)
55
+ nokogiri (1.6.1)
56
+ mini_portile (~> 0.5.0)
57
+ oauth2 (0.9.2)
58
+ faraday (~> 0.8)
59
+ httpauth (~> 0.2)
60
+ jwt (~> 0.1.4)
61
+ multi_json (~> 1.0)
62
+ multi_xml (~> 0.5)
63
+ rack (~> 1.2)
64
+ rack (1.5.2)
65
+ rake (10.1.1)
66
+ rdoc (4.1.1)
67
+ json (~> 1.4)
68
+ shoulda (3.5.0)
69
+ shoulda-context (~> 1.0, >= 1.0.1)
70
+ shoulda-matchers (>= 1.4.1, < 3.0)
71
+ shoulda-context (1.1.6)
72
+ shoulda-matchers (2.4.0)
73
+ activesupport (>= 3.0.0)
74
+ thread_safe (0.1.3)
75
+ atomic
76
+ tzinfo (0.3.38)
77
+
78
+ PLATFORMS
79
+ ruby
80
+
81
+ DEPENDENCIES
82
+ fakeweb
83
+ jeweler
84
+ jnunemaker-matchy
85
+ moxie-columbus!
86
+ shoulda
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 John Nunemaker
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,18 @@
1
+ = columbus
2
+
3
+ Autodiscovers feeds from urls.
4
+
5
+ = examples
6
+
7
+ See examples directory. Short example below.
8
+
9
+ require 'pp'
10
+ pp Columbus.new('http://www.railstips.org').primary
11
+
12
+ #<struct Columbus::Feed
13
+ url="http://feeds2.feedburner.com/railstips",
14
+ title="Railstips Articles">
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2009 John Nunemaker. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "moxie-columbus"
8
+ gem.summary = %Q{Autodiscovers feeds from urls}
9
+ gem.email = "nunemaker@gmail.com"
10
+ gem.homepage = "http://github.com/jnunemaker/columbus"
11
+ gem.authors = ["John Nunemaker"]
12
+ gem.rubyforge_project = 'columbus'
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ # require 'rake/task'
20
+ # Rake::Task.new do |rdoc|
21
+ # rdoc.rdoc_dir = 'rdoc'
22
+ # rdoc.title = 'columbus'
23
+ # rdoc.options << '--line-numbers' << '--inline-source'
24
+ # rdoc.rdoc_files.include('README*')
25
+ # rdoc.rdoc_files.include('lib/**/*.rb')
26
+ # end
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = false
33
+ end
34
+
35
+ begin
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/*_test.rb'
40
+ test.verbose = true
41
+ end
42
+ rescue LoadError
43
+ task :rcov do
44
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
45
+ end
46
+ end
47
+
48
+
49
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.2.1
data/examples/all.rb ADDED
@@ -0,0 +1,4 @@
1
+ require File.dirname(__FILE__) + '/../lib/columbus'
2
+ require 'pp'
3
+
4
+ pp Columbus.new('http://www.railstips.org').all
@@ -0,0 +1,4 @@
1
+ require File.dirname(__FILE__) + '/../lib/columbus'
2
+ require 'pp'
3
+
4
+ pp Columbus.new('http://www.railstips.org').primary
data/lib/columbus.rb ADDED
@@ -0,0 +1,47 @@
1
+ require 'logger'
2
+ require 'net/http'
3
+ require 'uri'
4
+ require 'rubygems'
5
+ require 'nokogiri'
6
+
7
+ require File.dirname(__FILE__) + '/columbus/feed'
8
+ require File.dirname(__FILE__) + '/columbus/link'
9
+ require File.dirname(__FILE__) + '/columbus/redirect_follower'
10
+
11
+ class Columbus
12
+ attr_reader :url
13
+
14
+ def initialize(url)
15
+ @url = url
16
+ end
17
+
18
+ def primary
19
+ @primary ||= begin
20
+ response = RedirectFollower.new(url).resolve
21
+ @url = response.url
22
+ if hpricot_link = parse_links(response.body)[0]
23
+ link_to_feed(hpricot_link)
24
+ end
25
+ end
26
+ end
27
+
28
+ def all
29
+ @all ||= begin
30
+ response = RedirectFollower.new(url).resolve
31
+ @url = response.url
32
+ parse_links(response.body).map { |hpricot_link| link_to_feed(hpricot_link) }
33
+ end
34
+ end
35
+
36
+ private
37
+ def link_to_feed(element)
38
+ link = Link.new(url, element.attributes['href'].to_s, element.attributes['title'].to_s)
39
+ Feed.new(link.absolute_url, link.clean_title)
40
+ end
41
+
42
+ def parse_links(html)
43
+ Nokogiri::HTML(html).search('link').select do |link|
44
+ link.attributes['type'].to_s =~ /application\/(rss|atom)\+xml/i
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,17 @@
1
+ class Columbus
2
+ class Feed < Struct.new(:url, :title)
3
+ attr_accessor :body
4
+
5
+ def initialize(*args)
6
+ super(*args)
7
+ determine_feed_endpoint
8
+ end
9
+
10
+ def determine_feed_endpoint
11
+ response = RedirectFollower.new(url).resolve
12
+ self.url = response.url
13
+ self.body = response.body
14
+ self
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ class Columbus
2
+ class Link < Struct.new(:url, :href, :title)
3
+ def clean_title
4
+ title.nil? ? nil : title.strip
5
+ end
6
+
7
+ def absolute_url
8
+ if relative?
9
+ "#{url}#{href}"
10
+ else
11
+ "#{href}"
12
+ end
13
+ end
14
+
15
+ def relative?
16
+ href =~ /^\//
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,46 @@
1
+ class Columbus
2
+ class RedirectFollower
3
+ class TooManyRedirects < StandardError; end
4
+
5
+ attr_accessor :url, :body, :redirect_limit, :response
6
+
7
+ def initialize(url, options={})
8
+ @url = url
9
+ @redirect_limit = options.delete(:limit) || 5
10
+ logger.level = options.delete(:level) || Logger::WARN
11
+ end
12
+
13
+ def logger
14
+ @logger ||= Logger.new(STDOUT)
15
+ end
16
+
17
+ def resolve
18
+ raise TooManyRedirects if redirect_limit < 0
19
+
20
+ self.response = Net::HTTP.get_response(URI.parse(url))
21
+
22
+ logger.info "redirect limit: #{redirect_limit}"
23
+ logger.info "response code: #{response.code}"
24
+ logger.debug "response body: #{response.body}"
25
+
26
+ if response.kind_of?(Net::HTTPRedirection)
27
+ self.url = redirect_url
28
+ self.redirect_limit -= 1
29
+
30
+ logger.info "redirect found, headed to #{url}"
31
+ resolve
32
+ end
33
+
34
+ self.body = response.body
35
+ self
36
+ end
37
+
38
+ def redirect_url
39
+ if response['location'].nil?
40
+ response.body.match(/<a href=\"([^>]+)\">/i)[1]
41
+ else
42
+ response['location']
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,71 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "moxie-columbus"
8
+ s.version = "0.1.2.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["John Nunemaker"]
12
+ s.date = "2014-01-09"
13
+ s.email = "nunemaker@gmail.com"
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "Gemfile",
20
+ "Gemfile.lock",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "examples/all.rb",
26
+ "examples/primary.rb",
27
+ "lib/columbus.rb",
28
+ "lib/columbus/feed.rb",
29
+ "lib/columbus/link.rb",
30
+ "lib/columbus/redirect_follower.rb",
31
+ "moxie-columbus.gemspec",
32
+ "test/columbus_test.rb",
33
+ "test/feed_test.rb",
34
+ "test/fixtures/railsquicktips.html",
35
+ "test/fixtures/railstips.html",
36
+ "test/fixtures/railstips_feedburner.html",
37
+ "test/fixtures/railstips_redirect",
38
+ "test/link_test.rb",
39
+ "test/test_helper.rb"
40
+ ]
41
+ s.homepage = "http://github.com/jnunemaker/columbus"
42
+ s.require_paths = ["lib"]
43
+ s.rubyforge_project = "columbus"
44
+ s.rubygems_version = "1.8.25"
45
+ s.summary = "Autodiscovers feeds from urls"
46
+
47
+ if s.respond_to? :specification_version then
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<moxie-columbus>, [">= 0"])
52
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
53
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
54
+ s.add_development_dependency(%q<fakeweb>, [">= 0"])
55
+ s.add_development_dependency(%q<jnunemaker-matchy>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<moxie-columbus>, [">= 0"])
58
+ s.add_dependency(%q<shoulda>, [">= 0"])
59
+ s.add_dependency(%q<jeweler>, [">= 0"])
60
+ s.add_dependency(%q<fakeweb>, [">= 0"])
61
+ s.add_dependency(%q<jnunemaker-matchy>, [">= 0"])
62
+ end
63
+ else
64
+ s.add_dependency(%q<moxie-columbus>, [">= 0"])
65
+ s.add_dependency(%q<shoulda>, [">= 0"])
66
+ s.add_dependency(%q<jeweler>, [">= 0"])
67
+ s.add_dependency(%q<fakeweb>, [">= 0"])
68
+ s.add_dependency(%q<jnunemaker-matchy>, [">= 0"])
69
+ end
70
+ end
71
+
@@ -0,0 +1,36 @@
1
+ $:.unshift '.';require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ColumbusTest < Test::Unit::TestCase
4
+ context "Initialization" do
5
+ should "accept a url" do
6
+ Columbus.new('http://foobar.com').url.should == 'http://foobar.com'
7
+ end
8
+ end
9
+
10
+ should "be able to get primary feed" do
11
+ FakeWeb.register_uri(:get, "http://railstips.org/", :string => fixture_file('railstips.html'))
12
+ FakeWeb.register_uri(:get, "http://feeds.feedburner.com/railstips", :string => fixture_file('railstips_feedburner.html'))
13
+ expected = Columbus::Feed.new('http://feeds.feedburner.com/railstips', 'Railstips Articles')
14
+ Columbus.new('http://railstips.org').primary.should == expected
15
+ end
16
+
17
+ should "be able to get all feeds" do
18
+ FakeWeb.register_uri(:get, "http://railstips.org/", :string => fixture_file('railstips.html'))
19
+ FakeWeb.register_uri(:get, "http://feeds.feedburner.com/railstips", :string => fixture_file('railstips_feedburner.html'))
20
+ FakeWeb.register_uri(:get, "http://feeds.feedburner.com/railsquicktips", :string => fixture_file('railsquicktips.html'))
21
+ Columbus.new('http://railstips.org').all.should == [
22
+ Columbus::Feed.new('http://feeds.feedburner.com/railstips', 'Railstips Articles'),
23
+ Columbus::Feed.new('http://feeds.feedburner.com/railsquicktips', 'Rails Quick Tips (links)')
24
+ ]
25
+ end
26
+
27
+ should "follow redirects" do
28
+ FakeWeb.register_uri(:get, "http://railstips.org/", :string => fixture_file('railstips.html'))
29
+ FakeWeb.register_uri(:get, "http://feeds.feedburner.com/railstips", :response => fixture_file('railstips_redirect'))
30
+ FakeWeb.register_uri(:get, "http://feeds2.feedburner.com/railstips", :string => fixture_file('railstips_feedburner.html'))
31
+ primary = Columbus.new('http://railstips.org').primary
32
+ primary.url.should == 'http://feeds2.feedburner.com/railstips'
33
+ primary.title.should == 'Railstips Articles'
34
+ end
35
+
36
+ end