maildir 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -6,7 +6,9 @@ A ruby library for reading and writing messages in the maildir format.
6
6
 
7
7
  See http://cr.yp.to/proto/maildir.html and http://en.wikipedia.org/wiki/Maildir
8
8
 
9
- As Daniel J. Berstein puts it: "Two words: no locks." The maildir format allows multiple processes to read and write arbitrary messages without file locks.
9
+ "Two words: no locks." -- Daniel J. Berstein
10
+
11
+ The maildir format allows multiple processes to read and write arbitrary messages without file locks.
10
12
 
11
13
  New messages are initially written to a "tmp" directory with an automatically-generated unique filename. After the message is written, it's moved to the "new" directory where other processes may read it.
12
14
 
@@ -104,9 +106,9 @@ It's trivial to create a custom serializer. Implement the following two methods:
104
106
  load(path)
105
107
  dump(data, path)
106
108
 
107
- == Credits
109
+ == Contributors
108
110
 
109
- niklas | brueckenschlaeger, http://github.com/nilclass added subdir & courierimapkeywords support
111
+ Niklas E. Cathor (http://github.com/nilclass) added subdir & courierimapkeywords support
110
112
 
111
113
  == Copyright
112
114
 
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ begin
15
15
  gemspec.description = "A ruby library for reading and writing arbitrary messages in DJB's maildir format"
16
16
  gemspec.email = "aaron@ktheory.com"
17
17
  gemspec.homepage = "http://github.com/ktheory/maildir"
18
- gemspec.authors = ["Aaron Suggs"]
18
+ gemspec.authors = ["Aaron Suggs", "Niklas E. Cathor"]
19
19
  gemspec.add_development_dependency "shoulda", ">= 0"
20
20
  gemspec.add_development_dependency "mail", ">= 0"
21
21
  gemspec.add_development_dependency "json", ">= 0"
@@ -29,4 +29,4 @@ end
29
29
  desc "Run benchmarks"
30
30
  task :bench do
31
31
  load File.join(File.dirname(__FILE__), "benchmarks", "runner")
32
- end
32
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.0
data/lib/maildir.rb CHANGED
@@ -2,7 +2,6 @@ require 'fileutils' # For create_directories
2
2
  class Maildir
3
3
 
4
4
  SUBDIRS = [:tmp, :new, :cur].freeze
5
- READABLE_DIRS = SUBDIRS.reject{|s| :tmp == s}.freeze
6
5
 
7
6
  include Comparable
8
7
 
@@ -1,22 +1,27 @@
1
1
  # implements IMAP Keywords as used by the Courier Mail Server
2
2
  # see http://www.courier-mta.org/imap/README.imapkeywords.html for details
3
3
 
4
- require 'ftools'
5
4
  require 'maildir'
6
5
  module Maildir::Keywords
7
6
  def self.included(base)
8
7
  Maildir::Message.send(:include, MessageExtension)
9
8
  end
10
9
 
10
+ def keyword_dir
11
+ @keyword_dir ||= File.join(path, 'courierimapkeywords')
12
+ Dir.mkdir(@keyword_dir) unless File.directory?(@keyword_dir)
13
+ return @keyword_dir
14
+ end
15
+
11
16
  # process contents of courierimapkeywords/ directory as described in README.imapkeywords
12
17
  def read_keywords
13
18
  messages = (list(:cur) + list(:new)).inject({}) { |m, msg| m[msg.unique_name] = msg ; m }
14
19
  t = Time.now.to_i / 300
15
- keyword_dir = File.join(path, 'courierimapkeywords')
16
20
  keywords = []
17
21
  state = :head
18
22
  # process :list
19
- File.open(File.join(keyword_dir, ':list')).each_line do |line|
23
+ list_file = File.join(keyword_dir, ':list')
24
+ File.open(list_file).each_line do |line|
20
25
  line.strip!
21
26
  if state == :head
22
27
  if line.empty?
@@ -30,7 +35,7 @@ module Maildir::Keywords
30
35
  msg.set_keywords(ids.split(/\s/).map {|id| keywords[id.to_i - 1] })
31
36
  end
32
37
  end
33
- end
38
+ end if File.exist?(list_file)
34
39
  # collect keyword files
35
40
  keyword_files = (Dir.entries(keyword_dir) - %w(. .. :list)).inject({}) do |keyword_files, file|
36
41
  if file =~ /^\.(\d+)\.(.*)$/
@@ -39,7 +44,7 @@ module Maildir::Keywords
39
44
  else
40
45
  n = t + 1
41
46
  key = file
42
- File.move(File.join(keyword_dir, file), File.join(keyword_dir, ".#{n}.#{key}"))
47
+ FileUtils.mv(File.join(keyword_dir, file), File.join(keyword_dir, ".#{n}.#{key}"))
43
48
  end
44
49
  if msg = messages[key]
45
50
  (keyword_files[key] ||= []) << [n, key]
@@ -49,13 +54,15 @@ module Maildir::Keywords
49
54
  File.unlink(fname)
50
55
  end
51
56
  end
57
+ next(keyword_files)
52
58
  end
53
59
  # process keyword files
54
60
  keyword_files.each_pair do |key, files|
55
61
  files.sort! { |a, b| a[0] <=> b[0] }
56
- files[0..-2].each { |f| File.unlink(File.join(keyword_dir, ".#{f.join('.')}")) } if n_files.last[0] < t
62
+ files[0..-2].each { |f| File.unlink(File.join(keyword_dir, ".#{f.join('.')}")) } if files.last[0] < t
57
63
  msg = messages[key]
58
- current_keywords = File.read(files.last).read.split(/\s+/)
64
+ file = (File.exist?(File.join(keyword_dir, files.last[1])) ? files.last[1] : ".#{files.last.join('.')}")
65
+ current_keywords = File.read(File.join(keyword_dir, file)).split(/\s+/)
59
66
  msg.set_keywords(current_keywords)
60
67
  if (add = (current_keywords - keywords)).any?
61
68
  keywords += add
@@ -72,7 +79,7 @@ module Maildir::Keywords
72
79
  @keywords[key] = msg.keywords
73
80
  end
74
81
  }
