maildir 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|