newman 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,40 @@
1
+ ### 0.3.0 (2012-03-08)
2
+
3
+ **Improvements:**
4
+
5
+ - Added documentation of all settings that can be modified via Newman configuration files.
6
+
7
+ - Added `Newman::Server#simple!`, which combines some of the flexibility of
8
+ manually building a server object with sensible defaults. This method is
9
+ useful for building simple tick-based servers, or for tweaking small details
10
+ such as which logger you want to use.
11
+
12
+ - Allow a locals hash to be passed to tilt via `Newman::Controller#template`,
13
+ and added some integration tests for template support.
14
+
15
+ **Behavior Changes:**
16
+
17
+ - Caching of logger object is less aggressive now, allowing
18
+ `Newman::Server#logger=` to be called at any time to change the
19
+ logger object used by the server.
20
+
21
+ - `Newman::Server.new` no longer accepts a custom logger argument.
22
+ Use `Newman::Server#logger=` instead.
23
+
24
+ - Locked explicitly to mail v2.3.0, because we're being bit by an upstream
25
+ bug. We will try to lock more optimistically in a future release of
26
+ Newman.
27
+
28
+ [Diff of all changes since 0.2.1](https://github.com/mendicant-university/newman/compare/v0.2.1...v0.3.0#diff-43)
29
+
1
30
  ### 0.2.1 (2012-02-11)
2
31
 
3
32
  - Fixed a bug with `Newman::Application#match`. It now normalizes keys to
4
33
  strings for easy use with `Newman::Application#compile_regex`, which
5
34
  fixes our substitution logic in patterns.
6
35
 
36
+ [Diff of all changes since 0.2.0](https://github.com/mendicant-university/newman/compare/v0.2.0...v0.2.1#diff-43)
37
+
7
38
  ### 0.2.0 (2012-02-08)
8
39
 
9
40
  - Internals mostly rewritten, changes too numerous to outline meaningfully.
@@ -25,6 +56,8 @@
25
56
  - Add a generic callback method to Newman::Application which allows for arbitrary
26
57
  callbacks to be run based on filters against the Mail::Message object.
27
58
 
59
+ [Diff of all changes since 0.1.1](https://github.com/mendicant-university/newman/compare/v0.1.1...v0.2.0#diff-43)
60
+
28
61
  ### 0.1.1 (2012-02-03)
29
62
 
30
63
  - First official release.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ![Newman](http://i.imgur.com/92bZB.jpg)
1
+ ![Newman](http://i.imgur.com/GCqaT.png)
2
2
 
3
3
  Newman is a microframework which aims to do for email-based
4
4
  applications what Rack and Sinatra have done for web programming. **While our
@@ -45,6 +45,9 @@ simple examples in this repository.
45
45
 
46
46
  Check out [Newman's Rocco-based API documentation](http://mendicant-university.github.com/newman/lib/newman.html).
47
47
 
48
+ We update this documentation on each gem release of newman, but to generate this documentation yourself,
49
+ you'll need to install the rocco gem.
50
+
48
51
  ### For general discussion, questions, and ideas about Newman:
49
52
 
50
53
  Find seacreature or ericgj in the #newman channel on Freenode or send an email to newman@librelist.org
@@ -1,8 +1,13 @@
1
- # This is a cheap and possibly buggy clone of librelist.org's automatic
2
- # mailing list creation
3
-
4
1
  require_relative "example_helper"
5
2
 
3
+ # This is a cheap and possibly buggy clone of librelist.org's automatic
4
+ # mailing list creation
5
+ #
6
+ # Settings:
7
+ #
8
+ # - `application.librelist_db`<br>
9
+ # path to mailing list pstore file, relative to application root
10
+ #
6
11
  module Newman
7
12
  module Examples
8
13
  LibreList = Newman::Application.new do
@@ -1,11 +1,9 @@
1
1
  require_relative "ping_pong"
2
2
 
3
-
4
- settings = Newman::Settings.from_file("config/environment.rb")
5
- mailer = Newman::Mailer.new(settings)
6
-
7
- server = Newman::Server.new(settings, mailer)
8
- server.apps << Newman::Examples::PingPong
3
+ server = Newman::Server.simple!(Newman::Examples::PingPong,
4
+ "config/environment.rb")
5
+ mailer = server.mailer
6
+ settings = server.settings
9
7
 
10
8
  mailer.deliver_message(:to => settings.application.ping_email,
11
9
  :from => settings.service.default_sender)
@@ -1,5 +1,12 @@
1
1
  require_relative "example_helper"
2
2
 
3
+ # The simplest possible mailing list app
4
+ #
5
+ # Settings:
6
+ #
7
+ # - `application.simplelist_db`<br>
8
+ # path to mailing list pstore file, relative to application root
9
+ #
3
10
  module Newman
4
11
  module Examples
5
12
 
@@ -0,0 +1,3 @@
1
+ The body of the request follows:
2
+
3
+ <%= request.decoded %>
@@ -0,0 +1 @@
1
+ It was sent <%= request.date %>.
@@ -0,0 +1 @@
1
+ The list it was routed to was <%= params[:list_id] %>.
@@ -0,0 +1 @@
1
+ The sender of this email was <%= sender %>.
@@ -0,0 +1,6 @@
1
+ The sender of this email was <%= sender %>.
2
+ It was sent <%= request.date %>.
3
+ The list it was routed to was <%= params[:list_id] %>.
4
+ The body of the request follows:
5
+
6
+ <%= request.decoded %>
@@ -0,0 +1,4 @@
1
+ <%= template('test/_echo_sender') %>
2
+ <%= template('test/_echo_date') %>
3
+ <%= template('test/_echo_list') %>
4
+ <%= template('test/_echo_body') %>
@@ -0,0 +1,3 @@
1
+ Pick 4: <%= pick_4.map(&:to_s).join("") %>
2
+
3
+ Your magic code is: <%= magic_code %>
@@ -226,16 +226,13 @@ module Newman
226
226
  # 2) If the selection of `matched_callbacks` is empty, it executes the default
227
227
  # callback in the context of a controller object. Otherwise, it runs each
228
228
  # callback in sequence, in the context of a controller object.
229
- #
230
- # This method may have some weird side effects because it relies on
231
- # awkward state mutations that could be either done in a better way or
232
- # replaced with a mostly stateless approach. We will look at fixing
233
- # this in a future Newman release.
234
229
 
235
230
  def trigger_callbacks(controller)
231
+ match_data = {}
232
+
236
233
  matched_callbacks = callbacks.select do |e|
237
234
  filter = e[:filter]
238
- e[:match_data] = filter.call(controller)
235
+ match_data[e] = filter.call(controller)
239
236
  end
240
237
 
241
238
  if matched_callbacks.empty?
@@ -243,7 +240,7 @@ module Newman
243
240
  else
244
241
  matched_callbacks.each do |e|
245
242
  action = e[:action]
246
- controller.params = e[:match_data] || {}
243
+ controller.params = match_data[e]
247
244
  controller.instance_exec(&action)
248
245
  end
249
246
  end
@@ -54,16 +54,18 @@ module Newman
54
54
  # ---
55
55
 
56
56
  # `Newman::Controller#template` is used to invoke a template file within the
57
- # context of the current controller object using Tilt. A name for the template is
57
+ # context of the current controller object using Tilt. A `name` for the template is
58
58
  # provided and then looked up in the directory referenced by
59
- # `settings.service.templates_dir`. While an example of using templates is
60
- # included in Newman's source, this feature hasn't really been tested
61
- # adequately. Please report any problems with this method in our
62
- # [issue tracker](https://github.com/mendicant-university/newman/issues).
63
-
64
- def template(name)
59
+ # `settings.service.templates_dir`. If a `locals` hash is provided, these
60
+ # local variables will be made available in templates.
61
+ #
62
+ # **NOTE: This is feature is one we haven't adequately used in Newman,
63
+ # if you have trouble with it, please let us know via our [issue
64
+ # tracker](http://github.com/mendicant-university/newman/issues).**
65
+ #
66
+ def template(name,locals={})
65
67
  Tilt.new(Dir.glob("#{settings.service.templates_dir}/#{name}.*").first)
66
- .render(self)
68
+ .render(self,locals)
67
69
  end
68
70
 
69
71
  # ---
@@ -2,34 +2,34 @@
2
2
  # to applications as a request, and then delivers a response email after the
3
3
  # applications have modified it.
4
4
  #
5
- # A `Newman::Server` object can be used in three distinct ways:
5
+ # A `Newman::Server` object can be used in four distinct ways:
6
6
  #
7
7
  # 1) Instantiated via `Newman::Server.test_mode` and then run tick by tick
8
8
  # in integration tests.
9
9
  #
10
10
  # 2) Instantiated via `Newman::Server.simple` which immediately executes
11
11
  # an infinite polling loop.
12
- #
13
- # 3) Instantiated explicitly and manually configured, for maximum control.
12
+ #
13
+ # 3) Instantiated via `Newman::Server.simple!`, and then run manually (either
14
+ # in a loop or by tick), using the same defaults used by `Newman::Server.simple`
15
+ #
16
+ # 4) Instantiated explicitly and manually configured, for maximum control.
14
17
  #
15
18
  # All of these different workflows are supported, but if you are simply looking
16
19
  # to build applications with `Newman`, you are most likely going to end up using
17
- # `Newman::Server.simple` because it takes care of most of the setup work for
18
- # you and is the easiest way to run a single Newman application.
20
+ # either `simple()` or `simple!()` because they care of most of the setup work
21
+ # for you.
19
22
  #
20
23
  # `Newman::Server` is part of Newman's **external interface**.
21
24
 
22
25
  module Newman
23
26
  class Server
24
27
  # ---
25
-
26
- # `Newman::Server.simple` automatically generates a `Newman::Mailer` object
27
- # and `Newman::Settings` object from the privded `settings_file`. These
28
+
29
+ # `Newman::Server.simple!` automatically generates a `Newman::Mailer` object
30
+ # and `Newman::Settings` object from the provided `settings_file`. These
28
31
  # objects are then passed on to `Newman::Server.new` and a server instance
29
- # is created. The server object is set up to run the specified `app`, with
30
- # request and response logging support enabled. Calling this method puts
31
- # the server in an infinite polling loop, because its final action is to
32
- # call `Newman::Server.run`.
32
+ # is created.
33
33
  #
34
34
  # The following example demonstrates how to use this method:
35
35
  #
@@ -42,18 +42,29 @@ module Newman
42
42
  # respond(:subject => "You missed the ball!")
43
43
  # end
44
44
  # end
45
- #
46
- # Newman::Server.simple(ping_pong, "config/environment.rb")
47
- #
48
- # Given a properly configured settings file, this code will launch a polling
49
- # server and run the simple `ping_pong` application.
50
-
51
- def self.simple(app, settings_file)
45
+ #
46
+ # s = Newman::Server.simple!(ping_pong, "config/environment.rb")
47
+ # # call s.tick or s.run at some later point.
48
+ #
49
+ # Given a proper configuration file, this will make it possible to easily
50
+ # get your applications up and running with simple request and response
51
+ # logging enabled.
52
+ def self.simple!(app, settings_file)
52
53
  settings = Settings.from_file(settings_file)
53
54
  mailer = Mailer.new(settings)
54
55
  server = new(settings, mailer)
55
- server.apps = [RequestLogger, app, ResponseLogger]
56
+ server.apps = [RequestLogger, app, ResponseLogger]
56
57
 
58
+ server
59
+ end
60
+
61
+ # ---
62
+
63
+ # `Newman::Server#simple` is the same as `Newman::Server#simple!`, but
64
+ # automatically starts an infinite polling loop.
65
+
66
+ def self.simple(app, settings_file)
67
+ server = simple!(app, settings_file)
57
68
  server.run
58
69
  end
59
70
 
@@ -64,7 +75,7 @@ module Newman
64
75
  # objects are then passed on to `Newman::Server.new` and a server instance
65
76
  # which is preconfigured for use in integration testing is returned.
66
77
  #
67
- # Using the application from the `Newman::Server.simple` documentation
78
+ # Using the application from the `Newman::Server.simple!` documentation
68
79
  # above, it'd be possible to write a simple integration test using this
69
80
  # method in the following way:
70
81
  #
@@ -96,19 +107,17 @@ module Newman
96
107
  # ---
97
108
 
98
109
  # To initialize a `Newman::Server` object, a settings object and mailer object must
99
- # be provided, and a logger object may also be provided. If a logger object
100
- # is not provided, `Newman::Server#default_logger` is called to create one.
101
- #
110
+ # be provided.
111
+ #
102
112
  # Instantiating a server object directly can be useful for building live
103
113
  # integration tests, or for building cron jobs which process email
104
114
  # periodically rather than in a busy-wait loop. See one of Newman's [live
105
115
  # tests](https://github.com/mendicant-university/newman/blob/master/examples/live_test.rb)
106
116
  # for an example of how this approach works.
107
117
 
108
- def initialize(settings, mailer, logger=nil)
118
+ def initialize(settings, mailer)
109
119
  self.settings = settings
110
120
  self.mailer = mailer
111
- self.logger = logger || default_logger
112
121
  self.apps = []
113
122
  end
114
123
 
@@ -120,7 +129,17 @@ module Newman
120
129
  # as an implementation detail; all important data will get passed down
121
130
  # into your apps on each `tick`.
122
131
 
123
- attr_accessor :settings, :mailer, :apps, :logger
132
+ attr_accessor :settings, :mailer, :apps
133
+ attr_writer :logger
134
+
135
+ # ---
136
+
137
+ # Returns the logger object that was set via `Newman::Server#logger=`,
138
+ # or delegates to `default_logger` if no custom logger was provided.
139
+ #
140
+ def logger
141
+ @logger || default_logger
142
+ end
124
143
 
125
144
  # ---
126
145
 
@@ -160,6 +179,12 @@ module Newman
160
179
  # exception is re-raised, typically taking the server down with it. This
161
180
  # setting is off by default.
162
181
  #
182
+ # 2b) If there are any server errors (such as an error retrieving messages
183
+ # via IMAP), those errors are logged and re-raised, taking the server
184
+ # down. Currently, you should use a process watcher to restart
185
+ # Newman to protect against such failures, but be careful about restarting
186
+ # without knowing what went wrong!
187
+ #
163
188
  # 3) Assuming an exception is not encountered, the response is delivered.
164
189
 
165
190
  def tick
@@ -187,6 +212,9 @@ module Newman
187
212
 
188
213
  response.deliver
189
214
  end
215
+ rescue Exception => e
216
+ logger.fatal("Caught exception: #{e}\n\n#{e.backtrace.join("\n")}")
217
+ raise
190
218
  end
191
219
 
192
220
  # ---
@@ -13,6 +13,38 @@
13
13
  # `Newman::Settings`is part of Newman's **internal API**, but
14
14
  # the setting file format and various settings that Newman depends
15
15
  # on should be considered part of the **external API**.
16
+ #
17
+ # The following settings are currently supported:
18
+ #
19
+ # imap.address
20
+ # imap.user
21
+ # imap.password
22
+ # imap.ssl_enabled (default false)
23
+ # imap.port
24
+ #
25
+ # smtp.address
26
+ # smtp.user
27
+ # smtp.password
28
+ # smtp.starttls_enabled (default false)
29
+ # smtp.port
30
+ #
31
+ # service.debug_mode
32
+ # log error backtraces and full request and response emails
33
+ #
34
+ # service.default_sender
35
+ # default FROM field for responses
36
+ #
37
+ # service.domain
38
+ # mail domain, used by filters and in building email addresses
39
+ #
40
+ # service.polling_interval
41
+ # idle seconds between server ticks
42
+ #
43
+ # service.raise_exceptions
44
+ # raise exceptions during server ticks, killing the server
45
+ #
46
+ # service.templates_dir
47
+ # directory of template files, relative to application root
16
48
 
17
49
  module Newman
18
50
  class Settings
@@ -4,8 +4,8 @@
4
4
  module Newman
5
5
  module Version
6
6
  MAJOR = 0
7
- MINOR = 2
8
- TINY = 1
7
+ MINOR = 3
8
+ TINY = 0
9
9
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
10
10
  end
11
11
  end
@@ -7,12 +7,17 @@ require_relative "../lib/newman"
7
7
  module Newman
8
8
  TEST_DIR = File.dirname(__FILE__)
9
9
 
10
- def self.new_test_server(app)
10
+ def self.new_test_server(apps)
11
+ apps = Array(apps)
11
12
  server = Newman::Server.test_mode(TEST_DIR + "/settings.rb")
12
- server.apps << app
13
+ apps.each {|app| server.apps << app }
13
14
  server.settings.application.simplelist_db = TEST_DIR + "/test.store"
14
15
  server.settings.service.templates_dir = TEST_DIR + "/../examples/views"
15
16
 
17
+ logger = ::Logger.new( TEST_DIR + "/log/test.log" )
18
+ logger.level = ::Logger::DEBUG
19
+ server.logger = logger
20
+
16
21
  server
17
22
  end
18
23
  end
@@ -0,0 +1,93 @@
1
+ require 'digest/md5'
2
+ require_relative "../helper"
3
+
4
+ describe "template" do
5
+ let(:app) do
6
+ Newman::Application.new do
7
+ match :list_id, /[^\.]+/
8
+
9
+ to :tag, "{list_id}.echo" do
10
+ respond(:subject => "RE: #{request.subject}",
11
+ :body => template('test/echo')
12
+ )
13
+ end
14
+
15
+ to :tag, "{list_id}.moneyball" do
16
+ pick_4 = [ rand(9), rand(9), rand(9), rand(9) ]
17
+ magic_code = Digest::MD5.hexdigest(
18
+ "#{sender}#{params[:list_id]}"
19
+ )
20
+ respond(:subject => "Today's Jackpots",
21
+ :body => template('test/moneyball', :pick_4 => pick_4,
22
+ :magic_code => magic_code)
23
+ )
24
+ end
25
+
26
+ to :tag, "{list_id}.partials" do
27
+ respond(:subject => "RE: #{request.subject}",
28
+ :body => template('test/echo_with_partials')
29
+ )
30
+ end
31
+
32
+ end
33
+ end
34
+
35
+ let(:server) {
36
+ Newman.new_test_server([Newman::RequestLogger, app, Newman::ResponseLogger])
37
+ }
38
+
39
+ let(:mailer) { server.mailer }
40
+
41
+ # -----
42
+
43
+ it "renders simple template without passed locals hash" do
44
+ mailer.deliver_message(:from => "me@example.com",
45
+ :to => "test+fizbiz.echo@test.com",
46
+ :body => "Could you call me about fizbiz please?")
47
+ server.tick
48
+
49
+ msgs = mailer.messages
50
+ assert_equal 1, msgs.count
51
+
52
+ actual = msgs.first.decoded
53
+
54
+ # assert that list_id, sender, and body is rendered in view
55
+ assert_match /\bme\@example\.com\b/, actual
56
+ assert_match /\bfizbiz\b/, actual
57
+ assert_match /Could you call me about fizbiz please\?/, actual
58
+ end
59
+
60
+ it "renders template with passed locals hash" do
61
+ mailer.deliver_message(:from => "me@example.com",
62
+ :to => "test+fizbiz.moneyball@test.com")
63
+ server.tick
64
+
65
+ msgs = mailer.messages
66
+ assert_equal 1, msgs.count
67
+
68
+ actual = msgs.first.decoded
69
+ expected_code = Digest::MD5.hexdigest("me@example.comfizbiz")
70
+
71
+ # assert that pick_4 and magic_code locals are rendered in view
72
+ assert_match(/Pick 4\: \d\d\d\d/, actual)
73
+ assert_match(/Your magic code is\: #{expected_code}/, actual)
74
+ end
75
+
76
+ it "renders template with partials" do
77
+ mailer.deliver_message(:from => "me@example.com",
78
+ :to => "test+fizbiz.partials@test.com",
79
+ :body => "Could you call me about fizbiz please?")
80
+ server.tick
81
+
82
+ msgs = mailer.messages
83
+ assert_equal 1, msgs.count
84
+
85
+ actual = msgs.first.decoded
86
+
87
+ # assert that list_id, sender, and body is rendered in view
88
+ assert_match /\bme\@example\.com\b/, actual
89
+ assert_match /\bfizbiz\b/, actual
90
+ assert_match /Could you call me about fizbiz please\?/, actual
91
+ end
92
+
93
+ end
@@ -4,4 +4,5 @@ SimpleCov.start
4
4
  require_relative "integration/acid_tests"
5
5
  require_relative "integration/skip_response_test"
6
6
  require_relative "integration/subject_filter_test"
7
+ require_relative "integration/template_test"
7
8
  require_relative "integration/to_filter_test"
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.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,22 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-12 00:00:00.000000000 Z
12
+ date: 2012-03-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mail
16
- requirement: &2153405740 !ruby/object:Gem::Requirement
16
+ requirement: &2164929320 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ~>
19
+ - - =
20
20
  - !ruby/object:Gem::Version
21
21
  version: 2.3.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153405740
24
+ version_requirements: *2164929320
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: tilt
27
- requirement: &2153405240 !ruby/object:Gem::Requirement
27
+ requirement: &2164924480 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.3.3
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2153405240
35
+ version_requirements: *2164924480
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: minitest
38
- requirement: &2153404780 !ruby/object:Gem::Requirement
38
+ requirement: &2164923220 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 2.11.1
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2153404780
46
+ version_requirements: *2164923220
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: simplecov
49
- requirement: &2153404380 !ruby/object:Gem::Requirement
49
+ requirement: &2164956100 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,21 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2153404380
57
+ version_requirements: *2164956100
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: purdytest
60
- requirement: &2153403880 !ruby/object:Gem::Requirement
61
- none: false
62
- requirements:
63
- - - ! '>='
64
- - !ruby/object:Gem::Version
65
- version: '0'
66
- type: :development
67
- prerelease: false
68
- version_requirements: *2153403880
69
- - !ruby/object:Gem::Dependency
70
- name: rocco
71
- requirement: &2153403360 !ruby/object:Gem::Requirement
60
+ requirement: &2164954780 !ruby/object:Gem::Requirement
72
61
  none: false
73
62
  requirements:
74
63
  - - ! '>='
@@ -76,10 +65,10 @@ dependencies:
76
65
  version: '0'
77
66
  type: :development
78
67
  prerelease: false
79
- version_requirements: *2153403360
68
+ version_requirements: *2164954780
80
69
  - !ruby/object:Gem::Dependency
81
70
  name: rake
82
- requirement: &2153402880 !ruby/object:Gem::Requirement
71
+ requirement: &2164953080 !ruby/object:Gem::Requirement
83
72
  none: false
84
73
  requirements:
85
74
  - - ! '>='
@@ -87,7 +76,7 @@ dependencies:
87
76
  version: '0'
88
77
  type: :development
89
78
  prerelease: false
90
- version_requirements: *2153402880
79
+ version_requirements: *2164953080
91
80
  description: A microframework for mail-centric applications
92
81
  email:
93
82
  - gregory.t.brown@gmail.com
@@ -121,12 +110,20 @@ files:
121
110
  - examples/views/non-subscriber-error.erb
122
111
  - examples/views/subscribe-error.erb
123
112
  - examples/views/subscribe-success.erb
113
+ - examples/views/test/_echo_body.erb
114
+ - examples/views/test/_echo_date.erb
115
+ - examples/views/test/_echo_list.erb
116
+ - examples/views/test/_echo_sender.erb
117
+ - examples/views/test/echo.erb
118
+ - examples/views/test/echo_with_partials.erb
119
+ - examples/views/test/moneyball.erb
124
120
  - examples/views/unsubscribe-error.erb
125
121
  - examples/views/unsubscribe-success.erb
126
122
  - test/helper.rb
127
123
  - test/integration/acid_tests.rb
128
124
  - test/integration/skip_response_test.rb
129
125
  - test/integration/subject_filter_test.rb
126
+ - test/integration/template_test.rb
130
127
  - test/integration/to_filter_test.rb
131
128
  - test/settings.rb
132
129
  - test/suite.rb