roda 1.3.0 → 2.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG +24 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -4
- data/doc/release_notes/2.0.0.txt +75 -0
- data/lib/roda/plugins/assets.rb +2 -2
- data/lib/roda/plugins/backtracking_array.rb +2 -11
- data/lib/roda/plugins/caching.rb +4 -2
- data/lib/roda/plugins/chunked.rb +4 -9
- data/lib/roda/plugins/class_level_routing.rb +1 -3
- data/lib/roda/plugins/default_headers.rb +1 -2
- data/lib/roda/plugins/error_email.rb +4 -14
- data/lib/roda/plugins/error_handler.rb +4 -4
- data/lib/roda/plugins/flash.rb +1 -3
- data/lib/roda/plugins/halt.rb +24 -5
- data/lib/roda/plugins/header_matchers.rb +2 -7
- data/lib/roda/plugins/hooks.rb +1 -3
- data/lib/roda/plugins/json.rb +4 -2
- data/lib/roda/plugins/mailer.rb +8 -7
- data/lib/roda/plugins/middleware.rb +21 -9
- data/lib/roda/plugins/not_found.rb +3 -3
- data/lib/roda/plugins/padrino_render.rb +60 -0
- data/lib/roda/plugins/param_matchers.rb +3 -3
- data/lib/roda/plugins/path.rb +2 -1
- data/lib/roda/plugins/render.rb +55 -37
- data/lib/roda/plugins/render_each.rb +4 -2
- data/lib/roda/plugins/static_path_info.rb +2 -63
- data/lib/roda/plugins/streaming.rb +4 -2
- data/lib/roda/version.rb +2 -2
- data/lib/roda.rb +71 -172
- data/spec/matchers_spec.rb +31 -82
- data/spec/plugin/assets_spec.rb +6 -6
- data/spec/plugin/error_handler_spec.rb +23 -0
- data/spec/plugin/halt_spec.rb +39 -0
- data/spec/plugin/middleware_spec.rb +7 -0
- data/spec/plugin/padrino_render_spec.rb +57 -0
- data/spec/plugin/render_each_spec.rb +1 -1
- data/spec/plugin/render_spec.rb +59 -5
- data/spec/request_spec.rb +0 -12
- data/spec/response_spec.rb +0 -24
- data/spec/views/_test.erb +1 -0
- metadata +7 -4
- data/lib/roda/plugins/delete_nil_headers.rb +0 -34
- data/spec/module_spec.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 035bdb54b566e77c48d1332fdd7ebf396a849193
|
4
|
+
data.tar.gz: 682a8a39b4dc9e25d1395102890f8650f750e12d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c219eb5e94a58c04d90256d87cbe5a86c1dc8c972666cbf61d97a34c5f3b4bc8d6b7de56fdee7aa65ef01ba70d7f4052d479c80211f49201dc94705e17e69308
|
7
|
+
data.tar.gz: ba8d204672492c04de406eb87d276c59e92af57047c4cc6bb479e7fc9efb1785fd314df682e496bc905327450571497f77581fef04a29346159de747172f07bc
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
= 2.0.0 (2015-02-13)
|
2
|
+
|
3
|
+
* Allow Roda app to be used as a regular rack app even when using the middleware plugin (jeremyevans)
|
4
|
+
|
5
|
+
* Make render plugin :layout option always be true or false (jeremyevans)
|
6
|
+
|
7
|
+
* Make :layout=>true view option use the default layout (jeremyevans)
|
8
|
+
|
9
|
+
* Make error_handler plugin rescue ScriptError in addition to StandardError (jeremyevans)
|
10
|
+
|
11
|
+
* Make halt plugin integrate with symbol_views, json, and similar plugins (jeremyevans)
|
12
|
+
|
13
|
+
* Add padrino_render plugin, adding render/partial methods that work similar to Padrino (jeremyevans)
|
14
|
+
|
15
|
+
* Add Roda#render_template private method for template rendering, for use by plugins (jeremyevans)
|
16
|
+
|
17
|
+
* Make Roda#initialize take env hash, #call take route_block, remove private #_route (jeremyevans)
|
18
|
+
|
19
|
+
* Remove keep_remaining_path/update_remaining_path private request methods (jeremyevans)
|
20
|
+
|
21
|
+
* Don't modify SCRIPT_NAME/PATH_INFO during routing, merging static_path_info plugin into core (jeremyevans)
|
22
|
+
|
23
|
+
* Remove code deprecated in Roda 1.3.0 (jeremyevans)
|
24
|
+
|
1
25
|
= 1.3.0 (2015-01-13)
|
2
26
|
|
3
27
|
* Make static_path_info plugin restore original SCRIPT_NAME/PATH_INFO before returning from r.run (jeremyevans)
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -292,7 +292,8 @@ Colons that are not followed by a <tt>\\w</tt> character are matched literally:
|
|
292
292
|
|
293
293
|
":/a" # matches "/:/a"
|
294
294
|
|
295
|
-
Note that
|
295
|
+
Note that other than colons, strings do no handle regular expression syntax, the
|
296
|
+
string is matched verbatim:
|
296
297
|
|
297
298
|
"\\d+(/\\w+)?" # matches "/\d+(/\w+)?"
|
298
299
|
"\\d+(/\\w+)?" # does not match "/123/abc"
|
@@ -499,12 +500,14 @@ you can use the module_include plugin.
|
|
499
500
|
|
500
501
|
Roda tries very hard to avoid polluting the scope of the +route+ block.
|
501
502
|
This should make it unlikely that Roda will cause namespace issues
|
502
|
-
with your application code. Some of the things Roda does
|
503
|
+
with your application code. Some of the things Roda does:
|
503
504
|
|
504
505
|
- The only instance variables defined by default in the scope of the +route+ block
|
505
|
-
are <tt>@_request</tt> and <tt>@_response</tt>.
|
506
|
+
are <tt>@_request</tt> and <tt>@_response</tt>. All instance variables in the
|
507
|
+
scope of the +route+ block used by plugins that ship with Roda are prefixed
|
508
|
+
with an underscore.
|
506
509
|
- The only methods defined (beyond the default methods for +Object+) are:
|
507
|
-
+env+, +opts+, +request+, +response+,
|
510
|
+
+call+, +env+, +opts+, +request+, +response+, and +session+.
|
508
511
|
- Constants inside the Roda namespace are all prefixed with +Roda+
|
509
512
|
(e.g., <tt>Roda::RodaRequest</tt>).
|
510
513
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
= Backwards Compatibility
|
2
|
+
|
3
|
+
* RodaResponse#set_cookie and #delete_cookie have been removed.
|
4
|
+
|
5
|
+
* Roda.request_module and .response_module have been removed.
|
6
|
+
|
7
|
+
* Roda.hash_matcher has been removed.
|
8
|
+
|
9
|
+
* The :extension hash matcher has been removed.
|
10
|
+
|
11
|
+
* The :param and :param! hash matchers have been removed.
|
12
|
+
|
13
|
+
* RodaRequest#full_path_info has been removed.
|
14
|
+
|
15
|
+
* The :opts render plugin option is no longer respected, Use the
|
16
|
+
:template_opts option instead.
|
17
|
+
|
18
|
+
* Plugin option hashes for the chunked, default_headers,
|
19
|
+
error_email, and render plugins are now frozen.
|
20
|
+
|
21
|
+
* The :header hash matcher in the header_matchers plugin now
|
22
|
+
yields the header value to the block.
|
23
|
+
|
24
|
+
* Roda.json_result_classes in the json plugin is now frozen.
|
25
|
+
|
26
|
+
* The PATH_INFO and SCRIPT_NAME env variables are no longer modified
|
27
|
+
during routing.
|
28
|
+
|
29
|
+
* Roda#initialize now takes an env hash, and #call now takes the
|
30
|
+
route block. The private #_route method has been removed.
|
31
|
+
|
32
|
+
* RodaRequest#keep_remaining_path/#updating_remaining_path private
|
33
|
+
methods have been removed.
|
34
|
+
|
35
|
+
* The render plugin's :layout option is now always set to true or
|
36
|
+
false, specifying whether a layout should be used by default.
|
37
|
+
The template used for a layout is now located as the :template
|
38
|
+
option inside :layout_opts.
|
39
|
+
|
40
|
+
= New Plugins
|
41
|
+
|
42
|
+
* A padrino_render plugin has been added, which adds render/partial
|
43
|
+
methods that work similarly to Padrino's.
|
44
|
+
|
45
|
+
= Other New Features
|
46
|
+
|
47
|
+
* A Roda#render_template private method has been added to the render
|
48
|
+
plugin. All internal users of render should switch to calling
|
49
|
+
render_template.
|
50
|
+
|
51
|
+
* The halt plugin now integrates with the symbol_views and json
|
52
|
+
plugins, allowing things like:
|
53
|
+
|
54
|
+
r.halt(:template)
|
55
|
+
r.halt('key'=>'value')
|
56
|
+
|
57
|
+
= Other Improvements
|
58
|
+
|
59
|
+
* The error_handler plugin now rescues ScriptError in addition to
|
60
|
+
StandardError. This handles SyntaxError (raised by ERB),
|
61
|
+
LoadError (raised by require), and NotImplementedError (raised
|
62
|
+
by TSort).
|
63
|
+
|
64
|
+
* Using a :layout=>true option to the render plugin's view method
|
65
|
+
now uses the default layout template, instead of a template named
|
66
|
+
'true'. It can be used to force a layout even if the render
|
67
|
+
plugin has been configured to not use a layout by default.
|
68
|
+
|
69
|
+
* Roda apps that use the middleware plugin can now be used as regular
|
70
|
+
rack apps. Previously, using the middleware plugin made it
|
71
|
+
impossible to use the app as a regular rack app.
|
72
|
+
|
73
|
+
* Roda#request and #response are now faster.
|
74
|
+
|
75
|
+
* Roda avoids creating unnecessary hashes in more places now.
|
data/lib/roda/plugins/assets.rb
CHANGED
@@ -396,7 +396,7 @@ class Roda
|
|
396
396
|
def compile_assets_files(files, type, dirs)
|
397
397
|
dirs = nil if dirs && dirs.empty?
|
398
398
|
o = assets_opts
|
399
|
-
app =
|
399
|
+
app = allocate
|
400
400
|
|
401
401
|
content = files.map do |file|
|
402
402
|
file = "#{dirs.join('/')}/#{file}" if dirs && o[:group_subdirs]
|
@@ -548,7 +548,7 @@ class Roda
|
|
548
548
|
# Render the given asset file using the render plugin, with the given options.
|
549
549
|
# +file+ should be the relative path to the file from the current directory.
|
550
550
|
def render_asset_file(file, options)
|
551
|
-
|
551
|
+
render_template({:path => file}, options)
|
552
552
|
end
|
553
553
|
end
|
554
554
|
|
@@ -36,11 +36,7 @@ class Roda
|
|
36
36
|
def _match_array(arg, rest=nil)
|
37
37
|
return super unless rest
|
38
38
|
|
39
|
-
|
40
|
-
e = @env
|
41
|
-
script = e[SCRIPT_NAME]
|
42
|
-
path = e[PATH_INFO]
|
43
|
-
end
|
39
|
+
path = @remaining_path
|
44
40
|
captures = @captures
|
45
41
|
caps = captures.dup
|
46
42
|
arg.each do |v|
|
@@ -55,12 +51,7 @@ class Roda
|
|
55
51
|
|
56
52
|
# Matching all remaining elements failed, reset state
|
57
53
|
captures.replace(caps)
|
58
|
-
|
59
|
-
@remaining_path = path
|
60
|
-
else
|
61
|
-
e[SCRIPT_NAME] = script
|
62
|
-
e[PATH_INFO] = path
|
63
|
-
end
|
54
|
+
@remaining_path = path
|
64
55
|
end
|
65
56
|
end
|
66
57
|
false
|
data/lib/roda/plugins/caching.rb
CHANGED
@@ -66,6 +66,8 @@ class Roda
|
|
66
66
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
67
67
|
# OTHER DEALINGS IN THE SOFTWARE.
|
68
68
|
module Caching
|
69
|
+
OPTS = {}.freeze
|
70
|
+
|
69
71
|
module RequestMethods
|
70
72
|
LAST_MODIFIED = 'Last-Modified'.freeze
|
71
73
|
HTTP_IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze
|
@@ -118,7 +120,7 @@ class Roda
|
|
118
120
|
#
|
119
121
|
# When the current request includes an If-Match header with a
|
120
122
|
# etag that doesn't match, immediately returns a response with a 412 status.
|
121
|
-
def etag(value, opts=
|
123
|
+
def etag(value, opts=OPTS)
|
122
124
|
# Before touching this code, please double check RFC 2616 14.24 and 14.26.
|
123
125
|
weak = opts[:weak]
|
124
126
|
new_resource = opts.fetch(:new_resource){post?}
|
@@ -194,7 +196,7 @@ class Roda
|
|
194
196
|
# be an integer number of seconds that the current request should be
|
195
197
|
# cached for. Also sets the Expires header, useful if you have
|
196
198
|
# HTTP 1.0 clients (Cache-Control is an HTTP 1.1 header).
|
197
|
-
def expires(max_age, opts=
|
199
|
+
def expires(max_age, opts=OPTS)
|
198
200
|
cache_control(opts.merge(:max_age=>max_age))
|
199
201
|
self[EXPIRES] = (Time.now + max_age).httpdate
|
200
202
|
end
|
data/lib/roda/plugins/chunked.rb
CHANGED
@@ -142,8 +142,7 @@ class Roda
|
|
142
142
|
def self.configure(app, opts=OPTS)
|
143
143
|
app.opts[:chunk_by_default] = opts[:chunk_by_default]
|
144
144
|
if opts[:headers]
|
145
|
-
app.opts[:chunk_headers] = (app.opts[:chunk_headers] || {}).merge(opts[:headers])
|
146
|
-
app.opts[:chunk_headers].extend(RodaDeprecateMutation)
|
145
|
+
app.opts[:chunk_headers] = (app.opts[:chunk_headers] || {}).merge(opts[:headers]).freeze
|
147
146
|
end
|
148
147
|
end
|
149
148
|
|
@@ -241,15 +240,11 @@ class Roda
|
|
241
240
|
@_out_buf = ''
|
242
241
|
end
|
243
242
|
|
244
|
-
if
|
245
|
-
|
246
|
-
layout_opts = render_opts[:layout_opts].merge(layout_opts)
|
247
|
-
end
|
248
|
-
|
249
|
-
@_out_buf = render(layout, layout_opts||OPTS) do
|
243
|
+
if layout_opts = view_layout_opts(opts)
|
244
|
+
@_out_buf = render_template(layout_opts) do
|
250
245
|
flush
|
251
246
|
block.call if block
|
252
|
-
yield opts[:content] ||
|
247
|
+
yield opts[:content] || render_template(template, opts)
|
253
248
|
nil
|
254
249
|
end
|
255
250
|
else
|
@@ -70,11 +70,9 @@ class Roda
|
|
70
70
|
end
|
71
71
|
|
72
72
|
module InstanceMethods
|
73
|
-
private
|
74
|
-
|
75
73
|
# If the normal routing tree doesn't handle an action, try each class level route
|
76
74
|
# to see if it matches.
|
77
|
-
def
|
75
|
+
def call
|
78
76
|
result = super
|
79
77
|
|
80
78
|
if result[0] == 404 && (v = result[2]).is_a?(Array) && v.empty?
|
@@ -20,8 +20,7 @@ class Roda
|
|
20
20
|
module DefaultHeaders
|
21
21
|
# Merge the given headers into the existing default headers, if any.
|
22
22
|
def self.configure(app, headers={})
|
23
|
-
app.opts[:default_headers] = (app.opts[:default_headers] || {}).merge(headers)
|
24
|
-
app.opts[:default_headers].extend(RodaDeprecateMutation)
|
23
|
+
app.opts[:default_headers] = (app.opts[:default_headers] || {}).merge(headers).freeze
|
25
24
|
end
|
26
25
|
|
27
26
|
module ClassMethods
|
@@ -28,6 +28,7 @@ class Roda
|
|
28
28
|
# for low traffic web applications. For high traffic web applications,
|
29
29
|
# use an error reporting service instead of this plugin.
|
30
30
|
module ErrorEmail
|
31
|
+
OPTS = {}.freeze
|
31
32
|
DEFAULTS = {
|
32
33
|
:headers=>{},
|
33
34
|
:host=>'localhost',
|
@@ -74,7 +75,7 @@ END
|
|
74
75
|
}
|
75
76
|
|
76
77
|
# Set default opts for plugin. See ErrorEmail module RDoc for options.
|
77
|
-
def self.configure(app, opts=
|
78
|
+
def self.configure(app, opts=OPTS)
|
78
79
|
email_opts = app.opts[:error_email] ||= DEFAULTS
|
79
80
|
email_opts = email_opts.merge(opts)
|
80
81
|
email_opts[:headers] = email_opts[:headers].dup
|
@@ -82,19 +83,8 @@ END
|
|
82
83
|
raise RodaError, "must provide :to and :from options to error_email plugin"
|
83
84
|
end
|
84
85
|
app.opts[:error_email] = email_opts
|
85
|
-
app.opts[:error_email].
|
86
|
-
app.opts[:error_email]
|
87
|
-
end
|
88
|
-
|
89
|
-
module ClassMethods
|
90
|
-
# Dup the error email opts in the subclass so changes to the subclass do not affect
|
91
|
-
# the superclass.
|
92
|
-
def inherited(subclass)
|
93
|
-
super
|
94
|
-
opts = subclass.opts[:error_email].dup
|
95
|
-
opts[:headers] = opts[:headers].dup.extend(RodaDeprecateMutation)
|
96
|
-
subclass.opts[:error_email] = opts.extend(RodaDeprecateMutation)
|
97
|
-
end
|
86
|
+
app.opts[:error_email][:headers].freeze
|
87
|
+
app.opts[:error_email].freeze
|
98
88
|
end
|
99
89
|
|
100
90
|
module InstanceMethods
|
@@ -46,18 +46,18 @@ class Roda
|
|
46
46
|
end
|
47
47
|
|
48
48
|
module InstanceMethods
|
49
|
-
private
|
50
|
-
|
51
49
|
# If an error occurs, set the response status to 500 and call
|
52
50
|
# the error handler.
|
53
|
-
def
|
51
|
+
def call
|
54
52
|
super
|
55
|
-
rescue => e
|
53
|
+
rescue StandardError, ScriptError => e
|
56
54
|
res = @_response = self.class::RodaResponse.new
|
57
55
|
res.status = 500
|
58
56
|
super{handle_error(e)}
|
59
57
|
end
|
60
58
|
|
59
|
+
private
|
60
|
+
|
61
61
|
# By default, have the error handler reraise the error, so using
|
62
62
|
# the plugin without installing an error handler doesn't change
|
63
63
|
# behavior.
|
data/lib/roda/plugins/flash.rb
CHANGED
@@ -87,11 +87,9 @@ class Roda
|
|
87
87
|
@_flash ||= FlashHash.new(session[KEY])
|
88
88
|
end
|
89
89
|
|
90
|
-
private
|
91
|
-
|
92
90
|
# If the routing doesn't raise an error, rotate the flash
|
93
91
|
# hash in the session so the next request has access to it.
|
94
|
-
def
|
92
|
+
def call
|
95
93
|
res = super
|
96
94
|
|
97
95
|
if f = @_flash
|
data/lib/roda/plugins/halt.rb
CHANGED
@@ -35,6 +35,23 @@ class Roda
|
|
35
35
|
# arguments and providing them as a single rack response array. With a rack response array,
|
36
36
|
# the values are used directly, while with 3 arguments, the headers given are merged into
|
37
37
|
# the existing headers and the given body is written to the existing response body.
|
38
|
+
#
|
39
|
+
# If using other plugins that recognize additional types of match block responses, such
|
40
|
+
# as +symbol_views+ and +json+, you can pass those additional types to +r.halt+:
|
41
|
+
#
|
42
|
+
# plugin :halt
|
43
|
+
# plugin :symbol_views
|
44
|
+
# plugin :json
|
45
|
+
# route do |r|
|
46
|
+
# r.halt(:template)
|
47
|
+
# r.halt(500, [{'error'=>'foo'}])
|
48
|
+
# r.halt(500, 'header=>'value', :other_template)
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# Note that when using the +json+ plugin with the +halt+ plugin, you cannot return a
|
52
|
+
# array as a single argument and have it be converted to json, since it would be interpreted
|
53
|
+
# as a rack response. You must use call +r.halt+ with either two or three argument forms
|
54
|
+
# in that case.
|
38
55
|
module Halt
|
39
56
|
module RequestMethods
|
40
57
|
# Expand default halt method to handle status codes, headers, and bodies. See Halt.
|
@@ -45,22 +62,24 @@ class Roda
|
|
45
62
|
case v = res[0]
|
46
63
|
when Integer
|
47
64
|
response.status = v
|
48
|
-
when String
|
49
|
-
response.write v
|
50
65
|
when Array
|
51
66
|
throw :halt, v
|
52
67
|
else
|
53
|
-
|
68
|
+
if result = block_result_body(v)
|
69
|
+
response.write(result)
|
70
|
+
else
|
71
|
+
raise Roda::RodaError, "singular argument given to #halt not handled: #{v.inspect}"
|
72
|
+
end
|
54
73
|
end
|
55
74
|
when 2
|
56
75
|
resp = response
|
57
76
|
resp.status = res[0]
|
58
|
-
resp.write
|
77
|
+
resp.write(block_result_body(res[1]))
|
59
78
|
when 3
|
60
79
|
resp = response
|
61
80
|
resp.status = res[0]
|
62
81
|
resp.headers.merge!(res[1])
|
63
|
-
resp.write
|
82
|
+
resp.write(block_result_body(res[2]))
|
64
83
|
else
|
65
84
|
raise Roda::RodaError, "too many arguments given to #halt (accepts 0-3, received #{res.length})"
|
66
85
|
end
|
@@ -8,7 +8,7 @@ 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
|
-
# r.on :header=>'X-App-Token' do
|
11
|
+
# r.on :header=>'X-App-Token' do |header_value|
|
12
12
|
# end
|
13
13
|
#
|
14
14
|
# It adds a +:host+ matcher for matching by the host of the request:
|
@@ -45,13 +45,8 @@ class Roda
|
|
45
45
|
# Match if the given uppercase key is present inside the environment.
|
46
46
|
def match_header(key)
|
47
47
|
if v = @env[key.upcase.tr("-","_")]
|
48
|
-
|
49
|
-
@captures << v
|
50
|
-
else
|
51
|
-
RodaPlugins.deprecate("The :header hash matcher will yield the header value in Roda 2. To turn on the Roda 2 behavior, set opts[:match_header_yield] to true for your Roda class.")
|
52
|
-
end
|
48
|
+
@captures << v
|
53
49
|
end
|
54
|
-
v
|
55
50
|
end
|
56
51
|
|
57
52
|
# Match if the host of the request is the same as the hostname. +hostname+
|
data/lib/roda/plugins/hooks.rb
CHANGED
@@ -67,11 +67,9 @@ class Roda
|
|
67
67
|
end
|
68
68
|
|
69
69
|
module InstanceMethods
|
70
|
-
private
|
71
|
-
|
72
70
|
# Before routing, execute the before hooks, and
|
73
71
|
# execute the after hooks before returning.
|
74
|
-
def
|
72
|
+
def call
|
75
73
|
if b = opts[:before_hook]
|
76
74
|
instance_exec(&b)
|
77
75
|
end
|
data/lib/roda/plugins/json.rb
CHANGED
@@ -33,13 +33,15 @@ class Roda
|
|
33
33
|
#
|
34
34
|
# plugin :json, :classes=>[Array, Hash, Sequel::Model]
|
35
35
|
module Json
|
36
|
+
OPTS = {}.freeze
|
37
|
+
|
36
38
|
# Set the classes to automatically convert to JSON
|
37
|
-
def self.configure(app, opts=
|
39
|
+
def self.configure(app, opts=OPTS)
|
38
40
|
classes = opts[:classes] || [Array, Hash]
|
39
41
|
app.opts[:json_result_classes] ||= []
|
40
42
|
app.opts[:json_result_classes] += classes
|
41
43
|
app.opts[:json_result_classes].uniq!
|
42
|
-
app.opts[:json_result_classes].
|
44
|
+
app.opts[:json_result_classes].freeze
|
43
45
|
end
|
44
46
|
|
45
47
|
module ClassMethods
|
data/lib/roda/plugins/mailer.rb
CHANGED
@@ -74,7 +74,7 @@ class Roda
|
|
74
74
|
# end
|
75
75
|
# end
|
76
76
|
#
|
77
|
-
# When sending a mail via +mail+ or +sendmail+,
|
77
|
+
# When sending a mail via +mail+ or +sendmail+, a RodaError will be raised
|
78
78
|
# if the mail object does not have a body. This is similar to the 404
|
79
79
|
# status that Roda uses by default for web requests that don't have
|
80
80
|
# a body. If you want to specifically send an email with an empty body, you
|
@@ -110,6 +110,7 @@ class Roda
|
|
110
110
|
MAIL = "MAIL".freeze
|
111
111
|
CONTENT_TYPE = 'Content-Type'.freeze
|
112
112
|
TEXT_PLAIN = "text/plain".freeze
|
113
|
+
OPTS = {}.freeze
|
113
114
|
|
114
115
|
# Error raised when the using the mail class method, but the routing
|
115
116
|
# tree doesn't return the mail object.
|
@@ -117,7 +118,7 @@ class Roda
|
|
117
118
|
|
118
119
|
# Set the options for the mailer. Options:
|
119
120
|
# :content_type :: The default content type for emails (default: text/plain)
|
120
|
-
def self.configure(app, opts=
|
121
|
+
def self.configure(app, opts=OPTS)
|
121
122
|
app.opts[:mailer] = (app.opts[:mailer]||{}).merge(opts).freeze
|
122
123
|
end
|
123
124
|
|
@@ -127,7 +128,7 @@ class Roda
|
|
127
128
|
# calling +deliver+ to send the mail.
|
128
129
|
def mail(path, *args)
|
129
130
|
mail = ::Mail.new
|
130
|
-
unless mail.equal?(
|
131
|
+
unless mail.equal?(new(PATH_INFO=>path, SCRIPT_NAME=>EMPTY_STRING, REQUEST_METHOD=>MAIL, RACK_INPUT=>StringIO.new, RODA_MAIL=>mail, RODA_MAIL_ARGS=>args).call(&route_block))
|
131
132
|
raise Error, "route did not return mail instance for #{path.inspect}, #{args.inspect}"
|
132
133
|
end
|
133
134
|
mail
|
@@ -203,19 +204,19 @@ class Roda
|
|
203
204
|
end
|
204
205
|
end
|
205
206
|
|
206
|
-
private
|
207
|
-
|
208
207
|
# If this is an email request, set the mail object in the response, as well
|
209
208
|
# as the default content_type for the email.
|
210
|
-
def
|
209
|
+
def initialize(env)
|
210
|
+
super
|
211
211
|
if mail = env[RODA_MAIL]
|
212
212
|
res = @_response
|
213
213
|
res.mail = mail
|
214
214
|
res.headers.delete(CONTENT_TYPE)
|
215
215
|
end
|
216
|
-
super
|
217
216
|
end
|
218
217
|
|
218
|
+
private
|
219
|
+
|
219
220
|
# Set the text_part or html_part (depending on the method) in the related email,
|
220
221
|
# using the given body and optional headers.
|
221
222
|
def _mail_part(meth, body, headers=nil)
|
@@ -30,15 +30,14 @@ class Roda
|
|
30
30
|
#
|
31
31
|
# run App
|
32
32
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# use it as a regular app.
|
33
|
+
# It is possible to use the Roda app as a regular app even when using
|
34
|
+
# the middleware plugin.
|
36
35
|
module Middleware
|
37
36
|
# Forward instances are what is actually used as middleware.
|
38
37
|
class Forwarder
|
39
38
|
# Store the current middleware and the next middleware to call.
|
40
39
|
def initialize(mid, app)
|
41
|
-
@mid = mid
|
40
|
+
@mid = mid
|
42
41
|
@app = app
|
43
42
|
end
|
44
43
|
|
@@ -49,7 +48,9 @@ class Roda
|
|
49
48
|
res = nil
|
50
49
|
|
51
50
|
call_next = catch(:next) do
|
52
|
-
|
51
|
+
scope = @mid.new(env)
|
52
|
+
scope.request.forward_next = true
|
53
|
+
res = scope.call(&@mid.route_block)
|
53
54
|
false
|
54
55
|
end
|
55
56
|
|
@@ -62,20 +63,31 @@ class Roda
|
|
62
63
|
end
|
63
64
|
|
64
65
|
module ClassMethods
|
65
|
-
# Create a Forwarder instead of a new instance.
|
66
|
+
# Create a Forwarder instead of a new instance if a non-Hash is given.
|
66
67
|
def new(app)
|
67
|
-
|
68
|
+
if app.is_a?(Hash)
|
69
|
+
super
|
70
|
+
else
|
71
|
+
Forwarder.new(self, app)
|
72
|
+
end
|
68
73
|
end
|
69
74
|
|
70
75
|
# Override the route block so that if no route matches, we throw so
|
71
76
|
# that the next middleware is called.
|
72
77
|
def route(&block)
|
73
78
|
super do |r|
|
74
|
-
instance_exec(r, &block)
|
75
|
-
throw :next, true
|
79
|
+
res = instance_exec(r, &block)
|
80
|
+
throw :next, true if r.forward_next
|
81
|
+
res
|
76
82
|
end
|
77
83
|
end
|
78
84
|
end
|
85
|
+
|
86
|
+
module RequestMethods
|
87
|
+
# Whether to forward the request to the next application. Set only if
|
88
|
+
# this request is being performed for middleware.
|
89
|
+
attr_accessor :forward_next
|
90
|
+
end
|
79
91
|
end
|
80
92
|
|
81
93
|
register_plugin(:middleware, Middleware)
|
@@ -40,11 +40,9 @@ class Roda
|
|
40
40
|
end
|
41
41
|
|
42
42
|
module InstanceMethods
|
43
|
-
private
|
44
|
-
|
45
43
|
# If routing returns a 404 response with an empty body, call
|
46
44
|
# the not_found handler.
|
47
|
-
def
|
45
|
+
def call
|
48
46
|
result = super
|
49
47
|
|
50
48
|
if result[0] == 404 && (v = result[2]).is_a?(Array) && v.empty?
|
@@ -55,6 +53,8 @@ class Roda
|
|
55
53
|
end
|
56
54
|
end
|
57
55
|
|
56
|
+
private
|
57
|
+
|
58
58
|
# Use an empty not_found_handler by default, so that loading
|
59
59
|
# the plugin without defining a not_found handler doesn't
|
60
60
|
# break things.
|