75
- File.move(tmp_file, File.join(keyword_dir, ':list'))
82
+ FileUtils.mv(tmp_file, list_file)
76
83
  end
77
84
 
78
85
  def keywords(key)
@@ -88,9 +95,9 @@ module Maildir::Keywords
88
95
 
89
96
  # sets given keywords on the message.
90
97
  def keywords=(list)
91
- tmp_fname = File.join(maildir.path, 'tmp', unique_name)
98
+ tmp_fname = File.join(@maildir.path, 'tmp', unique_name)
92
99
  File.open(tmp_fname, 'w') { |f| f.write(list.join("\n")) }
93
- File.move(tmp_fname, File.join(maildir.path, 'courierimapkeywords', unique_name))
100
+ FileUtils.mv(tmp_fname, File.join(@maildir.keyword_dir, unique_name))
94
101
  end
95
102
 
96
103
  # sets @keywords to the given list
@@ -11,6 +11,10 @@ module Maildir::Subdirs
11
11
  end
12
12
  end
13
13
 
14
+ def name
15
+ root? ? ROOT_NAME : subdir_parts(path).last
16
+ end
17
+
14
18
  def create_subdir(name)
15
19
  raise ArgumentError.new("'name' may not contain delimiter character (#{DELIM})") if name.include?(DELIM)
16
20
  full_name = (root? ? [] : subdir_parts(File.basename(path))).push(name).unshift('').join(DELIM)
@@ -54,6 +58,7 @@ module Maildir::Subdirs
54
58
  private
55
59
 
56
60
  def subdir_parts(path)
61
+ path.sub!(/\/$/, '') # remove trailing slash
57
62
  parts = (path.split(DELIM) - [''])
58
63
  # some clients (e.g. Thunderbird) mess up namespaces so subdirs
59
64
  # end up looking like '.INBOX.Trash' instead of '.Trash'
data/maildir.gemspec CHANGED
@@ -5,10 +5,10 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{maildir}
8
- s.version = "0.4.0"
8
+ s.version = "0.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Aaron Suggs"]
11
+ s.authors = ["Aaron Suggs", "Niklas E. Cathor"]
12
12
  s.date = %q{2010-01-24}
13
13
  s.description = %q{A ruby library for reading and writing arbitrary messages in DJB's maildir format}
14
14
  s.email = %q{aaron@ktheory.com}
@@ -35,9 +35,11 @@ Gem::Specification.new do |s|
35
35
  "lib/maildir/unique_name.rb",
36
36
  "maildir.gemspec",
37
37
  "test/test_helper.rb",
38
+ "test/test_keywords.rb",
38
39
  "test/test_maildir.rb",
39
40
  "test/test_message.rb",
40
41
  "test/test_serializers.rb",
42
+ "test/test_subdirs.rb",
41
43
  "test/test_unique_name.rb"
42
44
  ]
