maildir 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.
- data/LICENSE +20 -0
- data/NOTES.txt +17 -0
- data/README.rdoc +9 -0
- data/Rakefile +24 -0
- data/VERSION +1 -0
- data/benchmarks/runner +4 -0
- data/lib/maildir.rb +66 -0
- data/lib/maildir/message.rb +131 -0
- data/lib/maildir/unique_name.rb +72 -0
- data/test/test_helper.rb +24 -0
- data/test/test_maildir.rb +38 -0
- data/test/test_message.rb +152 -0
- data/test/test_unique_name.rb +43 -0
- metadata +80 -0
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2009 Aaron Suggs
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/NOTES.txt
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
md = Maildir.new(path)
|
|
2
|
+
|
|
3
|
+
md.add(data) => message
|
|
4
|
+
|
|
5
|
+
md.list_new => array of messages
|
|
6
|
+
|
|
7
|
+
md.list_cur => array of messages
|
|
8
|
+
|
|
9
|
+
message.process(flags) => moves message from new to cur and adds flags
|
|
10
|
+
|
|
11
|
+
message.flags
|
|
12
|
+
message.flags=
|
|
13
|
+
message.add_flag
|
|
14
|
+
message.remove_flag
|
|
15
|
+
|
|
16
|
+
message.info
|
|
17
|
+
message.info=
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'rake/testtask'
|
|
2
|
+
Rake::TestTask.new do |t|
|
|
3
|
+
t.libs << "test"
|
|
4
|
+
t.test_files = FileList['test/test*.rb']
|
|
5
|
+
t.verbose = true
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
task :default => :test
|
|
9
|
+
|
|
10
|
+
begin
|
|
11
|
+
require 'jeweler'
|
|
12
|
+
Jeweler::Tasks.new do |gemspec|
|
|
13
|
+
gemspec.name = "maildir"
|
|
14
|
+
gemspec.summary = "Read & write messages in the maildir format"
|
|
15
|
+
gemspec.description = "A ruby library for reading and writing arbitrary messages in DJB's maildir format"
|
|
16
|
+
gemspec.email = "aaron@ktheory.com"
|
|
17
|
+
gemspec.homepage = "http://github.com/ktheory/maildir"
|
|
18
|
+
gemspec.authors = ["Aaron Suggs"]
|
|
19
|
+
gemspec.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
|
20
|
+
end
|
|
21
|
+
Jeweler::GemcutterTasks.new
|
|
22
|
+
rescue LoadError
|
|
23
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
|
24
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
data/benchmarks/runner
ADDED
data/lib/maildir.rb
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
class Maildir
|
|
2
|
+
|
|
3
|
+
SUBDIRS = [:tmp, :new, :cur].freeze
|
|
4
|
+
READABLE_DIRS = SUBDIRS.reject{|s| :tmp == s}.freeze
|
|
5
|
+
|
|
6
|
+
attr_reader :path
|
|
7
|
+
def initialize(path, create = true)
|
|
8
|
+
@path = File.join(path, '/') # Ensure path has a trailing slash
|
|
9
|
+
create_subdirectories if create
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Maildirs are indentical if they have the same path
|
|
13
|
+
def ==(maildir)
|
|
14
|
+
return false unless Maildir === maildir
|
|
15
|
+
maildir.path == self.path
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# define methods tmp_path, new_path, & cur_path
|
|
19
|
+
SUBDIRS.each do |subdir|
|
|
20
|
+
define_method "#{subdir}_path" do
|
|
21
|
+
File.join(path, subdir.to_s)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Ensure subdirectories exist. This can safely be called multiple times, but
|
|
26
|
+
# must hit the disk. Avoid calling this if you're certain the directories
|
|
27
|
+
# exist.
|
|
28
|
+
def create_subdirectories
|
|
29
|
+
SUBDIRS.each do |subdir|
|
|
30
|
+
FileUtils.mkdir_p(self.send("#{subdir}_path"))
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def list(new_or_cur)
|
|
35
|
+
list_keys(new_or_cur).map{|key| get_message(key)}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def list_keys(new_or_cur)
|
|
39
|
+
new_or_cur = new_or_cur.to_sym
|
|
40
|
+
unless [:new, :cur].include? new_or_cur
|
|
41
|
+
raise ArgumentError, "first arg must be new or cur"
|
|
42
|
+
end
|
|
43
|
+
get_dir_listing(new_or_cur)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Writes IO object out as a new message. See Maildir::Message.create for
|
|
47
|
+
# more.
|
|
48
|
+
def add_message(io)
|
|
49
|
+
Maildir::Message.create(self, io)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def get_message(key)
|
|
53
|
+
Maildir::Message.new(self, key)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
protected
|
|
57
|
+
def get_dir_listing(new_or_cur)
|
|
58
|
+
search_path = File.join(self.path, new_or_cur.to_s, '*')
|
|
59
|
+
results = Dir.glob(search_path)
|
|
60
|
+
# Remove the maildir's path from the beginning of the message path
|
|
61
|
+
results.map!{|message_path| message_path.sub!(self.path, '')}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
require 'maildir/unique_name'
|
|
66
|
+
require 'maildir/message'
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
class Maildir::Message
|
|
2
|
+
# COLON seperates the unique name from the info
|
|
3
|
+
COLON = ':'
|
|
4
|
+
# The default info, to which flags are appended
|
|
5
|
+
INFO = "2,"
|
|
6
|
+
|
|
7
|
+
class << self
|
|
8
|
+
# Create a new message in maildir with the contents of io. The message is
|
|
9
|
+
# first written to the tmp dir, then moved to new. This is a shortcut for:
|
|
10
|
+
# message = Maildir::Message.new(maildir)
|
|
11
|
+
# message.write(io)
|
|
12
|
+
def create(maildir, io)
|
|
13
|
+
message = self.new(maildir)
|
|
14
|
+
message.write(io)
|
|
15
|
+
message
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attr_reader :dir, :unique_name, :info, :old_key
|
|
20
|
+
|
|
21
|
+
# Create a new, unwritten message:
|
|
22
|
+
# Message.new(maildir)
|
|
23
|
+
#
|
|
24
|
+
# Instantiate an existing message:
|
|
25
|
+
# Message.new(maildir, key)
|
|
26
|
+
def initialize(maildir, key=nil)
|
|
27
|
+
@maildir = maildir
|
|
28
|
+
if key.nil?
|
|
29
|
+
@dir = :tmp
|
|
30
|
+
else
|
|
31
|
+
parse_key(key)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
raise ArgumentError, "State must be in #{Maildir::SUBDIRS.inspect}" unless Maildir::SUBDIRS.include? dir
|
|
35
|
+
|
|
36
|
+
if :tmp == dir
|
|
37
|
+
@unique_name = Maildir::UniqueName.create
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Writes io to disk. Can only be called on messages instantiated without a
|
|
42
|
+
# key (which haven't been written to disk). If the io object has a 'read'
|
|
43
|
+
# method, calls io.read. Otherwise, calls io.to_s.
|
|
44
|
+
def write(io)
|
|
45
|
+
raise "Can only write to messages in tmp" unless :tmp == @dir
|
|
46
|
+
# Write out contents to tmp
|
|
47
|
+
File.open(path, 'w') do |file|
|
|
48
|
+
file.puts io.respond_to?(:read) ? io.read : io.to_s
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Rename to new
|
|
52
|
+
rename(:new)
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Move a message from new to cur, add info
|
|
57
|
+
def process
|
|
58
|
+
rename(:cur, INFO)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def info=(info)
|
|
62
|
+
raise "Can only set info on cur messages" unless :cur == @dir
|
|
63
|
+
rename(:cur, info)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Returns an array of single letter flags applied to the message
|
|
67
|
+
def flags
|
|
68
|
+
@info.sub(INFO,'').split('')
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def flags=(*flags)
|
|
72
|
+
self.info = INFO + sort_flags(flags.flatten.join(''))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def add_flag(flag)
|
|
76
|
+
self.flags = (flags << flag.upcase)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def remove_flag(flag)
|
|
80
|
+
self.flags = flags.delete_if{|f| f == flag.upcase}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# Returns the filename of the message
|
|
85
|
+
def filename
|
|
86
|
+
[unique_name, info].compact.join(COLON)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Returns the key to identify the message
|
|
90
|
+
def key
|
|
91
|
+
File.join(dir.to_s, filename)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Returns the full path to the message
|
|
95
|
+
def path
|
|
96
|
+
File.join(@maildir.path, key)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def old_path
|
|
100
|
+
File.join(@maildir.path, old_key)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
protected
|
|
104
|
+
# Sets dir, unique_name, and info based in key
|
|
105
|
+
def parse_key(key)
|
|
106
|
+
@dir, filename = key.split(File::SEPARATOR)
|
|
107
|
+
@dir = @dir.to_sym
|
|
108
|
+
@unique_name, @info = filename.split(COLON)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def sort_flags(flags)
|
|
112
|
+
flags.split('').map{|f| f.upcase}.sort!.uniq.join('')
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def rename(new_dir, new_info=nil)
|
|
116
|
+
# Safe the old key so we can revert to the old state
|
|
117
|
+
@old_key = key
|
|
118
|
+
|
|
119
|
+
# Set the new state
|
|
120
|
+
@dir = new_dir
|
|
121
|
+
@info = new_info if new_info
|
|
122
|
+
|
|
123
|
+
begin
|
|
124
|
+
File.rename(old_path, path) unless old_path == path
|
|
125
|
+
rescue Errno::ENOENT
|
|
126
|
+
# Restore ourselves to the old state
|
|
127
|
+
parse_key(@old_key)
|
|
128
|
+
raise
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Class for generating unique file names for new messages
|
|
2
|
+
class Maildir::UniqueName
|
|
3
|
+
require 'thread' # For mutex support
|
|
4
|
+
require 'socket' # For getting the hostname
|
|
5
|
+
class << self
|
|
6
|
+
# Return a thread-safe increasing counter
|
|
7
|
+
def counter
|
|
8
|
+
@counter_mutex ||= Mutex.new
|
|
9
|
+
@counter_mutex.synchronize do
|
|
10
|
+
@counter = @counter.to_i + 1
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
self.new.to_s
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Return a unique file name based on strategy
|
|
20
|
+
def initialize
|
|
21
|
+
# Use the same time object
|
|
22
|
+
@now = Time.now
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Return the name as a string
|
|
26
|
+
def to_s
|
|
27
|
+
[left, middle, right].join(".")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
protected
|
|
31
|
+
# The left part of the unique name is the number of seconds from since the
|
|
32
|
+
# UNIX epoch
|
|
33
|
+
def left
|
|
34
|
+
@now.to_i.to_s
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# The middle part contains the microsecond, the process id, and a
|
|
38
|
+
# per-process incrementing counter
|
|
39
|
+
def middle
|
|
40
|
+
"M#{microsecond}P#{process_id}Q#{delivery_count}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The right part is the hostname
|
|
44
|
+
def right
|
|
45
|
+
Socket.gethostname
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def secure_random(bytes=8)
|
|
49
|
+
# File.read("/dev/urandom", bytes).unpack("H*")[0]
|
|
50
|
+
raise "Not implemented"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def inode
|
|
54
|
+
raise "Not implemented"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def device_number
|
|
58
|
+
raise "Not implemented"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def microsecond
|
|
62
|
+
@now.usec.to_s
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def process_id
|
|
66
|
+
Process.pid.to_s
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def delivery_count
|
|
70
|
+
self.class.counter.to_s
|
|
71
|
+
end
|
|
72
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'tempfile'
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
require 'maildir'
|
|
8
|
+
|
|
9
|
+
# Create a reusable maildir that's cleaned up when the tests are done
|
|
10
|
+
def temp_maildir
|
|
11
|
+
return $maildir if $maildir
|
|
12
|
+
|
|
13
|
+
dir_path = Dir.mktmpdir("maildir_test")
|
|
14
|
+
at_exit do
|
|
15
|
+
puts "Cleaning up temp maildir"
|
|
16
|
+
FileUtils.rm_r(dir_path)
|
|
17
|
+
end
|
|
18
|
+
$maildir = Maildir.new(dir_path)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Useful for testing that strings defined & not empty
|
|
22
|
+
def assert_not_empty(obj, msg='')
|
|
23
|
+
assert !obj.nil? && !obj.empty?, msg
|
|
24
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
class TestMaildir < Test::Unit::TestCase
|
|
3
|
+
|
|
4
|
+
context "A maildir" do
|
|
5
|
+
|
|
6
|
+
should "be initialized" do
|
|
7
|
+
assert temp_maildir
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
should "have a path" do
|
|
11
|
+
assert_not_empty temp_maildir.path
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
should "create subdirectories by default" do
|
|
15
|
+
%w(tmp new cur).each do |subdir|
|
|
16
|
+
subdir_path = temp_maildir.send("#{subdir}_path")
|
|
17
|
+
assert File.directory?(subdir_path), "Subdir #{subdir} does not exist"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
should "not create directories if specified" do
|
|
22
|
+
tmp_dir = Dir.mktmpdir('new_maildir_test')
|
|
23
|
+
maildir = Maildir.new(tmp_dir, false)
|
|
24
|
+
%w(tmp new cur).each do |subdir|
|
|
25
|
+
subdir_path = maildir.send("#{subdir}_path")
|
|
26
|
+
assert !File.directory?(subdir_path), "Subdir #{subdir} exists"
|
|
27
|
+
end
|
|
28
|
+
FileUtils.rm_r(tmp_dir)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
should "be identical to maildirs with the same path" do
|
|
32
|
+
new_maildir = Maildir.new(temp_maildir.path)
|
|
33
|
+
assert_equal temp_maildir.path, new_maildir.path
|
|
34
|
+
assert_equal temp_maildir, new_maildir
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
class TestMessage < Test::Unit::TestCase
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
context "An new, unwritten message" do
|
|
6
|
+
setup do
|
|
7
|
+
@message = Maildir::Message.new(temp_maildir)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
should "be instantiated" do
|
|
11
|
+
assert @message
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
should "be in :tmp" do
|
|
15
|
+
assert_equal :tmp, @message.dir
|
|
16
|
+
assert_match(/tmp/, @message.path)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
should "have a unique name" do
|
|
20
|
+
assert_not_empty @message.unique_name
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
should "have a file name" do
|
|
24
|
+
assert_not_empty @message.filename
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
should "have no info" do
|
|
28
|
+
assert_nil @message.info
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
should "not be able to set info" do
|
|
32
|
+
assert_raises RuntimeError do
|
|
33
|
+
@message.info= "2,FRS"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context "when written with a string" do
|
|
38
|
+
setup do
|
|
39
|
+
@data = "foo\n"
|
|
40
|
+
@message.write(@data)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
should "not be writable" do
|
|
44
|
+
assert_raise RuntimeError do
|
|
45
|
+
@message.write("nope!")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
should "have no info" do
|
|
50
|
+
assert_nil @message.info
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
should "not be able to set info" do
|
|
54
|
+
assert_raises RuntimeError do
|
|
55
|
+
@message.info= "2,FRS"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
should "be in new dir" do
|
|
60
|
+
assert_equal :new, @message.dir
|
|
61
|
+
assert_match(/new/, @message.path)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
should "have have a file" do
|
|
65
|
+
assert File.exists?(@message.path)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
should "have the correct data" do
|
|
69
|
+
assert @data == File.open(@message.path).read
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context "when written with an IO object" do
|
|
74
|
+
setup do
|
|
75
|
+
@data = "foo\n"
|
|
76
|
+
@message.write(StringIO.open(@data))
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
should "have the correct data" do
|
|
80
|
+
assert @data == File.open(@message.path).read
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "A created message" do
|
|
86
|
+
setup do
|
|
87
|
+
@data = "foo\n"
|
|
88
|
+
@message = Maildir::Message.create(temp_maildir, @data)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
should "have the correct data" do
|
|
92
|
+
assert @data == File.open(@message.path).read
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context "when processed" do
|
|
96
|
+
setup do
|
|
97
|
+
@message.process
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
should "not be writable" do
|
|
101
|
+
assert_raise RuntimeError do
|
|
102
|
+
@message.write("nope!")
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
should "be in cur" do
|
|
107
|
+
assert_equal :cur, @message.dir
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
should "have info" do
|
|
111
|
+
assert_equal Maildir::Message::INFO, @message.info
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
should "set info" do
|
|
115
|
+
info = "2,FRS"
|
|
116
|
+
@message.info = "2,FRS"
|
|
117
|
+
assert_equal @message.info, info
|
|
118
|
+
assert_match /#{info}$/, @message.path
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
should "add and remove flags" do
|
|
122
|
+
@message.add_flag('S')
|
|
123
|
+
assert_equal ['S'], @message.flags
|
|
124
|
+
|
|
125
|
+
# Test lowercase
|
|
126
|
+
@message.add_flag('r')
|
|
127
|
+
assert_equal ['R', 'S'], @message.flags
|
|
128
|
+
|
|
129
|
+
@message.remove_flag('S')
|
|
130
|
+
assert_equal ['R'], @message.flags
|
|
131
|
+
|
|
132
|
+
# Test lowercase
|
|
133
|
+
@message.remove_flag('r')
|
|
134
|
+
assert_equal [], @message.flags
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
flag_tests = {
|
|
138
|
+
"FRS" => ['F', 'R', 'S'],
|
|
139
|
+
"Sr" => ['R', 'S'], # test capitalization & sorting
|
|
140
|
+
'' => []
|
|
141
|
+
}
|
|
142
|
+
flag_tests.each do |arg, results|
|
|
143
|
+
should "set flags: #{arg}" do
|
|
144
|
+
@message.flags = arg
|
|
145
|
+
assert_equal results, @message.flags
|
|
146
|
+
path_suffix = "#{Maildir::Message::INFO}#{results.join('')}"
|
|
147
|
+
assert_match /#{path_suffix}$/, @message.path
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
class TestUniqueName < Test::Unit::TestCase
|
|
3
|
+
|
|
4
|
+
context "A UniqueName" do
|
|
5
|
+
setup do
|
|
6
|
+
@raw_name = Maildir::UniqueName.new
|
|
7
|
+
@name = @raw_name.to_s
|
|
8
|
+
@now = @raw_name.send(:instance_variable_get, :@now)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
should "be initialized" do
|
|
12
|
+
assert @raw_name
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
should "have a name" do
|
|
16
|
+
assert_not_empty @name
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
should "begin with timestamp" do
|
|
20
|
+
assert_match /^#{@now.to_i}/, @name
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
should "end with hostname" do
|
|
24
|
+
assert_match /#{Socket.gethostname}$/, @name
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
should "be unique when created in the same microsecond" do
|
|
28
|
+
@new_name = Maildir::UniqueName.new
|
|
29
|
+
# Set @now be identical in both UniqueName instances
|
|
30
|
+
@new_name.send(:instance_variable_set, :@now, @now)
|
|
31
|
+
assert_not_equal @name, @new_name.to_s
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context "The UniqueName counter" do
|
|
37
|
+
should "increment when called" do
|
|
38
|
+
value1 = Maildir::UniqueName.counter
|
|
39
|
+
value2 = Maildir::UniqueName.counter
|
|
40
|
+
assert_equal value1+1, value2
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: maildir
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Aaron Suggs
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-12-05 00:00:00 -05:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies:
|
|
15
|
+
- !ruby/object:Gem::Dependency
|
|
16
|
+
name: thoughtbot-shoulda
|
|
17
|
+
type: :development
|
|
18
|
+
version_requirement:
|
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">="
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: "0"
|
|
24
|
+
version:
|
|
25
|
+
description: A ruby library for reading and writing arbitrary messages in DJB's maildir format
|
|
26
|
+
email: aaron@ktheory.com
|
|
27
|
+
executables: []
|
|
28
|
+
|
|
29
|
+
extensions: []
|
|
30
|
+
|
|
31
|
+
extra_rdoc_files:
|
|
32
|
+
- LICENSE
|
|
33
|
+
- README.rdoc
|
|
34
|
+
files:
|
|
35
|
+
- LICENSE
|
|
36
|
+
- NOTES.txt
|
|
37
|
+
- README.rdoc
|
|
38
|
+
- Rakefile
|
|
39
|
+
- VERSION
|
|
40
|
+
- benchmarks/runner
|
|
41
|
+
- lib/maildir.rb
|
|
42
|
+
- lib/maildir/message.rb
|
|
43
|
+
- lib/maildir/unique_name.rb
|
|
44
|
+
- test/test_helper.rb
|
|
45
|
+
- test/test_maildir.rb
|
|
46
|
+
- test/test_message.rb
|
|
47
|
+
- test/test_unique_name.rb
|
|
48
|
+
has_rdoc: true
|
|
49
|
+
homepage: http://github.com/ktheory/maildir
|
|
50
|
+
licenses: []
|
|
51
|
+
|
|
52
|
+
post_install_message:
|
|
53
|
+
rdoc_options:
|
|
54
|
+
- --charset=UTF-8
|
|
55
|
+
require_paths:
|
|
56
|
+
- lib
|
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: "0"
|
|
62
|
+
version:
|
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: "0"
|
|
68
|
+
version:
|
|
69
|
+
requirements: []
|
|
70
|
+
|
|
71
|
+
rubyforge_project:
|
|
72
|
+
rubygems_version: 1.3.5
|
|
73
|
+
signing_key:
|
|
74
|
+
specification_version: 3
|
|
75
|
+
summary: Read & write messages in the maildir format
|
|
76
|
+
test_files:
|
|
77
|
+
- test/test_helper.rb
|
|
78
|
+
- test/test_maildir.rb
|
|
79
|
+
- test/test_message.rb
|
|
80
|
+
- test/test_unique_name.rb
|