This repository has been archived by the owner on Jan 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
2,764 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1 @@ | ||
= sogger | ||
|
||
Description goes here. | ||
|
||
== Note on Patches/Pull Requests | ||
|
||
* Fork the project. | ||
* Make your feature addition or bug fix. | ||
* Add tests for it. This is important so I don't break it in a | ||
future version unintentionally. | ||
* Commit, do not mess with rakefile, version, or history. | ||
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull) | ||
* Send me a pull request. Bonus points for topic branches. | ||
|
||
== Copyright | ||
|
||
Copyright (c) 2009 Maxim Chernyak. See LICENSE for details. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/usr/bin/env ruby | ||
require 'rubygems' | ||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'sogger')) | ||
|
||
sogger = Sogger::Runner.new | ||
puts "Press CTRL+C to stop..." | ||
sogger.run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
require 'open-uri' | ||
require 'nokogiri' | ||
require 'meow' | ||
|
||
require File.dirname(__FILE__) + "/sogger/question.rb" | ||
require File.dirname(__FILE__) + "/sogger/sogger.rb" | ||
require File.dirname(__FILE__) + "/sogger/runner.rb" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
module Sogger | ||
class Question | ||
include Comparable | ||
attr_accessor :attributes | ||
|
||
def initialize(attributes = {}) | ||
@attributes = attributes | ||
end | ||
|
||
def self.from_xml(xml_element) | ||
attributes = { :title => xml_element.css('title').text, | ||
:url => xml_element.css('id').text, | ||
:tags => xml_element.css('category').map{|c| c['term']}, | ||
:published => DateTime.parse(xml_element.css('published').text) } | ||
new attributes | ||
end | ||
|
||
def title | ||
@attributes[:title] | ||
end | ||
|
||
def url | ||
@attributes[:url] | ||
end | ||
|
||
def tags | ||
@attributes[:tags] | ||
end | ||
|
||
def published | ||
@attributes[:published] | ||
end | ||
|
||
def <=>(other) | ||
other.published <=> published | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
module Sogger | ||
class Runner | ||
UPDATE_INTERVAL = 60 | ||
GROWL_INTERVAL = 20 | ||
|
||
def initialize | ||
@cached_sogger = Sogger.new | ||
@remote_sogger = Sogger.new | ||
@questions_buffer = [] | ||
@growler = Meow.new("Sogger") | ||
end | ||
|
||
def run | ||
updater = Thread.new("updater") do | ||
while true | ||
puts "Updater: Downloading feed..." | ||
@remote_sogger.download_feed! | ||
|
||
new_questions = [] | ||
unless @cached_sogger.questions.empty? | ||
puts "Updater: Comparing feeds..." | ||
new_questions = (@remote_sogger - @cached_sogger).questions | ||
end | ||
|
||
unless new_questions.empty? | ||
puts "Updater: Adding #{new_questions.size} questions to buffer..." | ||
@questions_buffer += new_questions | ||
end | ||
|
||
puts "Updater: Caching feed..." | ||
@remote_sogger.save! | ||
|
||
puts "Updater: Loading cached feed..." | ||
@cached_sogger.load! | ||
|
||
puts "Updater: Sleeping for #{UPDATE_INTERVAL} seconds..." | ||
sleep UPDATE_INTERVAL | ||
end | ||
end | ||
|
||
notifier = Thread.new("notifier") do | ||
while true | ||
unless @questions_buffer.empty? | ||
puts "\nNotifier: Growling..." | ||
growl(@questions_buffer.pop) | ||
end | ||
|
||
sleep GROWL_INTERVAL | ||
end | ||
end | ||
|
||
[updater, notifier].map(&:join) | ||
end | ||
|
||
def growl(question) | ||
@growler.notify(question.tags.join(', '), question.title) do | ||
system "open", question.url | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
module Sogger | ||
class Sogger | ||
class << self; attr_accessor :save_path end | ||
attr_reader :raw_data | ||
|
||
SO_FEED_URL = "http://stackoverflow.com/feeds" | ||
DEFAULT_SAVE_PATH = "tmp/feed.xml" | ||
self.save_path = DEFAULT_SAVE_PATH | ||
|
||
def initialize(questions = []) | ||
@questions = questions | ||
end | ||
|
||
def questions | ||
@questions.sort | ||
end | ||
|
||
def download_feed! | ||
@raw_data = open(SO_FEED_URL).read | ||
parse_raw_data | ||
end | ||
|
||
def save! | ||
File.open(self.class.save_path, "w") do |file| | ||
file.write @raw_data | ||
end | ||
end | ||
|
||
def load! | ||
@raw_data = File.read(self.class.save_path) | ||
parse_raw_data | ||
end | ||
|
||
def -(other) | ||
newest_other = other.questions.first | ||
Sogger.new(questions.select{|q| q < newest_other }) | ||
end | ||
|
||
private | ||
def parse_raw_data | ||
@data = Nokogiri::XML(@raw_data) | ||
@questions = @data.css('entry').map{ |e| Question.from_xml(e) } | ||
end | ||
end | ||
end |
Oops, something went wrong.