roda 3.30.0 → 3.35.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 +36 -0
- data/README.rdoc +4 -0
- data/doc/conventions.rdoc +17 -8
- 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/doc/release_notes/3.34.0.txt +17 -0
- data/doc/release_notes/3.35.0.txt +12 -0
- data/lib/roda.rb +8 -0
- data/lib/roda/plugins/_symbol_regexp_matchers.rb +2 -0
- data/lib/roda/plugins/all_verbs.rb +2 -0
- data/lib/roda/plugins/assets.rb +15 -7
- data/lib/roda/plugins/backtracking_array.rb +1 -3
- data/lib/roda/plugins/class_level_routing.rb +0 -1
- data/lib/roda/plugins/content_security_policy.rb +2 -0
- data/lib/roda/plugins/default_headers.rb +2 -0
- data/lib/roda/plugins/disallow_file_uploads.rb +2 -0
- data/lib/roda/plugins/exception_page.rb +15 -5
- data/lib/roda/plugins/hash_matcher.rb +1 -1
- data/lib/roda/plugins/indifferent_params.rb +2 -0
- data/lib/roda/plugins/match_affix.rb +1 -1
- data/lib/roda/plugins/not_allowed.rb +2 -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 +23 -17
- data/lib/roda/plugins/r.rb +35 -0
- data/lib/roda/plugins/relative_path.rb +73 -0
- data/lib/roda/plugins/render.rb +21 -5
- data/lib/roda/plugins/render_each.rb +11 -3
- data/lib/roda/plugins/render_locals.rb +2 -0
- data/lib/roda/plugins/sinatra_helpers.rb +4 -4
- data/lib/roda/plugins/symbol_matchers.rb +2 -2
- data/lib/roda/plugins/typecast_params.rb +4 -6
- data/lib/roda/plugins/view_options.rb +2 -0
- data/lib/roda/request.rb +2 -4
- data/lib/roda/version.rb +1 -1
- metadata +14 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 370e18bb1d1cfb9fb8b0c10fda1a4f57161a39c6d733b628ddd60058d231f896
|
|
4
|
+
data.tar.gz: fe0c8ddb499cdbafb0f047d9445fca726f742e38674f90731f3421132c373365
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60db0b47d97ae40437e0396bc795ac360194bd88067e6611cf277888d054e3c41786eb062f4ab31d6683cb4755a3a27d148a576236c77a4d46db67fc2accc7e1
|
|
7
|
+
data.tar.gz: 44745afaa29ccee2d51a132f7b7be4da6818191814a9ff8a2afd52f34636789cb0e4d22eb63ade49ea0411470a73b05a1996c7bb70cc7edf04264fb2fddadb83
|
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
= 3.35.0 (2020-08-14)
|
|
2
|
+
|
|
3
|
+
* Add r plugin for r method for accessing request, useful when r local variable is not in scope (jeremyevans)
|
|
4
|
+
|
|
5
|
+
* Warn when loading a plugin with arguments or a block if the plugin does not accept arguments or block (jeremyevans)
|
|
6
|
+
|
|
7
|
+
= 3.34.0 (2020-07-14)
|
|
8
|
+
|
|
9
|
+
* Remove unnecessary conditionals (jeremyevans)
|
|
10
|
+
|
|
11
|
+
* Allow loading the match_affix plugin with a single argument (jeremyevans)
|
|
12
|
+
|
|
13
|
+
* Do not include pre/post context sections if empty in the exception_page plugin (jeremyevans)
|
|
14
|
+
|
|
15
|
+
= 3.33.0 (2020-06-16)
|
|
16
|
+
|
|
17
|
+
* Add :brotli option to public plugin to supplement it to serve brotli-compressed files like :gzip does for gzipped files (hmdne) (#194)
|
|
18
|
+
|
|
19
|
+
* Add url method to path plugin, similar to path but returning the entire URL (jeremyevans)
|
|
20
|
+
|
|
21
|
+
= 3.32.0 (2020-05-15)
|
|
22
|
+
|
|
23
|
+
* Make :dependencies option in assets plugin work correctly with render plugin template caching (jeremyevans) (#191)
|
|
24
|
+
|
|
25
|
+
* Support render method :dependencies option for specifying which files to check for modification (jgarth, jeremyevans) (#192)
|
|
26
|
+
|
|
27
|
+
* Add each_partial to the partials plugin for rendering a partial for each element in an enumerable (jeremyevans)
|
|
28
|
+
|
|
29
|
+
* Make render_each in render_each plugin handle template names with directories and extensions (jeremyevans)
|
|
30
|
+
|
|
31
|
+
= 3.31.0 (2020-04-15)
|
|
32
|
+
|
|
33
|
+
* Add :relative option to path method in path plugin, for generating a method returning relative paths (jeremyevans)
|
|
34
|
+
|
|
35
|
+
* Add relative_path plugin, for turning absolute paths to paths relative to the current request (jeremyevans)
|
|
36
|
+
|
|
1
37
|
= 3.30.0 (2020-03-13)
|
|
2
38
|
|
|
3
39
|
* Support :relative_paths assets plugin option to use relative paths for the assets (jeremyevans)
|
data/README.rdoc
CHANGED
|
@@ -418,6 +418,10 @@ You can provide an array to specify multiple request methods and match on any of
|
|
|
418
418
|
{method: :post} # matches POST
|
|
419
419
|
{method: ['post', 'patch']} # matches POST and PATCH
|
|
420
420
|
|
|
421
|
+
=== true
|
|
422
|
+
|
|
423
|
+
If +true+ is given directly as a matcher, it always matches.
|
|
424
|
+
|
|
421
425
|
=== false, nil
|
|
422
426
|
|
|
423
427
|
If +false+ or +nil+ is given directly as a matcher, it doesn't match anything.
|
data/doc/conventions.rdoc
CHANGED
|
@@ -15,6 +15,8 @@ For a small application, the following directory layout is recommended:
|
|
|
15
15
|
Rakefile
|
|
16
16
|
app_name.rb
|
|
17
17
|
assets/
|
|
18
|
+
config.ru
|
|
19
|
+
db.rb
|
|
18
20
|
migrate/
|
|
19
21
|
models.rb
|
|
20
22
|
models/
|
|
@@ -25,6 +27,8 @@ For a small application, the following directory layout is recommended:
|
|
|
25
27
|
+app_name.rb+ should contain the Roda application, and should reflect the name of your application.
|
|
26
28
|
So, if your application is named +FooBar+, you should use +foo_bar.rb+.
|
|
27
29
|
|
|
30
|
+
+config.ru+ should contain the code the webserver uses to determine which application to run.
|
|
31
|
+
|
|
28
32
|
+views/+ should contain your template files. This assumes you are using the +render+ plugin
|
|
29
33
|
and server-side rendering. If you are creating a single page application and just serving
|
|
30
34
|
JSON, then you won't need a +views+ directory. For small applications, all view files should be
|
|
@@ -36,7 +40,11 @@ Again, for pure JSON applications, you won't need a +public+ directory.
|
|
|
36
40
|
+assets/+ should contain the source files for your CSS and javascript assets. If you are
|
|
37
41
|
not using the +assets+ plugin, you won't need an +assets+ directory.
|
|
38
42
|
|
|
39
|
-
+
|
|
43
|
+
+db.rb+ should contain the minimum code to setup a database connection, without loading any of
|
|
44
|
+
the applications models. This can be required in cases where you don't want the models loaded,
|
|
45
|
+
such as when running migrations. This file should be required by +models.rb+.
|
|
46
|
+
|
|
47
|
+
+models.rb+ should contain all code related to your ORM. This file should be required
|
|
40
48
|
by +app_name.rb+. This keeps your model code separate from your web code, making it easier
|
|
41
49
|
to use outside of your web code. It allows you to get an IRB shell for accessing your models
|
|
42
50
|
via <tt>irb -r ./models</tt>, without loading the Roda application.
|
|
@@ -46,7 +54,7 @@ via <tt>irb -r ./models</tt>, without loading the Roda application.
|
|
|
46
54
|
+migrate/+ should create your database migration files, if you are using an ORM that uses
|
|
47
55
|
migrations.
|
|
48
56
|
|
|
49
|
-
+spec/+ should contain your specifications/tests. For a small application, it's recommended
|
|
57
|
+
+spec/+ (or +test/+ should contain your specifications/tests. For a small application, it's recommended
|
|
50
58
|
to a have a single file for your model tests, and a single file for your web/integration tests.
|
|
51
59
|
|
|
52
60
|
+Rakefile+ should contain the rake tasks for the application. The convention is that the
|
|
@@ -83,7 +91,8 @@ The routes used by the +hash_routes+ or +multi_run+ should be stored in routing
|
|
|
83
91
|
directory, with one file per prefix.
|
|
84
92
|
|
|
85
93
|
For specs/tests, you should have +spec/models/+ and +spec/web/+, with one file per model in +spec/models/+
|
|
86
|
-
and one file per prefix in +spec/web/+.
|
|
94
|
+
and one file per prefix in +spec/web/+. Substitute +spec+ with +test+ if that is what you are using as the
|
|
95
|
+
name of the directory.
|
|
87
96
|
|
|
88
97
|
You should have a separate view subdirectory per prefix. If you are using +hash_routes+ and +view_options+ plugins,
|
|
89
98
|
use +set_view_subdir+ in your routing files to specify the subdirectory to use, so it doesn't need to be
|
|
@@ -105,7 +114,7 @@ subdirectories in the +routes/+ directory, and nested subdirectories in the +vie
|
|
|
105
114
|
For a small application, the convention in Roda is to layout your Roda application file (+app_name.rb+) like this:
|
|
106
115
|
|
|
107
116
|
require 'roda'
|
|
108
|
-
|
|
117
|
+
require_relative 'models'
|
|
109
118
|
|
|
110
119
|
class AppName < Roda
|
|
111
120
|
SOME_CONSTANT = 1
|
|
@@ -138,24 +147,24 @@ used in your route block or views.
|
|
|
138
147
|
For larger applications, there are some slight changes to the Roda application file layout:
|
|
139
148
|
|
|
140
149
|
require 'roda'
|
|
141
|
-
|
|
150
|
+
require_relative 'models'
|
|
142
151
|
|
|
143
152
|
class AppName < Roda
|
|
144
153
|
SOME_CONSTANT = 1
|
|
145
154
|
|
|
146
155
|
use SomeMiddleware
|
|
147
156
|
|
|
148
|
-
plugin :render, escape: true
|
|
157
|
+
plugin :render, escape: true, layout: './layout'
|
|
149
158
|
plugin :assets
|
|
150
159
|
plugin :view_options
|
|
151
160
|
plugin :hash_routes
|
|
152
|
-
Dir['
|
|
161
|
+
Dir['routes/*.rb'].each{|f| require_relative f}
|
|
153
162
|
|
|
154
163
|
route do |r|
|
|
155
164
|
r.hash_routes
|
|
156
165
|
end
|
|
157
166
|
|
|
158
|
-
Dir['
|
|
167
|
+
Dir['helpers/*.rb'].each{|f| require_relative f}
|
|
159
168
|
end
|
|
160
169
|
|
|
161
170
|
After loading the +view_options+ and +hash_routes+ plugin, you require all of your
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
= New Features
|
|
2
|
+
|
|
3
|
+
* A relative_path plugin has been added, adding a relative_path
|
|
4
|
+
method that will take an absolute path and make it relative to the
|
|
5
|
+
current request by prepending an appropriate prefix. This is
|
|
6
|
+
helpful when using Roda as a static site generator to generate a
|
|
7
|
+
site that can be hosted at any subpath or directly from the
|
|
8
|
+
filesystem.
|
|
9
|
+
|
|
10
|
+
* In the path plugin, the path method now accepts a :relative
|
|
11
|
+
option for generating relative paths instead of absolute paths.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
= New Features
|
|
2
|
+
|
|
3
|
+
* render_each in the render_each plugin now automatically handles
|
|
4
|
+
template names with subdirectories and extensions. Previously, these
|
|
5
|
+
caused issues unless the :local option was provided. So now you
|
|
6
|
+
can use:
|
|
7
|
+
|
|
8
|
+
render_each(foos, "items/foo")
|
|
9
|
+
|
|
10
|
+
instead of:
|
|
11
|
+
|
|
12
|
+
render_each(foos, "items/foo", :local=>:foo)
|
|
13
|
+
|
|
14
|
+
* each_partial has been added to the partials plugin. It operates
|
|
15
|
+
similarly to render_each, but uses the convention for partial
|
|
16
|
+
template naming. So this:
|
|
17
|
+
|
|
18
|
+
each_partial(foos, "items/foo")
|
|
19
|
+
|
|
20
|
+
is the same as:
|
|
21
|
+
|
|
22
|
+
render_each(foos, "items/_foo", :local=>:foo)
|
|
23
|
+
|
|
24
|
+
= Other Improvements
|
|
25
|
+
|
|
26
|
+
* The :dependencies option in the assets plugin now works correctly
|
|
27
|
+
with compiled templates in the render plugin in uncached mode
|
|
28
|
+
(the default in development). Previously, modifying a dependency
|
|
29
|
+
file would not result in recompiling the asset template when
|
|
30
|
+
requesting the main file.
|
|
31
|
+
|
|
32
|
+
* Method visibility issues in the following plugins have been fixed:
|
|
33
|
+
|
|
34
|
+
* content_security_policy
|
|
35
|
+
* default_headers
|
|
36
|
+
* indifferent_params
|
|
37
|
+
* placeholder_string_matchers
|
|
38
|
+
* symbol_matchers
|
|
39
|
+
|
|
40
|
+
Previously, these plugins made private methods public by mistake
|
|
41
|
+
when overriding them. Additionally, Roda.freeze no longer changes
|
|
42
|
+
the visibility of the set_default_headers private method.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
= New Features
|
|
2
|
+
|
|
3
|
+
* The path plugin now supports a url method, allowing for returning
|
|
4
|
+
the entire URL instead of just the path for class-based paths.
|
|
5
|
+
|
|
6
|
+
* The public plugin now supports a :brotli option that will directly
|
|
7
|
+
serve brotli-compressed files (with .br extension) similar to how the
|
|
8
|
+
:gzip option directly serves gzipped files (with the .gz extension).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
= Improvements
|
|
2
|
+
|
|
3
|
+
* Multiple unneeded conditionals have been removed.
|
|
4
|
+
|
|
5
|
+
* pre_content and post_context sections in backtraces are no longer
|
|
6
|
+
included in the exception_page plugin output if they would be
|
|
7
|
+
empty.
|
|
8
|
+
|
|
9
|
+
* The match_affix plugin can be loaded again with a single argument.
|
|
10
|
+
It was originally designed to accept a single argument, but a bug
|
|
11
|
+
introduced in 2.29.0 made it require two arguments.
|
|
12
|
+
|
|
13
|
+
* Core Roda and all plugins that ship with Roda now have 100% branch
|
|
14
|
+
coverage.
|
|
15
|
+
|
|
16
|
+
* The sinatra_helpers plugin no longer emits statement not reached
|
|
17
|
+
warnings in verbose mode.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
= New Features
|
|
2
|
+
|
|
3
|
+
* An r plugin has been added. This plugin adds an r method for the
|
|
4
|
+
request, useful for allowing the use of r.halt and r.redirect even
|
|
5
|
+
in methods where the r local variable is not in scope.
|
|
6
|
+
|
|
7
|
+
= Other Improvements
|
|
8
|
+
|
|
9
|
+
* Attempting to load a plugin with an argument or block when the plugin
|
|
10
|
+
does not accept arguments or a block now warns. This is because a
|
|
11
|
+
future update to support a block or an optional argument could break
|
|
12
|
+
the call.
|
data/lib/roda.rb
CHANGED
|
@@ -197,6 +197,8 @@ class Roda
|
|
|
197
197
|
if instance_method(:set_default_headers).owner == ResponseMethods &&
|
|
198
198
|
instance_method(:default_headers).owner == ResponseMethods
|
|
199
199
|
|
|
200
|
+
private
|
|
201
|
+
|
|
200
202
|
def set_default_headers
|
|
201
203
|
@headers['Content-Type'] ||= 'text/html'
|
|
202
204
|
end
|
|
@@ -270,6 +272,12 @@ class Roda
|
|
|
270
272
|
raise RodaError, "Cannot add a plugin to a frozen Roda class" if frozen?
|
|
271
273
|
plugin = RodaPlugins.load_plugin(plugin) if plugin.is_a?(Symbol)
|
|
272
274
|
raise RodaError, "Invalid plugin type: #{plugin.class.inspect}" unless plugin.is_a?(Module)
|
|
275
|
+
|
|
276
|
+
if !plugin.respond_to?(:load_dependencies) && !plugin.respond_to?(:configure) && (!args.empty? || block)
|
|
277
|
+
# RODA4: switch from warning to error
|
|
278
|
+
RodaPlugins.warn("Plugin #{plugin} does not accept arguments or a block, but arguments or a block was passed when loading this. This will raise an error in Roda 4.")
|
|
279
|
+
end
|
|
280
|
+
|
|
273
281
|
plugin.load_dependencies(self, *args, &block) if plugin.respond_to?(:load_dependencies)
|
|
274
282
|
include(plugin::InstanceMethods) if defined?(plugin::InstanceMethods)
|
|
275
283
|
extend(plugin::ClassMethods) if defined?(plugin::ClassMethods)
|
|
@@ -34,7 +34,9 @@ class Roda
|
|
|
34
34
|
module AllVerbs
|
|
35
35
|
module RequestMethods
|
|
36
36
|
%w'delete head options link patch put trace unlink'.each do |verb|
|
|
37
|
+
# :nocov:
|
|
37
38
|
if ::Rack::Request.method_defined?("#{verb}?")
|
|
39
|
+
# :nocov:
|
|
38
40
|
class_eval(<<-END, __FILE__, __LINE__+1)
|
|
39
41
|
def #{verb}(*args, &block)
|
|
40
42
|
_verb(args, &block) if #{verb}?
|
data/lib/roda/plugins/assets.rb
CHANGED
|
@@ -325,10 +325,14 @@ class Roda
|
|
|
325
325
|
|
|
326
326
|
# Load the render, caching, and h plugins, since the assets plugin
|
|
327
327
|
# depends on them.
|
|
328
|
-
def self.load_dependencies(app,
|
|
328
|
+
def self.load_dependencies(app, opts = OPTS)
|
|
329
329
|
app.plugin :render
|
|
330
330
|
app.plugin :caching
|
|
331
331
|
app.plugin :h
|
|
332
|
+
|
|
333
|
+
if opts[:relative_paths]
|
|
334
|
+
app.plugin :relative_path
|
|
335
|
+
end
|
|
332
336
|
end
|
|
333
337
|
|
|
334
338
|
# Setup the options for the plugin. See the Assets module RDoc
|
|
@@ -401,6 +405,11 @@ class Roda
|
|
|
401
405
|
opts[s] ||= {}
|
|
402
406
|
end
|
|
403
407
|
|
|
408
|
+
expanded_deps = opts[:expanded_dependencies] = {}
|
|
409
|
+
opts[:dependencies].each do |file, deps|
|
|
410
|
+
expanded_deps[File.expand_path(file)] = Array(deps)
|
|
411
|
+
end
|
|
412
|
+
|
|
404
413
|
if headers = opts[:headers]
|
|
405
414
|
opts[:css_headers] = headers.merge(opts[:css_headers])
|
|
406
415
|
opts[:js_headers] = headers.merge(opts[:js_headers])
|
|
@@ -408,7 +417,7 @@ class Roda
|
|
|
408
417
|
opts[:css_headers]['Content-Type'] ||= "text/css; charset=UTF-8".freeze
|
|
409
418
|
opts[:js_headers]['Content-Type'] ||= "application/javascript; charset=UTF-8".freeze
|
|
410
419
|
|
|
411
|
-
[:css_headers, :js_headers, :css_opts, :js_opts, :dependencies].each do |s|
|
|
420
|
+
[:css_headers, :js_headers, :css_opts, :js_opts, :dependencies, :expanded_dependencies].each do |s|
|
|
412
421
|
opts[s].freeze
|
|
413
422
|
end
|
|
414
423
|
[:headers, :css, :js].each do |s|
|
|
@@ -647,10 +656,9 @@ class Roda
|
|
|
647
656
|
end
|
|
648
657
|
end
|
|
649
658
|
|
|
650
|
-
if relative_paths
|
|
651
|
-
relative_prefix = "../" * (slash_count - 1)
|
|
659
|
+
if relative_paths
|
|
652
660
|
paths.map! do |path|
|
|
653
|
-
"#{relative_prefix}#{path
|
|
661
|
+
"#{relative_prefix}#{path}"
|
|
654
662
|
end
|
|
655
663
|
end
|
|
656
664
|
|
|
@@ -729,7 +737,7 @@ class Roda
|
|
|
729
737
|
content = if file.end_with?(".#{type}")
|
|
730
738
|
::File.read(file)
|
|
731
739
|
else
|
|
732
|
-
render_asset_file(file, :template_opts=>o[:"#{type}_opts"])
|
|
740
|
+
render_asset_file(file, :template_opts=>o[:"#{type}_opts"], :dependencies=>o[:expanded_dependencies][file])
|
|
733
741
|
end
|
|
734
742
|
|
|
735
743
|
o[:postprocessor] ? o[:postprocessor].call(file, type, content) : content
|
|
@@ -759,7 +767,7 @@ class Roda
|
|
|
759
767
|
# other files, check the modification times of all dependencies and
|
|
760
768
|
# return the maximum.
|
|
761
769
|
def asset_last_modified(file)
|
|
762
|
-
if deps = self.class.assets_opts[:
|
|
770
|
+
if deps = self.class.assets_opts[:expanded_dependencies][file]
|
|
763
771
|
([file] + Array(deps)).map{|f| ::File.stat(f).mtime}.max
|
|
764
772
|
else
|
|
765
773
|
::File.stat(file).mtime
|
|
@@ -33,9 +33,7 @@ class Roda
|
|
|
33
33
|
# elements. If the remaining elements could not be
|
|
34
34
|
# matched, reset the state and continue to the next
|
|
35
35
|
# entry in the array.
|
|
36
|
-
def _match_array(arg, rest
|
|
37
|
-
return super unless rest
|
|
38
|
-
|
|
36
|
+
def _match_array(arg, rest)
|
|
39
37
|
path = @remaining_path
|
|
40
38
|
captures = @captures
|
|
41
39
|
caps = captures.dup
|
|
@@ -31,6 +31,8 @@ class Roda
|
|
|
31
31
|
if owner == Base::ResponseMethods || (owner == response_class && app.opts[:set_default_headers_overridder] == response_class)
|
|
32
32
|
app.opts[:set_default_headers_overridder] = response_class
|
|
33
33
|
response_class.class_eval(<<-END, __FILE__, __LINE__+1)
|
|
34
|
+
private
|
|
35
|
+
|
|
34
36
|
def set_default_headers
|
|
35
37
|
h = @headers
|
|
36
38
|
#{headers.map{|k,v| "h[#{k.inspect}] ||= #{v.inspect}"}.join('; ')}
|
|
@@ -252,11 +252,21 @@ END
|
|
|
252
252
|
begin
|
|
253
253
|
lineno -= 1
|
|
254
254
|
lines = ::File.readlines(filename)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
255
|
+
if line = lines[lineno]
|
|
256
|
+
pre_lineno = [lineno-context, 0].max
|
|
257
|
+
if (pre_context = lines[pre_lineno...lineno]) && !pre_context.empty?
|
|
258
|
+
frame[:pre_context_lineno] = pre_lineno
|
|
259
|
+
frame[:pre_context] = pre_context
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
post_lineno = [lineno+context, lines.size].min
|
|
263
|
+
if (post_context = lines[lineno+1..post_lineno]) && !post_context.empty?
|
|
264
|
+
frame[:post_context_lineno] = post_lineno
|
|
265
|
+
frame[:post_context] = post_context
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
frame[:context_line] = line.chomp
|
|
269
|
+
end
|
|
260
270
|
rescue
|
|
261
271
|
end
|
|
262
272
|
|
|
@@ -28,7 +28,7 @@ class Roda
|
|
|
28
28
|
#
|
|
29
29
|
# This plugin automatically loads the placeholder_string_matchers plugin.
|
|
30
30
|
module MatchAffix
|
|
31
|
-
def self.load_dependencies(app, _prefix, _suffix)
|
|
31
|
+
def self.load_dependencies(app, _prefix, _suffix=nil)
|
|
32
32
|
app.plugin :placeholder_string_matchers
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -104,7 +104,9 @@ class Roda
|
|
|
104
104
|
# arguments, record the verb used. If given an argument, add an is
|
|
105
105
|
# check with the arguments.
|
|
106
106
|
%w'get post delete head options link patch put trace unlink'.each do |verb|
|
|
107
|
+
# :nocov:
|
|
107
108
|
if ::Rack::Request.method_defined?("#{verb}?")
|
|
109
|
+
# :nocov:
|
|
108
110
|
class_eval(<<-END, __FILE__, __LINE__+1)
|
|
109
111
|
def #{verb}(*args, &block)
|
|
110
112
|
if (empty = args.empty?) && @_is_verbs
|
|
@@ -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,24 @@ 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
|
+
headers['Content-Type'] = ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
|
|
114
|
+
headers['Content-Encoding'] = encoding
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
halt res
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
116
122
|
if ::Rack.release > '2'
|
|
117
123
|
# Serve the given path using the given Rack::File server.
|
|
118
124
|
def public_serve(server, path)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The r plugin adds an +r+ instance method that will return the request.
|
|
7
|
+
# This allows you to use common Roda idioms such as +r.halt+ and
|
|
8
|
+
# +r.redirect+ even when +r+ isn't a local variable in scope. Example:
|
|
9
|
+
#
|
|
10
|
+
# plugin :r
|
|
11
|
+
#
|
|
12
|
+
# def foo
|
|
13
|
+
# r.redirect "/bar"
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# route do |r|
|
|
17
|
+
# r.get "foo" do
|
|
18
|
+
# foo
|
|
19
|
+
# end
|
|
20
|
+
# r.get "bar" do
|
|
21
|
+
# "bar"
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
module R
|
|
25
|
+
module InstanceMethods
|
|
26
|
+
# The request object.
|
|
27
|
+
def r
|
|
28
|
+
@_request
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
register_plugin(:r, R)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -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
|
|
@@ -275,7 +287,9 @@ class Roda
|
|
|
275
287
|
false
|
|
276
288
|
end
|
|
277
289
|
|
|
290
|
+
# :nocov:
|
|
278
291
|
if COMPILED_METHOD_SUPPORT
|
|
292
|
+
# :nocov:
|
|
279
293
|
# Compile a method in the given module with the given name that will
|
|
280
294
|
# call the compiled template method, updating the compiled template method
|
|
281
295
|
def define_compiled_method(roda_class, method_name, locals_keys=EMPTY_ARRAY)
|
|
@@ -325,7 +339,9 @@ class Roda
|
|
|
325
339
|
def inherited(subclass)
|
|
326
340
|
super
|
|
327
341
|
opts = subclass.opts[:render] = subclass.opts[:render].dup
|
|
342
|
+
# :nocov:
|
|
328
343
|
if COMPILED_METHOD_SUPPORT
|
|
344
|
+
# :nocov:
|
|
329
345
|
opts[:template_method_cache] = (opts[:cache_class] || RodaCache).new
|
|
330
346
|
end
|
|
331
347
|
opts[:cache] = opts[:cache].dup
|
|
@@ -576,7 +592,7 @@ class Roda
|
|
|
576
592
|
!opts[:inline]
|
|
577
593
|
|
|
578
594
|
if render_opts[:check_template_mtime] && !opts[:template_block] && !cache
|
|
579
|
-
template = TemplateMtimeWrapper.new(opts[:template_class], opts[:path], 1, template_opts)
|
|
595
|
+
template = TemplateMtimeWrapper.new(opts[:template_class], opts[:path], opts[:dependencies], 1, template_opts)
|
|
580
596
|
|
|
581
597
|
if define_compiled_method
|
|
582
598
|
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
|
|
@@ -43,7 +43,9 @@ class Roda
|
|
|
43
43
|
module InstanceMethods
|
|
44
44
|
private
|
|
45
45
|
|
|
46
|
+
# :nocov:
|
|
46
47
|
if Render::COMPILED_METHOD_SUPPORT
|
|
48
|
+
# :nocov:
|
|
47
49
|
# Disable use of cached templates, since it assumes a render/view call with no
|
|
48
50
|
# options will have no locals.
|
|
49
51
|
def _cached_template_method(template)
|
|
@@ -374,7 +374,7 @@ class Roda
|
|
|
374
374
|
|
|
375
375
|
module ResponseMethods
|
|
376
376
|
# Set or retrieve the response status code.
|
|
377
|
-
def status(value = (return @status
|
|
377
|
+
def status(value = nil || (return @status))
|
|
378
378
|
@status = value
|
|
379
379
|
end
|
|
380
380
|
|
|
@@ -401,7 +401,7 @@ class Roda
|
|
|
401
401
|
|
|
402
402
|
# Set multiple response headers with Hash, or return the headers if no
|
|
403
403
|
# argument is given.
|
|
404
|
-
def headers(hash = (return @headers
|
|
404
|
+
def headers(hash = nil || (return @headers))
|
|
405
405
|
@headers.merge!(hash)
|
|
406
406
|
end
|
|
407
407
|
|
|
@@ -412,7 +412,7 @@ class Roda
|
|
|
412
412
|
|
|
413
413
|
# Set the Content-Type of the response body given a media type or file
|
|
414
414
|
# extension. See plugin documentation for options.
|
|
415
|
-
def content_type(type = (return @headers["Content-Type"]
|
|
415
|
+
def content_type(type = nil || (return @headers["Content-Type"]), opts = OPTS)
|
|
416
416
|
unless (mime_type = mime_type(type) || opts[:default])
|
|
417
417
|
raise RodaError, "Unknown media type: #{type}"
|
|
418
418
|
end
|
|
@@ -478,7 +478,7 @@ class Roda
|
|
|
478
478
|
# If a type and value are given, set the value in Rack's MIME registry.
|
|
479
479
|
# If only a type is given, lookup the type in Rack's MIME registry and
|
|
480
480
|
# return it.
|
|
481
|
-
def mime_type(type=(return
|
|
481
|
+
def mime_type(type=nil || (return), value = nil)
|
|
482
482
|
return type.to_s if type.to_s.include?('/')
|
|
483
483
|
type = ".#{type}" unless type.to_s[0] == ?.
|
|
484
484
|
if value
|
|
@@ -6,7 +6,7 @@ class Roda
|
|
|
6
6
|
# The symbol_matchers plugin allows you do define custom regexps to use
|
|
7
7
|
# for specific symbols. For example, if you have a route such as:
|
|
8
8
|
#
|
|
9
|
-
# r.on :username do
|
|
9
|
+
# r.on :username do |username|
|
|
10
10
|
# # ...
|
|
11
11
|
# end
|
|
12
12
|
#
|
|
@@ -28,7 +28,7 @@ class Roda
|
|
|
28
28
|
# If the placeholder_string_matchers plugin is loaded, this feature also applies to
|
|
29
29
|
# placeholders in strings, so the following:
|
|
30
30
|
#
|
|
31
|
-
# r.on "users/:username" do
|
|
31
|
+
# r.on "users/:username" do |username|
|
|
32
32
|
# # ...
|
|
33
33
|
# end
|
|
34
34
|
#
|
|
@@ -742,9 +742,7 @@ class Roda
|
|
|
742
742
|
return
|
|
743
743
|
end
|
|
744
744
|
|
|
745
|
-
|
|
746
|
-
v.subkey(keys, do_raise)
|
|
747
|
-
end
|
|
745
|
+
self[key].subkey(keys, do_raise)
|
|
748
746
|
rescue => e
|
|
749
747
|
handle_error(key, reason, e)
|
|
750
748
|
end
|
|
@@ -808,10 +806,10 @@ class Roda
|
|
|
808
806
|
@nested_params = nil
|
|
809
807
|
|
|
810
808
|
if capturing_started
|
|
811
|
-
# Unset capturing if capturing was
|
|
809
|
+
# Unset capturing if capturing was already started.
|
|
812
810
|
@capture = nil
|
|
813
811
|
else
|
|
814
|
-
# If capturing was already started, update cached nested params
|
|
812
|
+
# If capturing was not already started, update cached nested params
|
|
815
813
|
# before resetting symbolize setting.
|
|
816
814
|
@nested_params = nested_params
|
|
817
815
|
end
|
|
@@ -878,7 +876,7 @@ class Roda
|
|
|
878
876
|
def handle_error(key, reason, e, do_raise=false)
|
|
879
877
|
case e
|
|
880
878
|
when String
|
|
881
|
-
handle_error(key, reason, Error.new(e), do_raise
|
|
879
|
+
handle_error(key, reason, Error.new(e), do_raise)
|
|
882
880
|
when Error, ArgumentError
|
|
883
881
|
if @capture && (le = @capture.last) && le == e
|
|
884
882
|
raise e if do_raise
|
|
@@ -126,7 +126,9 @@ class Roda
|
|
|
126
126
|
|
|
127
127
|
private
|
|
128
128
|
|
|
129
|
+
# :nocov:
|
|
129
130
|
if Render::COMPILED_METHOD_SUPPORT
|
|
131
|
+
# :nocov:
|
|
130
132
|
# Return nil if using custom view or layout options.
|
|
131
133
|
# If using a view subdir, prefix the template key with the subdir.
|
|
132
134
|
def _cached_template_method_key(template)
|
data/lib/roda/request.rb
CHANGED
|
@@ -466,10 +466,8 @@ class Roda
|
|
|
466
466
|
rp = @remaining_path
|
|
467
467
|
if rp.getbyte(0) == 47
|
|
468
468
|
if last = rp.index('/', 1)
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
@remaining_path = rp[last, rp.length]
|
|
472
|
-
end
|
|
469
|
+
@captures << rp[1, last-1]
|
|
470
|
+
@remaining_path = rp[last, rp.length]
|
|
473
471
|
elsif rp.length > 1
|
|
474
472
|
@captures << rp[1,rp.length]
|
|
475
473
|
@remaining_path = ""
|
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.35.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: 2020-
|
|
11
|
+
date: 2020-08-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|
|
@@ -206,6 +206,11 @@ extra_rdoc_files:
|
|
|
206
206
|
- doc/release_notes/3.28.0.txt
|
|
207
207
|
- doc/release_notes/3.29.0.txt
|
|
208
208
|
- doc/release_notes/3.30.0.txt
|
|
209
|
+
- doc/release_notes/3.31.0.txt
|
|
210
|
+
- doc/release_notes/3.32.0.txt
|
|
211
|
+
- doc/release_notes/3.33.0.txt
|
|
212
|
+
- doc/release_notes/3.34.0.txt
|
|
213
|
+
- doc/release_notes/3.35.0.txt
|
|
209
214
|
files:
|
|
210
215
|
- CHANGELOG
|
|
211
216
|
- MIT-LICENSE
|
|
@@ -237,6 +242,11 @@ files:
|
|
|
237
242
|
- doc/release_notes/3.29.0.txt
|
|
238
243
|
- doc/release_notes/3.3.0.txt
|
|
239
244
|
- doc/release_notes/3.30.0.txt
|
|
245
|
+
- doc/release_notes/3.31.0.txt
|
|
246
|
+
- doc/release_notes/3.32.0.txt
|
|
247
|
+
- doc/release_notes/3.33.0.txt
|
|
248
|
+
- doc/release_notes/3.34.0.txt
|
|
249
|
+
- doc/release_notes/3.35.0.txt
|
|
240
250
|
- doc/release_notes/3.4.0.txt
|
|
241
251
|
- doc/release_notes/3.5.0.txt
|
|
242
252
|
- doc/release_notes/3.6.0.txt
|
|
@@ -316,6 +326,8 @@ files:
|
|
|
316
326
|
- lib/roda/plugins/placeholder_string_matchers.rb
|
|
317
327
|
- lib/roda/plugins/precompile_templates.rb
|
|
318
328
|
- lib/roda/plugins/public.rb
|
|
329
|
+
- lib/roda/plugins/r.rb
|
|
330
|
+
- lib/roda/plugins/relative_path.rb
|
|
319
331
|
- lib/roda/plugins/render.rb
|
|
320
332
|
- lib/roda/plugins/render_each.rb
|
|
321
333
|
- lib/roda/plugins/render_locals.rb
|