roda 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +70 -0
- data/README.rdoc +261 -302
- data/Rakefile +1 -1
- data/doc/release_notes/1.2.0.txt +406 -0
- data/lib/roda.rb +206 -124
- data/lib/roda/plugins/all_verbs.rb +11 -10
- data/lib/roda/plugins/assets.rb +5 -5
- data/lib/roda/plugins/backtracking_array.rb +12 -5
- data/lib/roda/plugins/caching.rb +10 -8
- data/lib/roda/plugins/class_level_routing.rb +94 -0
- data/lib/roda/plugins/content_for.rb +6 -0
- data/lib/roda/plugins/default_headers.rb +4 -11
- data/lib/roda/plugins/delay_build.rb +42 -0
- data/lib/roda/plugins/delegate.rb +64 -0
- data/lib/roda/plugins/drop_body.rb +33 -0
- data/lib/roda/plugins/empty_root.rb +48 -0
- data/lib/roda/plugins/environments.rb +68 -0
- data/lib/roda/plugins/error_email.rb +1 -2
- data/lib/roda/plugins/error_handler.rb +1 -1
- data/lib/roda/plugins/halt.rb +7 -5
- data/lib/roda/plugins/head.rb +4 -2
- data/lib/roda/plugins/header_matchers.rb +17 -9
- data/lib/roda/plugins/hooks.rb +16 -32
- data/lib/roda/plugins/json.rb +4 -10
- data/lib/roda/plugins/mailer.rb +233 -0
- data/lib/roda/plugins/match_affix.rb +48 -0
- data/lib/roda/plugins/multi_route.rb +9 -11
- data/lib/roda/plugins/multi_run.rb +81 -0
- data/lib/roda/plugins/named_templates.rb +93 -0
- data/lib/roda/plugins/not_allowed.rb +43 -48
- data/lib/roda/plugins/path.rb +63 -2
- data/lib/roda/plugins/render.rb +79 -48
- data/lib/roda/plugins/render_each.rb +6 -0
- data/lib/roda/plugins/sinatra_helpers.rb +523 -0
- data/lib/roda/plugins/slash_path_empty.rb +25 -0
- data/lib/roda/plugins/static_path_info.rb +64 -0
- data/lib/roda/plugins/streaming.rb +1 -1
- data/lib/roda/plugins/view_subdirs.rb +12 -8
- data/lib/roda/version.rb +1 -1
- data/spec/integration_spec.rb +33 -0
- data/spec/plugin/backtracking_array_spec.rb +24 -18
- data/spec/plugin/class_level_routing_spec.rb +138 -0
- data/spec/plugin/delay_build_spec.rb +23 -0
- data/spec/plugin/delegate_spec.rb +20 -0
- data/spec/plugin/drop_body_spec.rb +20 -0
- data/spec/plugin/empty_root_spec.rb +14 -0
- data/spec/plugin/environments_spec.rb +31 -0
- data/spec/plugin/h_spec.rb +1 -3
- data/spec/plugin/header_matchers_spec.rb +14 -0
- data/spec/plugin/hooks_spec.rb +3 -5
- data/spec/plugin/mailer_spec.rb +191 -0
- data/spec/plugin/match_affix_spec.rb +22 -0
- data/spec/plugin/multi_run_spec.rb +31 -0
- data/spec/plugin/named_templates_spec.rb +65 -0
- data/spec/plugin/path_spec.rb +66 -2
- data/spec/plugin/render_spec.rb +46 -1
- data/spec/plugin/sinatra_helpers_spec.rb +534 -0
- data/spec/plugin/slash_path_empty_spec.rb +22 -0
- data/spec/plugin/static_path_info_spec.rb +50 -0
- data/spec/request_spec.rb +23 -0
- data/spec/response_spec.rb +12 -1
- metadata +48 -6
@@ -0,0 +1,68 @@
|
|
1
|
+
class Roda
|
2
|
+
module RodaPlugins
|
3
|
+
# The environments plugin adds a environment class accessor to get
|
4
|
+
# the environment for the application, 3 predicate class methods
|
5
|
+
# to check for the current environment (development?, test? and
|
6
|
+
# production?), and a class configure method that takes environment(s)
|
7
|
+
# and yields to the block if the given environment(s) match the
|
8
|
+
# current environment.
|
9
|
+
#
|
10
|
+
# The default environment for the application is based on
|
11
|
+
# <tt>ENV['RACK_ENV']</tt>.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# class Roda
|
16
|
+
# plugin :environments
|
17
|
+
#
|
18
|
+
# environment # => :development
|
19
|
+
# development? # => true
|
20
|
+
# test? # => false
|
21
|
+
# production? # => false
|
22
|
+
#
|
23
|
+
# # Set the environment for the application
|
24
|
+
# self.environment = :test
|
25
|
+
# test? # => true
|
26
|
+
#
|
27
|
+
# configure do
|
28
|
+
# # called, as no environments given
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# configure :development, :production do
|
32
|
+
# # not called, as no environments match
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# configure :test do
|
36
|
+
# # called, as environment given matches current environment
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
module Environments
|
40
|
+
# Set the environment to use for the app. Default to ENV['RACK_ENV']
|
41
|
+
# if no environment is given. If ENV['RACK_ENV'] is not set and
|
42
|
+
# no environment is given, assume the development environment.
|
43
|
+
def self.configure(app, env=ENV["RACK_ENV"])
|
44
|
+
app.environment = (env || 'development').to_sym
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
# The current environment for the application, which should be stored
|
49
|
+
# as a symbol.
|
50
|
+
attr_accessor :environment
|
51
|
+
|
52
|
+
# If no environments are given or one of the given environments
|
53
|
+
# matches the current environment, yield the receiver to the block.
|
54
|
+
def configure(*envs)
|
55
|
+
if envs.empty? || envs.any?{|s| s == environment}
|
56
|
+
yield self
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
[:development, :test, :production].each do |env|
|
61
|
+
define_method("#{env}?"){environment == env}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
register_plugin(:environments, Environments)
|
67
|
+
end
|
68
|
+
end
|
@@ -41,7 +41,7 @@ class Roda
|
|
41
41
|
format = lambda{|h| h.map{|k, v| "#{k.inspect} => #{v.inspect}"}.sort.join("\n")}
|
42
42
|
|
43
43
|
message = <<END
|
44
|
-
Path: #{s.request.
|
44
|
+
Path: #{s.request.path}
|
45
45
|
|
46
46
|
Backtrace:
|
47
47
|
|
@@ -88,7 +88,6 @@ END
|
|
88
88
|
# the superclass.
|
89
89
|
def inherited(subclass)
|
90
90
|
super
|
91
|
-
subclass.opts[:error_email] = subclass.opts[:error_email].dup
|
92
91
|
subclass.opts[:error_email][:headers] = subclass.opts[:error_email][:headers].dup
|
93
92
|
end
|
94
93
|
end
|
data/lib/roda/plugins/halt.rb
CHANGED
@@ -53,12 +53,14 @@ class Roda
|
|
53
53
|
raise Roda::RodaError, "singular argument to #halt must be Integer, String, or Array"
|
54
54
|
end
|
55
55
|
when 2
|
56
|
-
|
57
|
-
|
56
|
+
resp = response
|
57
|
+
resp.status = res[0]
|
58
|
+
resp.write res[1]
|
58
59
|
when 3
|
59
|
-
|
60
|
-
|
61
|
-
|
60
|
+
resp = response
|
61
|
+
resp.status = res[0]
|
62
|
+
resp.headers.merge!(res[1])
|
63
|
+
resp.write res[2]
|
62
64
|
else
|
63
65
|
raise Roda::RodaError, "too many arguments given to #halt (accepts 0-3, received #{res.length})"
|
64
66
|
end
|
data/lib/roda/plugins/head.rb
CHANGED
@@ -23,13 +23,15 @@ class Roda
|
|
23
23
|
# HEAD requests for +/+, +/a+, and +/b+ will all return 200 status
|
24
24
|
# with an empty body.
|
25
25
|
module Head
|
26
|
+
EMPTY_ARRAY = [].freeze
|
27
|
+
|
26
28
|
module InstanceMethods
|
27
29
|
# Always use an empty response body for head requests, with a
|
28
30
|
# content length of 0.
|
29
31
|
def call(*)
|
30
32
|
res = super
|
31
|
-
if
|
32
|
-
res[2] =
|
33
|
+
if @_request.head?
|
34
|
+
res[2] = EMPTY_ARRAY
|
33
35
|
end
|
34
36
|
res
|
35
37
|
end
|
@@ -8,23 +8,23 @@ class Roda
|
|
8
8
|
# It adds a +:header+ matcher for matching on arbitrary headers, which matches
|
9
9
|
# if the header is present:
|
10
10
|
#
|
11
|
-
#
|
12
|
-
# r.on :header=>'X-App-Token' do
|
13
|
-
# end
|
11
|
+
# r.on :header=>'X-App-Token' do
|
14
12
|
# end
|
15
13
|
#
|
16
14
|
# It adds a +:host+ matcher for matching by the host of the request:
|
17
15
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
16
|
+
# r.on :host=>'foo.example.com' do
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# It adds a +:user_agent+ matcher for matching on a user agent patterns, which
|
20
|
+
# yields the regexp captures to the block:
|
21
|
+
#
|
22
|
+
# r.on :user_agent=>/Chrome\/([.\d]+)/ do |chrome_version|
|
21
23
|
# end
|
22
24
|
#
|
23
25
|
# It adds an +:accept+ matcher for matching based on the Accept header:
|
24
26
|
#
|
25
|
-
#
|
26
|
-
# r.on :accept=>'text/csv' do
|
27
|
-
# end
|
27
|
+
# r.on :accept=>'text/csv' do
|
28
28
|
# end
|
29
29
|
#
|
30
30
|
# Note that the accept matcher is very simple and cannot handle wildcards,
|
@@ -49,6 +49,14 @@ class Roda
|
|
49
49
|
def match_host(hostname)
|
50
50
|
hostname === host
|
51
51
|
end
|
52
|
+
|
53
|
+
# Match the submitted user agent to the given pattern, capturing any
|
54
|
+
# regexp match groups.
|
55
|
+
def match_user_agent(pattern)
|
56
|
+
if (user_agent = @env["HTTP_USER_AGENT"]) && user_agent.to_s =~ pattern
|
57
|
+
@captures.concat($~[1..-1])
|
58
|
+
end
|
59
|
+
end
|
52
60
|
end
|
53
61
|
end
|
54
62
|
|
data/lib/roda/plugins/hooks.rb
CHANGED
@@ -30,10 +30,8 @@ class Roda
|
|
30
30
|
# handle cases where before hooks are added after the route block.
|
31
31
|
module Hooks
|
32
32
|
def self.configure(app)
|
33
|
-
app.
|
34
|
-
|
35
|
-
@before ||= nil
|
36
|
-
end
|
33
|
+
app.opts[:before_hook] ||= nil
|
34
|
+
app.opts[:after_hook] ||= nil
|
37
35
|
end
|
38
36
|
|
39
37
|
module ClassMethods
|
@@ -42,17 +40,14 @@ class Roda
|
|
42
40
|
# then instance_execs the given after proc, so that the given
|
43
41
|
# after proc always executes after the previous one.
|
44
42
|
def after(&block)
|
45
|
-
if
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
instance_exec(res, &block)
|
50
|
-
end
|
51
|
-
else
|
52
|
-
block
|
43
|
+
opts[:after_hook] = if b = opts[:after_hook]
|
44
|
+
proc do |res|
|
45
|
+
instance_exec(res, &b)
|
46
|
+
instance_exec(res, &block)
|
53
47
|
end
|
48
|
+
else
|
49
|
+
block
|
54
50
|
end
|
55
|
-
@after
|
56
51
|
end
|
57
52
|
|
58
53
|
# Add a before hook. If there is already a before hook defined,
|
@@ -60,25 +55,14 @@ class Roda
|
|
60
55
|
# then instance_execs the existing before proc, so that the given
|
61
56
|
# before proc always executes before the previous one.
|
62
57
|
def before(&block)
|
63
|
-
if
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
instance_exec(&b)
|
68
|
-
end
|
69
|
-
else
|
70
|
-
block
|
58
|
+
opts[:before_hook] = if b = opts[:before_hook]
|
59
|
+
proc do
|
60
|
+
instance_exec(&block)
|
61
|
+
instance_exec(&b)
|
71
62
|
end
|
63
|
+
else
|
64
|
+
block
|
72
65
|
end
|
73
|
-
@before
|
74
|
-
end
|
75
|
-
|
76
|
-
# Copy the before and after hooks into the subclasses
|
77
|
-
# when inheriting
|
78
|
-
def inherited(subclass)
|
79
|
-
super
|
80
|
-
subclass.instance_variable_set(:@before, @before)
|
81
|
-
subclass.instance_variable_set(:@after, @after)
|
82
66
|
end
|
83
67
|
end
|
84
68
|
|
@@ -88,13 +72,13 @@ class Roda
|
|
88
72
|
# Before routing, execute the before hooks, and
|
89
73
|
# execute the after hooks before returning.
|
90
74
|
def _route(*, &block)
|
91
|
-
if b =
|
75
|
+
if b = opts[:before_hook]
|
92
76
|
instance_exec(&b)
|
93
77
|
end
|
94
78
|
|
95
79
|
res = super
|
96
80
|
ensure
|
97
|
-
if b =
|
81
|
+
if b = opts[:after_hook]
|
98
82
|
instance_exec(res, &b)
|
99
83
|
end
|
100
84
|
end
|
data/lib/roda/plugins/json.rb
CHANGED
@@ -36,19 +36,13 @@ class Roda
|
|
36
36
|
module Json
|
37
37
|
# Set the classes to automatically convert to JSON
|
38
38
|
def self.configure(app)
|
39
|
-
app.
|
40
|
-
@json_result_classes ||= [Array, Hash]
|
41
|
-
end
|
39
|
+
app.opts[:json_result_classes] ||= [Array, Hash]
|
42
40
|
end
|
43
41
|
|
44
42
|
module ClassMethods
|
45
43
|
# The classes that should be automatically converted to json
|
46
|
-
|
47
|
-
|
48
|
-
# Copy the json_result_classes into the subclass
|
49
|
-
def inherited(subclass)
|
50
|
-
super
|
51
|
-
subclass.instance_variable_set(:@json_result_classes, json_result_classes.dup)
|
44
|
+
def json_result_classes
|
45
|
+
opts[:json_result_classes]
|
52
46
|
end
|
53
47
|
end
|
54
48
|
|
@@ -63,7 +57,7 @@ class Roda
|
|
63
57
|
# application/json content-type.
|
64
58
|
def block_result_body(result)
|
65
59
|
case result
|
66
|
-
when *
|
60
|
+
when *roda_class.json_result_classes
|
67
61
|
response[CONTENT_TYPE] = APPLICATION_JSON
|
68
62
|
convert_to_json(result)
|
69
63
|
else
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'mail'
|
3
|
+
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The mailer plugin allows your Roda application to send emails easily.
|
7
|
+
#
|
8
|
+
# class App < Roda
|
9
|
+
# plugin :render
|
10
|
+
# plugin :mailer
|
11
|
+
#
|
12
|
+
# route do |r|
|
13
|
+
# r.on "albums" do
|
14
|
+
# r.mail "added" do |album|
|
15
|
+
# @album = album
|
16
|
+
# from 'from@example.com'
|
17
|
+
# to 'to@example.com'
|
18
|
+
# cc 'cc@example.com'
|
19
|
+
# bcc 'bcc@example.com'
|
20
|
+
# subject 'Album Added'
|
21
|
+
# add_file "path/to/album_added_img.jpg"
|
22
|
+
# render(:albums_added_email) # body
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# The default method for sending a mail is +sendmail+:
|
29
|
+
#
|
30
|
+
# App.sendmail("/albums/added", Album[1])
|
31
|
+
#
|
32
|
+
# If you want to return the <tt>Mail::Message</tt> instance for further modification,
|
33
|
+
# you can just use the +mail+ method:
|
34
|
+
#
|
35
|
+
# mail = App.mail("/albums/added", Album[1])
|
36
|
+
# mail.from 'from2@example.com'
|
37
|
+
# mail.deliver
|
38
|
+
#
|
39
|
+
# The mailer plugin uses the mail gem, so if you want to configure how
|
40
|
+
# email is sent, you can use <tt>Mail.defaults</tt> (see the mail gem documentation for
|
41
|
+
# more details):
|
42
|
+
#
|
43
|
+
# Mail.defaults do
|
44
|
+
# delivery_method :smtp, :address=>'smtp.example.com', :port=>587
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# You can support multipart emails using +text_part+ and +html_part+:
|
48
|
+
#
|
49
|
+
# r.mail "added" do |album_added|
|
50
|
+
# from 'from@example.com'
|
51
|
+
# to 'to@example.com'
|
52
|
+
# subject 'Album Added'
|
53
|
+
# text_part render('album_added.txt') # views/album_added.txt.erb
|
54
|
+
# html_part render('album_added.html') # views/album_added.html.erb
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# In addition to allowing you to use Roda's render plugin for rendering
|
58
|
+
# email bodies, you can use all of Roda's usual routing tree features
|
59
|
+
# to DRY up your code:
|
60
|
+
#
|
61
|
+
# r.on "albums/:d" do |album_id|
|
62
|
+
# @album = Album[album_id.to_i]
|
63
|
+
# from 'from@example.com'
|
64
|
+
# to 'to@example.com'
|
65
|
+
#
|
66
|
+
# r.mail "added" do
|
67
|
+
# subject 'Album Added'
|
68
|
+
# render(:albums_added_email)
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# r.mail "deleted" do
|
72
|
+
# subject 'Album Deleted'
|
73
|
+
# render(:albums_deleted_email)
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# When sending a mail via +mail+ or +sendmail+, an Error will be raised
|
78
|
+
# if the mail object does not have a body. This is similar to the 404
|
79
|
+
# status that Roda uses by default for web requests that don't have
|
80
|
+
# a body. If you want to specifically send an email with an empty body, you
|
81
|
+
# can use the explicit empty string:
|
82
|
+
#
|
83
|
+
# r.mail do
|
84
|
+
# from 'from@example.com'
|
85
|
+
# to 'to@example.com'
|
86
|
+
# subject 'No Body Here'
|
87
|
+
# ""
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# By default, the mailer uses text/plain as the Content-Type for emails.
|
91
|
+
# You can override the default by specifying a :content_type option when
|
92
|
+
# loading the plugin:
|
93
|
+
#
|
94
|
+
# plugin :mailer, :content_type=>'text/html'
|
95
|
+
#
|
96
|
+
# The mailer plugin does support being used inside a Roda application
|
97
|
+
# that is handling web requests, where the routing block for mails and
|
98
|
+
# web requests is shared. However, it's recommended that you create a
|
99
|
+
# separate Roda application for emails. This can be a subclass of your main
|
100
|
+
# Roda application if you want your helper methods to automatically be
|
101
|
+
# available in your email views.
|
102
|
+
module Mailer
|
103
|
+
REQUEST_METHOD = "REQUEST_METHOD".freeze
|
104
|
+
PATH_INFO = "PATH_INFO".freeze
|
105
|
+
SCRIPT_NAME = 'SCRIPT_NAME'.freeze
|
106
|
+
EMPTY_STRING = ''.freeze
|
107
|
+
RACK_INPUT = 'rack.input'.freeze
|
108
|
+
RODA_MAIL = 'roda.mail'.freeze
|
109
|
+
RODA_MAIL_ARGS = 'roda.mail_args'.freeze
|
110
|
+
MAIL = "MAIL".freeze
|
111
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
112
|
+
TEXT_PLAIN = "text/plain".freeze
|
113
|
+
|
114
|
+
# Error raised when the using the mail class method, but the routing
|
115
|
+
# tree doesn't return the mail object.
|
116
|
+
class Error < ::Roda::RodaError; end
|
117
|
+
|
118
|
+
# Set the options for the mailer. Options:
|
119
|
+
# :content_type :: The default content type for emails (default: text/plain)
|
120
|
+
def self.configure(app, opts={})
|
121
|
+
app.opts[:mailer] = (app.opts[:mailer]||{}).merge(opts).freeze
|
122
|
+
end
|
123
|
+
|
124
|
+
module ClassMethods
|
125
|
+
# Return a Mail::Message instance for the email for the given request path
|
126
|
+
# and arguments. You can further manipulate the returned mail object before
|
127
|
+
# calling +deliver+ to send the mail.
|
128
|
+
def mail(path, *args)
|
129
|
+
mail = ::Mail.new
|
130
|
+
unless mail.equal?(allocate.call(PATH_INFO=>path, SCRIPT_NAME=>EMPTY_STRING, REQUEST_METHOD=>MAIL, RACK_INPUT=>StringIO.new, RODA_MAIL=>mail, RODA_MAIL_ARGS=>args, &route_block))
|
131
|
+
raise Error, "route did not return mail instance for #{path.inspect}, #{args.inspect}"
|
132
|
+
end
|
133
|
+
mail
|
134
|
+
end
|
135
|
+
|
136
|
+
# Calls +mail+ and immediately sends the resulting mail.
|
137
|
+
def sendmail(*args)
|
138
|
+
mail(*args).deliver
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
module RequestMethods
|
143
|
+
# Similar to routing tree methods such as +get+ and +post+, this matches
|
144
|
+
# only if the request method is MAIL (only set when using the Roda class
|
145
|
+
# +mail+ or +sendmail+ methods) and the rest of the arguments match
|
146
|
+
# the request. This yields any of the captures to the block, as well as
|
147
|
+
# any arguments passed to the +mail+ or +sendmail+ Roda class methods.
|
148
|
+
def mail(*args)
|
149
|
+
if @env[REQUEST_METHOD] == MAIL
|
150
|
+
if_match(args) do |*vs|
|
151
|
+
yield *(vs + @env[RODA_MAIL_ARGS])
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
module ResponseMethods
|
158
|
+
# The mail object related to the current request.
|
159
|
+
attr_accessor :mail
|
160
|
+
|
161
|
+
# If the related request was an email request, add any response headers
|
162
|
+
# to the email, as well as adding the response body to the email.
|
163
|
+
# Return the email unless no body was set for it, which would indicate
|
164
|
+
# that the routing tree did not handle the request.
|
165
|
+
def finish
|
166
|
+
if m = mail
|
167
|
+
header_content_type = @headers.delete(CONTENT_TYPE)
|
168
|
+
m.headers(@headers)
|
169
|
+
m.body(@body.join) unless @body.empty?
|
170
|
+
|
171
|
+
if content_type = header_content_type || roda_class.opts[:mailer][:content_type]
|
172
|
+
if mail.multipart?
|
173
|
+
if mail.content_type =~ /multipart\/mixed/ &&
|
174
|
+
mail.parts.length >= 2 &&
|
175
|
+
(part = mail.parts.find{|p| !p.attachment && p.content_type == TEXT_PLAIN})
|
176
|
+
part.content_type = content_type
|
177
|
+
end
|
178
|
+
else
|
179
|
+
mail.content_type = content_type
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
unless m.body.to_s.empty? && m.parts.empty? && @body.empty?
|
184
|
+
m
|
185
|
+
end
|
186
|
+
else
|
187
|
+
super
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
module InstanceMethods
|
193
|
+
# Add delegates for common email methods.
|
194
|
+
[:from, :to, :cc, :bcc, :subject, :add_file].each do |meth|
|
195
|
+
define_method(meth) do |*args|
|
196
|
+
env[RODA_MAIL].send(meth, *args)
|
197
|
+
nil
|
198
|
+
end
|
199
|
+
end
|
200
|
+
[:text_part, :html_part].each do |meth|
|
201
|
+
define_method(meth) do |*args|
|
202
|
+
_mail_part(meth, *args)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
# If this is an email request, set the mail object in the response, as well
|
209
|
+
# as the default content_type for the email.
|
210
|
+
def _route
|
211
|
+
if mail = env[RODA_MAIL]
|
212
|
+
res = @_response
|
213
|
+
res.mail = mail
|
214
|
+
res.headers.delete(CONTENT_TYPE)
|
215
|
+
end
|
216
|
+
super
|
217
|
+
end
|
218
|
+
|
219
|
+
# Set the text_part or html_part (depending on the method) in the related email,
|
220
|
+
# using the given body and optional headers.
|
221
|
+
def _mail_part(meth, body, headers=nil)
|
222
|
+
env[RODA_MAIL].send(meth) do
|
223
|
+
body(body)
|
224
|
+
headers(headers) if headers
|
225
|
+
end
|
226
|
+
nil
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
register_plugin(:mailer, Mailer)
|
232
|
+
end
|
233
|
+
end
|