roda 3.36.0 → 3.41.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 +32 -0
- data/MIT-LICENSE +1 -1
- data/doc/release_notes/3.3.0.txt +1 -1
- data/doc/release_notes/3.37.0.txt +42 -0
- data/doc/release_notes/3.38.0.txt +5 -0
- data/doc/release_notes/3.39.0.txt +16 -0
- data/doc/release_notes/3.40.0.txt +24 -0
- data/doc/release_notes/3.41.0.txt +9 -0
- data/lib/roda.rb +6 -0
- data/lib/roda/cache.rb +7 -0
- data/lib/roda/plugins/custom_matchers.rb +87 -0
- data/lib/roda/plugins/default_headers.rb +1 -0
- data/lib/roda/plugins/error_email.rb +9 -2
- data/lib/roda/plugins/error_mail.rb +9 -2
- data/lib/roda/plugins/mail_processor.rb +2 -0
- data/lib/roda/plugins/precompile_templates.rb +96 -21
- data/lib/roda/plugins/relative_path.rb +4 -3
- data/lib/roda/plugins/render.rb +81 -15
- data/lib/roda/plugins/render_locals.rb +4 -0
- data/lib/roda/plugins/type_routing.rb +1 -0
- data/lib/roda/plugins/typecast_params.rb +4 -5
- data/lib/roda/version.rb +1 -1
- metadata +22 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f09e850b5f4ee0406c5686317145571fa0bc5e8158b0b39c5161bb9a3cbb3878
|
4
|
+
data.tar.gz: d839bbfa3ff4e7ef4a37501a46ce65c12425dc620ccbdf9aae174a059898aa84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dee1ec11e6ca9ca18f74fedf260f10e25e9c49efa3297ca2df02aab02efa6282464dd88f0f1f79e3529c8c56239749c72779d8bfb7fbf8508b40047470e4f6f6
|
7
|
+
data.tar.gz: c7b4d4e1d4cdf7f60707621a57cfdd6a622ef91f6d6724abd1b344fc18b59ab4271ee7536513417023c20c3f470cac73c94ff50675661162d6ec1e62df02cd70
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,35 @@
|
|
1
|
+
= 3.41.0 (2021-02-17)
|
2
|
+
|
3
|
+
* Improve view performance with :content option up to 3x by calling compiled template methods directly (jeremyevans)
|
4
|
+
|
5
|
+
= 3.40.0 (2021-01-14)
|
6
|
+
|
7
|
+
* Add freeze_template_caches! to the precompile_templates plugin, which ensures all templates are precompiled, and speeds up template access (jeremyevans)
|
8
|
+
|
9
|
+
* Add precompile_views to the precompile_templates plugin, which precompiles the optimized render methods (jeremyevans)
|
10
|
+
|
11
|
+
* Have RodaCache#freeze return the frozen internal hash (which no longer needs a mutex for thread-safety) (jeremyevans)
|
12
|
+
|
13
|
+
* Speed up the view method in the render plugin even more when freezing the application (jeremyevans)
|
14
|
+
|
15
|
+
* Speed up the view method in the render plugin when called with a single argument (jeremyevans)
|
16
|
+
|
17
|
+
= 3.39.0 (2020-12-15)
|
18
|
+
|
19
|
+
* Speed up relative_path plugin if relative_path or relative_prefix is called more than once (jeremyevans)
|
20
|
+
|
21
|
+
* Avoid method redefinition warnings in verbose warning mode (jeremyevans)
|
22
|
+
|
23
|
+
* Make typecast_params.convert! handle explicit nil values the same as missing values (jeremyevans)
|
24
|
+
|
25
|
+
= 3.38.0 (2020-11-16)
|
26
|
+
|
27
|
+
* Make error_email and error_mail plugins rescue invalid parameter errors when preparing the email body (jeremyevans)
|
28
|
+
|
29
|
+
= 3.37.0 (2020-10-16)
|
30
|
+
|
31
|
+
* Add custom_matchers plugin, for supporting arbitrary objects as matchers (jeremyevans)
|
32
|
+
|
1
33
|
= 3.36.0 (2020-09-14)
|
2
34
|
|
3
35
|
* Add multi_public plugin, for serving files from multiple public directories (jeremyevans)
|
data/MIT-LICENSE
CHANGED
data/doc/release_notes/3.3.0.txt
CHANGED
@@ -248,7 +248,7 @@
|
|
248
248
|
Note that if there are multiple conversion errors raised inside a
|
249
249
|
convert! or convert_each! block, they are recorded and a single
|
250
250
|
Roda::RodaPlugins::TypecastParams::Error instance is raised after
|
251
|
-
processing the block. TypecastParams::Error#
|
251
|
+
processing the block. TypecastParams::Error#param_names can be
|
252
252
|
called on the exception to get an array of all parameter names
|
253
253
|
with conversion issues, and TypecastParams::Error#all_errors
|
254
254
|
can be used to get an array of all Error instances.
|
@@ -0,0 +1,42 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A custom_matchers plugin has been added, which allows using
|
4
|
+
arbitrary objects as matchers, as long as the matcher has been
|
5
|
+
registered. You can register matchers using the custom_matcher
|
6
|
+
class method, which takes the class of the matcher, and a block
|
7
|
+
which is yielded the matcher object. The block should return
|
8
|
+
nil or false if the matcher doesn't match, and any other value
|
9
|
+
if the matcher does match. Example:
|
10
|
+
|
11
|
+
plugin :custom_matchers
|
12
|
+
method_segment = Struct.new(:request_method, :next_segment)
|
13
|
+
custom_matcher(method_segment) do |matcher|
|
14
|
+
# self is the request instance ("r" yielded in the route block below)
|
15
|
+
if matcher.request_method == self.request_method
|
16
|
+
match(matcher.next_segment)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
get_foo = method_segment.new('GET', 'foo')
|
21
|
+
post_any = method_segment.new('POST', String)
|
22
|
+
route do |r|
|
23
|
+
r.on('baz') do
|
24
|
+
r.on(get_foo) do
|
25
|
+
# GET method, /baz/foo prefix
|
26
|
+
end
|
27
|
+
|
28
|
+
r.is(post_any) do |seg|
|
29
|
+
# for POST /baz/bar, seg is "bar"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
r.on('quux') do
|
34
|
+
r.is(get_foo) do
|
35
|
+
# GET method, /quux/foo route
|
36
|
+
end
|
37
|
+
|
38
|
+
r.on(post_any) do |seg|
|
39
|
+
# for POST /quux/xyz, seg is "xyz"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The relative_path plugin is now faster if you are calling
|
4
|
+
relative_path or relative_prefix more than once when handling a
|
5
|
+
request.
|
6
|
+
|
7
|
+
* The typecast_params.convert! method in the typecast_params plugin
|
8
|
+
now handles explicit nil values the same as missing values.
|
9
|
+
Explicit nil values do not generally occur in normal Rack parameter
|
10
|
+
parsing, but they can occur when using the json_parser plugin to
|
11
|
+
parse JSON requests.
|
12
|
+
|
13
|
+
* Roda now avoids method redefinition warnings in verbose mode by
|
14
|
+
using a self alias. As Ruby 3 is dropping uninitialized instance
|
15
|
+
variable warnings, Roda will be verbose warning free if you are
|
16
|
+
using Ruby 3.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A precompile_views method has been added to the
|
4
|
+
precompile_templates plugin. This method works with Roda's
|
5
|
+
optimized compiled view methods, allowing additional memory
|
6
|
+
sharing between parent and child processes.
|
7
|
+
|
8
|
+
* A freeze_template_caches! method has been added to the
|
9
|
+
precompile_templates plugin. This freezes the template caches,
|
10
|
+
preventing the compilation of additional templates, useful for
|
11
|
+
enforcing that only precompiled templates are used. Additionally,
|
12
|
+
this speeds up access to the template caches.
|
13
|
+
|
14
|
+
* RodaCache#freeze now returns the frozen internal hash, which can
|
15
|
+
then be accessed without a mutex. Previously, freeze only froze
|
16
|
+
the receiver and not the internal hash, so it didn't have the
|
17
|
+
expected effect.
|
18
|
+
|
19
|
+
= Other Improvements
|
20
|
+
|
21
|
+
* The view method in the render plugin is now faster in most cases
|
22
|
+
when a single argument is used. When freezing the application,
|
23
|
+
an additional optimization is performed to increase the
|
24
|
+
performance of the view method even further.
|
@@ -0,0 +1,9 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The performance of the render plugin's view method when passed the
|
4
|
+
:content option and no other options or arguments has been improved
|
5
|
+
by about 3x, by calling compiled template methods directly.
|
6
|
+
|
7
|
+
* The compiled template method for the layout is cleared when the
|
8
|
+
render plugin is loaded again, which can fix issues when it is
|
9
|
+
loaded with different options that affect the layout.
|
data/lib/roda.rb
CHANGED
@@ -114,6 +114,7 @@ class Roda
|
|
114
114
|
alias_method meth, temp_method
|
115
115
|
undef_method temp_method
|
116
116
|
private meth
|
117
|
+
alias_method meth, meth
|
117
118
|
meth = :"#{meth}_arity"
|
118
119
|
elsif required_args > 1
|
119
120
|
b = block
|
@@ -144,6 +145,7 @@ class Roda
|
|
144
145
|
|
145
146
|
define_method(meth, &block)
|
146
147
|
private meth
|
148
|
+
alias_method meth, meth
|
147
149
|
|
148
150
|
if arity_meth
|
149
151
|
required_args, optional_args, rest, keyword = _define_roda_method_arg_numbers(instance_method(meth))
|
@@ -167,6 +169,7 @@ class Roda
|
|
167
169
|
send(meth, *a)
|
168
170
|
end
|
169
171
|
private arity_meth
|
172
|
+
alias_method arity_meth, arity_meth
|
170
173
|
end
|
171
174
|
|
172
175
|
call_meth
|
@@ -199,6 +202,7 @@ class Roda
|
|
199
202
|
|
200
203
|
private
|
201
204
|
|
205
|
+
alias set_default_headers set_default_headers
|
202
206
|
def set_default_headers
|
203
207
|
@headers['Content-Type'] ||= 'text/html'
|
204
208
|
end
|
@@ -403,6 +407,7 @@ class Roda
|
|
403
407
|
class_eval("def _roda_before; #{meths.join(';')} end", __FILE__, __LINE__)
|
404
408
|
end
|
405
409
|
private :_roda_before
|
410
|
+
alias_method :_roda_before, :_roda_before
|
406
411
|
end
|
407
412
|
end
|
408
413
|
|
@@ -419,6 +424,7 @@ class Roda
|
|
419
424
|
class_eval("def _roda_after(res); #{meths.map{|s| "#{s}(res)"}.join(';')} end", __FILE__, __LINE__)
|
420
425
|
end
|
421
426
|
private :_roda_after
|
427
|
+
alias_method :_roda_after, :_roda_after
|
422
428
|
end
|
423
429
|
end
|
424
430
|
|
data/lib/roda/cache.rb
CHANGED
@@ -22,6 +22,13 @@ class Roda
|
|
22
22
|
@mutex.synchronize{@hash[key] = value}
|
23
23
|
end
|
24
24
|
|
25
|
+
# Return the frozen internal hash. The internal hash can then
|
26
|
+
# be accessed directly since it is frozen and there are no
|
27
|
+
# thread safety issues.
|
28
|
+
def freeze
|
29
|
+
@hash.freeze
|
30
|
+
end
|
31
|
+
|
25
32
|
private
|
26
33
|
|
27
34
|
# Create a copy of the cache with a separate mutex.
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The custom_matchers plugin supports using arbitrary objects
|
7
|
+
# as matchers, as long as the application has been configured
|
8
|
+
# to accept such objects.
|
9
|
+
#
|
10
|
+
# After loading the plugin, support for custom matchers can be
|
11
|
+
# configured using the +custom_matcher+ class method. This
|
12
|
+
# method is generally passed the class of the object you want
|
13
|
+
# to use as a custom matcher, as well as a block. The block
|
14
|
+
# will be called in the context of the request instance
|
15
|
+
# with the specific matcher used in the match method.
|
16
|
+
#
|
17
|
+
# Blocks can append to the captures in order to yield the appropriate
|
18
|
+
# values to match blocks, or call request methods that append to the
|
19
|
+
# captures.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
#
|
23
|
+
# plugin :custom_matchers
|
24
|
+
# method_segment = Struct.new(:request_method, :next_segment)
|
25
|
+
# custom_matcher(method_segment) do |matcher|
|
26
|
+
# # self is the request instance ("r" yielded in the route block below)
|
27
|
+
# if matcher.request_method == self.request_method
|
28
|
+
# match(matcher.next_segment)
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# get_foo = method_segment.new('GET', 'foo')
|
33
|
+
# post_any = method_segment.new('POST', String)
|
34
|
+
# route do |r|
|
35
|
+
# r.on('baz') do
|
36
|
+
# r.on(get_foo) do
|
37
|
+
# # GET method, /baz/foo prefix
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# r.is(post_any) do |seg|
|
41
|
+
# # for POST /baz/bar, seg is "bar"
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# r.on('quux') do
|
46
|
+
# r.is(get_foo) do
|
47
|
+
# # GET method, /quux/foo route
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# r.on(post_any) do |seg|
|
51
|
+
# # for POST /quux/xyz, seg is "xyz"
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
module CustomMatchers
|
56
|
+
def self.configure(app)
|
57
|
+
app.opts[:custom_matchers] ||= OPTS
|
58
|
+
end
|
59
|
+
|
60
|
+
module ClassMethods
|
61
|
+
def custom_matcher(match_class, &block)
|
62
|
+
custom_matchers = Hash[opts[:custom_matchers]]
|
63
|
+
meth = custom_matchers[match_class] = custom_matchers[match_class] || :"_custom_matcher_#{match_class}"
|
64
|
+
opts[:custom_matchers] = custom_matchers.freeze
|
65
|
+
self::RodaRequest.send(:define_method, meth, &block)
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module RequestMethods
|
71
|
+
# Try custom matchers before calling super
|
72
|
+
def unsupported_matcher(matcher)
|
73
|
+
roda_class.opts[:custom_matchers].each do |match_class, meth|
|
74
|
+
if match_class === matcher
|
75
|
+
return send(meth, matcher)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
register_plugin(:custom_matchers, CustomMatchers)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
@@ -54,6 +54,13 @@ class Roda
|
|
54
54
|
:body=>lambda do |s, e|
|
55
55
|
format = lambda{|h| h.map{|k, v| "#{k.inspect} => #{v.inspect}"}.sort.join("\n")}
|
56
56
|
|
57
|
+
begin
|
58
|
+
params = s.request.params
|
59
|
+
params = (format[params] unless params.empty?)
|
60
|
+
rescue
|
61
|
+
params = 'Invalid Parameters!'
|
62
|
+
end
|
63
|
+
|
57
64
|
message = String.new
|
58
65
|
message << <<END
|
59
66
|
Path: #{s.request.path}
|
@@ -73,12 +80,12 @@ ENV:
|
|
73
80
|
#{format[s.env]}
|
74
81
|
END
|
75
82
|
|
76
|
-
|
83
|
+
if params
|
77
84
|
message << <<END
|
78
85
|
|
79
86
|
Params:
|
80
87
|
|
81
|
-
#{
|
88
|
+
#{params}
|
82
89
|
END
|
83
90
|
end
|
84
91
|
|
@@ -71,6 +71,13 @@ class Roda
|
|
71
71
|
|
72
72
|
format = lambda{|h| h.map{|k, v| "#{k.inspect} => #{v.inspect}"}.sort.join("\n")}
|
73
73
|
|
74
|
+
begin
|
75
|
+
params = request.params
|
76
|
+
params = (format[params] unless params.empty?)
|
77
|
+
rescue
|
78
|
+
params = 'Invalid Parameters!'
|
79
|
+
end
|
80
|
+
|
74
81
|
message = String.new
|
75
82
|
message << <<END
|
76
83
|
Path: #{request.path}
|
@@ -91,12 +98,12 @@ ENV:
|
|
91
98
|
#{format[env]}
|
92
99
|
END
|
93
100
|
|
94
|
-
|
101
|
+
if params
|
95
102
|
message << <<END
|
96
103
|
|
97
104
|
Params:
|
98
105
|
|
99
|
-
#{
|
106
|
+
#{params}
|
100
107
|
END
|
101
108
|
end
|
102
109
|
|
@@ -13,32 +13,33 @@ class Roda
|
|
13
13
|
# all of the child processes can use the same precompiled templates, which
|
14
14
|
# saves memory.
|
15
15
|
#
|
16
|
-
#
|
17
|
-
# the
|
16
|
+
# Another advantage of the precompile_templates plugin is that after
|
17
|
+
# template precompilation, access to the template file in the file system is
|
18
|
+
# no longer needed, so this can be used with security features that do not
|
19
|
+
# allow access to the template files at runtime.
|
20
|
+
#
|
21
|
+
# After loading the plugin, you should call precompile_views with an array
|
22
|
+
# of views to compile, using the same argument you are passing to view or
|
23
|
+
# render:
|
18
24
|
#
|
19
25
|
# plugin :precompile_templates
|
20
|
-
#
|
26
|
+
# precompile_views %w'view1 view2'
|
27
|
+
#
|
28
|
+
# If the view requires local variables, you should call precompile_views with a second
|
29
|
+
# argument for the local variables:
|
21
30
|
#
|
22
|
-
#
|
23
|
-
#
|
31
|
+
# plugin :precompile_templates
|
32
|
+
# precompile_views :view3, [:local_var1, :local_var2]
|
24
33
|
#
|
25
|
-
#
|
26
|
-
#
|
34
|
+
# After all templates are precompiled, you can optionally use freeze_template_caches!,
|
35
|
+
# which will freeze the template caches so that any template compilation at runtime
|
36
|
+
# will result in an error. This also speeds up template cache access, since the
|
37
|
+
# template caches no longer need a mutex.
|
27
38
|
#
|
28
|
-
#
|
39
|
+
# freeze_template_caches!
|
29
40
|
#
|
30
41
|
# Note that you should use Tilt 2.0.1+ if you are using this plugin, so
|
31
42
|
# that locals are handled in the same order.
|
32
|
-
#
|
33
|
-
# You can specify other render options when calling +precompile_templates+,
|
34
|
-
# including +:cache_key+, +:template_class+, and +:template_opts+. If you
|
35
|
-
# are passing any of those options to render/view for the template, you
|
36
|
-
# should pass the same options when precompiling the template.
|
37
|
-
#
|
38
|
-
# To compile inline templates, just pass a single hash containing an :inline
|
39
|
-
# to +precompile_templates+:
|
40
|
-
#
|
41
|
-
# precompile_templates inline: some_template_string
|
42
43
|
module PrecompileTemplates
|
43
44
|
# Load the render plugin as precompile_templates depends on it.
|
44
45
|
def self.load_dependencies(app, opts=OPTS)
|
@@ -46,8 +47,49 @@ class Roda
|
|
46
47
|
end
|
47
48
|
|
48
49
|
module ClassMethods
|
49
|
-
#
|
50
|
-
#
|
50
|
+
# Freeze the template caches. Should be called after precompiling all templates during
|
51
|
+
# application startup, if you don't want to allow templates to be cached at runtime.
|
52
|
+
# In addition to ensuring that no templates are compiled at runtime, this also speeds
|
53
|
+
# up rendering by freezing the template caches, so that a mutex is not needed to access
|
54
|
+
# them.
|
55
|
+
def freeze_template_caches!
|
56
|
+
_freeze_layout_method
|
57
|
+
|
58
|
+
opts[:render] = render_opts.merge(
|
59
|
+
:cache=>render_opts[:cache].freeze,
|
60
|
+
:template_method_cache=>render_opts[:template_method_cache].freeze,
|
61
|
+
).freeze
|
62
|
+
self::RodaCompiledTemplates.freeze
|
63
|
+
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
# Precompile the templates using the given options. Note that this doesn't
|
68
|
+
# handle optimized template methods supported in newer versions of Roda, but
|
69
|
+
# there are still cases where makes sense to use it.
|
70
|
+
#
|
71
|
+
# You can call +precompile_templates+ with the pattern of templates you would
|
72
|
+
# like to precompile:
|
73
|
+
#
|
74
|
+
# precompile_templates "views/**/*.erb"
|
75
|
+
#
|
76
|
+
# That will precompile all erb template files in the views directory or
|
77
|
+
# any subdirectory.
|
78
|
+
#
|
79
|
+
# If the templates use local variables, you need to specify which local
|
80
|
+
# variables to precompile, which should be an array of symbols:
|
81
|
+
#
|
82
|
+
# precompile_templates 'views/users/_*.erb', locals: [:user]
|
83
|
+
#
|
84
|
+
# You can specify other render options when calling +precompile_templates+,
|
85
|
+
# including +:cache_key+, +:template_class+, and +:template_opts+. If you
|
86
|
+
# are passing any of those options to render/view for the template, you
|
87
|
+
# should pass the same options when precompiling the template.
|
88
|
+
#
|
89
|
+
# To compile inline templates, just pass a single hash containing an :inline
|
90
|
+
# to +precompile_templates+:
|
91
|
+
#
|
92
|
+
# precompile_templates inline: some_template_string
|
51
93
|
def precompile_templates(pattern, opts=OPTS)
|
52
94
|
if pattern.is_a?(Hash)
|
53
95
|
opts = pattern.merge(opts)
|
@@ -68,7 +110,40 @@ class Roda
|
|
68
110
|
instance = allocate
|
69
111
|
compile_opts.each do |compile_opt|
|
70
112
|
template = instance.send(:retrieve_template, compile_opt)
|
71
|
-
|
113
|
+
begin
|
114
|
+
Render.tilt_template_compiled_method(template, locals, self)
|
115
|
+
rescue NotImplementedError
|
116
|
+
# When freezing template caches, you may want to precompile a template for a
|
117
|
+
# template type that doesn't support template precompilation, just to populate
|
118
|
+
# the cache. Tilt rescues NotImplementedError in this case, which we can ignore.
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
nil
|
124
|
+
end
|
125
|
+
|
126
|
+
# Precompile the given views with the given locals, handling optimized template methods.
|
127
|
+
def precompile_views(views, locals=EMPTY_ARRAY)
|
128
|
+
instance = allocate
|
129
|
+
views = Array(views)
|
130
|
+
|
131
|
+
if locals.empty?
|
132
|
+
opts = OPTS
|
133
|
+
else
|
134
|
+
locals_hash = {}
|
135
|
+
locals.each{|k| locals_hash[k] = nil}
|
136
|
+
opts = {:locals=>locals_hash}
|
137
|
+
end
|
138
|
+
|
139
|
+
views.each do |view|
|
140
|
+
instance.send(:retrieve_template, instance.send(:render_template_opts, view, opts))
|
141
|
+
end
|
142
|
+
|
143
|
+
if locals_hash
|
144
|
+
views.each do |view|
|
145
|
+
instance.send(:_optimized_render_method_for_locals, view, locals_hash)
|
146
|
+
end
|
72
147
|
end
|
73
148
|
|
74
149
|
nil
|
@@ -41,6 +41,7 @@ class Roda
|
|
41
41
|
# Return a relative prefix to append to an absolute path to a relative path
|
42
42
|
# based on the current path of the request.
|
43
43
|
def relative_prefix
|
44
|
+
return @_relative_prefix if @_relative_prefix
|
44
45
|
env = @_request.env
|
45
46
|
script_name = env["SCRIPT_NAME"]
|
46
47
|
path_info = env["PATH_INFO"]
|
@@ -50,16 +51,16 @@ class Roda
|
|
50
51
|
case script_name.getbyte(0)
|
51
52
|
when nil # SCRIPT_NAME empty
|
52
53
|
unless path_info.getbyte(0) == 47 # PATH_INFO starts with /
|
53
|
-
return ''
|
54
|
+
return(@_relative_prefix = '')
|
54
55
|
end
|
55
56
|
when 47 # SCRIPT_NAME starts with /
|
56
57
|
# nothing
|
57
58
|
else
|
58
|
-
return ''
|
59
|
+
return(@_relative_prefix = '')
|
59
60
|
end
|
60
61
|
|
61
62
|
slash_count = script_name.count('/') + path_info.count('/')
|
62
|
-
if slash_count > 1
|
63
|
+
@_relative_prefix = if slash_count > 1
|
63
64
|
("../" * (slash_count - 2)) << ".."
|
64
65
|
else
|
65
66
|
"."
|
data/lib/roda/plugins/render.rb
CHANGED
@@ -106,7 +106,7 @@ class Roda
|
|
106
106
|
# :template_block :: Pass this block when creating the underlying template,
|
107
107
|
# ignored when using :inline. Disables caching of the
|
108
108
|
# template by default.
|
109
|
-
# :template_class :: Provides the template class to use,
|
109
|
+
# :template_class :: Provides the template class to use, instead of using
|
110
110
|
# Tilt or <tt>Tilt[:engine]</tt>.
|
111
111
|
#
|
112
112
|
# Here's an example of using these options:
|
@@ -183,6 +183,7 @@ class Roda
|
|
183
183
|
app.const_set(:RodaCompiledTemplates, compiled_templates_module)
|
184
184
|
end
|
185
185
|
opts[:template_method_cache] = orig_method_cache || (opts[:cache_class] || RodaCache).new
|
186
|
+
opts[:template_method_cache][:_roda_layout] = nil if opts[:template_method_cache][:_roda_layout]
|
186
187
|
opts[:cache] = orig_cache || (opts[:cache_class] || RodaCache).new
|
187
188
|
|
188
189
|
opts[:layout_opts] = (opts[:layout_opts] || {}).dup
|
@@ -333,6 +334,25 @@ class Roda
|
|
333
334
|
end
|
334
335
|
|
335
336
|
module ClassMethods
|
337
|
+
# :nocov:
|
338
|
+
if COMPILED_METHOD_SUPPORT
|
339
|
+
# :nocov:
|
340
|
+
# If using compiled methods and there is an optimized layout, speed up
|
341
|
+
# access to the layout method to improve the performance of view.
|
342
|
+
def freeze
|
343
|
+
begin
|
344
|
+
_freeze_layout_method
|
345
|
+
rescue
|
346
|
+
# This is only for optimization, if any errors occur, they can be ignored.
|
347
|
+
# One possibility for error is the app doesn't use a layout, but doesn't
|
348
|
+
# specifically set the :layout=>false plugin option.
|
349
|
+
nil
|
350
|
+
end
|
351
|
+
|
352
|
+
super
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
336
356
|
# Copy the rendering options into the subclass, duping
|
337
357
|
# them as necessary to prevent changes in the subclass
|
338
358
|
# affecting the parent class.
|
@@ -352,6 +372,27 @@ class Roda
|
|
352
372
|
def render_opts
|
353
373
|
opts[:render]
|
354
374
|
end
|
375
|
+
|
376
|
+
private
|
377
|
+
|
378
|
+
# Precompile the layout method, to reduce method calls to look it up at runtime.
|
379
|
+
def _freeze_layout_method
|
380
|
+
if render_opts[:layout]
|
381
|
+
instance = allocate
|
382
|
+
instance.send(:retrieve_template, instance.send(:view_layout_opts, OPTS))
|
383
|
+
|
384
|
+
# :nocov:
|
385
|
+
if COMPILED_METHOD_SUPPORT
|
386
|
+
# :nocov:
|
387
|
+
if (layout_template = render_opts[:optimize_layout]) && !opts[:render][:optimized_layout_method_created]
|
388
|
+
instance.send(:retrieve_template, :template=>layout_template, :cache_key=>nil, :template_method_cache_key => :_roda_layout)
|
389
|
+
layout_method = opts[:render][:template_method_cache][:_roda_layout]
|
390
|
+
define_method(:_layout_method){layout_method}
|
391
|
+
opts[:render] = opts[:render].merge(:optimized_layout_method_created=>true)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
355
396
|
end
|
356
397
|
|
357
398
|
module InstanceMethods
|
@@ -375,19 +416,21 @@ class Roda
|
|
375
416
|
# Render the given template. If there is a default layout
|
376
417
|
# for the class, take the result of the template rendering
|
377
418
|
# and render it inside the layout. See Render for details.
|
378
|
-
def view(template, opts = (
|
379
|
-
if
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
if
|
384
|
-
|
385
|
-
|
386
|
-
retrieve_template(:template=>layout_template, :cache_key=>nil, :template_method_cache_key => :_roda_layout)
|
387
|
-
layout_method = method_cache[:_roda_layout]
|
388
|
-
end
|
419
|
+
def view(template, opts = (content = _optimized_view_content(template); OPTS))
|
420
|
+
if content
|
421
|
+
# First, check if the optimized layout method has already been created,
|
422
|
+
# and use it if so. This way avoids the extra conditional and local variable
|
423
|
+
# assignments in the next section.
|
424
|
+
if layout_method = _layout_method
|
425
|
+
return send(layout_method, OPTS){content}
|
426
|
+
end
|
389
427
|
|
390
|
-
|
428
|
+
# If we have an optimized template method but no optimized layout method, create the
|
429
|
+
# optimized layout method if possible and use it. If you can't create the optimized
|
430
|
+
# layout method, fall through to the slower approach.
|
431
|
+
if layout_template = self.class.opts[:render][:optimize_layout]
|
432
|
+
retrieve_template(:template=>layout_template, :cache_key=>nil, :template_method_cache_key => :_roda_layout)
|
433
|
+
if layout_method = _layout_method
|
391
434
|
return send(layout_method, OPTS){content}
|
392
435
|
end
|
393
436
|
end
|
@@ -428,6 +471,11 @@ class Roda
|
|
428
471
|
method_cache[template]
|
429
472
|
end
|
430
473
|
|
474
|
+
# Return a symbol containing the optimized layout method
|
475
|
+
def _layout_method
|
476
|
+
self.class.opts[:render][:template_method_cache][:_roda_layout]
|
477
|
+
end
|
478
|
+
|
431
479
|
# Use an optimized render path for templates with a hash of locals. Returns the result
|
432
480
|
# of the template render if the optimized path is used, or nil if the optimized
|
433
481
|
# path is not used and the long method needs to be used.
|
@@ -469,19 +517,37 @@ class Roda
|
|
469
517
|
end
|
470
518
|
end
|
471
519
|
end
|
520
|
+
|
521
|
+
# Get the content for #view, or return nil to use the unoptimized approach. Only called if
|
522
|
+
# a single argument is passed to view.
|
523
|
+
def _optimized_view_content(template)
|
524
|
+
if optimized_template = _cached_template_method(template)
|
525
|
+
send(optimized_template, OPTS)
|
526
|
+
elsif template.is_a?(Hash) && template.length == 1
|
527
|
+
template[:content]
|
528
|
+
end
|
529
|
+
end
|
472
530
|
else
|
473
531
|
# :nocov:
|
474
|
-
def _cached_template_method(
|
532
|
+
def _cached_template_method(_)
|
475
533
|
nil
|
476
534
|
end
|
477
535
|
|
478
|
-
def _cached_template_method_key(
|
536
|
+
def _cached_template_method_key(_)
|
537
|
+
nil
|
538
|
+
end
|
539
|
+
|
540
|
+
def _layout_method
|
479
541
|
nil
|
480
542
|
end
|
481
543
|
|
482
544
|
def _optimized_render_method_for_locals(_, _)
|
483
545
|
nil
|
484
546
|
end
|
547
|
+
|
548
|
+
def _optimized_view_content(template)
|
549
|
+
nil
|
550
|
+
end
|
485
551
|
# :nocov:
|
486
552
|
end
|
487
553
|
|
@@ -229,7 +229,7 @@ class Roda
|
|
229
229
|
#
|
230
230
|
# Note that if there are multiple conversion Error raised inside a +convert!+ or +convert_each!+
|
231
231
|
# block, they are recorded and a single TypecastParams::Error instance is raised after
|
232
|
-
# processing the block. TypecastParams::Error#
|
232
|
+
# processing the block. TypecastParams::Error#param_names can be called on the exception to
|
233
233
|
# get an array of all parameter names with conversion issues, and TypecastParams::Error#all_errors
|
234
234
|
# can be used to get an array of all Error instances.
|
235
235
|
#
|
@@ -609,10 +609,9 @@ class Roda
|
|
609
609
|
when nil
|
610
610
|
keys = (0...@obj.length)
|
611
611
|
|
612
|
-
valid =
|
613
|
-
when Array
|
612
|
+
valid = if @obj.is_a?(Array)
|
614
613
|
true
|
615
|
-
|
614
|
+
else
|
616
615
|
keys = keys.map(&:to_s)
|
617
616
|
keys.all?{|k| @obj.has_key?(k)}
|
618
617
|
end
|
@@ -725,7 +724,7 @@ class Roda
|
|
725
724
|
raise Error, "parameter #{param_name(nil)} is not a hash" if do_raise
|
726
725
|
return
|
727
726
|
end
|
728
|
-
present =
|
727
|
+
present = !@obj[key].nil?
|
729
728
|
when Integer
|
730
729
|
unless @obj.is_a?(Array)
|
731
730
|
raise Error, "parameter #{param_name(nil)} is not an array" if do_raise
|
data/lib/roda/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.41.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -174,16 +174,8 @@ extra_rdoc_files:
|
|
174
174
|
- MIT-LICENSE
|
175
175
|
- CHANGELOG
|
176
176
|
- doc/conventions.rdoc
|
177
|
-
- doc/release_notes/3.7.0.txt
|
178
177
|
- doc/release_notes/3.0.0.txt
|
179
178
|
- doc/release_notes/3.1.0.txt
|
180
|
-
- doc/release_notes/3.2.0.txt
|
181
|
-
- doc/release_notes/3.3.0.txt
|
182
|
-
- doc/release_notes/3.4.0.txt
|
183
|
-
- doc/release_notes/3.5.0.txt
|
184
|
-
- doc/release_notes/3.6.0.txt
|
185
|
-
- doc/release_notes/3.8.0.txt
|
186
|
-
- doc/release_notes/3.9.0.txt
|
187
179
|
- doc/release_notes/3.10.0.txt
|
188
180
|
- doc/release_notes/3.11.0.txt
|
189
181
|
- doc/release_notes/3.12.0.txt
|
@@ -195,6 +187,7 @@ extra_rdoc_files:
|
|
195
187
|
- doc/release_notes/3.17.0.txt
|
196
188
|
- doc/release_notes/3.18.0.txt
|
197
189
|
- doc/release_notes/3.19.0.txt
|
190
|
+
- doc/release_notes/3.2.0.txt
|
198
191
|
- doc/release_notes/3.20.0.txt
|
199
192
|
- doc/release_notes/3.21.0.txt
|
200
193
|
- doc/release_notes/3.22.0.txt
|
@@ -205,6 +198,7 @@ extra_rdoc_files:
|
|
205
198
|
- doc/release_notes/3.27.0.txt
|
206
199
|
- doc/release_notes/3.28.0.txt
|
207
200
|
- doc/release_notes/3.29.0.txt
|
201
|
+
- doc/release_notes/3.3.0.txt
|
208
202
|
- doc/release_notes/3.30.0.txt
|
209
203
|
- doc/release_notes/3.31.0.txt
|
210
204
|
- doc/release_notes/3.32.0.txt
|
@@ -212,6 +206,17 @@ extra_rdoc_files:
|
|
212
206
|
- doc/release_notes/3.34.0.txt
|
213
207
|
- doc/release_notes/3.35.0.txt
|
214
208
|
- doc/release_notes/3.36.0.txt
|
209
|
+
- doc/release_notes/3.37.0.txt
|
210
|
+
- doc/release_notes/3.38.0.txt
|
211
|
+
- doc/release_notes/3.39.0.txt
|
212
|
+
- doc/release_notes/3.4.0.txt
|
213
|
+
- doc/release_notes/3.40.0.txt
|
214
|
+
- doc/release_notes/3.41.0.txt
|
215
|
+
- doc/release_notes/3.5.0.txt
|
216
|
+
- doc/release_notes/3.6.0.txt
|
217
|
+
- doc/release_notes/3.7.0.txt
|
218
|
+
- doc/release_notes/3.8.0.txt
|
219
|
+
- doc/release_notes/3.9.0.txt
|
215
220
|
files:
|
216
221
|
- CHANGELOG
|
217
222
|
- MIT-LICENSE
|
@@ -249,7 +254,12 @@ files:
|
|
249
254
|
- doc/release_notes/3.34.0.txt
|
250
255
|
- doc/release_notes/3.35.0.txt
|
251
256
|
- doc/release_notes/3.36.0.txt
|
257
|
+
- doc/release_notes/3.37.0.txt
|
258
|
+
- doc/release_notes/3.38.0.txt
|
259
|
+
- doc/release_notes/3.39.0.txt
|
252
260
|
- doc/release_notes/3.4.0.txt
|
261
|
+
- doc/release_notes/3.40.0.txt
|
262
|
+
- doc/release_notes/3.41.0.txt
|
253
263
|
- doc/release_notes/3.5.0.txt
|
254
264
|
- doc/release_notes/3.6.0.txt
|
255
265
|
- doc/release_notes/3.7.0.txt
|
@@ -275,6 +285,7 @@ files:
|
|
275
285
|
- lib/roda/plugins/content_security_policy.rb
|
276
286
|
- lib/roda/plugins/cookies.rb
|
277
287
|
- lib/roda/plugins/csrf.rb
|
288
|
+
- lib/roda/plugins/custom_matchers.rb
|
278
289
|
- lib/roda/plugins/default_headers.rb
|
279
290
|
- lib/roda/plugins/default_status.rb
|
280
291
|
- lib/roda/plugins/delay_build.rb
|
@@ -387,7 +398,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
387
398
|
- !ruby/object:Gem::Version
|
388
399
|
version: '0'
|
389
400
|
requirements: []
|
390
|
-
rubygems_version: 3.
|
401
|
+
rubygems_version: 3.2.3
|
391
402
|
signing_key:
|
392
403
|
specification_version: 4
|
393
404
|
summary: Routing tree web toolkit
|