roda 3.28.0 → 3.33.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 +40 -0
- data/README.rdoc +15 -1
- data/doc/conventions.rdoc +17 -8
- data/doc/release_notes/3.29.0.txt +15 -0
- data/doc/release_notes/3.30.0.txt +14 -0
- data/doc/release_notes/3.31.0.txt +11 -0
- data/doc/release_notes/3.32.0.txt +42 -0
- data/doc/release_notes/3.33.0.txt +8 -0
- data/lib/roda.rb +3 -0
- data/lib/roda/plugins/_symbol_regexp_matchers.rb +2 -0
- data/lib/roda/plugins/assets.rb +26 -5
- data/lib/roda/plugins/caching.rb +2 -0
- data/lib/roda/plugins/common_logger.rb +1 -1
- data/lib/roda/plugins/content_security_policy.rb +2 -0
- data/lib/roda/plugins/default_headers.rb +2 -0
- data/lib/roda/plugins/exception_page.rb +9 -5
- data/lib/roda/plugins/hash_matcher.rb +1 -1
- data/lib/roda/plugins/header_matchers.rb +5 -1
- data/lib/roda/plugins/indifferent_params.rb +4 -0
- data/lib/roda/plugins/partials.rb +33 -6
- data/lib/roda/plugins/path.rb +42 -15
- data/lib/roda/plugins/placeholder_string_matchers.rb +2 -0
- data/lib/roda/plugins/public.rb +25 -17
- data/lib/roda/plugins/relative_path.rb +73 -0
- data/lib/roda/plugins/render.rb +17 -5
- data/lib/roda/plugins/render_each.rb +11 -3
- data/lib/roda/plugins/run_append_slash.rb +1 -1
- data/lib/roda/plugins/symbol_matchers.rb +2 -2
- data/lib/roda/version.rb +1 -1
- metadata +13 -214
- data/Rakefile +0 -108
- data/doc/release_notes/1.0.0.txt +0 -329
- data/doc/release_notes/1.1.0.txt +0 -226
- data/doc/release_notes/1.2.0.txt +0 -406
- data/doc/release_notes/1.3.0.txt +0 -109
- data/doc/release_notes/2.0.0.txt +0 -75
- data/doc/release_notes/2.1.0.txt +0 -124
- data/doc/release_notes/2.10.0.txt +0 -27
- data/doc/release_notes/2.11.0.txt +0 -70
- data/doc/release_notes/2.12.0.txt +0 -40
- data/doc/release_notes/2.13.0.txt +0 -10
- data/doc/release_notes/2.14.0.txt +0 -44
- data/doc/release_notes/2.15.0.txt +0 -53
- data/doc/release_notes/2.16.0.txt +0 -48
- data/doc/release_notes/2.17.0.txt +0 -62
- data/doc/release_notes/2.18.0.txt +0 -69
- data/doc/release_notes/2.19.0.txt +0 -30
- data/doc/release_notes/2.2.0.txt +0 -97
- data/doc/release_notes/2.20.0.txt +0 -5
- data/doc/release_notes/2.21.0.txt +0 -17
- data/doc/release_notes/2.22.0.txt +0 -41
- data/doc/release_notes/2.23.0.txt +0 -29
- data/doc/release_notes/2.24.0.txt +0 -65
- data/doc/release_notes/2.25.0.txt +0 -14
- data/doc/release_notes/2.26.0.txt +0 -13
- data/doc/release_notes/2.27.0.txt +0 -56
- data/doc/release_notes/2.28.0.txt +0 -17
- data/doc/release_notes/2.29.0.txt +0 -156
- data/doc/release_notes/2.3.0.txt +0 -109
- data/doc/release_notes/2.4.0.txt +0 -55
- data/doc/release_notes/2.5.0.txt +0 -23
- data/doc/release_notes/2.5.1.txt +0 -4
- data/doc/release_notes/2.6.0.txt +0 -21
- data/doc/release_notes/2.7.0.txt +0 -75
- data/doc/release_notes/2.8.0.txt +0 -44
- data/doc/release_notes/2.9.0.txt +0 -6
- data/spec/all.rb +0 -1
- data/spec/assets/css/app.scss +0 -1
- data/spec/assets/css/no_access.css +0 -1
- data/spec/assets/css/raw.css +0 -1
- data/spec/assets/js/head/app.js +0 -1
- data/spec/composition_spec.rb +0 -31
- data/spec/define_roda_method_spec.rb +0 -274
- data/spec/env_spec.rb +0 -11
- data/spec/freeze_spec.rb +0 -37
- data/spec/integration_spec.rb +0 -209
- data/spec/matchers_spec.rb +0 -832
- data/spec/opts_spec.rb +0 -42
- data/spec/plugin/_after_hook_spec.rb +0 -19
- data/spec/plugin/all_verbs_spec.rb +0 -29
- data/spec/plugin/assets_preloading_spec.rb +0 -98
- data/spec/plugin/assets_spec.rb +0 -745
- data/spec/plugin/backtracking_array_spec.rb +0 -42
- data/spec/plugin/branch_locals_spec.rb +0 -106
- data/spec/plugin/caching_spec.rb +0 -337
- data/spec/plugin/chunked_spec.rb +0 -201
- data/spec/plugin/class_level_routing_spec.rb +0 -164
- data/spec/plugin/class_matchers_spec.rb +0 -40
- data/spec/plugin/common_logger_spec.rb +0 -85
- data/spec/plugin/content_for_spec.rb +0 -162
- data/spec/plugin/content_security_policy_spec.rb +0 -175
- data/spec/plugin/cookies_spec.rb +0 -51
- data/spec/plugin/csrf_spec.rb +0 -111
- data/spec/plugin/default_headers_spec.rb +0 -82
- data/spec/plugin/default_status_spec.rb +0 -95
- data/spec/plugin/delay_build_spec.rb +0 -23
- data/spec/plugin/delegate_spec.rb +0 -23
- data/spec/plugin/delete_empty_headers_spec.rb +0 -27
- data/spec/plugin/direct_call_spec.rb +0 -28
- data/spec/plugin/disallow_file_uploads_spec.rb +0 -25
- data/spec/plugin/drop_body_spec.rb +0 -24
- data/spec/plugin/early_hints_spec.rb +0 -19
- data/spec/plugin/empty_root_spec.rb +0 -14
- data/spec/plugin/environments_spec.rb +0 -42
- data/spec/plugin/error_email_spec.rb +0 -97
- data/spec/plugin/error_handler_spec.rb +0 -216
- data/spec/plugin/error_mail_spec.rb +0 -93
- data/spec/plugin/exception_page_spec.rb +0 -168
- data/spec/plugin/flash_spec.rb +0 -121
- data/spec/plugin/h_spec.rb +0 -11
- data/spec/plugin/halt_spec.rb +0 -119
- data/spec/plugin/hash_matcher_spec.rb +0 -27
- data/spec/plugin/hash_routes_spec.rb +0 -535
- data/spec/plugin/head_spec.rb +0 -52
- data/spec/plugin/header_matchers_spec.rb +0 -98
- data/spec/plugin/heartbeat_spec.rb +0 -74
- data/spec/plugin/hooks_spec.rb +0 -152
- data/spec/plugin/indifferent_params_spec.rb +0 -14
- data/spec/plugin/json_parser_spec.rb +0 -141
- data/spec/plugin/json_spec.rb +0 -83
- data/spec/plugin/mail_processor_spec.rb +0 -451
- data/spec/plugin/mailer_spec.rb +0 -282
- data/spec/plugin/match_affix_spec.rb +0 -43
- data/spec/plugin/match_hook_spec.rb +0 -79
- data/spec/plugin/middleware_spec.rb +0 -237
- data/spec/plugin/middleware_stack_spec.rb +0 -81
- data/spec/plugin/module_include_spec.rb +0 -48
- data/spec/plugin/multi_route_spec.rb +0 -268
- data/spec/plugin/multi_run_spec.rb +0 -87
- data/spec/plugin/multi_view_spec.rb +0 -50
- data/spec/plugin/multibyte_string_matcher_spec.rb +0 -44
- data/spec/plugin/named_templates_spec.rb +0 -96
- data/spec/plugin/not_allowed_spec.rb +0 -69
- data/spec/plugin/not_found_spec.rb +0 -128
- data/spec/plugin/optimized_string_matchers_spec.rb +0 -43
- data/spec/plugin/padrino_render_spec.rb +0 -34
- data/spec/plugin/param_matchers_spec.rb +0 -69
- data/spec/plugin/params_capturing_spec.rb +0 -33
- data/spec/plugin/partials_spec.rb +0 -43
- data/spec/plugin/pass_spec.rb +0 -29
- data/spec/plugin/path_matchers_spec.rb +0 -42
- data/spec/plugin/path_rewriter_spec.rb +0 -45
- data/spec/plugin/path_spec.rb +0 -222
- data/spec/plugin/placeholder_string_matchers_spec.rb +0 -126
- data/spec/plugin/precompile_templates_spec.rb +0 -61
- data/spec/plugin/public_spec.rb +0 -85
- data/spec/plugin/render_each_spec.rb +0 -82
- data/spec/plugin/render_locals_spec.rb +0 -114
- data/spec/plugin/render_spec.rb +0 -912
- data/spec/plugin/request_aref_spec.rb +0 -51
- data/spec/plugin/request_headers_spec.rb +0 -39
- data/spec/plugin/response_request_spec.rb +0 -43
- data/spec/plugin/route_block_args_spec.rb +0 -86
- data/spec/plugin/route_csrf_spec.rb +0 -305
- data/spec/plugin/run_append_slash_spec.rb +0 -77
- data/spec/plugin/run_handler_spec.rb +0 -53
- data/spec/plugin/sessions_spec.rb +0 -452
- data/spec/plugin/shared_vars_spec.rb +0 -45
- data/spec/plugin/sinatra_helpers_spec.rb +0 -537
- data/spec/plugin/slash_path_empty_spec.rb +0 -22
- data/spec/plugin/static_routing_spec.rb +0 -192
- data/spec/plugin/static_spec.rb +0 -30
- data/spec/plugin/status_303_spec.rb +0 -28
- data/spec/plugin/status_handler_spec.rb +0 -158
- data/spec/plugin/streaming_spec.rb +0 -246
- data/spec/plugin/strip_path_prefix_spec.rb +0 -24
- data/spec/plugin/symbol_matchers_spec.rb +0 -51
- data/spec/plugin/symbol_status_spec.rb +0 -25
- data/spec/plugin/symbol_views_spec.rb +0 -32
- data/spec/plugin/timestamp_public_spec.rb +0 -85
- data/spec/plugin/type_routing_spec.rb +0 -348
- data/spec/plugin/typecast_params_spec.rb +0 -1370
- data/spec/plugin/unescape_path_spec.rb +0 -22
- data/spec/plugin/view_options_spec.rb +0 -170
- data/spec/plugin_spec.rb +0 -71
- data/spec/redirect_spec.rb +0 -41
- data/spec/request_spec.rb +0 -97
- data/spec/response_spec.rb +0 -199
- data/spec/route_spec.rb +0 -39
- data/spec/session_middleware_spec.rb +0 -129
- data/spec/session_spec.rb +0 -37
- data/spec/spec_helper.rb +0 -137
- data/spec/version_spec.rb +0 -14
- data/spec/views/_test.erb +0 -1
- data/spec/views/a.erb +0 -1
- data/spec/views/a.rdoc +0 -2
- data/spec/views/about.erb +0 -1
- data/spec/views/about.str +0 -1
- data/spec/views/about/_test.css.gz +0 -0
- data/spec/views/about/_test.erb +0 -1
- data/spec/views/about/_test.erb.gz +0 -0
- data/spec/views/about/comp_test.erb +0 -1
- data/spec/views/b.erb +0 -1
- data/spec/views/c.erb +0 -1
- data/spec/views/comp_layout.erb +0 -1
- data/spec/views/comp_test.erb +0 -1
- data/spec/views/content-yield.erb +0 -1
- data/spec/views/each.str +0 -1
- data/spec/views/home.erb +0 -2
- data/spec/views/home.str +0 -2
- data/spec/views/iv.erb +0 -1
- data/spec/views/layout-alternative.erb +0 -2
- data/spec/views/layout-yield.erb +0 -3
- data/spec/views/layout.erb +0 -2
- data/spec/views/layout.str +0 -2
- data/spec/views/multiple-layout.erb +0 -1
- data/spec/views/multiple.erb +0 -1
|
@@ -51,7 +51,11 @@ class Roda
|
|
|
51
51
|
|
|
52
52
|
# Match if the given uppercase key is present inside the environment.
|
|
53
53
|
def match_header(key)
|
|
54
|
-
|
|
54
|
+
key = key.upcase.tr("-","_")
|
|
55
|
+
unless key == "CONTENT_TYPE" || key == "CONTENT_LENGTH"
|
|
56
|
+
key = "HTTP_#{key}"
|
|
57
|
+
end
|
|
58
|
+
if v = @env[key]
|
|
55
59
|
@captures << v
|
|
56
60
|
end
|
|
57
61
|
end
|
|
@@ -42,6 +42,8 @@ class Roda
|
|
|
42
42
|
INDIFFERENT_PROC = lambda{|h,k| h[k.to_s] if k.is_a?(Symbol)}
|
|
43
43
|
|
|
44
44
|
if Rack.release > '2'
|
|
45
|
+
require 'rack/query_parser'
|
|
46
|
+
|
|
45
47
|
class QueryParser < Rack::QueryParser
|
|
46
48
|
# Work around for invalid optimization in rack
|
|
47
49
|
def parse_nested_query(qs, d=nil)
|
|
@@ -62,6 +64,8 @@ class Roda
|
|
|
62
64
|
module RequestMethods
|
|
63
65
|
QUERY_PARSER = Rack::Utils.default_query_parser = QueryParser.new(QueryParser::Params, 65536, 100)
|
|
64
66
|
|
|
67
|
+
private
|
|
68
|
+
|
|
65
69
|
def query_parser
|
|
66
70
|
QUERY_PARSER
|
|
67
71
|
end
|
|
@@ -18,27 +18,54 @@ class Roda
|
|
|
18
18
|
# render('_test')
|
|
19
19
|
# render('dir/_test')
|
|
20
20
|
#
|
|
21
|
-
#
|
|
21
|
+
# To render the same template once for each object in an enumerable,
|
|
22
|
+
# you can use the +render_partials+ method:
|
|
23
|
+
#
|
|
24
|
+
# each_partial([1,2,3], :foo) # uses _foo.erb
|
|
25
|
+
#
|
|
26
|
+
# This is basically equivalent to:
|
|
27
|
+
#
|
|
28
|
+
# render_each([1,2,3], "_foo", local: :foo)
|
|
29
|
+
#
|
|
30
|
+
# This plugin depends on the render and render_each plugins.
|
|
22
31
|
module Partials
|
|
23
|
-
# Depend on the render plugin,
|
|
24
|
-
#
|
|
32
|
+
# Depend on the render plugin, passing received options to it.
|
|
33
|
+
# Also depend on the render_each plugin.
|
|
25
34
|
def self.load_dependencies(app, opts=OPTS)
|
|
26
35
|
app.plugin :render, opts
|
|
36
|
+
app.plugin :render_each
|
|
27
37
|
end
|
|
28
38
|
|
|
29
39
|
module InstanceMethods
|
|
40
|
+
# For each object in the given enumerable, render the given
|
|
41
|
+
# template (prefixing the template filename with an underscore).
|
|
42
|
+
def each_partial(enum, template, opts=OPTS)
|
|
43
|
+
unless opts.has_key?(:local)
|
|
44
|
+
opts = Hash[opts]
|
|
45
|
+
opts[:local] = render_each_default_local(template)
|
|
46
|
+
end
|
|
47
|
+
render_each(enum, partial_template_name(template.to_s), opts)
|
|
48
|
+
end
|
|
49
|
+
|
|
30
50
|
# Renders the given template without a layout, but
|
|
31
51
|
# prefixes the template filename to use with an
|
|
32
52
|
# underscore.
|
|
33
53
|
def partial(template, opts=OPTS)
|
|
34
54
|
opts = parse_template_opts(template, opts)
|
|
35
55
|
if opts[:template]
|
|
36
|
-
template = opts[:template]
|
|
37
|
-
template[-1] = "_#{template[-1]}"
|
|
38
|
-
opts[:template] = template.join('/')
|
|
56
|
+
opts[:template] = partial_template_name(opts[:template])
|
|
39
57
|
end
|
|
40
58
|
render_template(opts)
|
|
41
59
|
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
# Prefix the template base filename with an underscore.
|
|
64
|
+
def partial_template_name(template)
|
|
65
|
+
segments = template.split('/')
|
|
66
|
+
segments[-1] = "_#{segments[-1]}"
|
|
67
|
+
segments.join('/')
|
|
68
|
+
end
|
|
42
69
|
end
|
|
43
70
|
end
|
|
44
71
|
|
data/lib/roda/plugins/path.rb
CHANGED
|
@@ -10,7 +10,8 @@ class Roda
|
|
|
10
10
|
#
|
|
11
11
|
# Additionally, you can call the +path+ class method with a class and a block, and it will register
|
|
12
12
|
# the class. You can then call the +path+ instance method with an instance of that class, and it will
|
|
13
|
-
# execute the block in the context of the route block scope with the arguments provided to path.
|
|
13
|
+
# execute the block in the context of the route block scope with the arguments provided to path. You
|
|
14
|
+
# can call the +url+ instance method with the same arguments as the +path+ method to get the full URL.
|
|
14
15
|
#
|
|
15
16
|
# Example:
|
|
16
17
|
#
|
|
@@ -46,21 +47,23 @@ class Roda
|
|
|
46
47
|
#
|
|
47
48
|
# r.post 'quux' do
|
|
48
49
|
# bar = Quux[1]
|
|
49
|
-
# r.redirect
|
|
50
|
+
# r.redirect url(quux, '/bar') # http://example.com/quux/1/bar
|
|
50
51
|
# end
|
|
51
52
|
# end
|
|
52
53
|
#
|
|
53
|
-
# The path method accepts the following options when not called with a class:
|
|
54
|
+
# The path class method accepts the following options when not called with a class:
|
|
54
55
|
#
|
|
55
56
|
# :add_script_name :: Prefix the path generated with SCRIPT_NAME. This defaults to the app's
|
|
56
57
|
# :add_script_name option.
|
|
57
58
|
# :name :: Provide a different name for the method, instead of using <tt>*_path</tt>.
|
|
59
|
+
# :relative :: Generate paths relative to the current request instead of absolute paths by prepending
|
|
60
|
+
# an appropriate prefix. This implies :add_script_name.
|
|
58
61
|
# :url :: Create a url method in addition to the path method, which will prefix the string generated
|
|
59
62
|
# with the appropriate scheme, host, and port. If true, creates a <tt>*_url</tt>
|
|
60
63
|
# method. If a Symbol or String, uses the value as the url method name.
|
|
61
64
|
# :url_only :: Do not create a path method, just a url method.
|
|
62
65
|
#
|
|
63
|
-
# Note that if :add_script_name, :url, or :url_only is used, the path method will also create a
|
|
66
|
+
# Note that if :add_script_name, :relative, :url, or :url_only is used, the path method will also create a
|
|
64
67
|
# <tt>_*_path</tt> private method.
|
|
65
68
|
module Path
|
|
66
69
|
DEFAULT_PORTS = {'http' => 80, 'https' => 443}.freeze
|
|
@@ -121,16 +124,31 @@ class Roda
|
|
|
121
124
|
|
|
122
125
|
meth = opts[:name] || "#{name}_path"
|
|
123
126
|
url = opts[:url]
|
|
127
|
+
url_only = opts[:url_only]
|
|
128
|
+
relative = opts[:relative]
|
|
124
129
|
add_script_name = opts.fetch(:add_script_name, self.opts[:add_script_name])
|
|
125
130
|
|
|
126
|
-
if
|
|
131
|
+
if relative
|
|
132
|
+
if (url || url_only)
|
|
133
|
+
raise RodaError, "cannot provide :url or :url_only option if using :relative option"
|
|
134
|
+
end
|
|
135
|
+
add_script_name = true
|
|
136
|
+
plugin :relative_path
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
if add_script_name || url || url_only || relative
|
|
127
140
|
_meth = "_#{meth}"
|
|
128
141
|
define_method(_meth, &block)
|
|
129
142
|
private _meth
|
|
130
143
|
end
|
|
131
144
|
|
|
132
|
-
unless
|
|
133
|
-
if
|
|
145
|
+
unless url_only
|
|
146
|
+
if relative
|
|
147
|
+
define_method(meth) do |*a, &blk|
|
|
148
|
+
# Allow calling private _method to get path
|
|
149
|
+
relative_path(request.script_name.to_s + send(_meth, *a, &blk))
|
|
150
|
+
end
|
|
151
|
+
elsif add_script_name
|
|
134
152
|
define_method(meth) do |*a, &blk|
|
|
135
153
|
# Allow calling private _method to get path
|
|
136
154
|
request.script_name.to_s + send(_meth, *a, &blk)
|
|
@@ -140,7 +158,7 @@ class Roda
|
|
|
140
158
|
end
|
|
141
159
|
end
|
|
142
160
|
|
|
143
|
-
if url ||
|
|
161
|
+
if url || url_only
|
|
144
162
|
url_meth = if url.is_a?(String) || url.is_a?(Symbol)
|
|
145
163
|
url
|
|
146
164
|
else
|
|
@@ -148,14 +166,8 @@ class Roda
|
|
|
148
166
|
end
|
|
149
167
|
|
|
150
168
|
url_block = lambda do |*a, &blk|
|
|
151
|
-
r = request
|
|
152
|
-
scheme = r.scheme
|
|
153
|
-
port = r.port
|
|
154
|
-
uri = ["#{scheme}://#{r.host}#{":#{port}" unless DEFAULT_PORTS[scheme] == port}"]
|
|
155
|
-
uri << request.script_name.to_s if add_script_name
|
|
156
169
|
# Allow calling private _method to get path
|
|
157
|
-
|
|
158
|
-
File.join(uri)
|
|
170
|
+
"#{_base_url}#{request.script_name if add_script_name}#{send(_meth, *a, &blk)}"
|
|
159
171
|
end
|
|
160
172
|
|
|
161
173
|
define_method(url_meth, &url_block)
|
|
@@ -190,6 +202,21 @@ class Roda
|
|
|
190
202
|
path = request.script_name.to_s + path if opts[:add_script_name]
|
|
191
203
|
path
|
|
192
204
|
end
|
|
205
|
+
|
|
206
|
+
# Similar to #path, but returns a complete URL.
|
|
207
|
+
def url(*args, &block)
|
|
208
|
+
"#{_base_url}#{path(*args, &block)}"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
private
|
|
212
|
+
|
|
213
|
+
# The string to prepend to the path to make the path a URL.
|
|
214
|
+
def _base_url
|
|
215
|
+
r = @_request
|
|
216
|
+
scheme = r.scheme
|
|
217
|
+
port = r.port
|
|
218
|
+
"#{scheme}://#{r.host}#{":#{port}" unless DEFAULT_PORTS[scheme] == port}"
|
|
219
|
+
end
|
|
193
220
|
end
|
|
194
221
|
end
|
|
195
222
|
|
data/lib/roda/plugins/public.rb
CHANGED
|
@@ -42,6 +42,8 @@ class Roda
|
|
|
42
42
|
# :default_mime :: The default mime type to use if the mime type is not recognized.
|
|
43
43
|
# :gzip :: Whether to serve already gzipped files with a .gz extension for clients
|
|
44
44
|
# supporting gzipped transfer encoding.
|
|
45
|
+
# :brotli :: Whether to serve already brotli-compressed files with a .br extension
|
|
46
|
+
# for clients supporting brotli transfer encoding.
|
|
45
47
|
# :headers :: A hash of headers to use for statically served files
|
|
46
48
|
# :root :: Use this option for the root of the public directory (default: "public")
|
|
47
49
|
def self.configure(app, opts={})
|
|
@@ -52,6 +54,7 @@ class Roda
|
|
|
52
54
|
end
|
|
53
55
|
app.opts[:public_server] = ::Rack::File.new(app.opts[:public_root], opts[:headers]||{}, opts[:default_mime] || 'text/plain')
|
|
54
56
|
app.opts[:public_gzip] = opts[:gzip]
|
|
57
|
+
app.opts[:public_brotli] = opts[:brotli]
|
|
55
58
|
end
|
|
56
59
|
|
|
57
60
|
module RequestMethods
|
|
@@ -65,23 +68,8 @@ class Roda
|
|
|
65
68
|
server = roda_opts[:public_server]
|
|
66
69
|
path = ::File.join(server.root, *public_path_segments(path))
|
|
67
70
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if public_file_readable?(gzip_path)
|
|
72
|
-
res = public_serve(server, gzip_path)
|
|
73
|
-
headers = res[1]
|
|
74
|
-
|
|
75
|
-
unless res[0] == 304
|
|
76
|
-
if mime_type = ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
|
|
77
|
-
headers['Content-Type'] = mime_type
|
|
78
|
-
end
|
|
79
|
-
headers['Content-Encoding'] = 'gzip'
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
halt res
|
|
83
|
-
end
|
|
84
|
-
end
|
|
71
|
+
public_serve_compressed(server, path, '.br', 'br') if roda_opts[:public_brotli]
|
|
72
|
+
public_serve_compressed(server, path, '.gz', 'gzip') if roda_opts[:public_gzip]
|
|
85
73
|
|
|
86
74
|
if public_file_readable?(path)
|
|
87
75
|
halt public_serve(server, path)
|
|
@@ -113,6 +101,26 @@ class Roda
|
|
|
113
101
|
# :nocov:
|
|
114
102
|
end
|
|
115
103
|
|
|
104
|
+
def public_serve_compressed(server, path, suffix, encoding)
|
|
105
|
+
if env['HTTP_ACCEPT_ENCODING'] =~ /\b#{encoding}\b/
|
|
106
|
+
compressed_path = path + suffix
|
|
107
|
+
|
|
108
|
+
if public_file_readable?(compressed_path)
|
|
109
|
+
res = public_serve(server, compressed_path)
|
|
110
|
+
headers = res[1]
|
|
111
|
+
|
|
112
|
+
unless res[0] == 304
|
|
113
|
+
if mime_type = ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
|
|
114
|
+
headers['Content-Type'] = mime_type
|
|
115
|
+
end
|
|
116
|
+
headers['Content-Encoding'] = encoding
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
halt res
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
116
124
|
if ::Rack.release > '2'
|
|
117
125
|
# Serve the given path using the given Rack::File server.
|
|
118
126
|
def public_serve(server, path)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The relative_path plugin adds a relative_path method that accepts
|
|
7
|
+
# an absolute path and returns a path relative to the current request
|
|
8
|
+
# by adding an appropriate prefix:
|
|
9
|
+
#
|
|
10
|
+
# plugin :relative_path
|
|
11
|
+
# route do |r|
|
|
12
|
+
# relative_path("/foo")
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# # GET /
|
|
16
|
+
# "./foo"
|
|
17
|
+
#
|
|
18
|
+
# # GET /bar
|
|
19
|
+
# "./foo"
|
|
20
|
+
#
|
|
21
|
+
# # GET /bar/
|
|
22
|
+
# "../foo"
|
|
23
|
+
#
|
|
24
|
+
# # GET /bar/baz/quux
|
|
25
|
+
# "../../foo"
|
|
26
|
+
#
|
|
27
|
+
# It also offers a relative_prefix method that returns a string that can
|
|
28
|
+
# be prepended to an absolute path. This can be more efficient if you
|
|
29
|
+
# need to convert multiple paths.
|
|
30
|
+
#
|
|
31
|
+
# This plugin is mostly designed for applications using Roda as a static
|
|
32
|
+
# site generator, where the generated site can be hosted at any subpath.
|
|
33
|
+
module RelativePath
|
|
34
|
+
module InstanceMethods
|
|
35
|
+
# Return a relative path for the absolute path based on the current path
|
|
36
|
+
# of the request by adding the appropriate prefix.
|
|
37
|
+
def relative_path(absolute_path)
|
|
38
|
+
relative_prefix + absolute_path
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Return a relative prefix to append to an absolute path to a relative path
|
|
42
|
+
# based on the current path of the request.
|
|
43
|
+
def relative_prefix
|
|
44
|
+
env = @_request.env
|
|
45
|
+
script_name = env["SCRIPT_NAME"]
|
|
46
|
+
path_info = env["PATH_INFO"]
|
|
47
|
+
|
|
48
|
+
# Check path begins with slash. All valid paths should, but in case this
|
|
49
|
+
# request is bad, just skip using a relative prefix.
|
|
50
|
+
case script_name.getbyte(0)
|
|
51
|
+
when nil # SCRIPT_NAME empty
|
|
52
|
+
unless path_info.getbyte(0) == 47 # PATH_INFO starts with /
|
|
53
|
+
return ''
|
|
54
|
+
end
|
|
55
|
+
when 47 # SCRIPT_NAME starts with /
|
|
56
|
+
# nothing
|
|
57
|
+
else
|
|
58
|
+
return ''
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
slash_count = script_name.count('/') + path_info.count('/')
|
|
62
|
+
if slash_count > 1
|
|
63
|
+
("../" * (slash_count - 2)) << ".."
|
|
64
|
+
else
|
|
65
|
+
"."
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
register_plugin(:relative_path, RelativePath)
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/roda/plugins/render.rb
CHANGED
|
@@ -241,12 +241,13 @@ class Roda
|
|
|
241
241
|
# template file has been modified. This is an internal class and
|
|
242
242
|
# the API is subject to change at any time.
|
|
243
243
|
class TemplateMtimeWrapper
|
|
244
|
-
def initialize(template_class, path, *template_args)
|
|
244
|
+
def initialize(template_class, path, dependencies, *template_args)
|
|
245
245
|
@template_class = template_class
|
|
246
246
|
@path = path
|
|
247
247
|
@template_args = template_args
|
|
248
|
+
@dependencies = ([path] + Array(dependencies)) if dependencies
|
|
248
249
|
|
|
249
|
-
@mtime =
|
|
250
|
+
@mtime = template_last_modified if File.file?(path)
|
|
250
251
|
@template = template_class.new(path, *template_args)
|
|
251
252
|
end
|
|
252
253
|
|
|
@@ -257,17 +258,28 @@ class Roda
|
|
|
257
258
|
@template.render(*args, &block)
|
|
258
259
|
end
|
|
259
260
|
|
|
261
|
+
# Return when the template was last modified. If the template depends on any
|
|
262
|
+
# other files, check the modification times of all dependencies and
|
|
263
|
+
# return the maximum.
|
|
264
|
+
def template_last_modified
|
|
265
|
+
if deps = @dependencies
|
|
266
|
+
deps.map{|f| File.mtime(f)}.max
|
|
267
|
+
else
|
|
268
|
+
File.mtime(@path)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
260
272
|
# If the template file has been updated, return true and update
|
|
261
273
|
# the template object and the modification time. Other return false.
|
|
262
274
|
def modified?
|
|
263
275
|
begin
|
|
264
|
-
mtime =
|
|
276
|
+
mtime = template_last_modified
|
|
265
277
|
rescue
|
|
266
278
|
# ignore errors
|
|
267
279
|
else
|
|
268
280
|
if mtime != @mtime
|
|
269
281
|
@mtime = mtime
|
|
270
|
-
@template = @template_class.new(path, *@template_args)
|
|
282
|
+
@template = @template_class.new(@path, *@template_args)
|
|
271
283
|
return true
|
|
272
284
|
end
|
|
273
285
|
end
|
|
@@ -576,7 +588,7 @@ class Roda
|
|
|
576
588
|
!opts[:inline]
|
|
577
589
|
|
|
578
590
|
if render_opts[:check_template_mtime] && !opts[:template_block] && !cache
|
|
579
|
-
template = TemplateMtimeWrapper.new(opts[:template_class], opts[:path], 1, template_opts)
|
|
591
|
+
template = TemplateMtimeWrapper.new(opts[:template_class], opts[:path], opts[:dependencies], 1, template_opts)
|
|
580
592
|
|
|
581
593
|
if define_compiled_method
|
|
582
594
|
method_name = :"_roda_template_#{self.class.object_id}_#{method_cache_key}"
|
|
@@ -26,7 +26,9 @@ class Roda
|
|
|
26
26
|
#
|
|
27
27
|
# Will render the +foo+ template, but the local variable used inside
|
|
28
28
|
# the template will be +bar+. You can use <tt>local: nil</tt> to
|
|
29
|
-
# not set a local variable inside the template.
|
|
29
|
+
# not set a local variable inside the template. By default, the
|
|
30
|
+
# local variable name is based on the template name, with any
|
|
31
|
+
# directories and file extensions removed.
|
|
30
32
|
module RenderEach
|
|
31
33
|
# Load the render plugin before this plugin, since this plugin
|
|
32
34
|
# calls the render method.
|
|
@@ -45,11 +47,11 @@ class Roda
|
|
|
45
47
|
# set a local variable. If not set, uses the template name.
|
|
46
48
|
def render_each(enum, template, opts=(no_opts = true; optimized_template = _cached_render_each_template_method(template); OPTS))
|
|
47
49
|
if optimized_template
|
|
48
|
-
return _optimized_render_each(enum, optimized_template, template
|
|
50
|
+
return _optimized_render_each(enum, optimized_template, render_each_default_local(template), {})
|
|
49
51
|
elsif opts.has_key?(:local)
|
|
50
52
|
as = opts[:local]
|
|
51
53
|
else
|
|
52
|
-
as = template
|
|
54
|
+
as = render_each_default_local(template)
|
|
53
55
|
if no_opts && optimized_template.nil? && (optimized_template = _optimized_render_method_for_locals(template, (locals = {as=>nil})))
|
|
54
56
|
return _optimized_render_each(enum, optimized_template, as, locals)
|
|
55
57
|
end
|
|
@@ -77,6 +79,12 @@ class Roda
|
|
|
77
79
|
|
|
78
80
|
private
|
|
79
81
|
|
|
82
|
+
# The default local variable name to use for the template, if the :local option
|
|
83
|
+
# is not used when calling render_each.
|
|
84
|
+
def render_each_default_local(template)
|
|
85
|
+
File.basename(template.to_s).sub(/\..+\z/, '').to_sym
|
|
86
|
+
end
|
|
87
|
+
|
|
80
88
|
if Render::COMPILED_METHOD_SUPPORT
|
|
81
89
|
# If compiled method support is enabled in the render plugin, return the
|
|
82
90
|
# method name to call to render the template. Return false if not given
|