Skip to content

Commit

Permalink
updating docs and changing fetcher api slightly
Browse files Browse the repository at this point in the history
  • Loading branch information
dweinand committed Jun 11, 2007
1 parent 071a84e commit dc16a0b
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 38 deletions.
19 changes: 16 additions & 3 deletions 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
4 changes: 4 additions & 0 deletions generators/fetcher_daemon/templates/daemon
Expand Up @@ -21,5 +21,9 @@ class <%=class_name%>FetcherDaemon < Daemon::Base
end
end

def self.stop
puts "Stopping <%=class_name%>Fetcher"
end

end

12 changes: 12 additions & 0 deletions 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'
41 changes: 22 additions & 19 deletions 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
14 changes: 8 additions & 6 deletions lib/fetcher/imap.rb
Expand Up @@ -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
Expand Down
15 changes: 9 additions & 6 deletions lib/fetcher/pop.rb
Expand Up @@ -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
Expand All @@ -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
Expand Down
49 changes: 45 additions & 4 deletions test/fetcher_test.rb
Expand Up @@ -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.