maildir 0.4.0 → 0.5.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.
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