imap-feeder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.project +23 -0
  3. data/History.txt +4 -0
  4. data/License.txt +341 -0
  5. data/Manifest.txt +48 -0
  6. data/README.txt +77 -0
  7. data/Rakefile +4 -0
  8. data/TODO.txt +11 -0
  9. data/bin/imap-feeder +68 -0
  10. data/config/hoe.rb +77 -0
  11. data/config/requirements.rb +17 -0
  12. data/lib/imap-feeder.rb +87 -0
  13. data/lib/imap-feeder/createconfigparser.rb +40 -0
  14. data/lib/imap-feeder/fakeserver.rb +23 -0
  15. data/lib/imap-feeder/feedfolder.rb +23 -0
  16. data/lib/imap-feeder/feedreader.rb +81 -0
  17. data/lib/imap-feeder/imapfeederconfig.rb +74 -0
  18. data/lib/imap-feeder/message.rb +152 -0
  19. data/lib/imap-feeder/messagestore.rb +35 -0
  20. data/lib/imap-feeder/opmlreader.rb +50 -0
  21. data/lib/imap-feeder/server.rb +77 -0
  22. data/lib/imap-feeder/version.rb +9 -0
  23. data/script/destroy +14 -0
  24. data/script/generate +14 -0
  25. data/script/txt2html +77 -0
  26. data/settings.rb.example +58 -0
  27. data/setup.rb +1585 -0
  28. data/tasks/deployment.rake +34 -0
  29. data/tasks/environment.rake +7 -0
  30. data/tasks/website.rake +15 -0
  31. data/test/data/encoded.rss +22 -0
  32. data/test/data/erroneous.yml +7 -0
  33. data/test/data/last_messages.yaml +0 -0
  34. data/test/data/rss20_no_body.xml +10 -0
  35. data/test/data/rss20_one_entry.xml +11 -0
  36. data/test/data/rss20_two_entries.xml +17 -0
  37. data/test/data/rss20_with_authors.xml +21 -0
  38. data/test/data/simple.opml +9 -0
  39. data/test/functional_test_server.rb +95 -0
  40. data/test/test_feedreader.rb +92 -0
  41. data/test/test_imap-feeder.rb +66 -0
  42. data/test/test_imapfeederconfig.rb +56 -0
  43. data/test/test_message.rb +312 -0
  44. data/test/test_messagestore.rb +54 -0
  45. data/test/test_opmlreader.rb +73 -0
  46. data/test/testlogger.rb +22 -0
  47. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  48. data/website/stylesheets/screen.css +137 -0
  49. data/website/template.rhtml +49 -0
  50. metadata +175 -0
  51. metadata.gz.sig +0 -0
