sortah 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/.rvmrc +2 -0
- data/.travis.yml +3 -0
- data/CONTRIBUTION.md +23 -0
- data/FUTURE_PLANS.md +73 -0
- data/Gemfile +10 -0
- data/KNOWN_BUGS.md +12 -0
- data/LICENSE +27 -0
- data/README.md +216 -0
- data/Rakefile +14 -0
- data/TUTORIAL.md +43 -0
- data/bin/sortah +33 -0
- data/lib/sortah.rb +10 -0
- data/lib/sortah/cleanroom.rb +47 -0
- data/lib/sortah/components.rb +3 -0
- data/lib/sortah/components/destination.rb +41 -0
- data/lib/sortah/components/lens.rb +49 -0
- data/lib/sortah/components/router.rb +13 -0
- data/lib/sortah/email.rb +31 -0
- data/lib/sortah/errors.rb +15 -0
- data/lib/sortah/handler.rb +46 -0
- data/lib/sortah/parser.rb +57 -0
- data/lib/sortah/patches.rb +7 -0
- data/lib/sortah/util/component.rb +28 -0
- data/lib/sortah/util/component_collection.rb +22 -0
- data/lib/sortah/version.rb +3 -0
- data/sortah.gemspec +31 -0
- data/spec/bin_spec.rb +54 -0
- data/spec/destination_spec.rb +42 -0
- data/spec/email_spec.rb +13 -0
- data/spec/fixtures/rc +8 -0
- data/spec/parser_spec.rb +270 -0
- data/spec/semantic_spec.rb +310 -0
- data/spec/sortah_handler_spec.rb +21 -0
- data/spec/spec_helper.rb +3 -0
- metadata +117 -0
data/spec/bin_spec.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
def run_with(arg, email = "")
|
2
|
+
#uses the sortah defn in spec/fixtures/rc
|
3
|
+
cmd =<<-CMD
|
4
|
+
bundle exec bin/sortah #{arg} --rc "spec/fixtures/rc" <<-EMAIL
|
5
|
+
#{email}
|
6
|
+
EMAIL
|
7
|
+
CMD
|
8
|
+
result = `#{cmd}`
|
9
|
+
|
10
|
+
{ result: result, status: $?.to_i }
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
describe "the sortah executable" do
|
15
|
+
before :all do
|
16
|
+
Mail.defaults do
|
17
|
+
delivery_method :test
|
18
|
+
end
|
19
|
+
|
20
|
+
@email = Mail.new do
|
21
|
+
to 'testa@example.com'
|
22
|
+
from 'chuck@nope.com'
|
23
|
+
subject "Taximerdizin'"
|
24
|
+
body <<-TXT
|
25
|
+
OJAI VALLEY TAXIDERMY
|
26
|
+
|
27
|
+
BET YOU THOUGHT THIS EMAIL WAS REAL
|
28
|
+
|
29
|
+
NOPE. CHUCK TESTA
|
30
|
+
TXT
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
before :each do
|
35
|
+
Sortah::Parser.clear!
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when executing in dry-run mode, " do
|
39
|
+
it "should have a dry-run mode" do
|
40
|
+
cmd = run_with("--dry-run")
|
41
|
+
cmd[:result].should =~ /Dry-run mode/
|
42
|
+
cmd[:status].should == 0
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not write any files when in dry-run mode" do
|
46
|
+
run_with('--dry-run', @email.to_s)
|
47
|
+
Dir['/tmp/mail/*'].size.should == 0
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should print to STDOUT the location it intends to write the file" do
|
51
|
+
run_with('--dry-run', @email.to_s)[:result].should =~ %r|writing email to: /tmp/\.mail/foo/|
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sortah::Destination do
|
4
|
+
|
5
|
+
context "when creating a destination" do
|
6
|
+
it "should be able to show me it's destination path" do
|
7
|
+
dest = Sortah::Destination.new(:foo, "bar")
|
8
|
+
dest.path.should == "bar"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when comparing a destination with another object, " do
|
13
|
+
it "should be equal to itself" do
|
14
|
+
dest = Sortah::Destination.new(:foo, "bar")
|
15
|
+
(dest == dest).should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should not be equal to a destination which has a different path" do
|
19
|
+
dest = Sortah::Destination.new(:foo, "bar")
|
20
|
+
dest2 = Sortah::Destination.new(:bar, "baz")
|
21
|
+
(dest == dest2).should_not be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not be equal to a destination which has the same path, but different name" do
|
25
|
+
dest = Sortah::Destination.new(:foo, "baz")
|
26
|
+
dest2 = Sortah::Destination.new(:bar, "baz")
|
27
|
+
(dest == dest2).should_not be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should be equal to an equivalent destination" do
|
31
|
+
dest = Sortah::Destination.new(:foo, "baz")
|
32
|
+
dest2 = Sortah::Destination.new(:foo, "baz")
|
33
|
+
(dest == dest2).should be_true
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should be equal to a string which is identical to the absolute path it describes" do
|
37
|
+
dest = Sortah::Destination.new(:foo, "baz")
|
38
|
+
(dest == "baz").should be_true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/spec/email_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Sortah::Email do
|
3
|
+
before :each do
|
4
|
+
@email = Sortah::Email.wrap(Mail.new)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should proxy the Mail class" do
|
8
|
+
(Mail.new.methods - Object.methods).each do |method|
|
9
|
+
@email.should respond_to method
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
data/spec/fixtures/rc
ADDED
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Sortah::Parser do
|
4
|
+
context "when parsing language components, " do
|
5
|
+
before :each do
|
6
|
+
Sortah::Parser.clear!
|
7
|
+
end
|
8
|
+
|
9
|
+
context "when parsing destinations, " do
|
10
|
+
it "should provide an environment for definiton" do
|
11
|
+
expect {
|
12
|
+
sortah do
|
13
|
+
end
|
14
|
+
}.should_not raise_error
|
15
|
+
sortah.should_not be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should parse defined 'simple' destinations" do
|
19
|
+
expect {
|
20
|
+
sortah do
|
21
|
+
destination :place, "somewhere/"
|
22
|
+
end
|
23
|
+
}.should_not raise_error
|
24
|
+
sortah.destinations[:place].should == "somewhere/"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse defined 'absolute path' destinations" do
|
28
|
+
expect {
|
29
|
+
sortah do
|
30
|
+
destination :place, :abs => "/home/user/.mail/.somewhere.else/"
|
31
|
+
end
|
32
|
+
}.should_not raise_error
|
33
|
+
sortah.destinations[:place].should == "/home/user/.mail/.somewhere.else/"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should parse defined 'alias' destinations in a dereferenced way" do
|
37
|
+
expect {
|
38
|
+
sortah do
|
39
|
+
destination :place, "somewhere/"
|
40
|
+
destination :other_place, :place
|
41
|
+
end
|
42
|
+
}.should_not raise_error
|
43
|
+
sortah.destinations[:other_place].should == "somewhere/"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should throw a parse error when you try to redefine a destination" do
|
47
|
+
expect {
|
48
|
+
sortah do
|
49
|
+
destination :same_dest, "dest/"
|
50
|
+
destination :same_dest, "dest/"
|
51
|
+
end
|
52
|
+
}.should raise_error Sortah::ParseErrorException
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when parsing lenses," do
|
58
|
+
|
59
|
+
it "should parse a lens definition" do
|
60
|
+
expect {
|
61
|
+
sortah do
|
62
|
+
lens :test_value do
|
63
|
+
1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
}.should_not raise_error
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should parse a lens definition that depends on another lens" do
|
70
|
+
expect {
|
71
|
+
sortah do
|
72
|
+
lens :dep do
|
73
|
+
1
|
74
|
+
end
|
75
|
+
|
76
|
+
lens :test_value, lenses: [:dep] do
|
77
|
+
2
|
78
|
+
end
|
79
|
+
end
|
80
|
+
}.should_not raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should throw a parse error if you try to define the same lens (by name) twice" do
|
84
|
+
expect {
|
85
|
+
sortah do
|
86
|
+
lens :same_name do
|
87
|
+
end
|
88
|
+
lens :same_name do
|
89
|
+
end
|
90
|
+
end
|
91
|
+
}.should raise_error Sortah::ParseErrorException
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should throw a parse error if you try to reference a lens which does not exist" do
|
95
|
+
expect {
|
96
|
+
sortah do
|
97
|
+
lens :other_name, :lenses => [:non_existant] do
|
98
|
+
end
|
99
|
+
end
|
100
|
+
}.should raise_error Sortah::ParseErrorException
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should not throw a parse error if you try to forward-reference a lens" do
|
105
|
+
expect {
|
106
|
+
sortah do
|
107
|
+
lens :forward_reference, :lenses => [:ahead] do
|
108
|
+
end
|
109
|
+
lens :ahead do
|
110
|
+
end
|
111
|
+
end
|
112
|
+
}.should_not raise_error Sortah::ParseErrorException
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should not throw a parse error if you have a cyclic-lens dependency" do
|
116
|
+
expect {
|
117
|
+
sortah do
|
118
|
+
lens :circle_one, :lenses => [:circle_two] do
|
119
|
+
end
|
120
|
+
lens :circle_two, :lenses => [:circle_one] do
|
121
|
+
end
|
122
|
+
end
|
123
|
+
}.should_not raise_error Sortah::ParseErrorException
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when parsing routers, " do
|
129
|
+
|
130
|
+
it "should parse a router definition" do
|
131
|
+
expect {
|
132
|
+
sortah do
|
133
|
+
router :test_router do
|
134
|
+
end
|
135
|
+
end
|
136
|
+
}.should_not raise_error
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should parse a root-router definition" do
|
141
|
+
expect {
|
142
|
+
sortah do
|
143
|
+
router do
|
144
|
+
end
|
145
|
+
end
|
146
|
+
}.should_not raise_error
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should parse a router with lenses" do
|
150
|
+
expect {
|
151
|
+
sortah do
|
152
|
+
lens :foo do
|
153
|
+
end
|
154
|
+
|
155
|
+
router :test_router, :lenses => [:foo] do
|
156
|
+
end
|
157
|
+
end
|
158
|
+
}.should_not raise_error
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should parse a root-router with lenses" do
|
162
|
+
expect {
|
163
|
+
sortah do
|
164
|
+
lens :foo do
|
165
|
+
end
|
166
|
+
|
167
|
+
router :lenses => [:foo] do
|
168
|
+
end
|
169
|
+
end
|
170
|
+
}.should_not raise_error
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should parse a router with a forward reference to a lens" do
|
174
|
+
expect {
|
175
|
+
sortah do
|
176
|
+
router :foo_router, :lenses => [:foo] do
|
177
|
+
end
|
178
|
+
|
179
|
+
lens :foo do
|
180
|
+
end
|
181
|
+
end
|
182
|
+
}.should_not raise_error
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should parse a root-router with a forward reference to a lens" do
|
186
|
+
expect {
|
187
|
+
sortah do
|
188
|
+
router :lenses => [:foo] do
|
189
|
+
end
|
190
|
+
|
191
|
+
lens :foo do
|
192
|
+
end
|
193
|
+
end
|
194
|
+
}.should_not raise_error
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
context "when dealing in general with sortah, " do
|
200
|
+
|
201
|
+
it "should maintain one state across multiple sortah blocks" do
|
202
|
+
expect {
|
203
|
+
sortah do
|
204
|
+
destination :place, "somewhere/"
|
205
|
+
end
|
206
|
+
}.should_not raise_error
|
207
|
+
|
208
|
+
expect {
|
209
|
+
sortah do
|
210
|
+
destination :new_place, :place
|
211
|
+
end
|
212
|
+
}.should_not raise_error
|
213
|
+
|
214
|
+
sortah.destinations[:place].should == "somewhere/"
|
215
|
+
sortah.destinations[:new_place].should == "somewhere/"
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should allow for configuration" do
|
219
|
+
sortah do
|
220
|
+
maildir "/home/user/.mail" #mail directory, maildir format
|
221
|
+
end
|
222
|
+
sortah.maildir.should == "/home/user/.mail"
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should use the last defined maildir" do
|
226
|
+
sortah do
|
227
|
+
maildir "/home/user/.mail/work"
|
228
|
+
maildir "/home/user/.mail/personal"
|
229
|
+
end
|
230
|
+
sortah.maildir.should == "/home/user/.mail/personal"
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
#acceptance criteria
|
236
|
+
it "should parse an example sortah file, which contains all of the language elements" do
|
237
|
+
expect {
|
238
|
+
sortah do
|
239
|
+
destination :place, "somewhere"
|
240
|
+
destination :devnull, :abs => "/dev/null"
|
241
|
+
destination :bitbucket, :devnull
|
242
|
+
|
243
|
+
lens :random_value do
|
244
|
+
rand
|
245
|
+
end
|
246
|
+
|
247
|
+
lens :random_spam_value, :lenses => [:random_value] do
|
248
|
+
email.random_value * 10
|
249
|
+
end
|
250
|
+
|
251
|
+
lens :also_depends_on_random_value, :lenses => [:random_value] do
|
252
|
+
email.random_value * 100
|
253
|
+
end
|
254
|
+
|
255
|
+
router :root, :lenses => [:random_spam_value] do
|
256
|
+
if email.random_spam_value > 0.5
|
257
|
+
send_to :other_router
|
258
|
+
else
|
259
|
+
send_to :bitbucket
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
router :other_router, :lenses => [:also_depends_on_random_value] do
|
264
|
+
send_to :place
|
265
|
+
end
|
266
|
+
end
|
267
|
+
}.should_not raise_error
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
@@ -0,0 +1,310 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mail'
|
3
|
+
|
4
|
+
#TODO: Move to spec_helper?
|
5
|
+
def basic_sortah_definition
|
6
|
+
sortah do
|
7
|
+
maildir "/home/jfredett/.mail"
|
8
|
+
destination :foo, "foo/"
|
9
|
+
destination :bar, "bar/"
|
10
|
+
router do
|
11
|
+
if email.from.any? { |sender| sender =~ /chuck/ }
|
12
|
+
send_to :foo
|
13
|
+
else
|
14
|
+
send_to :bar
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Sortah do
|
21
|
+
context "when sorting an email" do
|
22
|
+
before :all do
|
23
|
+
Mail.defaults do
|
24
|
+
delivery_method :test
|
25
|
+
end
|
26
|
+
|
27
|
+
@email = Mail.new do
|
28
|
+
to 'testa@example.com'
|
29
|
+
from 'chuck@nope.com'
|
30
|
+
subject "Taximerdizin'"
|
31
|
+
body <<-TXT
|
32
|
+
OJAI VALLEY TAXIDERMY
|
33
|
+
|
34
|
+
BET YOU THOUGHT THIS EMAIL WAS REAL
|
35
|
+
|
36
|
+
NOPE. CHUCK TESTA
|
37
|
+
TXT
|
38
|
+
end
|
39
|
+
|
40
|
+
@reply_email = Mail.new do
|
41
|
+
to 'chuck@nope.com'
|
42
|
+
from 'jgf@somewhere.com'
|
43
|
+
subject "Re: Taximerdizin'"
|
44
|
+
reply_to 'chuck@nope.com'
|
45
|
+
body <<-TXT
|
46
|
+
> OJAI VALLEY TAXIDERMY
|
47
|
+
>
|
48
|
+
> BET YOU THOUGHT THIS EMAIL WAS REAL
|
49
|
+
>
|
50
|
+
> NOPE. CHUCK TESTA
|
51
|
+
|
52
|
+
Do you taxidermize pets?
|
53
|
+
TXT
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
before :each do
|
58
|
+
Sortah::Parser.clear!
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should provide a way to sort a single email" do
|
62
|
+
sortah.should respond_to :sort
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should throw a sematic error when calling #sort with no root router is provided" do
|
66
|
+
sortah do
|
67
|
+
destination :foo, "foo/"
|
68
|
+
router :not_root do
|
69
|
+
send_to :foo
|
70
|
+
end
|
71
|
+
end
|
72
|
+
expect { sortah.sort(@email) }.should raise_error Sortah::NoRootRouterException
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#sort" do
|
76
|
+
it "should return an object which responds to #destination" do
|
77
|
+
basic_sortah_definition
|
78
|
+
sortah.sort(@email).should respond_to :destination
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should return an object which responds to #metadata" do
|
82
|
+
basic_sortah_definition
|
83
|
+
sortah.sort(@email).should respond_to :metadata
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should sort emails based on the sortah definitions" do
|
87
|
+
basic_sortah_definition
|
88
|
+
sortah.sort(@email).destination.should == "foo/"
|
89
|
+
sortah.sort(@reply_email).destination.should == "bar/"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should defer to a second router if it is sent to one" do
|
93
|
+
sortah do
|
94
|
+
destination :foo, "foo/"
|
95
|
+
destination :bar, "bar/"
|
96
|
+
|
97
|
+
router do
|
98
|
+
if email.from.any? { |sender| sender =~ /chuck/ }
|
99
|
+
send_to :foo
|
100
|
+
else
|
101
|
+
send_to :secondary_router
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
router :secondary_router do
|
106
|
+
send_to :bar
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
sortah.sort(@email).destination.should == "foo/"
|
111
|
+
sortah.sort(@reply_email).destination.should == "bar/"
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should run dependent lenses for the root router" do
|
115
|
+
sortah do
|
116
|
+
destination :foo, "foo/"
|
117
|
+
|
118
|
+
lens :senders do
|
119
|
+
email.from.map { |s| s.split('@').first }
|
120
|
+
end
|
121
|
+
|
122
|
+
router :root, :lenses => [:senders] do
|
123
|
+
send_to :foo
|
124
|
+
end
|
125
|
+
end
|
126
|
+
sortah.sort(@email).metadata(:senders).should == ["chuck"]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should run dependent lenses for the non-root router, but only if the router gets called" do
|
130
|
+
sortah do
|
131
|
+
destination :foo, "foo/"
|
132
|
+
|
133
|
+
lens :senders do
|
134
|
+
email.from.map { |s| s.split('@').first }
|
135
|
+
end
|
136
|
+
|
137
|
+
lens :never_called do
|
138
|
+
"This should never be called, since the router that depends on it never gets called"
|
139
|
+
end
|
140
|
+
|
141
|
+
router :root, :lenses => [:senders] do
|
142
|
+
send_to :foo
|
143
|
+
end
|
144
|
+
|
145
|
+
router :bar, :lenses => [:never_called] do
|
146
|
+
"doesn't matter what I put in here"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
sortah.sort(@email).metadata(:never_called).should be_nil
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should never run a lens that isn't a dependency" do
|
153
|
+
sortah do
|
154
|
+
destination :foo, "foo/"
|
155
|
+
|
156
|
+
lens :senders do
|
157
|
+
email.from.map { |s| s.split('@').first }
|
158
|
+
end
|
159
|
+
|
160
|
+
lens :never_called do
|
161
|
+
"This should never be called, since the router that depends on it never gets called"
|
162
|
+
end
|
163
|
+
|
164
|
+
router :root, :lenses => [:senders] do
|
165
|
+
send_to :foo
|
166
|
+
end
|
167
|
+
end
|
168
|
+
sortah.sort(@email).metadata(:never_called).should be_nil
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should run provide access to the metadata generated by a lens through the email object" do
|
172
|
+
sortah do
|
173
|
+
destination :foo, "foo/"
|
174
|
+
destination :bar, "bar/"
|
175
|
+
|
176
|
+
lens :senders do
|
177
|
+
email.from.map { |s| s.split('@').first }
|
178
|
+
end
|
179
|
+
|
180
|
+
lens :never_called do
|
181
|
+
"This should never be called, since the router that depends on it never gets called"
|
182
|
+
end
|
183
|
+
|
184
|
+
router :root, :lenses => [:senders] do
|
185
|
+
if email.senders.include? "chuck"
|
186
|
+
send_to :foo
|
187
|
+
else
|
188
|
+
send_to :bar
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
sortah.sort(@email).destination.should == "foo/"
|
193
|
+
sortah.sort(@reply_email).destination.should == "bar/"
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should run subdependencies of lenses" do
|
197
|
+
sortah do
|
198
|
+
destination :foo, "foo/"
|
199
|
+
destination :bar, "bar/"
|
200
|
+
|
201
|
+
lens :senders, :lenses => [:sub_dep] do
|
202
|
+
email.from.map { |s| s.split('@').first }
|
203
|
+
end
|
204
|
+
|
205
|
+
lens :sub_dep do
|
206
|
+
"Sub Dep Ran"
|
207
|
+
end
|
208
|
+
|
209
|
+
router :root, :lenses => [:senders] do
|
210
|
+
if email.senders.include? "chuck"
|
211
|
+
send_to :foo
|
212
|
+
else
|
213
|
+
send_to :bar
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
sortah.sort(@email).metadata(:sub_dep).should == "Sub Dep Ran"
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should not run the same lens twice" do
|
221
|
+
$count = 0 #evil, pure evil
|
222
|
+
sortah do
|
223
|
+
destination :bar, "bar/"
|
224
|
+
|
225
|
+
lens :inc do
|
226
|
+
$count += 1
|
227
|
+
end
|
228
|
+
|
229
|
+
router :root, :lenses => [:inc] do
|
230
|
+
send_to :baz
|
231
|
+
end
|
232
|
+
|
233
|
+
router :baz, :lenses => [:inc] do
|
234
|
+
send_to :bar
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
sortah.sort(@email).metadata(:inc).should == 1
|
239
|
+
|
240
|
+
$count = nil #undefine $count
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should not set any metadata for a :pass_through lens" do
|
244
|
+
sortah do
|
245
|
+
destination :foo, "foo/"
|
246
|
+
|
247
|
+
lens :passthrough, :pass_through => true do
|
248
|
+
"some external service call"
|
249
|
+
end
|
250
|
+
|
251
|
+
router :root, :lenses => [:passthrough] do
|
252
|
+
send_to :baz
|
253
|
+
end
|
254
|
+
|
255
|
+
router :baz, :lenses => [:passthrough] do
|
256
|
+
send_to :foo
|
257
|
+
end
|
258
|
+
end
|
259
|
+
sortah.sort(@email).metadata(:passthrough).should be_nil
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should not run a pass_through lens more than once" do
|
263
|
+
$count = 0
|
264
|
+
sortah do
|
265
|
+
destination :foo, "foo/"
|
266
|
+
|
267
|
+
lens :passthrough, :pass_through => true do
|
268
|
+
$count += 1
|
269
|
+
end
|
270
|
+
|
271
|
+
router :root, :lenses => [:passthrough] do
|
272
|
+
send_to :baz
|
273
|
+
end
|
274
|
+
|
275
|
+
router :baz, :lenses => [:passthrough] do
|
276
|
+
send_to :foo
|
277
|
+
end
|
278
|
+
end
|
279
|
+
sortah.sort(@email)
|
280
|
+
$count.should == 1
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should execute only until the first #send_to call" do
|
284
|
+
sortah do
|
285
|
+
destination :foo, "foo/"
|
286
|
+
router do
|
287
|
+
send_to :foo
|
288
|
+
throw Exception
|
289
|
+
end
|
290
|
+
end
|
291
|
+
expect { sortah.sort(@email) }.should_not raise_error Exception
|
292
|
+
sortah.sort(@email).destination.should == "foo/"
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "#full_destination" do
|
296
|
+
it "should return the full path (including the maildir basepath) to which an email will be routed" do
|
297
|
+
sortah do
|
298
|
+
maildir '/tmp/'
|
299
|
+
destination :foo, "foo/"
|
300
|
+
router do
|
301
|
+
send_to :foo
|
302
|
+
end
|
303
|
+
end
|
304
|
+
sortah.sort(@email).full_destination.should == "/tmp/foo/"
|
305
|
+
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|