ultra-max-sys 0.0.1
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.
Potentially problematic release.
This version of ultra-max-sys might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/roda-3.106.0/MIT-LICENSE +21 -0
- data/roda-3.106.0/lib/roda/cache.rb +42 -0
- data/roda-3.106.0/lib/roda/plugins/Integer_matcher_max.rb +55 -0
- data/roda-3.106.0/lib/roda/plugins/_after_hook.rb +11 -0
- data/roda-3.106.0/lib/roda/plugins/_base64.rb +34 -0
- data/roda-3.106.0/lib/roda/plugins/_before_hook.rb +41 -0
- data/roda-3.106.0/lib/roda/plugins/_optimized_matching.rb +227 -0
- data/roda-3.106.0/lib/roda/plugins/_symbol_class_matchers.rb +108 -0
- data/roda-3.106.0/lib/roda/plugins/_symbol_regexp_matchers.rb +24 -0
- data/roda-3.106.0/lib/roda/plugins/additional_render_engines.rb +61 -0
- data/roda-3.106.0/lib/roda/plugins/additional_view_directories.rb +66 -0
- data/roda-3.106.0/lib/roda/plugins/all_verbs.rb +50 -0
- data/roda-3.106.0/lib/roda/plugins/assets.rb +902 -0
- data/roda-3.106.0/lib/roda/plugins/assets_preloading.rb +89 -0
- data/roda-3.106.0/lib/roda/plugins/assume_ssl.rb +28 -0
- data/roda-3.106.0/lib/roda/plugins/autoload_hash_branches.rb +79 -0
- data/roda-3.106.0/lib/roda/plugins/autoload_named_routes.rb +65 -0
- data/roda-3.106.0/lib/roda/plugins/backtracking_array.rb +88 -0
- data/roda-3.106.0/lib/roda/plugins/bearer_token.rb +28 -0
- data/roda-3.106.0/lib/roda/plugins/branch_locals.rb +76 -0
- data/roda-3.106.0/lib/roda/plugins/break.rb +43 -0
- data/roda-3.106.0/lib/roda/plugins/caching.rb +206 -0
- data/roda-3.106.0/lib/roda/plugins/capture_erb.rb +94 -0
- data/roda-3.106.0/lib/roda/plugins/chunked.rb +333 -0
- data/roda-3.106.0/lib/roda/plugins/class_level_routing.rb +111 -0
- data/roda-3.106.0/lib/roda/plugins/class_matchers.rb +155 -0
- data/roda-3.106.0/lib/roda/plugins/common_logger.rb +82 -0
- data/roda-3.106.0/lib/roda/plugins/conditional_sessions.rb +67 -0
- data/roda-3.106.0/lib/roda/plugins/content_for.rb +105 -0
- data/roda-3.106.0/lib/roda/plugins/content_security_policy.rb +333 -0
- data/roda-3.106.0/lib/roda/plugins/cookie_flags.rb +157 -0
- data/roda-3.106.0/lib/roda/plugins/cookies.rb +51 -0
- data/roda-3.106.0/lib/roda/plugins/csrf.rb +81 -0
- data/roda-3.106.0/lib/roda/plugins/custom_block_results.rb +85 -0
- data/roda-3.106.0/lib/roda/plugins/custom_matchers.rb +89 -0
- data/roda-3.106.0/lib/roda/plugins/default_headers.rb +64 -0
- data/roda-3.106.0/lib/roda/plugins/default_status.rb +35 -0
- data/roda-3.106.0/lib/roda/plugins/delay_build.rb +18 -0
- data/roda-3.106.0/lib/roda/plugins/delegate.rb +77 -0
- data/roda-3.106.0/lib/roda/plugins/delete_empty_headers.rb +36 -0
- data/roda-3.106.0/lib/roda/plugins/direct_call.rb +38 -0
- data/roda-3.106.0/lib/roda/plugins/disallow_file_uploads.rb +38 -0
- data/roda-3.106.0/lib/roda/plugins/drop_body.rb +43 -0
- data/roda-3.106.0/lib/roda/plugins/each_part.rb +87 -0
- data/roda-3.106.0/lib/roda/plugins/early_hints.rb +25 -0
- data/roda-3.106.0/lib/roda/plugins/empty_root.rb +49 -0
- data/roda-3.106.0/lib/roda/plugins/environments.rb +79 -0
- data/roda-3.106.0/lib/roda/plugins/erb_h.rb +43 -0
- data/roda-3.106.0/lib/roda/plugins/error_email.rb +152 -0
- data/roda-3.106.0/lib/roda/plugins/error_handler.rb +133 -0
- data/roda-3.106.0/lib/roda/plugins/error_mail.rb +149 -0
- data/roda-3.106.0/lib/roda/plugins/exception_page.rb +445 -0
- data/roda-3.106.0/lib/roda/plugins/filter_common_logger.rb +46 -0
- data/roda-3.106.0/lib/roda/plugins/flash.rb +119 -0
- data/roda-3.106.0/lib/roda/plugins/h.rb +59 -0
- data/roda-3.106.0/lib/roda/plugins/halt.rb +108 -0
- data/roda-3.106.0/lib/roda/plugins/hash_branch_view_subdir.rb +76 -0
- data/roda-3.106.0/lib/roda/plugins/hash_branches.rb +145 -0
- data/roda-3.106.0/lib/roda/plugins/hash_matcher.rb +39 -0
- data/roda-3.106.0/lib/roda/plugins/hash_paths.rb +128 -0
- data/roda-3.106.0/lib/roda/plugins/hash_public.rb +125 -0
- data/roda-3.106.0/lib/roda/plugins/hash_public_cache.rb +91 -0
- data/roda-3.106.0/lib/roda/plugins/hash_routes.rb +304 -0
- data/roda-3.106.0/lib/roda/plugins/head.rb +99 -0
- data/roda-3.106.0/lib/roda/plugins/header_matchers.rb +88 -0
- data/roda-3.106.0/lib/roda/plugins/heartbeat.rb +41 -0
- data/roda-3.106.0/lib/roda/plugins/hmac_paths.rb +413 -0
- data/roda-3.106.0/lib/roda/plugins/hooks.rb +92 -0
- data/roda-3.106.0/lib/roda/plugins/host_authorization.rb +155 -0
- data/roda-3.106.0/lib/roda/plugins/host_routing.rb +194 -0
- data/roda-3.106.0/lib/roda/plugins/hsts.rb +35 -0
- data/roda-3.106.0/lib/roda/plugins/indifferent_params.rb +126 -0
- data/roda-3.106.0/lib/roda/plugins/inject_erb.rb +33 -0
- data/roda-3.106.0/lib/roda/plugins/invalid_request_body.rb +107 -0
- data/roda-3.106.0/lib/roda/plugins/ip_from_header.rb +34 -0
- data/roda-3.106.0/lib/roda/plugins/json.rb +119 -0
- data/roda-3.106.0/lib/roda/plugins/json_parser.rb +107 -0
- data/roda-3.106.0/lib/roda/plugins/link_to.rb +83 -0
- data/roda-3.106.0/lib/roda/plugins/mail_processor.rb +629 -0
- data/roda-3.106.0/lib/roda/plugins/mailer.rb +285 -0
- data/roda-3.106.0/lib/roda/plugins/map_matcher.rb +48 -0
- data/roda-3.106.0/lib/roda/plugins/match_affix.rb +64 -0
- data/roda-3.106.0/lib/roda/plugins/match_hook.rb +34 -0
- data/roda-3.106.0/lib/roda/plugins/match_hook_args.rb +93 -0
- data/roda-3.106.0/lib/roda/plugins/middleware.rb +225 -0
- data/roda-3.106.0/lib/roda/plugins/middleware_stack.rb +101 -0
- data/roda-3.106.0/lib/roda/plugins/module_include.rb +96 -0
- data/roda-3.106.0/lib/roda/plugins/multi_public.rb +95 -0
- data/roda-3.106.0/lib/roda/plugins/multi_route.rb +156 -0
- data/roda-3.106.0/lib/roda/plugins/multi_run.rb +144 -0
- data/roda-3.106.0/lib/roda/plugins/multi_view.rb +83 -0
- data/roda-3.106.0/lib/roda/plugins/multibyte_string_matcher.rb +57 -0
- data/roda-3.106.0/lib/roda/plugins/named_routes.rb +167 -0
- data/roda-3.106.0/lib/roda/plugins/named_templates.rb +102 -0
- data/roda-3.106.0/lib/roda/plugins/not_allowed.rb +151 -0
- data/roda-3.106.0/lib/roda/plugins/not_found.rb +55 -0
- data/roda-3.106.0/lib/roda/plugins/optimized_segment_matchers.rb +53 -0
- data/roda-3.106.0/lib/roda/plugins/optimized_string_matchers.rb +50 -0
- data/roda-3.106.0/lib/roda/plugins/padrino_render.rb +42 -0
- data/roda-3.106.0/lib/roda/plugins/param_matchers.rb +83 -0
- data/roda-3.106.0/lib/roda/plugins/params_capturing.rb +118 -0
- data/roda-3.106.0/lib/roda/plugins/part.rb +76 -0
- data/roda-3.106.0/lib/roda/plugins/partials.rb +74 -0
- data/roda-3.106.0/lib/roda/plugins/pass.rb +47 -0
- data/roda-3.106.0/lib/roda/plugins/path.rb +255 -0
- data/roda-3.106.0/lib/roda/plugins/path_matchers.rb +54 -0
- data/roda-3.106.0/lib/roda/plugins/path_rewriter.rb +111 -0
- data/roda-3.106.0/lib/roda/plugins/permissions_policy.rb +340 -0
- data/roda-3.106.0/lib/roda/plugins/placeholder_string_matchers.rb +48 -0
- data/roda-3.106.0/lib/roda/plugins/plain_hash_response_headers.rb +32 -0
- data/roda-3.106.0/lib/roda/plugins/precompile_templates.rb +156 -0
- data/roda-3.106.0/lib/roda/plugins/public.rb +182 -0
- data/roda-3.106.0/lib/roda/plugins/r.rb +35 -0
- data/roda-3.106.0/lib/roda/plugins/recheck_precompiled_assets.rb +107 -0
- data/roda-3.106.0/lib/roda/plugins/redirect_http_to_https.rb +99 -0
- data/roda-3.106.0/lib/roda/plugins/redirect_path.rb +59 -0
- data/roda-3.106.0/lib/roda/plugins/relative_path.rb +76 -0
- data/roda-3.106.0/lib/roda/plugins/render.rb +998 -0
- data/roda-3.106.0/lib/roda/plugins/render_coverage.rb +105 -0
- data/roda-3.106.0/lib/roda/plugins/render_each.rb +224 -0
- data/roda-3.106.0/lib/roda/plugins/render_locals.rb +102 -0
- data/roda-3.106.0/lib/roda/plugins/request_aref.rb +77 -0
- data/roda-3.106.0/lib/roda/plugins/request_headers.rb +83 -0
- data/roda-3.106.0/lib/roda/plugins/response_attachment.rb +94 -0
- data/roda-3.106.0/lib/roda/plugins/response_content_type.rb +79 -0
- data/roda-3.106.0/lib/roda/plugins/response_request.rb +36 -0
- data/roda-3.106.0/lib/roda/plugins/route_block_args.rb +50 -0
- data/roda-3.106.0/lib/roda/plugins/route_csrf.rb +388 -0
- data/roda-3.106.0/lib/roda/plugins/run_append_slash.rb +51 -0
- data/roda-3.106.0/lib/roda/plugins/run_handler.rb +51 -0
- data/roda-3.106.0/lib/roda/plugins/run_require_slash.rb +46 -0
- data/roda-3.106.0/lib/roda/plugins/sec_fetch_site_csrf.rb +131 -0
- data/roda-3.106.0/lib/roda/plugins/send_file.rb +127 -0
- data/roda-3.106.0/lib/roda/plugins/sessions.rb +537 -0
- data/roda-3.106.0/lib/roda/plugins/shape_friendly.rb +232 -0
- data/roda-3.106.0/lib/roda/plugins/shared_vars.rb +86 -0
- data/roda-3.106.0/lib/roda/plugins/sinatra_helpers.rb +444 -0
- data/roda-3.106.0/lib/roda/plugins/slash_path_empty.rb +26 -0
- data/roda-3.106.0/lib/roda/plugins/static.rb +42 -0
- data/roda-3.106.0/lib/roda/plugins/static_routing.rb +89 -0
- data/roda-3.106.0/lib/roda/plugins/status_303.rb +34 -0
- data/roda-3.106.0/lib/roda/plugins/status_handler.rb +86 -0
- data/roda-3.106.0/lib/roda/plugins/streaming.rb +170 -0
- data/roda-3.106.0/lib/roda/plugins/strip_path_prefix.rb +33 -0
- data/roda-3.106.0/lib/roda/plugins/symbol_matchers.rb +188 -0
- data/roda-3.106.0/lib/roda/plugins/symbol_status.rb +32 -0
- data/roda-3.106.0/lib/roda/plugins/symbol_views.rb +37 -0
- data/roda-3.106.0/lib/roda/plugins/timestamp_public.rb +78 -0
- data/roda-3.106.0/lib/roda/plugins/type_routing.rb +217 -0
- data/roda-3.106.0/lib/roda/plugins/typecast_params.rb +1185 -0
- data/roda-3.106.0/lib/roda/plugins/typecast_params_sized_integers.rb +108 -0
- data/roda-3.106.0/lib/roda/plugins/unescape_path.rb +41 -0
- data/roda-3.106.0/lib/roda/plugins/view_options.rb +203 -0
- data/roda-3.106.0/lib/roda/plugins/view_subdir_leading_slash.rb +49 -0
- data/roda-3.106.0/lib/roda/plugins.rb +68 -0
- data/roda-3.106.0/lib/roda/request.rb +722 -0
- data/roda-3.106.0/lib/roda/response.rb +221 -0
- data/roda-3.106.0/lib/roda/session_middleware.rb +184 -0
- data/roda-3.106.0/lib/roda/version.rb +18 -0
- data/roda-3.106.0/lib/roda.rb +741 -0
- data/ultra-max-sys.gemspec +12 -0
- metadata +202 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The multi_run plugin provides the ability to easily dispatch to other
|
|
7
|
+
# rack applications based on the request path prefix.
|
|
8
|
+
# First, load the plugin:
|
|
9
|
+
#
|
|
10
|
+
# class App < Roda
|
|
11
|
+
# plugin :multi_run
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# Then, other rack applications can register with the multi_run plugin:
|
|
15
|
+
#
|
|
16
|
+
# App.run "ra", PlainRackApp
|
|
17
|
+
# App.run "ro", OtherRodaApp
|
|
18
|
+
# App.run "si", SinatraApp
|
|
19
|
+
#
|
|
20
|
+
# Inside your route block, you can call +r.multi_run+ to dispatch to all
|
|
21
|
+
# three rack applications based on the prefix:
|
|
22
|
+
#
|
|
23
|
+
# App.route do |r|
|
|
24
|
+
# r.multi_run
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# This will dispatch routes starting with +/ra+ to +PlainRackApp+, routes
|
|
28
|
+
# starting with +/ro+ to +OtherRodaApp+, and routes starting with +/si+ to
|
|
29
|
+
# SinatraApp.
|
|
30
|
+
#
|
|
31
|
+
# You can pass a block to +r.multi_run+ that will be called with the prefix,
|
|
32
|
+
# before dispatching to the rack app:
|
|
33
|
+
#
|
|
34
|
+
# App.route do |r|
|
|
35
|
+
# r.multi_run do |prefix|
|
|
36
|
+
# # do something based on prefix before the request is passed further
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# This is useful for modifying the environment before passing it to the rack app.
|
|
41
|
+
#
|
|
42
|
+
# You can also call +Roda.run+ with a block:
|
|
43
|
+
#
|
|
44
|
+
# App.run("ra"){PlainRackApp}
|
|
45
|
+
# App.run("ro"){OtherRodaApp}
|
|
46
|
+
# App.run("si"){SinatraApp}
|
|
47
|
+
#
|
|
48
|
+
# When called with a block, Roda will call the block to get the app to dispatch to
|
|
49
|
+
# every time the block is called. The expected usage is with autoloaded classes,
|
|
50
|
+
# so that the related classes are not loaded until there is a request for the
|
|
51
|
+
# related route. This can sigficantly speedup startup or testing a subset of the
|
|
52
|
+
# application. When freezing an application, the blocks are called once to get the
|
|
53
|
+
# app to dispatch to, and that is cached, to ensure the any autoloads are completed
|
|
54
|
+
# before the application is frozen.
|
|
55
|
+
#
|
|
56
|
+
# The multi_run plugin is similar to the hash_branches and multi_route plugins, with
|
|
57
|
+
# the difference being the hash_branches and multi_route plugins keep all routing
|
|
58
|
+
# subtrees in the same Roda app/class, while multi_run dispatches to other rack apps.
|
|
59
|
+
# If you want to isolate your routing subtrees, multi_run is a better approach, but
|
|
60
|
+
# it does not let you set instance variables in the main Roda app and have those
|
|
61
|
+
# instance variables usable in the routing subtrees.
|
|
62
|
+
#
|
|
63
|
+
# To handle development environments that reload code, you can call the
|
|
64
|
+
# +run+ class method without an app to remove dispatching for the prefix.
|
|
65
|
+
module MultiRun
|
|
66
|
+
# Initialize the storage for the dispatched applications
|
|
67
|
+
def self.configure(app)
|
|
68
|
+
app.opts[:multi_run_apps] ||= {}
|
|
69
|
+
app.opts[:multi_run_app_blocks] ||= {}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
module ClassMethods
|
|
73
|
+
# Convert app blocks into apps by calling them, in order to force autoloads
|
|
74
|
+
# and to speed up subsequent calls.
|
|
75
|
+
# Freeze the multi_run apps so that there can be no thread safety issues at runtime.
|
|
76
|
+
def freeze
|
|
77
|
+
app_blocks = opts[:multi_run_app_blocks]
|
|
78
|
+
apps = opts[:multi_run_apps]
|
|
79
|
+
app_blocks.each do |prefix, block|
|
|
80
|
+
apps[prefix] = block.call
|
|
81
|
+
end
|
|
82
|
+
app_blocks.clear.freeze
|
|
83
|
+
apps.freeze
|
|
84
|
+
self::RodaRequest.refresh_multi_run_regexp!
|
|
85
|
+
super
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Hash storing rack applications to dispatch to, keyed by the prefix
|
|
89
|
+
# for the application.
|
|
90
|
+
def multi_run_apps
|
|
91
|
+
opts[:multi_run_apps]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Add a rack application to dispatch to for the given prefix when
|
|
95
|
+
# r.multi_run is called. If a block is given, it is called every time
|
|
96
|
+
# there is a request for the route to get the app to call. If neither
|
|
97
|
+
# a block or an app is provided, any stored route for the prefix is
|
|
98
|
+
# removed. It is an error to provide both an app and block in the same call.
|
|
99
|
+
def run(prefix, app=nil, &block)
|
|
100
|
+
prefix = prefix.to_s
|
|
101
|
+
if app
|
|
102
|
+
raise Roda::RodaError, "cannot provide both app and block to Roda.run" if block
|
|
103
|
+
opts[:multi_run_apps][prefix] = app
|
|
104
|
+
opts[:multi_run_app_blocks].delete(prefix)
|
|
105
|
+
elsif block
|
|
106
|
+
opts[:multi_run_apps].delete(prefix)
|
|
107
|
+
opts[:multi_run_app_blocks][prefix] = block
|
|
108
|
+
else
|
|
109
|
+
opts[:multi_run_apps].delete(prefix)
|
|
110
|
+
opts[:multi_run_app_blocks].delete(prefix)
|
|
111
|
+
end
|
|
112
|
+
self::RodaRequest.refresh_multi_run_regexp!
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
module RequestClassMethods
|
|
117
|
+
# Refresh the multi_run_regexp, using the stored route prefixes,
|
|
118
|
+
# preferring longer routes before shorter routes.
|
|
119
|
+
def refresh_multi_run_regexp!
|
|
120
|
+
@multi_run_regexp = /(#{Regexp.union((roda_class.opts[:multi_run_apps].keys + roda_class.opts[:multi_run_app_blocks].keys).sort.reverse)})/
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Refresh the multi_run_regexp if it hasn't been loaded yet.
|
|
124
|
+
def multi_run_regexp
|
|
125
|
+
@multi_run_regexp || refresh_multi_run_regexp!
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
module RequestMethods
|
|
130
|
+
# If one of the stored route prefixes match the current request,
|
|
131
|
+
# dispatch the request to the appropriate rack application.
|
|
132
|
+
def multi_run
|
|
133
|
+
on self.class.multi_run_regexp do |prefix|
|
|
134
|
+
yield prefix if defined?(yield)
|
|
135
|
+
opts = scope.opts
|
|
136
|
+
run(opts[:multi_run_apps][prefix] || opts[:multi_run_app_blocks][prefix].call)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
register_plugin(:multi_run, MultiRun)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The multi_view plugin makes it easy to render multiple views, where the
|
|
7
|
+
# view template is the same as the matched element. It adds an +r.multi_view+
|
|
8
|
+
# method, which takes an argument that is passed to +r.get+, and should
|
|
9
|
+
# capture a single argument, which is treated as the template name to pass
|
|
10
|
+
# to +view+. This makes it possible to pass in an array of strings, or a
|
|
11
|
+
# regexp with a single capture.
|
|
12
|
+
#
|
|
13
|
+
# The advantage of using a regexp over an array of strings is that the regexp
|
|
14
|
+
# is generally faster and uses less memory. However, constructing the regexps
|
|
15
|
+
# is more cumbersome. To make it easier, the multi_view plugin also offers a
|
|
16
|
+
# +multi_view_compile+ class method that will take an array of view template
|
|
17
|
+
# names and construct a regexp that can be passed to +r.multi_view+.
|
|
18
|
+
#
|
|
19
|
+
# Example:
|
|
20
|
+
#
|
|
21
|
+
# plugin :multi_view
|
|
22
|
+
#
|
|
23
|
+
# route do |r|
|
|
24
|
+
# r.multi_view(['foo', 'bar', 'baz'])
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# # or:
|
|
28
|
+
#
|
|
29
|
+
# route do |r|
|
|
30
|
+
# r.multi_view(/(foo|bar|baz)/)
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# # or:
|
|
34
|
+
#
|
|
35
|
+
# regexp = multi_view_compile(['foo', 'bar', 'baz'])
|
|
36
|
+
# route do |r|
|
|
37
|
+
# r.multi_view(regexp)
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# # all are equivalent to:
|
|
41
|
+
#
|
|
42
|
+
# route do |r|
|
|
43
|
+
# r.get 'foo' do
|
|
44
|
+
# view('foo')
|
|
45
|
+
# end
|
|
46
|
+
#
|
|
47
|
+
# r.get 'bar' do
|
|
48
|
+
# view('bar')
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# r.get 'baz' do
|
|
52
|
+
# view('baz')
|
|
53
|
+
# end
|
|
54
|
+
# end
|
|
55
|
+
module MultiView
|
|
56
|
+
# Depend on the render plugin, since this plugin only makes
|
|
57
|
+
# sense when the render plugin is used.
|
|
58
|
+
def self.load_dependencies(app)
|
|
59
|
+
app.plugin :render
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
module ClassMethods
|
|
63
|
+
# Given the array of view template names, return a regexp that will
|
|
64
|
+
# match on any of the names and capture the matched name.
|
|
65
|
+
def multi_view_compile(array)
|
|
66
|
+
/(#{Regexp.union(array)})/
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
module RequestMethods
|
|
71
|
+
# Pass the argument to +get+, and assume if the matchers match that
|
|
72
|
+
# there is one capture, and call view with that capture.
|
|
73
|
+
def multi_view(arg)
|
|
74
|
+
get(arg) do |page|
|
|
75
|
+
scope.view(page)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
register_plugin(:multi_view, MultiView)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The multibyte_string_matcher plugin allows multibyte
|
|
7
|
+
# strings to be used in matchers. Roda's default string
|
|
8
|
+
# matcher does not handle multibyte strings for performance
|
|
9
|
+
# reasons.
|
|
10
|
+
#
|
|
11
|
+
# As browsers send multibyte characters in request paths URL
|
|
12
|
+
# escaped, so this also loads the unescape_path plugin to
|
|
13
|
+
# unescape the paths.
|
|
14
|
+
#
|
|
15
|
+
# plugin :multibyte_string_matcher
|
|
16
|
+
#
|
|
17
|
+
# path = "\xD0\xB8".force_encoding('UTF-8')
|
|
18
|
+
# route do |r|
|
|
19
|
+
# r.get path do
|
|
20
|
+
# # GET /\xD0\xB8 (request.path in UTF-8 format)
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# r.get /y-(#{path})/u do |x|
|
|
24
|
+
# # GET /y-\xD0\xB8 (request.path in UTF-8 format)
|
|
25
|
+
# x => "\xD0\xB8".force_encoding('BINARY')
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
module MultibyteStringMatcher
|
|
29
|
+
# Must load unescape_path plugin to decode multibyte
|
|
30
|
+
# paths, which are submitted escaped.
|
|
31
|
+
def self.load_dependencies(app)
|
|
32
|
+
app.plugin :unescape_path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module RequestMethods
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# Use multibyte safe string matcher, using the same
|
|
39
|
+
# approach as in Roda 3.0.
|
|
40
|
+
def _match_string(str)
|
|
41
|
+
rp = @remaining_path
|
|
42
|
+
if rp.start_with?("/#{str}")
|
|
43
|
+
last = str.length + 1
|
|
44
|
+
case rp[last]
|
|
45
|
+
when "/"
|
|
46
|
+
@remaining_path = rp[last, rp.length]
|
|
47
|
+
when nil
|
|
48
|
+
@remaining_path = ""
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
register_plugin(:multibyte_string_matcher, MultibyteStringMatcher)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The named_routes plugin allows for multiple named routes, which the
|
|
7
|
+
# main route block can dispatch to by name at any point by calling +r.route+.
|
|
8
|
+
# If the named route doesn't handle the request, execution will continue,
|
|
9
|
+
# and if the named route does handle the request, the response returned by
|
|
10
|
+
# the named route will be returned.
|
|
11
|
+
#
|
|
12
|
+
# Example:
|
|
13
|
+
#
|
|
14
|
+
# plugin :named_routes
|
|
15
|
+
#
|
|
16
|
+
# route('foo') do |r|
|
|
17
|
+
# r.is 'bar' do
|
|
18
|
+
# '/foo/bar'
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# route('bar') do |r|
|
|
23
|
+
# r.is 'foo' do
|
|
24
|
+
# '/bar/foo'
|
|
25
|
+
# end
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# route do |r|
|
|
29
|
+
# r.on "foo" do
|
|
30
|
+
# r.route 'foo'
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# r.on "bar" do
|
|
34
|
+
# r.route 'bar'
|
|
35
|
+
# end
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# Note that in multi-threaded code, you should not attempt to add a
|
|
39
|
+
# named route after accepting requests.
|
|
40
|
+
#
|
|
41
|
+
# To handle development environments that reload code, you can call the
|
|
42
|
+
# +route+ class method without a block to remove an existing named route.
|
|
43
|
+
#
|
|
44
|
+
# == Routing Files
|
|
45
|
+
#
|
|
46
|
+
# The convention when using the named_routes plugin is to have a single
|
|
47
|
+
# named route per file, and these routing files should be stored in
|
|
48
|
+
# a routes subdirectory in your application. So for the above example, you
|
|
49
|
+
# would use the following files:
|
|
50
|
+
#
|
|
51
|
+
# routes/bar.rb
|
|
52
|
+
# routes/foo.rb
|
|
53
|
+
#
|
|
54
|
+
# == Namespace Support
|
|
55
|
+
#
|
|
56
|
+
# The named_routes plugin also has support for namespaces, allowing you to
|
|
57
|
+
# use +r.route+ at multiple levels in your routing tree. Example:
|
|
58
|
+
#
|
|
59
|
+
# route('foo') do |r|
|
|
60
|
+
# r.on("baz"){r.route("baz", "foo")}
|
|
61
|
+
# r.on("quux"){r.route("quux", "foo")}
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# route('bar') do |r|
|
|
65
|
+
# r.on("baz"){r.route("baz", "bar")}
|
|
66
|
+
# r.on("quux"){r.route("quux", "bar")}
|
|
67
|
+
# end
|
|
68
|
+
#
|
|
69
|
+
# route('baz', 'foo') do |r|
|
|
70
|
+
# # handles /foo/baz prefix
|
|
71
|
+
# end
|
|
72
|
+
#
|
|
73
|
+
# route('quux', 'foo') do |r|
|
|
74
|
+
# # handles /foo/quux prefix
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# route('baz', 'bar') do |r|
|
|
78
|
+
# # handles /bar/baz prefix
|
|
79
|
+
# end
|
|
80
|
+
#
|
|
81
|
+
# route('quux', 'bar') do |r|
|
|
82
|
+
# # handles /bar/quux prefix
|
|
83
|
+
# end
|
|
84
|
+
#
|
|
85
|
+
# route do |r|
|
|
86
|
+
# r.on "foo" do
|
|
87
|
+
# r.route("foo")
|
|
88
|
+
# end
|
|
89
|
+
#
|
|
90
|
+
# r.on "bar" do
|
|
91
|
+
# r.route("bar")
|
|
92
|
+
# end
|
|
93
|
+
# end
|
|
94
|
+
#
|
|
95
|
+
# === Routing Files
|
|
96
|
+
#
|
|
97
|
+
# The convention when using namespaces with the multi_route plugin is to
|
|
98
|
+
# store the routing files in subdirectories per namespace. So for the
|
|
99
|
+
# above example, you would have the following routing files:
|
|
100
|
+
#
|
|
101
|
+
# routes/bar.rb
|
|
102
|
+
# routes/bar/baz.rb
|
|
103
|
+
# routes/bar/quux.rb
|
|
104
|
+
# routes/foo.rb
|
|
105
|
+
# routes/foo/baz.rb
|
|
106
|
+
# routes/foo/quux.rb
|
|
107
|
+
module NamedRoutes
|
|
108
|
+
# Initialize storage for the named routes.
|
|
109
|
+
def self.configure(app)
|
|
110
|
+
app.opts[:namespaced_routes] ||= {}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
module ClassMethods
|
|
114
|
+
# Freeze the namespaced routes so that there can be no thread safety issues at runtime.
|
|
115
|
+
def freeze
|
|
116
|
+
opts[:namespaced_routes].freeze.each_value(&:freeze)
|
|
117
|
+
super
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Copy the named routes into the subclass when inheriting.
|
|
121
|
+
def inherited(subclass)
|
|
122
|
+
super
|
|
123
|
+
nsr = subclass.opts[:namespaced_routes]
|
|
124
|
+
opts[:namespaced_routes].each{|k, v| nsr[k] = v.dup}
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# The names for the currently stored named routes
|
|
128
|
+
def named_routes(namespace=nil)
|
|
129
|
+
unless routes = opts[:namespaced_routes][namespace]
|
|
130
|
+
raise RodaError, "unsupported named_routes namespace used: #{namespace.inspect}"
|
|
131
|
+
end
|
|
132
|
+
routes.keys
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Return the named route with the given name.
|
|
136
|
+
def named_route(name, namespace=nil)
|
|
137
|
+
opts[:namespaced_routes][namespace][name]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# If the given route has a name, treat it as a named route and
|
|
141
|
+
# store the route block. Otherwise, this is the main route, so
|
|
142
|
+
# call super.
|
|
143
|
+
def route(name=nil, namespace=nil, &block)
|
|
144
|
+
if name
|
|
145
|
+
routes = opts[:namespaced_routes][namespace] ||= {}
|
|
146
|
+
if block
|
|
147
|
+
routes[name] = define_roda_method(routes[name] || "named_routes_#{namespace}_#{name}", 1, &convert_route_block(block))
|
|
148
|
+
elsif meth = routes.delete(name)
|
|
149
|
+
remove_method(meth)
|
|
150
|
+
end
|
|
151
|
+
else
|
|
152
|
+
super(&block)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
module RequestMethods
|
|
158
|
+
# Dispatch to the named route with the given name.
|
|
159
|
+
def route(name, namespace=nil)
|
|
160
|
+
scope.send(roda_class.named_route(name, namespace), self)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
register_plugin(:named_routes, NamedRoutes)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The named_templates plugin allows you to specify templates by name,
|
|
7
|
+
# providing the template code to use for a given name:
|
|
8
|
+
#
|
|
9
|
+
# plugin :named_templates
|
|
10
|
+
#
|
|
11
|
+
# template :layout do
|
|
12
|
+
# "<html><body><%= yield %></body></html>"
|
|
13
|
+
# end
|
|
14
|
+
# template :index do
|
|
15
|
+
# "<p>Hello <%= @user %>!</p>"
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# route do |r|
|
|
19
|
+
# @user = 'You'
|
|
20
|
+
# render(:index)
|
|
21
|
+
# end
|
|
22
|
+
# # => "<html><body><p>Hello You!</p></body></html>"
|
|
23
|
+
#
|
|
24
|
+
# You can provide options for the template, for example to change the
|
|
25
|
+
# engine that the template uses:
|
|
26
|
+
#
|
|
27
|
+
# template :index, engine: :str do
|
|
28
|
+
# "<p>Hello #{@user}!</p>"
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# The block you use is reevaluted on every call, allowing you to easily
|
|
32
|
+
# include additional setup logic:
|
|
33
|
+
#
|
|
34
|
+
# template :index do
|
|
35
|
+
# greeting = ['hello', 'hi', 'howdy'].sample
|
|
36
|
+
# @user.downcase!
|
|
37
|
+
# "<p>#{greating} <%= @user %>!</p>"
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# This plugin also works with the view_options plugin, as long as you
|
|
41
|
+
# prefix the template name with the view subdirectory:
|
|
42
|
+
#
|
|
43
|
+
# template "main/index" do
|
|
44
|
+
# "<html><body><%= yield %></body></html>"
|
|
45
|
+
# end
|
|
46
|
+
#
|
|
47
|
+
# route do |r|
|
|
48
|
+
# set_view_subdir("main")
|
|
49
|
+
# @user = 'You'
|
|
50
|
+
# render(:index)
|
|
51
|
+
# end
|
|
52
|
+
module NamedTemplates
|
|
53
|
+
# Depend on the render plugin
|
|
54
|
+
def self.load_dependencies(app)
|
|
55
|
+
app.plugin :render
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Initialize the storage for named templates.
|
|
59
|
+
def self.configure(app)
|
|
60
|
+
app.opts[:named_templates] ||= {}
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
module ClassMethods
|
|
64
|
+
# Freeze the named templates so that there can be no thread safety issues at runtime.
|
|
65
|
+
def freeze
|
|
66
|
+
opts[:named_templates].freeze
|
|
67
|
+
super
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Store a new template block and options for the given template name.
|
|
71
|
+
def template(name, options=nil, &block)
|
|
72
|
+
opts[:named_templates][name.to_s] = [options, define_roda_method("named_templates_#{name}", 0, &block)].freeze
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
module InstanceMethods
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
# If a template name is given and it matches a named template, call
|
|
81
|
+
# the named template block to get the inline template to use.
|
|
82
|
+
def find_template(options)
|
|
83
|
+
if options[:template] && (template_opts, meth = opts[:named_templates][template_name(options)]; meth)
|
|
84
|
+
if template_opts
|
|
85
|
+
options = template_opts.merge(options)
|
|
86
|
+
else
|
|
87
|
+
options = Hash[options]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
options[:inline] = send(meth)
|
|
91
|
+
|
|
92
|
+
super(options)
|
|
93
|
+
else
|
|
94
|
+
super
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
register_plugin(:named_templates, NamedTemplates)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The not_allowed plugin makes Roda attempt to automatically
|
|
7
|
+
# support the 405 Method Not Allowed response status. The plugin
|
|
8
|
+
# changes the +r.get+ and +r.post+ verb methods to automatically
|
|
9
|
+
# return a 405 status if they are called with any arguments, and
|
|
10
|
+
# the arguments match but the request method does not match. So
|
|
11
|
+
# this code:
|
|
12
|
+
#
|
|
13
|
+
# r.get '' do
|
|
14
|
+
# "a"
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# will return a 200 response for <tt>GET /</tt> and a 405
|
|
18
|
+
# response for <tt>POST /</tt>.
|
|
19
|
+
#
|
|
20
|
+
# This plugin changes the +r.root+ method to return a 405 status
|
|
21
|
+
# for non-GET requests to +/+.
|
|
22
|
+
#
|
|
23
|
+
# This plugin also changes the +r.is+ method so that if you use
|
|
24
|
+
# a verb method inside +r.is+, it returns a 405 status if none
|
|
25
|
+
# of the verb methods match. So this code:
|
|
26
|
+
#
|
|
27
|
+
# r.is '' do
|
|
28
|
+
# r.get do
|
|
29
|
+
# "a"
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# r.post do
|
|
33
|
+
# "b"
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# will return a 200 response for <tt>GET /</tt> and <tt>POST /</tt>,
|
|
38
|
+
# but a 405 response for <tt>PUT /</tt>.
|
|
39
|
+
#
|
|
40
|
+
# Note that this plugin will probably not do what you want for
|
|
41
|
+
# code such as:
|
|
42
|
+
#
|
|
43
|
+
# r.get '' do
|
|
44
|
+
# "a"
|
|
45
|
+
# end
|
|
46
|
+
#
|
|
47
|
+
# r.post '' do
|
|
48
|
+
# "b"
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# Since for a <tt>POST /</tt> request, when +r.get+ method matches
|
|
52
|
+
# the path but not the request method, it will return an immediate
|
|
53
|
+
# 405 response. You must DRY up this code for it work correctly,
|
|
54
|
+
# like this:
|
|
55
|
+
#
|
|
56
|
+
# r.is '' do
|
|
57
|
+
# r.get do
|
|
58
|
+
# "a"
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
# r.post do
|
|
62
|
+
# "b"
|
|
63
|
+
# end
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# In all cases where it uses a 405 response, it also sets the +Allow+
|
|
67
|
+
# header in the response to contain the request methods supported.
|
|
68
|
+
#
|
|
69
|
+
# This plugin depends on the all_verbs plugin.
|
|
70
|
+
module NotAllowed
|
|
71
|
+
REQUEST_INSTANCE_VARIABLES = [:@_is_verbs].freeze
|
|
72
|
+
|
|
73
|
+
# Depend on the all_verbs plugin, as this plugin overrides methods
|
|
74
|
+
# defined by it and calls super.
|
|
75
|
+
def self.load_dependencies(app)
|
|
76
|
+
app.plugin :all_verbs
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
module RequestMethods
|
|
80
|
+
# Keep track of verb calls inside the block. If there are any
|
|
81
|
+
# verb calls inside the block, but the block returned, assume
|
|
82
|
+
# that the verb calls inside the block did not match, and
|
|
83
|
+
# since there was already a successful terminal match, the
|
|
84
|
+
# request method must not be allowed, so return a 405
|
|
85
|
+
# response in that case.
|
|
86
|
+
def is(*args)
|
|
87
|
+
super(*args) do
|
|
88
|
+
begin
|
|
89
|
+
is_verbs = @_is_verbs = []
|
|
90
|
+
|
|
91
|
+
ret = if args.empty?
|
|
92
|
+
yield
|
|
93
|
+
else
|
|
94
|
+
yield(*captures)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
unless is_verbs.empty?
|
|
98
|
+
method_not_allowed(is_verbs.join(', '))
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
ret
|
|
102
|
+
ensure
|
|
103
|
+
@_is_verbs = nil
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Treat +r.root+ similar to <tt>r.get ''</tt>, using a 405
|
|
109
|
+
# response for non-GET requests.
|
|
110
|
+
def root
|
|
111
|
+
super
|
|
112
|
+
if @remaining_path == "/" && !is_get?
|
|
113
|
+
always{method_not_allowed("GET")}
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Setup methods for all verbs. If inside an is block and not given
|
|
118
|
+
# arguments, record the verb used. If given an argument, add an is
|
|
119
|
+
# check with the arguments.
|
|
120
|
+
%w'get post delete head options link patch put trace unlink'.each do |verb|
|
|
121
|
+
if ::Rack::Request.method_defined?("#{verb}?")
|
|
122
|
+
class_eval(<<-END, __FILE__, __LINE__+1)
|
|
123
|
+
def #{verb}(*args, &block)
|
|
124
|
+
if (empty = args.empty?) && @_is_verbs
|
|
125
|
+
@_is_verbs << "#{verb.to_s.upcase}"
|
|
126
|
+
end
|
|
127
|
+
super
|
|
128
|
+
unless empty
|
|
129
|
+
is(*args){method_not_allowed("#{verb.to_s.upcase}")}
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
END
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
# Set the response status to 405 (Method Not Allowed), and set the Allow header
|
|
139
|
+
# to the given string of allowed request methods.
|
|
140
|
+
def method_not_allowed(verbs)
|
|
141
|
+
res = response
|
|
142
|
+
res.status = 405
|
|
143
|
+
res[RodaResponseHeaders::ALLOW] = verbs
|
|
144
|
+
nil
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
register_plugin(:not_allowed, NotAllowed)
|
|
150
|
+
end
|
|
151
|
+
end
|