ruml 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
1
  source :rubygems
2
2
 
3
- gem 'mail'
3
+ gemspec
@@ -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
- mail
26
+ minitest
27
+ ruml!
data/README.md CHANGED
@@ -2,7 +2,10 @@
2
2
 
3
3
  Ruby mailing list software
4
4
 
5
- ## File structure
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!(STDIN.read)
26
+ ml.broadcast!($stdin.read)
@@ -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 recipient
67
+ mail.bcc recipients
70
68
 
71
69
  add_headers! mail
72
70
  add_body! mail
73
- deliver! mail
74
- end
75
71
 
76
- def deliver! mail
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
@@ -1,10 +1,10 @@
1
1
  module Ruml
2
2
  class List
3
- attr_reader :name
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
@@ -1,3 +1,3 @@
1
1
  module Ruml
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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
- # specify any dependencies here; for example:
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,7 @@
1
+ info@example.com
2
+ foo@example.com
3
+ Foo@example.com
4
+ # Some empty entries
5
+ # commented unused@example.com
6
+ # with space
7
+
@@ -0,0 +1 @@
1
+ [Test ML]
@@ -0,0 +1 @@
1
+ test-ml@example.com
@@ -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: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
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-27 00:00:00 Z
18
+ date: 2011-10-29 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: mail
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: *id001
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