43
45
  s.homepage = %q{http://github.com/ktheory/maildir}
@@ -47,9 +49,11 @@ Gem::Specification.new do |s|
47
49
  s.summary = %q{Read & write messages in the maildir format}
48
50
  s.test_files = [
49
51
  "test/test_helper.rb",
52
+ "test/test_keywords.rb",
50
53
  "test/test_maildir.rb",
51
54
  "test/test_message.rb",
52
55
  "test/test_serializers.rb",
56
+ "test/test_subdirs.rb",
53
57
  "test/test_unique_name.rb"
54
58
  ]
55
59
 
data/test/test_helper.rb CHANGED
@@ -1,7 +1,5 @@
1
- require 'rubygems'
2
1
  require 'test/unit'
3
2
  require 'shoulda'
4
- require 'fileutils'
5
3
  require 'maildir'
6
4
 
7
5
  # Require all the serializers
@@ -20,7 +18,19 @@ def temp_maildir
20
18
  Maildir.new("/tmp/maildir_test")
21
19
  end
22
20
 
23
- # Useful for testing that strings defined & not empty
21
+ # create the subdir tree:
22
+ # | INBOX
23
+ # |-- a
24
+ # | |-- x
25
+ # | |-- y
26
+ # |-- b
27
+ def setup_subdirs(maildir)
28
+ %w(a b a.x a.y).each do |x|
29
+ Maildir.new(File.join(maildir.path, ".#{x}"))
30
+ end
31
+ end
32
+
33
+ # Test that objects are neither nil nor empty
24
34
  def assert_not_empty(obj, msg='')
25
35
  assert !obj.nil? && !obj.empty?, msg
26
36
  end
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+ require 'maildir/keywords'
3
+ class TestKeywords < Test::Unit::TestCase
4
+ context "A message" do
5
+ setup do
6
+ @data = "foo\n"
7
+ @msg = Maildir::Message.create(temp_maildir, @data)
8
+ end
9
+
10
+ should "remember keywords" do
11
+ kw = %w(Junk Seen)
12
+ @msg.keywords = kw
13
+ assert (@msg.keywords & kw).size == 2
14
+ end
15
+ end
16
+ end
data/test/test_maildir.rb CHANGED
@@ -70,4 +70,4 @@ class TestMaildir < Test::Unit::TestCase
70
70
  assert_equal stale_tmp, temp_maildir.get_stale_tmp
71
71
  end
72
72
  end
73
- end
73
+ end
@@ -16,7 +16,7 @@ class TestSerializers < Test::Unit::TestCase
16
16
  when Maildir::Serializer::Mail
17
17
  Mail.new
18
18
  else
19
- # Test a few common data structures
19
+ # Test a few common types
20
20
  [1, nil, {"foo" => true}]
21
21
  end
22
22
 
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+ require 'maildir/subdirs'
3
+ class TestSubdirs < Test::Unit::TestCase
4
+ context "A maildir" do
5
+ setup do
6
+ FakeFS::FileSystem.clear
7
+ @maildir = temp_maildir
8
+ setup_subdirs(@maildir)
9
+ end
10
+
11
+ should "have subdirs" do
12
+ assert @maildir.subdirs.any?
13
+ end
14
+
15
+ should "be called INBOX" do
16
+ assert @maildir.name == 'INBOX'
17
+ end
18
+
19
+ should "include direct subdirs" do
20
+ subdir_names = @maildir.subdirs.map(&:name)
21
+ assert subdir_names.include?('a') && subdir_names.include?('b')
22
+ end
23
+
24
+ should "not include deeper subdirs" do
25
+ subdir_names = @maildir.subdirs.map(&:name)
26
+ assert ! subdir_names.include?('x') && ! subdir_names.include?('a.x')
27
+ end
28
+
29
+ should "create more subdirs" do
30
+ @maildir.create_subdir("test")
31
+ assert @maildir.subdirs.map(&:name).include?("test")
32
+ end
33
+ end
34
+
35
+ context "A subdir" do
36
+ setup do
37
+ FakeFS::FileSystem.clear
38
+ @maildir = temp_maildir
39
+ setup_subdirs(@maildir)
40
+ end
41
+
42
+ should "include more subdirs" do
43
+ assert_not_empty @maildir.subdirs.select{ |sd| sd.name == 'a'}.first.subdirs
44
+ end
45
+ end
46
+ end
metadata CHANGED
@@ -1,10 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maildir
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Suggs
8
+ - Niklas E. Cathor
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
@@ -80,9 +81,11 @@ files:
80
81
  - lib/maildir/unique_name.rb
81
82
  - maildir.gemspec
82
83
  - test/test_helper.rb
84
+ - test/test_keywords.rb
83
85
  - test/test_maildir.rb
84
86
  - test/test_message.rb
85
87
  - test/test_serializers.rb
88
+ - test/test_subdirs.rb
86
89
  - test/test_unique_name.rb
87
90
  has_rdoc: true
88
91
  homepage: http://github.com/ktheory/maildir
@@ -114,7 +117,9 @@ specification_version: 3
114
117
  summary: Read & write messages in the maildir format
115
118
  test_files:
116
119
  - test/test_helper.rb
120
+ - test/test_keywords.rb
117
121
  - test/test_maildir.rb
118
122
  - test/test_message.rb
119
123
  - test/test_serializers.rb
124
+ - test/test_subdirs.rb
120
125
  - test/test_unique_name.rb