sortah 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/.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
|