Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

updating docs and changing fetcher api slightly

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

0 comments on commit dc16a0b

Please sign in to comment.
Something went wrong with that request. Please try again.