newman 0.0.1 → 0.1.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/README.md CHANGED
@@ -1,6 +1,7 @@
1
- ## Newman: A microframework for mail-centric applications
1
+ ## Newman: Because the mail never stops!
2
2
 
3
3
  This is going to be an experiment in building a simple framework for developing
4
4
  email-based applications. It is based on ideas from an exercise in
5
5
  Mendicant University's January 2012 core skills course, and also serves as a
6
6
  demo application for an article in the Practicing Ruby Journal.
7
+
@@ -0,0 +1,59 @@
1
+ require_relative "ping_pong"
2
+ require_relative "simple_mailing_list"
3
+
4
+ require "minitest/autorun"
5
+
6
+ server = Newman::Server
7
+ server.test_mode("config/test.rb")
8
+
9
+ mailer = server.mailer
10
+
11
+ describe "Ping Pong" do
12
+ it "responds to an email sent to test+ping@test.com" do
13
+ mailer.deliver_message(:to => "test+ping@test.com")
14
+ server.tick(Newman::Examples::PingPong)
15
+ mailer.messages.first.subject.must_equal("pong")
16
+ end
17
+
18
+ it "responds to an email sent to test+bad@test.com" do
19
+ mailer.deliver_message(:to => "test+bad@test.com")
20
+ server.tick(Newman::Examples::PingPong)
21
+ mailer.messages.first.subject.must_equal("unknown command")
22
+ end
23
+ end
24
+
25
+ describe "SimpleList" do
26
+ it "emulates a simple mailing list" do
27
+ mailer.deliver_message(:from => "tester@test.com",
28
+ :to => "test@test.com")
29
+
30
+ server.tick(Newman::Examples::SimpleList)
31
+ mailer.messages.first.subject.must_equal("You are not subscribed")
32
+
33
+ mailer.deliver_message(:from => "tester@test.com",
34
+ :to => "test+subscribe@test.com")
35
+
36
+ server.tick(Newman::Examples::SimpleList)
37
+ mailer.messages.first.subject.must_equal("SUBSCRIBED!")
38
+
39
+
40
+ mailer.deliver_message(:from => "tester@test.com",
41
+ :to => "test@test.com",
42
+ :subject => "WIN!")
43
+
44
+ server.tick(Newman::Examples::SimpleList)
45
+ mailer.messages.first.subject.must_equal("WIN!")
46
+
47
+ mailer.deliver_message(:from => "tester@test.com",
48
+ :to => "test+unsubscribe@test.com")
49
+
50
+ server.tick(Newman::Examples::SimpleList)
51
+ mailer.messages.first.subject.must_equal("UNSUBSCRIBED!")
52
+ end
53
+
54
+ after do
55
+ if File.exist?(server.settings.application.simplelist_db)
56
+ File.unlink(server.settings.application.simplelist_db)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,17 @@
1
+ imap.address = "mail.<<DOMAIN>>"
2
+ imap.user = "<<USERNAME>>@<<DOMAIN>>"
3
+ imap.password = "<<PASSWORD>>"
4
+
5
+ smtp.address = "mail.<<DOMAIN>>"
6
+ smtp.user = "<<USER>>@<<DOMAIN>>"
7
+ smtp.password = "<<PASSWORD>>"
8
+
9
+ service.domain = "<<DOMAIN>>"
10
+ service.templates_dir = "views"
11
+ service.default_sender = "<<USERNAME>>@<<DOMAIN>>"
12
+ service.polling_interval = 10
13
+
14
+ application.simplelist_db = "db/lists/simple_mailing_list.store"
15
+ application.librelist_db = "db/lists/libre.store"
16
+ application.ping_email = "<<USERNAME>>+ping@<<DOMAIN>>"
17
+ application.live_test_delay = 5
@@ -0,0 +1,21 @@
1
+ imap.address = "imap.gmail.com"
2
+ imap.user = "<<USERNAME>>@gmail.com"
3
+ imap.password = "<<PASSWORD>>"
4
+ imap.ssl_enabled = true
5
+ imap.port = 993
6
+
7
+ smtp.address = "smtp.gmail.com"
8
+ smtp.user = "<<USERNAME>>@gmail.com"
9
+ smtp.password = "<<PASSWORD>>"
10
+ smtp.starttls_enabled = true
11
+ smtp.port = 587
12
+
13
+ service.domain = "gmail.com"
14
+ service.templates_dir = "views"
15
+ service.default_sender = "<<USERNAME>>@gmail.com"
16
+ service.polling_interval = 10
17
+
18
+ application.simplelist_db = "db/lists/simple_mailing_list.store"
19
+ application.librelist_db = "db/lists/libre.store"
20
+ application.ping_email = "<<USERNAME>>+ping@gmail.com"
21
+ application.live_test_delay = 5
@@ -0,0 +1,7 @@
1
+ service.domain = "test.com"
2
+ service.templates_dir = "views"
3
+ service.default_sender = "test@test.com"
4
+ service.polling_interval = 10
5
+
6
+ application.simplelist_db = "db/lists/simple_mailing_list-test.store"
7
+ application.librelist_db = "db/lists/libre-test.store"
@@ -0,0 +1 @@
1
+ require_relative "../lib/newman"
@@ -0,0 +1,43 @@
1
+ require_relative "example_helper"
2
+
3
+ module Newman
4
+ module Examples
5
+ Jester = Newman::Application.new do
6
+ match :genre, '\S+'
7
+ match :title, '.*'
8
+ match :email, '[\w\d\._-]+@[\w\d\._-]+' #not legit, I'm sure
9
+
10
+ subject(:match, "a {genre} story '{title}'") do
11
+ respond :subject => "No one would consider '#{params[:title]}' to be #{params[:genre]}"
12
+ end
13
+
14
+ subject(:match, "what stories do you know?") do
15
+ respond :subject => "What stories do YOU know?"
16
+ end
17
+
18
+ subject(:match, "tell something {genre} to {email}") do
19
+ respond :subject => "Why don't you tell something #{params[:genre]} to #{params[:email]}?"
20
+ end
21
+
22
+ subject(:match, "tell me something {genre}") do
23
+ respond :subject => "Your face is #{params[:genre]}"
24
+ end
25
+
26
+ subject(:match, "tell me '{title}'") do
27
+ respond :subject => "Once upon a time there was a #{params[:title]}. THE END."
28
+ end
29
+
30
+ subject(:match, "help") do
31
+ respond :subject => "Please deposit $10, and then try again"
32
+ end
33
+
34
+ default do
35
+ respond :subject => "FAIL"
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ if __FILE__ == $PROGRAM_NAME
42
+ Newman::Server.simple(Newman::Examples::Jester, "config/environment.rb")
43
+ end
@@ -0,0 +1,71 @@
1
+ # This is a cheap and possibly buggy clone of librelist.org's automatic
2
+ # mailing list creation
3
+
4
+ require_relative "example_helper"
5
+
6
+ module Newman
7
+ module Examples
8
+ LibreList = Newman::Application.new do
9
+ helpers do
10
+ def load_list(name)
11
+ store = Newman::Store.new(settings.application.librelist_db)
12
+ Newman::MailingList.new(name, store)
13
+ end
14
+ end
15
+
16
+ match :list_id, "[^.]+"
17
+
18
+ to(:tag, "{list_id}.subscribe") do
19
+ list = load_list(params[:list_id])
20
+
21
+ if list.subscriber?(sender)
22
+ respond :subject => "ERROR: Already subscribed",
23
+ :body => template("subscribe-error"),
24
+ :reply_to => "test+#{params[:list_id]}@#{domain}"
25
+ else
26
+ list.subscribe(sender)
27
+
28
+ respond :subject => "SUBSCRIBED!",
29
+ :body => template("subscribe-success"),
30
+ :reply_to => "test+#{params[:list_id]}@#{domain}"
31
+ end
32
+ end
33
+
34
+ to(:tag, "{list_id}.unsubscribe") do
35
+ list = load_list(params[:list_id])
36
+
37
+ if list.subscriber?(sender)
38
+ list.unsubscribe(sender)
39
+
40
+ respond :subject => "UNSUBSCRIBED!",
41
+ :body => template("unsubscribe-success")
42
+ else
43
+ respond :subject => "ERROR: Not on subscriber list",
44
+ :body => template("unsubscribe-error"),
45
+ :reply_to => "test+#{params[:list_id]}@#{domain}"
46
+ end
47
+ end
48
+
49
+ to(:tag, "{list_id}") do
50
+ list = load_list(params[:list_id])
51
+
52
+ if list.subscriber?(sender)
53
+ forward_message :bcc => list.subscribers.join(", "),
54
+ :reply_to => "test+#{params[:list_id]}@#{domain}"
55
+ else
56
+ respond :subject => "You are not subscribed",
57
+ :body => template("non-subscriber-error"),
58
+ :reply_to => "test+#{params[:list_id]}@#{domain}"
59
+ end
60
+ end
61
+
62
+ default do
63
+ respond :subject => "FAIL"
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ if __FILE__ == $PROGRAM_NAME
70
+ Newman::Server.simple(Newman::Examples::LibreList, "config/environment.rb")
71
+ end
@@ -0,0 +1,47 @@
1
+ require_relative "ping_pong"
2
+
3
+
4
+ settings = Newman::Settings.from_file("config/environment.rb")
5
+
6
+ mailer = Newman::Mailer
7
+ mailer.configure(settings)
8
+
9
+ server = Newman::Server
10
+ server.settings = settings
11
+ server.mailer = mailer
12
+
13
+ mailer.deliver_message(:to => settings.application.ping_email,
14
+ :from => settings.service.default_sender)
15
+
16
+ puts "Checking in..."
17
+ settings.application.live_test_delay.downto(1) do |i|
18
+ print "#{i}. "
19
+ sleep(1)
20
+ end
21
+ puts
22
+
23
+ Newman::Server.tick(Newman::Examples::PingPong)
24
+
25
+ remaining_attempts = 3
26
+ loop do
27
+ if remaining_attempts == 0
28
+ abort "FAIL: Did not receive mail yet"
29
+ else
30
+ incoming = mailer.messages
31
+ case
32
+ when incoming.empty?
33
+ sleep settings.service.polling_interval
34
+ when incoming.length > 1
35
+ abort "FAIL: More than one message in inbox"
36
+ else
37
+ if incoming.first.subject == "pong"
38
+ puts "OK"
39
+ exit
40
+ else
41
+ abort "FAIL: Expected 'pong', got #{incoming.first.subject}"
42
+ end
43
+ end
44
+
45
+ remaining_attempts -= 1
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "example_helper"
2
+
3
+ module Newman
4
+ module Examples
5
+ PingPong = Newman::Application.new do
6
+ to(:tag, "ping") do
7
+ respond(:subject => "pong")
8
+ end
9
+
10
+ default do
11
+ respond(:subject => "unknown command")
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ if __FILE__ == $PROGRAM_NAME
18
+ Newman::Server.simple(Newman::Examples::PingPong, "config/environment.rb")
19
+ end
@@ -0,0 +1,53 @@
1
+ require_relative "example_helper"
2
+
3
+ module Newman
4
+ module Examples
5
+
6
+ SimpleList = Newman::Application.new do
7
+ helpers do
8
+ def list
9
+ store = Newman::Store.new(settings.application.simplelist_db)
10
+
11
+ Newman::MailingList.new("simple_list", store)
12
+ end
13
+ end
14
+
15
+ to(:tag, "subscribe") do
16
+ if list.subscriber?(sender)
17
+ respond :subject => "ERROR: Already subscribed",
18
+ :body => template("subscribe-error")
19
+ else
20
+ list.subscribe(sender)
21
+
22
+ respond :subject => "SUBSCRIBED!",
23
+ :body => template("subscribe-success")
24
+ end
25
+ end
26
+
27
+ to(:tag, "unsubscribe") do
28
+ if list.subscriber?(sender)
29
+ list.unsubscribe(sender)
30
+
31
+ respond :subject => "UNSUBSCRIBED!",
32
+ :body => template("unsubscribe-success")
33
+ else
34
+ respond :subject => "ERROR: Not on subscriber list",
35
+ :body => template("unsubscribe-error")
36
+ end
37
+ end
38
+
39
+ default do
40
+ if list.subscriber?(sender)
41
+ forward_message :bcc => list.subscribers.join(", ")
42
+ else
43
+ respond :subject => "You are not subscribed",
44
+ :body => template("non-subscriber-error")
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ if __FILE__ == $PROGRAM_NAME
52
+ Newman::Server.simple(Newman::Examples::SimpleList, "config/environment.rb")
53
+ end
@@ -0,0 +1 @@
1
+ Sorry, we don't have <%= sender %> on our list of subscribers. Your message was dropped.
@@ -0,0 +1 @@
1
+ <%= sender %> is already a subscriber of this mailing list.
@@ -0,0 +1 @@
1
+ Welcome to the club, pal! We've added <%= sender %> to our list of people to spam.
@@ -0,0 +1,2 @@
1
+ Goose egg! Looks like <%= sender %> isn't on our mailing list. Are you sure you
2
+ entered the right address?
@@ -0,0 +1,2 @@
1
+ Sorry for bothering you. We've removed <%= sender %> from our list of people to
2
+ spam.
data/lib/newman.rb ADDED
@@ -0,0 +1,17 @@
1
+ require "pstore"
2
+ require "ostruct"
3
+ require "fileutils"
4
+
5
+ require "mail"
6
+ require "tilt"
7
+
8
+ require_relative "newman/server"
9
+ require_relative "newman/commands"
10
+ require_relative "newman/application"
11
+ require_relative "newman/controller"
12
+ require_relative "newman/mailing_list"
13
+ require_relative "newman/settings"
14
+ require_relative "newman/store"
15
+ require_relative "newman/mailer"
16
+ require_relative "newman/test_mailer"
17
+ require_relative "newman/version"
@@ -0,0 +1,23 @@
1
+ module Newman
2
+ class Application
3
+ include Commands
4
+
5
+ def initialize(&block)
6
+ self.callbacks = []
7
+ self.matchers = {}
8
+ self.extensions = []
9
+
10
+ instance_eval(&block) if block_given?
11
+ end
12
+
13
+ def call(params)
14
+ controller = Controller.new(params)
15
+ extensions.each { |mod| controller.extend(mod) }
16
+ trigger_callbacks(controller)
17
+ end
18
+
19
+ private
20
+
21
+ attr_accessor :callbacks, :default_callback, :matchers, :extensions
22
+ end
23
+ end
@@ -0,0 +1,72 @@
1
+ module Newman
2
+ module Commands
3
+ def use(extension)
4
+ extensions << extension
5
+ end
6
+
7
+ def helpers(&block)
8
+ extensions << Module.new(&block)
9
+ end
10
+
11
+ def match(id, pattern)
12
+ matchers[id.to_s] = pattern
13
+ end
14
+
15
+ def to(pattern_type, pattern, &callback)
16
+ raise NotImplementedError unless pattern_type == :tag
17
+
18
+ pattern = compile_pattern(pattern)
19
+
20
+ matcher = lambda do
21
+ request.to.each do |e|
22
+ md = e.match(/\+#{pattern}@#{Regexp.escape(domain)}/)
23
+ return md if md
24
+ end
25
+
26
+ false
27
+ end
28
+
29
+ callbacks << { :matcher => matcher, :callback => callback }
30
+ end
31
+
32
+ def subject(pattern_type, pattern, &callback)
33
+ raise NotImplementedError unless pattern_type == :match
34
+
35
+ pattern = compile_pattern(pattern)
36
+
37
+ matcher = lambda do
38
+ md = request.subject.match(/#{pattern}/)
39
+
40
+ md || false
41
+ end
42
+
43
+ callbacks << { :matcher => matcher, :callback => callback }
44
+ end
45
+
46
+ def default(&callback)
47
+ self.default_callback = callback
48
+ end
49
+
50
+ def trigger_callbacks(controller)
51
+ matched_callbacks = callbacks.select do |e|
52
+ matcher = e[:matcher]
53
+ e[:match_data] = controller.instance_exec(&matcher)
54
+ end
55
+
56
+ if matched_callbacks.empty?
57
+ controller.instance_exec(&default_callback)
58
+ else
59
+ matched_callbacks.each do |e|
60
+ callback = e[:callback]
61
+ controller.params = e[:match_data] || {}
62
+ controller.instance_exec(&callback)
63
+ end
64
+ end
65
+ end
66
+
67
+ def compile_pattern(pattern)
68
+ pattern.gsub('.','\.')
69
+ .gsub(/\{(.*?)\}/) { |m| "(?<#{$1}>#{matchers[$1]})" }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,49 @@
1
+ module Newman
2
+ class Controller
3
+ def initialize(params)
4
+ self.settings = params.fetch(:settings)
5
+ self.request = params.fetch(:request)
6
+ self.response = params.fetch(:response)
7
+ end
8
+
9
+ attr_accessor :params
10
+
11
+ def respond(params)
12
+ params.each { |k,v| response.send("#{k}=", v) }
13
+ end
14
+
15
+ def template(name)
16
+ Tilt.new(Dir.glob("#{settings.service.templates_dir}/#{name}.*").first)
17
+ .render(self)
18
+ end
19
+
20
+ def sender
21
+ request.from.first.to_s
22
+ end
23
+
24
+ def domain
25
+ settings.service.domain
26
+ end
27
+
28
+ def forward_message(params={})
29
+ response.from = request.from
30
+ response.reply_to = settings.service.default_sender
31
+ response.subject = request.subject
32
+
33
+ params.each do |k,v|
34
+ response.send("#{k}=", v)
35
+ end
36
+
37
+ if request.multipart?
38
+ response.text_part = request.text_part
39
+ response.html_part = request.html_part
40
+ else
41
+ response.body = request.body.to_s
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ attr_accessor :settings, :request, :response
48
+ end
49
+ end
@@ -0,0 +1,41 @@
1
+ module Newman
2
+ Mailer = Object.new
3
+
4
+ class << Mailer
5
+ def configure(settings)
6
+ imap = settings.imap
7
+ smtp = settings.smtp
8
+
9
+ Mail.defaults do
10
+ retriever_method :imap,
11
+ :address => imap.address,
12
+ :user_name => imap.user,
13
+ :password => imap.password,
14
+ :enable_ssl => imap.ssl_enabled || false,
15
+ :port => imap.port
16
+
17
+ delivery_method :smtp,
18
+ :address => smtp.address,
19
+ :user_name => smtp.user,
20
+ :password => smtp.password,
21
+ :authentication => :plain,
22
+ :enable_starttls_auto => smtp.starttls_enabled || false,
23
+ :port => smtp.port
24
+ end
25
+
26
+ def messages
27
+ Mail.all(:delete_after_find => true)
28
+ end
29
+
30
+ def new_message(*a, &b)
31
+ Mail.new(*a, &b)
32
+ end
33
+
34
+ def deliver_message(*a, &b)
35
+ new_message(*a, &b).deliver
36
+ end
37
+ end
38
+
39
+ attr_accessor :settings
40
+ end
41
+ end
@@ -0,0 +1,29 @@
1
+ module Newman
2
+ class MailingList
3
+ def initialize(name, store)
4
+ self.name = name
5
+ self.store = store
6
+ end
7
+
8
+ def subscribe(email)
9
+ store[name].create(email)
10
+ end
11
+
12
+ def unsubscribe(email)
13
+ record = store[name].find { |e| e.contents == email }
14
+ store[name].destroy(record.id)
15
+ end
16
+
17
+ def subscriber?(email)
18
+ store[name].any? { |r| r.contents == email }
19
+ end
20
+
21
+ def subscribers
22
+ store[name].map { |r| r.contents }
23
+ end
24
+
25
+ private
26
+
27
+ attr_accessor :name, :store
28
+ end
29
+ end
@@ -0,0 +1,45 @@
1
+ module Newman
2
+ Server = Object.new
3
+
4
+ class << Server
5
+ attr_accessor :settings, :mailer
6
+
7
+ def test_mode(settings_file)
8
+ self.settings = Newman::Settings.from_file(settings_file)
9
+ self.mailer = Newman::TestMailer
10
+
11
+ mailer.configure(settings)
12
+ end
13
+
14
+ def simple(apps, settings_file)
15
+ self.settings = Newman::Settings.from_file(settings_file)
16
+ self.mailer = Newman::Mailer
17
+
18
+ mailer.configure(settings)
19
+
20
+ run(apps)
21
+ end
22
+
23
+ def run(apps)
24
+ loop do
25
+ tick(apps)
26
+ sleep settings.service.polling_interval
27
+ end
28
+ end
29
+
30
+ def tick(apps)
31
+ mailer.messages.each do |request|
32
+ response = mailer.new_message(:to => request.from,
33
+ :from => settings.service.default_sender)
34
+
35
+ Array(apps).each do |a|
36
+ a.call(:request => request,
37
+ :response => response,
38
+ :settings => settings)
39
+ end
40
+
41
+ response.deliver
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ module Newman
2
+ class Settings
3
+ def self.from_file(filename)
4
+ new.tap { |o| o.load_config(filename) }
5
+ end
6
+
7
+ def initialize
8
+ self.imap = OpenStruct.new
9
+ self.smtp = OpenStruct.new
10
+ self.service = OpenStruct.new
11
+ self.application = OpenStruct.new
12
+ end
13
+
14
+ def load_config(filename)
15
+ eval(File.read(filename), binding)
16
+ end
17
+
18
+
19
+ attr_accessor :imap, :smtp, :service, :application
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "store/recorder"
2
+
3
+ module Newman
4
+ class Store
5
+ def initialize(filename)
6
+ FileUtils.mkdir_p(File.dirname(filename))
7
+
8
+ self.data = PStore.new(filename)
9
+
10
+ write do
11
+ data[:identifiers] ||= {}
12
+ data[:columns] ||= {}
13
+ end
14
+ end
15
+
16
+ attr_reader :identifiers
17
+
18
+ def [](column)
19
+ Recorder.new(column, self)
20
+ end
21
+
22
+ def read
23
+ data.transaction(:read_only) { yield(data) }
24
+ end
25
+
26
+ def write
27
+ data.transaction { yield(data) }
28
+ end
29
+
30
+ private
31
+
32
+ attr_accessor :data
33
+ end
34
+ end
@@ -0,0 +1,63 @@
1
+ module Newman
2
+ class Store
3
+ Record = Struct.new(:column, :id, :contents)
4
+
5
+ class Recorder
6
+ include Enumerable
7
+
8
+ def initialize(column, store)
9
+ self.column = column
10
+ self.store = store
11
+
12
+ store.write do |data|
13
+ data[:identifiers][column] ||= 0
14
+ data[:columns][column] ||= {}
15
+ end
16
+ end
17
+
18
+ def each
19
+ store.read do |data|
20
+ data[:columns][column].each do |id, contents|
21
+ yield(Record.new(column, id,contents))
22
+ end
23
+ end
24
+ end
25
+
26
+ def create(contents)
27
+ store.write do |data|
28
+ id = (data[:identifiers][column] += 1)
29
+
30
+ data[:columns][column][id] = contents
31
+
32
+ Record.new(column, id, contents)
33
+ end
34
+ end
35
+
36
+ def read(id)
37
+ store.read do |data|
38
+ Record.new(column, id, data[:columns][column][id])
39
+ end
40
+ end
41
+
42
+ def update(id)
43
+ store.write do |data|
44
+ data[:columns][column][id] = yield(data[:columns][column][id])
45
+
46
+ Record.new(column, id, data[:columns][column][id])
47
+ end
48
+ end
49
+
50
+ def destroy(id)
51
+ store.write do |data|
52
+ data[:columns][column].delete(id)
53
+ end
54
+
55
+ true
56
+ end
57
+
58
+ private
59
+
60
+ attr_accessor :column, :store
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,27 @@
1
+ module Newman
2
+ TestMailer = Object.new
3
+
4
+ class << TestMailer
5
+ def configure(settings)
6
+ Mail.defaults do
7
+ retriever_method :test
8
+ delivery_method :test
9
+ end
10
+ end
11
+
12
+ def messages
13
+ msgs = Marshal.load(Marshal.dump(Mail::TestMailer.deliveries))
14
+ Mail::TestMailer.deliveries.clear
15
+
16
+ msgs
17
+ end
18
+
19
+ def new_message(*a, &b)
20
+ Mail.new(*a, &b)
21
+ end
22
+
23
+ def deliver_message(*a, &b)
24
+ new_message(*a, &b).deliver
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ module Newman
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 0
6
+ STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
7
+ end
8
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,29 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
  date: 2012-02-02 00:00:00.000000000 Z
13
- dependencies: []
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mail
16
+ requirement: &2171081700 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.3.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2171081700
25
+ - !ruby/object:Gem::Dependency
26
+ name: tilt
27
+ requirement: &2171081200 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.3.3
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2171081200
14
36
  description: A microframework for mail-centric applications
15
37
  email:
16
38
  - gregory.t.brown@gmail.com
@@ -18,6 +40,33 @@ executables: []
18
40
  extensions: []
19
41
  extra_rdoc_files: []
20
42
  files:
43
+ - lib/newman/application.rb
44
+ - lib/newman/commands.rb
45
+ - lib/newman/controller.rb
46
+ - lib/newman/mailer.rb
47
+ - lib/newman/mailing_list.rb
48
+ - lib/newman/server.rb
49
+ - lib/newman/settings.rb
50
+ - lib/newman/store/recorder.rb
51
+ - lib/newman/store.rb
52
+ - lib/newman/test_mailer.rb
53
+ - lib/newman/version.rb
54
+ - lib/newman.rb
55
+ - examples/acid_tests.rb
56
+ - examples/config/dreamhost.rb.example
57
+ - examples/config/gmail.rb.example
58
+ - examples/config/test.rb
59
+ - examples/example_helper.rb
60
+ - examples/jester_clone.rb
61
+ - examples/libre_list_clone.rb
62
+ - examples/live_test.rb
63
+ - examples/ping_pong.rb
64
+ - examples/simple_mailing_list.rb
65
+ - examples/views/non-subscriber-error.erb
66
+ - examples/views/subscribe-error.erb
67
+ - examples/views/subscribe-success.erb
68
+ - examples/views/unsubscribe-error.erb
69
+ - examples/views/unsubscribe-success.erb
21
70
  - README.md
22
71
  homepage: http://github.com/mendicant-university/newman
23
72
  licenses: []