Skip to content

Commit

Permalink
add Seinfeld::Feed object for parsing the feeds
Browse files Browse the repository at this point in the history
  • Loading branch information
technoweenie committed May 2, 2010
1 parent d1925c6 commit 78d0e78
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ app/config.ru
app/config.rb
app/tmp
app/*.log

config/database.yml
log
5 changes: 5 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ end
desc 'Default: run specs.'
task :default => 'test'

desc "Open an irb session preloaded with this library"
task :console do
sh "irb -rubygems -r ./lib/seinfeld.rb"
end

desc "cron task for keeping the CAN updated. Run once every hour."
task :cron => 'seinfeld:init' do
if Time.now.hour % 4 == 0
Expand Down
7 changes: 1 addition & 6 deletions config/database.sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@ development:
username: root
password:
host: localhost
<% if File.exist?("/var/run/mysql5/mysqld.sock") %>
socket: /var/run/mysql5/mysqld.sock
<% elsif File.exist? "/tmp/mysql.sock" %>
socket: /tmp/mysql.sock
<% end %>

test:
adapter: sqlite3
encoding: utf8
database: :memory:
database: ":memory:"
18 changes: 14 additions & 4 deletions lib/seinfeld.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
$LOAD_PATH.unshift *Dir["#{dir}/../vendor/**/lib"]

require 'erb'
require 'logger'
require 'active_record' # v3

# Gives all the AR models their own tablenamespace:
Expand All @@ -27,19 +28,28 @@ class << self
attr_reader :logger
end

[:Feed].each do |const|
autoload const, "seinfeld/#{const.to_s.underscore}"
end

def self.logger
@logger ||= Logger.new(path_from_root(log_path))
@logger ||= begin
file = path_from_root(log_path)
FileUtils.mkdir_p File.dirname(file)
Logger.new(file)
end
end

# Public: Reads the database.yml config and starts up the connection to the
# database.
#
# Returns nothing.
def self.configure
Time.zone = "UTC"
path = path_from_root(db_config_path)
yaml = ERB.new(IO.read(path).result)
ActiveRecord::Base.configurations = YAML.load(yaml)
ActiveRecord::Base.establish_connection
yaml = ERB.new(IO.read(path)).result
data = YAML.load(yaml)
ActiveRecord::Base.establish_connection data[env.to_s]
ActiveRecord::Base.logger = logger
end

Expand Down
103 changes: 103 additions & 0 deletions lib/seinfeld/feed.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
require 'time'
require 'sax-machine'
require 'open-uri'

class Seinfeld
class Feed
# A Seinfeld::Feed::Atom reference to the parsed feed.
attr_reader :atom

# The String GitHub account name.
attr_reader :login

# The String url that the atom feed was fetched from (default: :direct)
attr_reader :url

# Public: Downloads a user's public feed from GitHub.
#
# login - String login name from GitHub.
#
# Returns Seinfeld::Feed instance.
def self.fetch(login)
feed = nil
url = "http://github.com/#{login}.atom"
open(url) { |f| feed = new(login, f.read, url) }
feed
end

# Parses the given data with SAX Machine.
#
# data - String atom data.
# url - String url that was used. (default: :direct)
#
# Returns Seinfeld::Feed.
def initialize(login, data, url = :direct)
@login = login.to_s
@url = url
@atom = Atom.parse(data)
end

# Public: Scans the parsed atom entries and pulls out all committed days.
#
# Returns Array of unique Date objects.
def committed_days
@committed_days ||= begin
days = []
entries.each do |entry|
committed?(entry) && days << entry.published_date
end
days.uniq!
days
end
end