@@ -0,0 +1,34 @@
1
+ desc 'Release the website and new gem version'
2
+ task :deploy => [:check_version, :website, :release] do
3
+ puts "Remember to create SVN tag:"
4
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
5
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
6
+ puts "Suggested comment:"
7
+ puts "Tagging release #{CHANGES}"
8
+ end
9
+
10
+ desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
11
+ task :local_deploy => [:website_generate, :install_gem]
12
+
13
+ task :check_version do
14
+ unless ENV['VERSION']
15
+ puts 'Must pass a VERSION=x.y.z release version'
16
+ exit
17
+ end
18
+ unless ENV['VERSION'] == VERS
19
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
20
+ exit
21
+ end
22
+ end
23
+
24
+ desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
25
+ task :install_gem_no_doc => [:clean, :package] do
26
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
27
+ end
28
+
29
+ namespace :manifest do
30
+ desc 'Recreate Manifest.txt to include ALL files'
31
+ task :refresh do
32
+ `rake check_manifest | patch -p0 > Manifest.txt`
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ task :ruby_env do
2
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
3
+ "jruby"
4
+ else
5
+ "ruby"
6
+ end unless defined? RUBY_APP
7
+ end
@@ -0,0 +1,15 @@
1
+ desc 'Generate website files'
2
+ task :website_generate => :ruby_env do
3
+ sh %{ #{RUBY_APP} script/txt2html README.txt > website/index.html}
4
+ end
5
+
6
+ desc 'Upload website files to rubyforge'
7
+ task :website_upload do
8
+ host = "#{rubyforge_username}@rubyforge.org"
9
+ remote_dir = "/var/www/gforge-projects/#{PATH}/"
10
+ local_dir = 'website'
11
+ sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
12
+ end
13
+
14
+ desc 'Generate and upload website files'
15
+ task :website => [:website_generate, :website_upload, :publish_docs]
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+
3
+ <rss version="2.0"
4
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
5
+ xmlns:admin="http://webns.net/mvcb/"
6
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
7
+ xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
8
+ xmlns:wfw="http://wellformedweb.org/CommentAPI/"
9
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
10
+ >
11
+ <channel>
12
+ <item>
13
+ <title>This is the title!</title>
14
+ <link>http://test.ch</link>
15
+ <author>Mirko Stocker</author>
16
+ <content:encoded>
17
+ &lt;&quot;ja!&quot; &gt;
18
+ </content:encoded>
19
+ <pubDate>Thu, 12 Apr 2007 19:06:00 +0200</pubDate>
20
+ </item>
21
+ </channel>
22
+ </rss>
@@ -0,0 +1,7 @@
1
+ ---
2
+ - feed:
3
+ url: http://misto.chh
4
+ path: "INBOX.Planets.Planet KDE's"
5
+ - feed:
6
+ url: http://misto.ch/invalid.html
7
+ path: INBOX.Planets.Planet Gentoo
File without changes
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0"?>
2
+ <rss version="2.0">
3
+ <channel>
4
+ <item>
5
+ <title>Mirko Stocker: KDE in Heroes!</title>
6
+ <link>http://blog.misto.ch/archives/324</link>
7
+ <pubDate>Wed, 15 Feb 2007 00:05 +0100</pubDate>
8
+ </item>
9
+ </channel>
10
+ </rss>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0"?>
2
+ <rss version="2.0">
3
+ <channel>
4
+ <item>
5
+ <title>title1</title>
6
+ <link>http://link1</link>
7
+ <description>description1</description>
8
+ <pubDate>Wed, 15 Feb 2007 00:05 +0100</pubDate>
9
+ </item>
10
+ </channel>
11
+ </rss>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <rss version="2.0">
3
+ <channel>
4
+ <item>
5
+ <title>title1</title>
6
+ <link>http://link1</link>
7
+ <description>description1</description>
8
+ <pubDate>Wed, 15 Feb 2007 00:05 +0100</pubDate>
9
+ </item>
10
+ <item>
11
+ <title>title2</title>
12
+ <link>http://link2</link>
13
+ <description>description2</description>
14
+ <pubDate>Monday 12 February 2007 17:09</pubDate>
15
+ </item>
16
+ </channel>
17
+ </rss>
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0" encoding="ISO-8859-15"?>
2
+ <rss version="2.0">
3
+ <channel>
4
+ <item>
5
+ <title>
6
+ WikifeatureUpdates
7
+ </title>
8
+ <author>MaxMuster</author>
9
+ <link>http://http</link>
10
+ <description>Changed..</description>
11
+ <pubDate>Wed, 07 Feb 2007 15:29:01 +0100</pubDate></item>
12
+ <item>
13
+ <title>
14
+ WikiInput
15
+ </title>
16
+ <author>MirkoStocker</author>
17
+ <link>http://http</link>
18
+ <description>MirkoStocker changed something</description>
19
+ <pubDate>Wed, 31 Jan 2007 14:03:18 +0100</pubDate></item>
20
+ </channel>
21
+ </rss>
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <opml version="1.0" >
3
+ <body>
4
+ <outline isOpen="false" text="Planets">
5
+ <outline title="Planet KDE" xmlUrl="http://planetkde.org/rss20.xml"/>
6
+ <outline xmlUrl="http://planet.gentoo.org/rss20.xml" title="Planet Gentoo"/>
7
+ </outline>
8
+ </body>
9
+ </opml>
@@ -0,0 +1,95 @@
1
+ require 'imap-feeder/server'
2
+ require 'imap-feeder/message'
3
+
4
+ class ServerConnectionTest < Test::Unit::TestCase
5
+
6
+ def test_server_host_not_found
7
+ assert_throws :host_not_found do
8
+ @server = Server.new(:host => "misto.chh")
9
+ end
10
+ end
11
+
12
+ def test_server_login_failed
13
+ assert_throws :login_failed do
14
+ @server = Server.new(:host => $host, :user => $user, :pass => "a")
15
+ end
16
+ end
17
+
18
+ def test_server_creation
19
+ assert_nothing_thrown do
20
+ @server = Server.new :host => $host, :user => $user, :pass => $pass
21
+ assert @server.connected
22
+ end
23
+ end
24
+ end
25
+
26
+ class ServerTest < Test::Unit::TestCase
27
+
28
+ def setup
29
+ @server = Server.new :host => $host, :user => $user, :pass => $pass
30
+ end
31
+
32
+ def teardown
33
+ @server.disconnect if @server
34
+ end
35
+
36
+ def test_server_send_simple_message
37
+ m = Message.new(:title => "test-message", :body => "body")
38
+ assert @server.send(m, "INBOX")
39
+ assert @server.has?("test-message", "INBOX")
40
+ m = @server.retrieve("test-message", "INBOX")
41
+ assert_equal("test-message", m.title)
42
+ ensure
43
+ @server.delete(m, "INBOX")
44
+ end
45
+
46
+ def test_server_send_simple_message_to_subfolder
47
+ @server.create_folder "INBOX.test-folder"
48
+
49
+ m = Message.new(:title => "test-message2", :body => "body")
50
+ assert @server.send(m, "INBOX.test-folder")
51
+ assert ! @server.has?("test-message2", "INBOX")
52
+ assert @server.has?("test-message2", "INBOX.test-folder")
53
+ ensure
54
+ @server.delete_folder "INBOX.test-folder"
55
+ end
56
+
57
+ def test_server_retrieve_invalid_message_header
58
+ m = @server.retrieve("test-message invalid", "INBOX")
59
+ assert_nil m
60
+ end
61
+
62
+ def test_server_has_invalid_message?
63
+ assert ! @server.has?("test-message invalid", "INBOX")
64
+ end
65
+
66
+ def test_has_folder_inbox?
67
+ assert @server.has_folder?("INBOX")
68
+ end
69
+
70
+ def test_has_invalid_folder?
71
+ assert ! @server.has_folder?("InvalidFolder")
72
+ end
73
+
74
+ def test_delete_not_existing
75
+ assert_throws :cannot_delete do
76
+ @server.delete_folder "Inbox.not-existing-folder"
77
+ end
78
+ end
79
+
80
+ def test_create_already_existing
81
+ @server.create_folder "INBOX.test_dir"
82
+ assert_throws :cannot_create do
83
+ @server.create_folder "INBOX.test_dir"
84
+ end
85
+ ensure
86
+ @server.delete_folder "Inbox.test_dir"
87
+ end
88
+
89
+ def test_create_and_delete_folder
90
+ assert_nothing_thrown { @server.create_folder "INBOX.test_dir" }
91
+ assert @server.has_folder?("INBOX.test_dir")
92
+ assert_nothing_thrown { @server.delete_folder "INBOX.test_dir" }
93
+ assert ! @server.has_folder?("INBOX.test_dir")
94
+ end
95
+ end
@@ -0,0 +1,92 @@
1
+ require 'imap-feeder/feedreader'
2
+ require 'imap-feeder/message'
3
+
4
+ class TestFeedReader < Test::Unit::TestCase
5
+
6
+ RSS20_ONE_ENTRY = "#{File.dirname(__FILE__)}/data/rss20_one_entry.xml"
7
+ RSS20_TWO_ENTRIES = "#{File.dirname(__FILE__)}/data/rss20_two_entries.xml"
8
+ RSS20_WITH_AUTHORS = "#{File.dirname(__FILE__)}/data/rss20_with_authors.xml"
9
+ RSS20_NO_BODY = "#{File.dirname(__FILE__)}/data/rss20_no_body.xml"
10
+ ENCODED_RSS = "#{File.dirname(__FILE__)}/data/encoded.rss"
11
+
12
+ def test_reading_first_feed
13
+ messages = FeedReader.new(RSS20_ONE_ENTRY).get_new []
14
+ assert_equal(1, messages.size)
15
+ assert_equal(Time.parse("Wed, 15 Feb 2007 00:05 +0100").rfc2822, messages.first.time)
16
+ assert_equal("title1", messages.first.title)
17
+ assert_equal("description1", messages.first.body)
18
+ end
19
+
20
+ def test_size_one
21
+ assert_equal(1, FeedReader.new(RSS20_ONE_ENTRY).number_of_entries)
22
+ end
23
+
24
+ def test_size_two
25
+ assert_equal(2, FeedReader.new(RSS20_TWO_ENTRIES).number_of_entries)
26
+ end
27
+
28
+ def test_reading_second_feed
29
+ messages = FeedReader.new(RSS20_TWO_ENTRIES).get_new []
30
+ assert_equal(2, messages.size)
31
+ assert_equal(Time.parse("Wed, 15 Feb 2007 00:05 +0100").rfc2822, messages[0].time)
32
+ assert_equal("title1", messages[0].title)
33
+ assert_equal("description1", messages[0].body)
34
+
35
+ assert_equal(Time.parse("Monday 12 February 2007 17:09").rfc2822, messages[1].time)
36
+ assert_equal("title2", messages[1].title)
37
+ assert_equal("description2", messages[1].body)
38
+ end
39
+
40
+ def test_get_latest
41
+ reader = FeedReader.new(RSS20_TWO_ENTRIES)
42
+ messages = reader.get_new []
43
+ new_messages = reader.get_new([messages.last.generate_identifier])
44
+
45
+ assert_equal(1, new_messages.size)
46
+ assert_equal("title1", new_messages.first.title)
47
+ end
48
+
49
+ def test_get_latest_or_all
50
+ reader = FeedReader.new(RSS20_TWO_ENTRIES)
51
+ new_messages = reader.get_new(["Mirko Stocker: "])
52
+
53
+ assert_equal(2, new_messages.size)
54
+ assert_equal("title1", new_messages.first.title)
55
+ assert_equal("title2", new_messages[1].title)
56
+ end
57
+
58
+ def test_get_authors
59
+ messages = FeedReader.new(RSS20_WITH_AUTHORS).get_new []
60
+ assert_equal(2, messages.size)
61
+ assert_equal("MaxMuster", messages.first.from)
62
+ assert_equal("MirkoStocker", messages.last.from)
63
+ end
64
+
65
+ def test_no_body
66
+ messages = FeedReader.new(RSS20_NO_BODY).get_new []
67
+ assert_equal(1, messages.size)
68
+ assert_equal("", messages.first.body)
69
+ end
70
+
71
+ def test_get_nothing
72
+ reader = FeedReader.new(RSS20_TWO_ENTRIES)
73
+ msgs = reader.get_new []
74
+ identifiers = msgs.map {|msg| msg.generate_identifier}
75
+ new_messages = reader.get_new(identifiers)
76
+ assert new_messages.empty?
77
+ end
78
+
79
+ def test_get_all
80
+ reader = FeedReader.new(RSS20_TWO_ENTRIES)
81
+ messages = reader.messages
82
+ new_messages = reader.get_new(nil)
83
+ assert_equal(2, new_messages.size)
84
+ end
85
+
86
+ def test__content_encoded
87
+ reader = FeedReader.new(ENCODED_RSS)
88
+ messages = reader.messages
89
+ new_messages = reader.get_new(nil)
90
+ assert_equal "<\"ja!\" >", new_messages.first.body
91
+ end
92
+ end
@@ -0,0 +1,66 @@
1
+ require 'tempfile'
2
+ require 'imap-feeder'
3
+ require 'test/testlogger'
4
+
5
+ class TestServer
6
+ attr_reader :sent
7
+
8
+ def initialize
9
+ @sent = []
10
+ end
11
+
12
+ def has_folder?(folder)
13
+ true
14
+ end
15
+
16
+ def create_folder(folder)
17
+ end
18
+
19
+ def send(msg, complete_path)
20
+ @sent << [msg, complete_path]
21
+ end
22
+ end
23
+
24
+ class TestImapFeeder < Test::Unit::TestCase
25
+
26
+ TEST_FEEDS = "#{File.dirname(__FILE__)}/data"
27
+
28
+ def setup
29
+ $log = TestLogger.new
30
+ @server = TestServer.new
31
+ @store = MessageStore.new(Tempfile.new("message_store_temp").path)
32
+ end
33
+
34
+ def title(index)
35
+ @server.sent[index].first.title
36
+ end
37
+
38
+ def body(index)
39
+ @server.sent[index].first.body
40
+ end
41
+
42
+ def folder(index)
43
+ @server.sent[index].last
44
+ end
45
+
46
+ def test_simple_rss20
47
+ config = <<EOS
48
+ - feed:
49
+ url: "#{TEST_FEEDS}/rss20_two_entries.xml"
50
+ path: INBOX.TestFolder
51
+ EOS
52
+
53
+ ImapFeeder.new(@server, @store, config).run
54
+ assert_equal("Started", $log.info_msg[0])
55
+ assert_equal("Processing INBOX.TestFolder", $log.info_msg[1])
56
+
57
+ assert_equal(2, @server.sent.length)
58
+ assert_equal("INBOX.TestFolder", folder(0))
59
+ assert_equal("description1", body(0))
60
+ assert_equal("title1", title(0))
61
+ assert_equal("INBOX.TestFolder", folder(1))
62
+ assert_equal("description2", body(1))
63
+ assert_equal("title2", title(1))
64
+
65
+ end
66
+ end
@@ -0,0 +1,56 @@
1
+ require 'open-uri'
2
+
3
+ require 'imap-feeder/imapfeederconfig'
4
+ require 'test/testlogger'
5
+
6
+
7
+ class ConfigTest < Test::Unit::TestCase
8
+
9
+ OPML_FILE = "#{File.dirname(__FILE__)}/data/simple.opml"
10
+ ERRONEOUS_FILE = "#{File.dirname(__FILE__)}/data/erroneous.yml"
11
+ FEEDS_FILE = "#{Dir.pwd}/feeds.yml"
12
+ SETTINGS_FILE = "#{Dir.pwd}/settings.rb"
13
+
14
+ def setup
15
+ $log = TestLogger.new
16
+ end
17
+
18
+ def test_create_with_root
19
+ ImapFeederConfig.create(OPML_FILE, "root")
20
+ result = YAML.load(open(FEEDS_FILE))
21
+ File.delete FEEDS_FILE
22
+
23
+ assert_equal("INBOX.root.Planets.Planet KDE", result.first['feed']['path'])
24
+
25
+ assert File.exists?(SETTINGS_FILE)
26
+ File.delete SETTINGS_FILE
27
+ end
28
+
29
+ def test_create
30
+ ImapFeederConfig.create(OPML_FILE, nil)
31
+ result = YAML.load(open(FEEDS_FILE))
32
+ File.delete FEEDS_FILE
33
+
34
+ assert_equal("http://planetkde.org/rss20.xml", result.first['feed']['url'])
35
+ assert_equal("INBOX.Planets.Planet KDE", result.first['feed']['path'])
36
+
37
+ assert_equal("http://planet.gentoo.org/rss20.xml", result.last['feed']['url'])
38
+ assert_equal("INBOX.Planets.Planet Gentoo", result.last['feed']['path'])
39
+
40
+ assert($log.error_msg.empty?)
41
+ assert($log.warn_msg.empty?)
42
+ assert_equal(2, $log.debug_msg.length)
43
+
44
+ assert File.exists?(SETTINGS_FILE)
45
+ File.delete SETTINGS_FILE
46
+ end
47
+
48
+ def test_check
49
+ ImapFeederConfig.check(File.open(ERRONEOUS_FILE))
50
+
51
+ assert_equal("Invalid character found in 'INBOX.Planets.Planet KDE's': '", $log.error_msg.first)
52
+ assert_match(/Exception while connecting to/, $log.warn_msg.first)
53
+ assert_match(/connecting/, $log.warn_msg.last)
54
+ end
55
+
56
+ end