Permalink
Browse files

Initial commit of working code. Need some automated tests now.

  • Loading branch information...
jnunemaker committed Mar 26, 2009
1 parent c651b1f commit 56b6890f559f9d32bfc3e6f36f7f564bc2065d52
Showing with 137 additions and 0 deletions.
  1. +4 −0 examples/all.rb
  2. +4 −0 examples/primary.rb
  3. +46 −0 lib/columbus.rb
  4. +17 −0 lib/columbus/feed.rb
  5. +19 −0 lib/columbus/link.rb
  6. +46 −0 lib/columbus/redirect_follower.rb
  7. +1 −0 test/test_helper.rb
View
@@ -0,0 +1,4 @@
+require File.dirname(__FILE__) + '/../lib/columbus'
+require 'pp'
+
+pp Columbus.new('http://www.railstips.org').all
View
@@ -0,0 +1,4 @@
+require File.dirname(__FILE__) + '/../lib/columbus'
+require 'pp'
+
+pp Columbus.new('http://www.railstips.org').primary
View
@@ -0,0 +1,46 @@
+require 'logger'
+require 'net/http'
+require 'uri'
+require 'rubygems'
+require 'hpricot'
+
+require File.dirname(__FILE__) + '/columbus/feed'
+require File.dirname(__FILE__) + '/columbus/link'
+require File.dirname(__FILE__) + '/columbus/redirect_follower'
+
+class Columbus
+ attr_reader :url
+
+ def initialize(url)
+ @url = url
+ end
+
+ def primary
+ @primary ||= begin
+ response = RedirectFollower.new(url).resolve
+ @url = response.url
+ if hpricot_link = parse_links(response.body)[0]
+ link_to_feed(hpricot_link)
+ end
+ end
+ end
+
+ def all
+ @all ||= begin
+ response = RedirectFollower.new(url).resolve
+ @url = response.url
+ parse_links(response.body).map { |hpricot_link| link_to_feed(hpricot_link) }
+ end
+ end
+
+ def link_to_feed(element)
+ link = Link.new(url, element.attributes['href'], element.attributes['title'])
+ Feed.new(link.absolute_url, link.clean_title)
+ end
+
+ def parse_links(html)
+ Hpricot(html).search('link').select do |link|
+ link.attributes['type'] =~ /application\/(rss|atom)\+xml/i
+ end
+ end
+end
View
@@ -0,0 +1,17 @@
+class Columbus
+ class Feed < Struct.new(:url, :title)
+ attr_accessor :body
+
+ def initialize(*args)
+ super(*args)
+ determine_feed_endpoint!
+ end
+
+ def determine_feed_endpoint!
+ response = RedirectFollower.new(url).resolve
+ self.url = response.url
+ self.body = response.body
+ self
+ end
+ end
+end
View
@@ -0,0 +1,19 @@
+class Columbus
+ class Link < Struct.new(:url, :href, :title)
+ def clean_title
+ title.nil? ? nil : title.strip
+ end
+
+ def absolute_url
+ if relative?
+ "#{url}#{href}"
+ else
+ "#{href}"
+ end
+ end
+
+ def relative?
+ href =~ /^\//
+ end
+ end
+end
@@ -0,0 +1,46 @@
+class Columbus
+ class RedirectFollower
+ class TooManyRedirects < StandardError; end
+
+ attr_accessor :url, :body, :redirect_limit, :response
+
+ def initialize(url, options={})
+ @url = url
+ @redirect_limit = options.delete(:limit) || 5
+ logger.level = options.delete(:level) || Logger::WARN
+ end
+
+ def logger
+ @logger ||= Logger.new(STDOUT)
+ end
+
+ def resolve
+ raise TooManyRedirects if redirect_limit < 0
+
+ self.response = Net::HTTP.get_response(URI.parse(url))
+
+ logger.info "redirect limit: #{redirect_limit}"
+ logger.info "response code: #{response.code}"
+ logger.debug "response body: #{response.body}"
+
+ if response.kind_of?(Net::HTTPRedirection)
+ self.url = redirect_url
+ self.redirect_limit -= 1
+
+ logger.info "redirect found, headed to #{url}"
+ resolve
+ end
+
+ self.body = response.body
+ self
+ end
+
+ def redirect_url
+ if response['location'].nil?
+ response.body.match(/<a href=\"([^>]+)\">/i)[1]
+ else
+ response['location']
+ end
+ end
+ end
+end
View
@@ -1,6 +1,7 @@
require 'rubygems'
require 'test/unit'
require 'shoulda'
+require 'fakeweb'
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))

0 comments on commit 56b6890

Please sign in to comment.