# Determines whether the given entry counts as a commit or not.
#
# entry - Seinfeld::Feed::AtomEntry instance.
#
# Returns true if the entry is a commit, and false if it isn't.
def committed?(entry)
return false if entry.author != @login
!!(entry.title.downcase =~
%r{^#{@login.downcase} (pushed|committed|applied fork commits|created branch)})
end

# Accesses each parsed atom entry.
#
# Returns an Array of Seinfeld::Feed::AtomEntry instances.
def entries
atom.entries
end

def inspect
%(#<Seinfeld::Feed:#{@url} (#{entries.size})>)
end

class AtomEntry
include SAXMachine
element :published
element :title
element :author, :as => :author_name

def author
@author ||= begin
author_name.strip!
author_name
end
end

def published_at
@published_at ||= Time.zone.parse(published)
end

def published_date
Date.civil(published_at.year, published_at.month, published_at.day)
end
end

class Atom
include SAXMachine
elements :entry, :as => :entries, :class => AtomEntry
end
end
end
Empty file added log/.placeholder
Empty file.
29 changes: 29 additions & 0 deletions test/feed_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require File.join(File.dirname(__FILE__), "test_helper")

class FeedTest < ActiveSupport::TestCase
data = feed_data(:simple)

setup_once do
@feed = Seinfeld::Feed.new :technoweenie, data
end

test "parses atom data" do
assert_kind_of Seinfeld::Feed::Atom, @feed.atom
end

test "parses atom entries" do
assert_equal 9, @feed.entries.size
end

test "parses entry published timestamp" do
assert_equal Time.zone.local(2009, 12, 19, 14, 42, 13), @feed.entries[0].published_at
end

test "scans for committed days" do
assert_equal [
Date.civil(2009, 12, 19),
Date.civil(2009, 12, 17),
Date.civil(2009, 12, 16),
Date.civil(2009, 12, 15)], @feed.committed_days
end
end
98 changes: 98 additions & 0 deletions test/feeds/simple.atom
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<id>tag:github.com,2008:/technoweenie</id>
<link type="text/html" href="http://github.com" rel="alternate"/>
<link type="application/atom+xml" href="http://github.com/technoweenie.atom" rel="self"/>
<title>technoweenie's Activity</title>
<updated>2009-12-19T15:00:51-08:00</updated>
<entry>
<id>tag:github.com,2008:PushEvent/113902146</id>
<published>2009-12-19T14:42:13-08:00</published>
<updated>2009-12-19T14:42:13-08:00</updated>
<link type="text/html" href="http://github.com/technoweenie/faraday/commits/master" rel="alternate"/>
<title>technoweenie committed to master at technoweenie/faraday</title>
<author>
<name>technoweenie</name>
</author>
</entry>
<entry>
<id>tag:github.com,2008:IssuesEvent/114814260</id>
<published>2009-12-18T18:40:40-08:00</published>
<updated>2009-12-21T19:40:40-08:00</updated>
<link type="text/html" href="http://github.com/mxcl/homebrew/issues/240/find" rel="alternate"/>
<title>traviscline opened issue 240 on mxcl/homebrew</title>
<author>
<name>traviscline</name>
</author>
</entry>
<entry>
<id>tag:github.com,2008:PushEvent/113902146</id>
<published>2009-12-17T14:42:13-08:00</published>
<updated>2009-12-19T14:42:13-08:00</updated>
<link type="text/html" href="http://github.com/technoweenie/faraday/commits/master" rel="alternate"/>
<title>technoweenie pushed to master at technoweenie/faraday</title>
<author>
<name>technoweenie</name>
</author>
</entry>
<entry>
<id>tag:github.com,2008:PushEvent/113902146</id>
<published>2009-12-16T14:42:13-08:00</published>
<updated>2009-12-19T14:42:13-08:00</updated>
<link type="text/html" href="http://github.com/technoweenie/faraday/commits/master" rel="alternate"/>
<title>technoweenie applied fork commits to master at technoweenie/faraday</title>
<author>
<name>technoweenie</name>
</author>
</entry>
<entry>
<id>tag:github.com,2008:PushEvent/113902146</id>
<published>2009-12-15T14:42:13-08:00</published>
<updated>2009-12-19T14:42:13-08:00</updated>
<link type="text/html" href="http://github.com/technoweenie/faraday/commits/master" rel="alternate"/>
<title>technoweenie created branch master at technoweenie/faraday</title>
<author>
<name>technoweenie</name>
</author>
</entry>
<entry>
<id>tag:github.com,2008:PushEvent/113902146</id>
<published>2009-12-15T14:42:13-08:00</published>
<updated>2009-12-19T14:42:13-08:00</updated>
<link type="text/html" href="http://github.com/technoweenie/faraday/commits/master" rel="alternate"/>
<title>technoweenie created branch master at technoweenie/faraday</title>
<author>
<name>technoweenie</name>
</author>
</entry>
<entry>
<id>tag:github.com,2008:PushEvent/113902146</id>
<published>2009-12-14T14:42:13-08:00</published>
<updated>2009-12-19T14:42:13-08:00</updated>
<link type="text/html" href="http://github.com/technoweenie/faraday/commits/master" rel="alternate"/>
<title>technoweenie open sourced technoweenie/faraday</title>
<author>
<name>technoweenie</name>
</author>
</entry>
<entry>
<id>tag:github.com,2008:PushEvent/113902146</id>
<published>2009-12-13T14:42:13-08:00</published>
<updated>2009-12-19T14:42:13-08:00</updated>
<link type="text/html" href="http://github.com/technoweenie/faraday/commits/master" rel="alternate"/>
<title>technoweenie created branch technoweenie/faraday</title>
<author>
<name>otherguy</name>
</author>
</entry>
<entry>
<id>tag:github.com,2008:PushEvent/113902146</id>
<published>2009-12-13T14:42:13-08:00</published>
<updated>2009-12-19T14:42:13-08:00</updated>
<link type="text/html" href="http://github.com/technoweenie/faraday/commits/master" rel="alternate"/>
<title>otherguy created branch technoweenie/faraday</title>
<author>
<name>technoweenie</name>
</author>
</entry>
</feed>
10 changes: 9 additions & 1 deletion test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@
class ActiveSupport::TestCase
FEED_PATH = File.join(File.dirname(__FILE__), 'feeds')

def feed_data(feed)
def self.feed_data(feed)
IO.read File.join(FEED_PATH, "#{feed}.atom")
end

def feed_data(feed)
self.class.feed_data(feed)
end
end

Seinfeld.env = 'test'
Seinfeld.configure
Time.zone = 'Pacific Time (US & Canada)'

begin
require 'ruby-debug'
Debugger.start
Expand Down

0 comments on commit 78d0e78

Please sign in to comment.