ruml 0.0.1 → 0.0.2
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/Gemfile +1 -1
- data/Gemfile.lock +9 -1
- data/README.md +31 -1
- data/Rakefile +11 -0
- data/bin/ruml +21 -3
- data/lib/ruml/broadcaster.rb +6 -16
- data/lib/ruml/list.rb +3 -3
- data/lib/ruml/version.rb +1 -1
- data/ruml.gemspec +3 -2
- data/test/fixtures/example_ml/bounce_to +1 -0
- data/test/fixtures/example_ml/members +7 -0
- data/test/fixtures/example_ml/name +1 -0
- data/test/fixtures/example_ml/to +1 -0
- data/test/helper.rb +55 -0
- data/test/integration_test.rb +80 -0
- metadata +26 -6
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruml (0.0.1)
|
5
|
+
mail (~> 2.3.0)
|
6
|
+
|
1
7
|
GEM
|
2
8
|
remote: http://rubygems.org/
|
3
9
|
specs:
|
@@ -7,6 +13,7 @@ GEM
|
|
7
13
|
mime-types (~> 1.16)
|
8
14
|
treetop (~> 1.4.8)
|
9
15
|
mime-types (1.17.2)
|
16
|
+
minitest (2.7.0)
|
10
17
|
polyglot (0.3.2)
|
11
18
|
treetop (1.4.10)
|
12
19
|
polyglot
|
@@ -16,4 +23,5 @@ PLATFORMS
|
|
16
23
|
ruby
|
17
24
|
|
18
25
|
DEPENDENCIES
|
19
|
-
|
26
|
+
minitest
|
27
|
+
ruml!
|
data/README.md
CHANGED
@@ -2,7 +2,10 @@
|
|
2
2
|
|
3
3
|
Ruby mailing list software
|
4
4
|
|
5
|
-
|
5
|
+
|
6
|
+
## Configration (ruml)
|
7
|
+
|
8
|
+
### File based
|
6
9
|
|
7
10
|
<pre>
|
8
11
|
testml/
|
@@ -17,6 +20,33 @@ testml/
|
|
17
20
|
* member - List of member's addresses
|
18
21
|
* bounce_to - Bounce mails go to this email (optional)
|
19
22
|
|
23
|
+
|
24
|
+
## Configuration (Postfix)
|
25
|
+
|
26
|
+
### Postfix
|
27
|
+
|
28
|
+
#### /etc/postfix/ml-maps
|
29
|
+
|
30
|
+
<pre>
|
31
|
+
/^testml@example.com$/ ml-testml
|
32
|
+
/^testml-bounce@mail.info$/ testml-bounce@mail.info
|
33
|
+
</pre>
|
34
|
+
|
35
|
+
#### /etc/postfix/ml-aliases
|
36
|
+
|
37
|
+
<pre>
|
38
|
+
ml-testml: "|/path/to/bin/ruml /var/spool/ruml/lists/testml"
|
39
|
+
</pre>
|
40
|
+
|
41
|
+
#### /etc/postfix/main.cf
|
42
|
+
|
43
|
+
<pre>
|
44
|
+
virtual_alias_maps = regexp:/etc/postfix/ml-maps
|
45
|
+
alias_maps = hash:/etc/postfix/ml-aliases
|
46
|
+
alias_database = hash:/etc/postfix/ml-aliases
|
47
|
+
</pre>
|
48
|
+
|
49
|
+
|
20
50
|
## TODO
|
21
51
|
|
22
52
|
* Write tests!
|
data/Rakefile
CHANGED
@@ -1 +1,12 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
# Test
|
4
|
+
require 'rake/testtask'
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
Rake::TestTask.new(:test) do |test|
|
9
|
+
test.test_files = FileList.new('test/*_test.rb')
|
10
|
+
test.libs << 'test'
|
11
|
+
test.verbose = true
|
12
|
+
end
|
data/bin/ruml
CHANGED
@@ -1,8 +1,26 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$debug = ENV['DEBUG']
|
4
|
-
|
5
3
|
require 'ruml'
|
6
4
|
|
5
|
+
# TODO test!
|
6
|
+
if %w[true 1 on].include?(ENV['DEBUG'])
|
7
|
+
Mail.defaults do
|
8
|
+
spitter = Class.new do
|
9
|
+
def initialize(settings)
|
10
|
+
end
|
11
|
+
|
12
|
+
def deliver!(mail)
|
13
|
+
puts mail
|
14
|
+
puts "=" * 80
|
15
|
+
end
|
16
|
+
end
|
17
|
+
delivery_method spitter
|
18
|
+
end
|
19
|
+
else
|
20
|
+
Mail.defaults do
|
21
|
+
delivery_method :sendmail
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
7
25
|
ml = Ruml.new(ARGV[0])
|
8
|
-
ml.broadcast!(
|
26
|
+
ml.broadcast!($stdin.read)
|
data/lib/ruml/broadcaster.rb
CHANGED
@@ -47,6 +47,10 @@ module Ruml
|
|
47
47
|
@ml.to
|
48
48
|
end
|
49
49
|
|
50
|
+
def recipients
|
51
|
+
@ml.members
|
52
|
+
end
|
53
|
+
|
50
54
|
def subject
|
51
55
|
if @ml.name && !@message.subject.include?(@ml.name)
|
52
56
|
"#{@ml.name} #{@message.subject}"
|
@@ -56,30 +60,16 @@ module Ruml
|
|
56
60
|
end
|
57
61
|
|
58
62
|
def send!
|
59
|
-
@ml.members.each do |recipient|
|
60
|
-
send_to(recipient)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def send_to(recipient)
|
65
63
|
mail = Mail.new
|
66
64
|
mail.subject subject
|
67
65
|
mail.from from
|
68
66
|
mail.to to
|
69
|
-
mail.bcc
|
67
|
+
mail.bcc recipients
|
70
68
|
|
71
69
|
add_headers! mail
|
72
70
|
add_body! mail
|
73
|
-
deliver! mail
|
74
|
-
end
|
75
71
|
|
76
|
-
|
77
|
-
if $debug
|
78
|
-
puts mail.to_s
|
79
|
-
else
|
80
|
-
mail.delivery_method :sendmail
|
81
|
-
mail.deliver
|
82
|
-
end
|
72
|
+
mail.deliver
|
83
73
|
end
|
84
74
|
end
|
85
75
|
end
|
data/lib/ruml/list.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Ruml
|
2
2
|
class List
|
3
|
-
attr_reader :
|
3
|
+
attr_reader :dir
|
4
4
|
|
5
5
|
def initialize(dir)
|
6
|
+
raise ArgumentError, "Couldn't find mailing list in #{dir.inspect}" unless File.directory?(dir)
|
6
7
|
@dir = dir
|
7
|
-
raise "Unknown ml #{name} (#{@dir})" unless File.directory?(@dir)
|
8
8
|
end
|
9
9
|
|
10
10
|
def id
|
@@ -16,7 +16,7 @@ module Ruml
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def members
|
19
|
-
@members ||= readlines("members").reject { |member| member =~ /^#|^$/ }
|
19
|
+
@members ||= readlines("members").map(&:downcase).uniq.reject { |member| member =~ /^#|^$/ }
|
20
20
|
end
|
21
21
|
|
22
22
|
def to
|
data/lib/ruml/version.rb
CHANGED
data/ruml.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "ruml"
|
3
|
+
require "ruml/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "ruml"
|
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
|
19
|
-
|
19
|
+
s.add_development_dependency "minitest"
|
20
|
+
|
20
21
|
s.add_runtime_dependency "mail", "~> 2.3.0"
|
21
22
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
test-ml-bounce@example.com
|
@@ -0,0 +1 @@
|
|
1
|
+
[Test ML]
|
@@ -0,0 +1 @@
|
|
1
|
+
test-ml@example.com
|
data/test/helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'minitest/spec'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
|
7
|
+
require 'ruml'
|
8
|
+
|
9
|
+
Mail.defaults do
|
10
|
+
delivery_method :test
|
11
|
+
end
|
12
|
+
|
13
|
+
module RumlTestSupport
|
14
|
+
def exec_ruml(arg, input)
|
15
|
+
# TODO execute "bin/ruml" directly
|
16
|
+
begin
|
17
|
+
ml = Ruml.new(arg)
|
18
|
+
ml.broadcast!(input)
|
19
|
+
"" # empty output
|
20
|
+
rescue => e
|
21
|
+
"#{e.message} (#{e.class})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def fixture_path(*name)
|
26
|
+
File.join(File.dirname(__FILE__), "fixtures", *name.map(&:to_s))
|
27
|
+
end
|
28
|
+
|
29
|
+
def deliveries
|
30
|
+
Mail::TestMailer.deliveries
|
31
|
+
end
|
32
|
+
|
33
|
+
def example_ml_path
|
34
|
+
fixture_path "example_ml"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
MiniTest::Unit::TestCase.send :include, RumlTestSupport
|
39
|
+
|
40
|
+
MiniTest::Unit::TestCase.add_setup_hook do
|
41
|
+
Mail::TestMailer.deliveries.clear
|
42
|
+
end
|
43
|
+
|
44
|
+
module Kernel
|
45
|
+
def capture_output
|
46
|
+
out = StringIO.new
|
47
|
+
$stdout = out
|
48
|
+
$stderr = out
|
49
|
+
yield
|
50
|
+
return out.string
|
51
|
+
ensure
|
52
|
+
$stdout = STDOUT
|
53
|
+
$stdout = STDERR
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe "Ruml binary" do
|
4
|
+
it "fails with TypeError w/o arguments" do
|
5
|
+
output = exec_ruml nil, nil
|
6
|
+
output.must_match "can't convert nil into String (TypeError)"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "fails with ArgumentError using invalid list path" do
|
10
|
+
output = exec_ruml "invalid path", nil
|
11
|
+
output.must_match "Couldn't find mailing list in \"invalid path\" (ArgumentError)"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "fails with NoMethodError on empty input" do
|
15
|
+
output = exec_ruml example_ml_path, nil
|
16
|
+
output.must_match "undefined method `size' for nil:NilClass (NoMethodError)"
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "with example_ml" do
|
20
|
+
let(:mailing_list) { Ruml::List.new(example_ml_path) }
|
21
|
+
|
22
|
+
it "refuse email from unknown member" do
|
23
|
+
mail = compose_mail(mailing_list, :from => "unknown@member.com")
|
24
|
+
output = exec_ruml mailing_list.dir, mail.to_s
|
25
|
+
output.must_be_empty
|
26
|
+
deliveries.must_be_empty
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "from valid member" do
|
30
|
+
let(:mail) { compose_mail(mailing_list) }
|
31
|
+
let(:output) { exec_ruml mailing_list.dir, mail.to_s }
|
32
|
+
let(:delivery) { output; deliveries.first }
|
33
|
+
|
34
|
+
it "output is empty" do
|
35
|
+
output.must_be_empty
|
36
|
+
end
|
37
|
+
|
38
|
+
it "delivers to mailing list & its members" do
|
39
|
+
k = (mailing_list.members + [ mailing_list.to ]).sort
|
40
|
+
delivery.destinations.sort.must_equal k
|
41
|
+
deliveries.size.must_equal 1
|
42
|
+
end
|
43
|
+
|
44
|
+
it "contains valid headers" do
|
45
|
+
delivery.subject.must_include mailing_list.name
|
46
|
+
delivery.subject.must_include mail.subject
|
47
|
+
delivery.from.must_equal mail.from
|
48
|
+
delivery.to.must_equal [ mailing_list.to ]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "contains valid extra headers" do
|
52
|
+
delivery['X-BeenThere'].value.must_equal mailing_list.to
|
53
|
+
delivery['List-Id'].value.must_include mailing_list.id
|
54
|
+
delivery['List-Post'].value.must_include "mailto:"
|
55
|
+
delivery['List-Post'].value.must_include mailing_list.to
|
56
|
+
delivery['Sender'].value.must_equal mailing_list.bounce_to
|
57
|
+
delivery['Errors-To'].value.must_equal mailing_list.bounce_to
|
58
|
+
end
|
59
|
+
|
60
|
+
#it "contains users agent" do
|
61
|
+
#end
|
62
|
+
|
63
|
+
it "contains correct body" do
|
64
|
+
delivery.body.encoded.must_equal mail.body.encoded
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def compose_mail(ml, options={}, &block)
|
72
|
+
defaults = {
|
73
|
+
:from => ml.members.first,
|
74
|
+
:to => ml.to,
|
75
|
+
:subject => "Some subject",
|
76
|
+
:body => "some body"
|
77
|
+
}
|
78
|
+
Mail.new(defaults.merge(options), &block)
|
79
|
+
end
|
80
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Peter Suschlik
|
@@ -15,12 +15,26 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-10-
|
18
|
+
date: 2011-10-29 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
21
|
+
name: minitest
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: mail
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
24
38
|
none: false
|
25
39
|
requirements:
|
26
40
|
- - ~>
|
@@ -32,7 +46,7 @@ dependencies:
|
|
32
46
|
- 0
|
33
47
|
version: 2.3.0
|
34
48
|
type: :runtime
|
35
|
-
version_requirements: *
|
49
|
+
version_requirements: *id002
|
36
50
|
description: ""
|
37
51
|
email:
|
38
52
|
- peter@suschlik.de
|
@@ -59,6 +73,12 @@ files:
|
|
59
73
|
- lib/ruml/list.rb
|
60
74
|
- lib/ruml/version.rb
|
61
75
|
- ruml.gemspec
|
76
|
+
- test/fixtures/example_ml/bounce_to
|
77
|
+
- test/fixtures/example_ml/members
|
78
|
+
- test/fixtures/example_ml/name
|
79
|
+
- test/fixtures/example_ml/to
|
80
|
+
- test/helper.rb
|
81
|
+
- test/integration_test.rb
|
62
82
|
homepage: https://github.com/splattael/ruml
|
63
83
|
licenses: []
|
64
84
|
|