Browse files

updating docs and changing fetcher api slightly

  • Loading branch information...
1 parent 071a84e commit dc16a0bcfcf4a14b99355a1bf1a0b039f547ab04 @dweinand dweinand committed Jun 11, 2007
Showing with 116 additions and 38 deletions.
  1. +16 −3 README
  2. +4 −0 generators/fetcher_daemon/templates/daemon
  3. +12 −0 lib/fetcher.rb
  4. +22 −19 lib/fetcher/base.rb
  5. +8 −6 lib/fetcher/imap.rb
  6. +9 −6 lib/fetcher/pop.rb
  7. +45 −4 test/fetcher_test.rb
View
19 README
@@ -1,4 +1,17 @@
-Fetcher
-=======
+= Fetcher
-Simplified message fetching
+Simplified message fetching
+
+Install using:
+script/plugin install svn://rubyforge.org/var/svn/slantwise/fetcher/trunk
+
+== Usage
+
+ @fetcher = Fetcher.new(:pop, :server => 'mail.example.com',
+ :username => 'user',
+ :password => 'pass',
+ :reciever => IncomingMailHandler)
+ loop do
+ @fetcher.fetch
+ sleep 60
+ end
View
4 generators/fetcher_daemon/templates/daemon
@@ -21,5 +21,9 @@ class <%=class_name%>FetcherDaemon < Daemon::Base
end
end
+ def self.stop
+ puts "Stopping <%=class_name%>Fetcher"
+ end
+
end
View
12 lib/fetcher.rb
@@ -1,3 +1,15 @@
+module Fetcher
+ # Use factory-style initialization or insantiate directly from a subclass
+ #
+ # Example:
+ #
+ # Fetcher.new(:pop) is equivalent to
+ # Fetcher::Pop.new()
+ def self.new(klass, options={})
+ module_eval "#{klass.to_s.capitalize}.new(options)"
+ end
+end
+
require 'fetcher/base'
require 'fetcher/pop'
require 'fetcher/imap'
View
41 lib/fetcher/base.rb
@@ -1,42 +1,45 @@
module Fetcher
class Base
-
+
def initialize(options={})
- klass = options.delete(:type)
-
- if klass
- module_eval "#{klass.to_s.capitalize}.new(#{options})"
- else
- assign_options(options)
+ %w(server username password receiver).each do |opt|
+ raise ArgumentError, "#{opt} is required" unless options[opt.to_sym]
+ instance_eval("@#{opt} = options[:#{opt}]")
end
-
end
-
+
+ # Run the fetching process
def fetch
establish_connection
get_messages
close_connection
end
-
+
protected
- def assign_options(options={})
- %w(server username password receiver).each do |opt|
- instance_eval("@#{opt} = options[:#{opt}]")
- end
+ # Stub. Should be overridden by subclass.
+ def establish_connection #:nodoc:
+ raise NotImplementedError, "This method should be overridden by subclass"
end
-
- def establish_connection
+
+ # Stub. Should be overridden by subclass.
+ def get_messages #:nodoc:
raise NotImplementedError, "This method should be overridden by subclass"
end
- def get_messages
+ # Stub. Should be overridden by subclass.
+ def close_connection #:nodoc:
raise NotImplementedError, "This method should be overridden by subclass"
end
- def close_connection
+ # Send message to receiver object
+ def process_message(message)
+ @receiver.receive(message)
+ end
+
+ # Stub. Should be overridden by subclass.
+ def handle_bogus_message(message) #:nodoc:
raise NotImplementedError, "This method should be overridden by subclass"
end
-
end
end
View
14 lib/fetcher/imap.rb
@@ -5,38 +5,40 @@ class Imap < Base
protected
- def assign_options(options={})
+ # Adds authentication option
+ def initialize(options={})
@authentication = options.delete(:authentication) || 'PLAIN'
- super
+ super(options)
end
+ # Open connection and login to server
def establish_connection
@connection = Net::IMAP.new(@server)
@connection.authenticate(@authentication, @username, @password)
end
+ # Retrieve messages from server
def get_messages
@connection.select('INBOX')
@connection.search(['ALL']).each do |message_id|
msg = @connection.fetch(message_id,'RFC822')[0].attr['RFC822']
- # process the email message
begin
- @receiver.receive(msg)
+ process_message(msg)
rescue
- # Store the message for inspection if the receiver errors
handle_bogus_message(msg)
end
# Mark message as deleted
@connection.store(message_id, "+FLAGS", [:Deleted])
end
end
+ # Store the message for inspection if the receiver errors
def handle_bogus_message(message)
@connection.append('bogus', message)
end
+ # Delete messages and log out
def close_connection
- # expunge messages and log out.
@connection.expunge
@connection.logout
@connection.disconnect
View
15 lib/fetcher/pop.rb
@@ -5,25 +5,26 @@ class Pop < Base
protected
- def assign_options(options={})
+ # Adds ssl option
+ def initialize(options={})
@ssl = options.delete(:ssl)
- super
+ super(options)
end
+ # Open connection and login to server
def establish_connection
@connection = Net::POP3.new(@server)
@connection.enable_ssl(OpenSSL::SSL::VERIFY_NONE) if @ssl
@connection.start(@username, @password)
end
+ # Retrieve messages from server
def get_messages
unless @connection.mails.empty?
@connection.each_mail do |msg|
- # Process the message
begin
- @receiver.receive(msg.pop)
+ process_message(msg.pop)
rescue
- # Store the message for inspection if the receiver errors
handle_bogus_message(msg.pop)
end
# Delete message from server
@@ -32,10 +33,12 @@ def get_messages
end
end
+ # Store the message for inspection if the receiver errors
def handle_bogus_message(message)
-
+ # This needs a good solution
end
+ # Close connection to server
def close_connection
@connection.finish
end
View
49 test/fetcher_test.rb
@@ -8,22 +8,63 @@ class FetcherTest < Test::Unit::TestCase
def setup
@receiver = mock()
- @fetcher = Fetcher::Base.new(:server => 'test.host',
- :username => 'name',
- :password => 'password',
- :receiver => @receiver)
end
def test_should_set_configuration_instance_variables
+ create_fetcher
assert_equal 'test.host', @fetcher.instance_variable_get(:@server)
assert_equal 'name', @fetcher.instance_variable_get(:@username)
assert_equal 'password', @fetcher.instance_variable_get(:@password)
assert_equal @receiver, @fetcher.instance_variable_get(:@receiver)
end
def test_should_require_subclass
+ create_fetcher
assert_raise(NotImplementedError) { @fetcher.fetch }
end
+
+ def test_should_require_server
+ assert_raise(ArgumentError) { create_fetcher(:server => nil) }
+ end
+
+ def test_should_require_username
+ assert_raise(ArgumentError) { create_fetcher(:username => nil) }
+ end
+
+ def test_should_require_password
+ assert_raise(ArgumentError) { create_fetcher(:password => nil) }
+ end
+
+ def test_should_require_receiver
+ assert_raise(ArgumentError) { create_fetcher(:receiver => nil) }
+ end
+
+ def create_fetcher(options={})
+ @fetcher = Fetcher::Base.new({:server => 'test.host', :username => 'name', :password => 'password', :receiver => @receiver}.merge(options))
+ end
+
+end
+
+class FactoryFetcherTest < Test::Unit::TestCase
+
+ def setup
+ @receiver = mock()
+ @pop_fetcher = Fetcher.new(:pop, :server => 'test.host',
+ :username => 'name',
+ :password => 'password',
+ :receiver => @receiver)
+
+ @imap_fetcher = Fetcher.new(:imap, :server => 'test.host',
+ :username => 'name',
+ :password => 'password',
+ :receiver => @receiver)
+ end
+
+ def test_should_be_sublcass
+ assert_equal Fetcher::Pop, @pop_fetcher.class
+ assert_equal Fetcher::Imap, @imap_fetcher.class
+ end
+
end
# Write tests for sub-classes

0 comments on commit dc16a0b

Please sign in to comment.