ultra-lite-hub 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.
- checksums.yaml +7 -0
- data/roda-3.105.0/MIT-LICENSE +21 -0
- data/roda-3.105.0/lib/roda/cache.rb +42 -0
- data/roda-3.105.0/lib/roda/plugins/Integer_matcher_max.rb +55 -0
- data/roda-3.105.0/lib/roda/plugins/_after_hook.rb +11 -0
- data/roda-3.105.0/lib/roda/plugins/_base64.rb +34 -0
- data/roda-3.105.0/lib/roda/plugins/_before_hook.rb +41 -0
- data/roda-3.105.0/lib/roda/plugins/_optimized_matching.rb +227 -0
- data/roda-3.105.0/lib/roda/plugins/_symbol_class_matchers.rb +108 -0
- data/roda-3.105.0/lib/roda/plugins/_symbol_regexp_matchers.rb +24 -0
- data/roda-3.105.0/lib/roda/plugins/additional_render_engines.rb +61 -0
- data/roda-3.105.0/lib/roda/plugins/additional_view_directories.rb +66 -0
- data/roda-3.105.0/lib/roda/plugins/all_verbs.rb +50 -0
- data/roda-3.105.0/lib/roda/plugins/assets.rb +902 -0
- data/roda-3.105.0/lib/roda/plugins/assets_preloading.rb +89 -0
- data/roda-3.105.0/lib/roda/plugins/assume_ssl.rb +28 -0
- data/roda-3.105.0/lib/roda/plugins/autoload_hash_branches.rb +79 -0
- data/roda-3.105.0/lib/roda/plugins/autoload_named_routes.rb +65 -0
- data/roda-3.105.0/lib/roda/plugins/backtracking_array.rb +88 -0
- data/roda-3.105.0/lib/roda/plugins/bearer_token.rb +28 -0
- data/roda-3.105.0/lib/roda/plugins/branch_locals.rb +74 -0
- data/roda-3.105.0/lib/roda/plugins/break.rb +43 -0
- data/roda-3.105.0/lib/roda/plugins/caching.rb +206 -0
- data/roda-3.105.0/lib/roda/plugins/capture_erb.rb +94 -0
- data/roda-3.105.0/lib/roda/plugins/chunked.rb +331 -0
- data/roda-3.105.0/lib/roda/plugins/class_level_routing.rb +111 -0
- data/roda-3.105.0/lib/roda/plugins/class_matchers.rb +155 -0
- data/roda-3.105.0/lib/roda/plugins/common_logger.rb +80 -0
- data/roda-3.105.0/lib/roda/plugins/conditional_sessions.rb +67 -0
- data/roda-3.105.0/lib/roda/plugins/content_for.rb +103 -0
- data/roda-3.105.0/lib/roda/plugins/content_security_policy.rb +329 -0
- data/roda-3.105.0/lib/roda/plugins/cookie_flags.rb +157 -0
- data/roda-3.105.0/lib/roda/plugins/cookies.rb +51 -0
- data/roda-3.105.0/lib/roda/plugins/csrf.rb +81 -0
- data/roda-3.105.0/lib/roda/plugins/custom_block_results.rb +85 -0
- data/roda-3.105.0/lib/roda/plugins/custom_matchers.rb +89 -0
- data/roda-3.105.0/lib/roda/plugins/default_headers.rb +64 -0
- data/roda-3.105.0/lib/roda/plugins/default_status.rb +35 -0
- data/roda-3.105.0/lib/roda/plugins/delay_build.rb +18 -0
- data/roda-3.105.0/lib/roda/plugins/delegate.rb +77 -0
- data/roda-3.105.0/lib/roda/plugins/delete_empty_headers.rb +36 -0
- data/roda-3.105.0/lib/roda/plugins/direct_call.rb +38 -0
- data/roda-3.105.0/lib/roda/plugins/disallow_file_uploads.rb +38 -0
- data/roda-3.105.0/lib/roda/plugins/drop_body.rb +43 -0
- data/roda-3.105.0/lib/roda/plugins/each_part.rb +87 -0
- data/roda-3.105.0/lib/roda/plugins/early_hints.rb +25 -0
- data/roda-3.105.0/lib/roda/plugins/empty_root.rb +49 -0
- data/roda-3.105.0/lib/roda/plugins/environments.rb +79 -0
- data/roda-3.105.0/lib/roda/plugins/erb_h.rb +43 -0
- data/roda-3.105.0/lib/roda/plugins/error_email.rb +152 -0
- data/roda-3.105.0/lib/roda/plugins/error_handler.rb +133 -0
- data/roda-3.105.0/lib/roda/plugins/error_mail.rb +149 -0
- data/roda-3.105.0/lib/roda/plugins/exception_page.rb +445 -0
- data/roda-3.105.0/lib/roda/plugins/filter_common_logger.rb +46 -0
- data/roda-3.105.0/lib/roda/plugins/flash.rb +117 -0
- data/roda-3.105.0/lib/roda/plugins/h.rb +59 -0
- data/roda-3.105.0/lib/roda/plugins/halt.rb +108 -0
- data/roda-3.105.0/lib/roda/plugins/hash_branch_view_subdir.rb +76 -0
- data/roda-3.105.0/lib/roda/plugins/hash_branches.rb +145 -0
- data/roda-3.105.0/lib/roda/plugins/hash_matcher.rb +39 -0
- data/roda-3.105.0/lib/roda/plugins/hash_paths.rb +128 -0
- data/roda-3.105.0/lib/roda/plugins/hash_public.rb +125 -0
- data/roda-3.105.0/lib/roda/plugins/hash_public_cache.rb +91 -0
- data/roda-3.105.0/lib/roda/plugins/hash_routes.rb +304 -0
- data/roda-3.105.0/lib/roda/plugins/head.rb +99 -0
- data/roda-3.105.0/lib/roda/plugins/header_matchers.rb +88 -0
- data/roda-3.105.0/lib/roda/plugins/heartbeat.rb +41 -0
- data/roda-3.105.0/lib/roda/plugins/hmac_paths.rb +413 -0
- data/roda-3.105.0/lib/roda/plugins/hooks.rb +92 -0
- data/roda-3.105.0/lib/roda/plugins/host_authorization.rb +155 -0
- data/roda-3.105.0/lib/roda/plugins/host_routing.rb +190 -0
- data/roda-3.105.0/lib/roda/plugins/hsts.rb +35 -0
- data/roda-3.105.0/lib/roda/plugins/indifferent_params.rb +124 -0
- data/roda-3.105.0/lib/roda/plugins/inject_erb.rb +33 -0
- data/roda-3.105.0/lib/roda/plugins/invalid_request_body.rb +107 -0
- data/roda-3.105.0/lib/roda/plugins/ip_from_header.rb +34 -0
- data/roda-3.105.0/lib/roda/plugins/json.rb +119 -0
- data/roda-3.105.0/lib/roda/plugins/json_parser.rb +107 -0
- data/roda-3.105.0/lib/roda/plugins/link_to.rb +83 -0
- data/roda-3.105.0/lib/roda/plugins/mail_processor.rb +629 -0
- data/roda-3.105.0/lib/roda/plugins/mailer.rb +283 -0
- data/roda-3.105.0/lib/roda/plugins/map_matcher.rb +48 -0
- data/roda-3.105.0/lib/roda/plugins/match_affix.rb +64 -0
- data/roda-3.105.0/lib/roda/plugins/match_hook.rb +34 -0
- data/roda-3.105.0/lib/roda/plugins/match_hook_args.rb +93 -0
- data/roda-3.105.0/lib/roda/plugins/middleware.rb +225 -0
- data/roda-3.105.0/lib/roda/plugins/middleware_stack.rb +101 -0
- data/roda-3.105.0/lib/roda/plugins/module_include.rb +96 -0
- data/roda-3.105.0/lib/roda/plugins/multi_public.rb +95 -0
- data/roda-3.105.0/lib/roda/plugins/multi_route.rb +156 -0
- data/roda-3.105.0/lib/roda/plugins/multi_run.rb +144 -0
- data/roda-3.105.0/lib/roda/plugins/multi_view.rb +83 -0
- data/roda-3.105.0/lib/roda/plugins/multibyte_string_matcher.rb +57 -0
- data/roda-3.105.0/lib/roda/plugins/named_routes.rb +167 -0
- data/roda-3.105.0/lib/roda/plugins/named_templates.rb +102 -0
- data/roda-3.105.0/lib/roda/plugins/not_allowed.rb +149 -0
- data/roda-3.105.0/lib/roda/plugins/not_found.rb +55 -0
- data/roda-3.105.0/lib/roda/plugins/optimized_segment_matchers.rb +53 -0
- data/roda-3.105.0/lib/roda/plugins/optimized_string_matchers.rb +50 -0
- data/roda-3.105.0/lib/roda/plugins/padrino_render.rb +42 -0
- data/roda-3.105.0/lib/roda/plugins/param_matchers.rb +83 -0
- data/roda-3.105.0/lib/roda/plugins/params_capturing.rb +116 -0
- data/roda-3.105.0/lib/roda/plugins/part.rb +76 -0
- data/roda-3.105.0/lib/roda/plugins/partials.rb +74 -0
- data/roda-3.105.0/lib/roda/plugins/pass.rb +47 -0
- data/roda-3.105.0/lib/roda/plugins/path.rb +255 -0
- data/roda-3.105.0/lib/roda/plugins/path_matchers.rb +54 -0
- data/roda-3.105.0/lib/roda/plugins/path_rewriter.rb +111 -0
- data/roda-3.105.0/lib/roda/plugins/permissions_policy.rb +336 -0
- data/roda-3.105.0/lib/roda/plugins/placeholder_string_matchers.rb +48 -0
- data/roda-3.105.0/lib/roda/plugins/plain_hash_response_headers.rb +32 -0
- data/roda-3.105.0/lib/roda/plugins/precompile_templates.rb +156 -0
- data/roda-3.105.0/lib/roda/plugins/public.rb +182 -0
- data/roda-3.105.0/lib/roda/plugins/r.rb +35 -0
- data/roda-3.105.0/lib/roda/plugins/recheck_precompiled_assets.rb +107 -0
- data/roda-3.105.0/lib/roda/plugins/redirect_http_to_https.rb +99 -0
- data/roda-3.105.0/lib/roda/plugins/redirect_path.rb +59 -0
- data/roda-3.105.0/lib/roda/plugins/relative_path.rb +74 -0
- data/roda-3.105.0/lib/roda/plugins/render.rb +998 -0
- data/roda-3.105.0/lib/roda/plugins/render_coverage.rb +105 -0
- data/roda-3.105.0/lib/roda/plugins/render_each.rb +224 -0
- data/roda-3.105.0/lib/roda/plugins/render_locals.rb +102 -0
- data/roda-3.105.0/lib/roda/plugins/request_aref.rb +77 -0
- data/roda-3.105.0/lib/roda/plugins/request_headers.rb +81 -0
- data/roda-3.105.0/lib/roda/plugins/response_attachment.rb +94 -0
- data/roda-3.105.0/lib/roda/plugins/response_content_type.rb +79 -0
- data/roda-3.105.0/lib/roda/plugins/response_request.rb +29 -0
- data/roda-3.105.0/lib/roda/plugins/route_block_args.rb +50 -0
- data/roda-3.105.0/lib/roda/plugins/route_csrf.rb +388 -0
- data/roda-3.105.0/lib/roda/plugins/run_append_slash.rb +51 -0
- data/roda-3.105.0/lib/roda/plugins/run_handler.rb +51 -0
- data/roda-3.105.0/lib/roda/plugins/run_require_slash.rb +46 -0
- data/roda-3.105.0/lib/roda/plugins/sec_fetch_site_csrf.rb +131 -0
- data/roda-3.105.0/lib/roda/plugins/send_file.rb +127 -0
- data/roda-3.105.0/lib/roda/plugins/sessions.rb +537 -0
- data/roda-3.105.0/lib/roda/plugins/shared_vars.rb +86 -0
- data/roda-3.105.0/lib/roda/plugins/sinatra_helpers.rb +443 -0
- data/roda-3.105.0/lib/roda/plugins/slash_path_empty.rb +26 -0
- data/roda-3.105.0/lib/roda/plugins/static.rb +42 -0
- data/roda-3.105.0/lib/roda/plugins/static_routing.rb +89 -0
- data/roda-3.105.0/lib/roda/plugins/status_303.rb +34 -0
- data/roda-3.105.0/lib/roda/plugins/status_handler.rb +86 -0
- data/roda-3.105.0/lib/roda/plugins/streaming.rb +170 -0
- data/roda-3.105.0/lib/roda/plugins/strip_path_prefix.rb +33 -0
- data/roda-3.105.0/lib/roda/plugins/symbol_matchers.rb +188 -0
- data/roda-3.105.0/lib/roda/plugins/symbol_status.rb +32 -0
- data/roda-3.105.0/lib/roda/plugins/symbol_views.rb +37 -0
- data/roda-3.105.0/lib/roda/plugins/timestamp_public.rb +78 -0
- data/roda-3.105.0/lib/roda/plugins/type_routing.rb +215 -0
- data/roda-3.105.0/lib/roda/plugins/typecast_params.rb +1183 -0
- data/roda-3.105.0/lib/roda/plugins/typecast_params_sized_integers.rb +108 -0
- data/roda-3.105.0/lib/roda/plugins/unescape_path.rb +41 -0
- data/roda-3.105.0/lib/roda/plugins/view_options.rb +201 -0
- data/roda-3.105.0/lib/roda/plugins/view_subdir_leading_slash.rb +49 -0
- data/roda-3.105.0/lib/roda/plugins.rb +68 -0
- data/roda-3.105.0/lib/roda/request.rb +722 -0
- data/roda-3.105.0/lib/roda/response.rb +221 -0
- data/roda-3.105.0/lib/roda/session_middleware.rb +183 -0
- data/roda-3.105.0/lib/roda/version.rb +18 -0
- data/roda-3.105.0/lib/roda.rb +586 -0
- data/ultra-lite-hub.gemspec +12 -0
- metadata +201 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The custom_matchers plugin supports using arbitrary objects
|
|
7
|
+
# as matchers, as long as the application has been configured
|
|
8
|
+
# to accept such objects.
|
|
9
|
+
#
|
|
10
|
+
# After loading the plugin, support for custom matchers can be
|
|
11
|
+
# configured using the +custom_matcher+ class method. This
|
|
12
|
+
# method is generally passed the class of the object you want
|
|
13
|
+
# to use as a custom matcher, as well as a block. The block
|
|
14
|
+
# will be called in the context of the request instance
|
|
15
|
+
# with the specific matcher used in the match method.
|
|
16
|
+
#
|
|
17
|
+
# Blocks can append to the captures in order to yield the appropriate
|
|
18
|
+
# values to match blocks, or call request methods that append to the
|
|
19
|
+
# captures.
|
|
20
|
+
#
|
|
21
|
+
# Example:
|
|
22
|
+
#
|
|
23
|
+
# plugin :custom_matchers
|
|
24
|
+
# method_segment = Struct.new(:request_method, :next_segment)
|
|
25
|
+
# custom_matcher(method_segment) do |matcher|
|
|
26
|
+
# # self is the request instance ("r" yielded in the route block below)
|
|
27
|
+
# if matcher.request_method == self.request_method
|
|
28
|
+
# match(matcher.next_segment)
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# get_foo = method_segment.new('GET', 'foo')
|
|
33
|
+
# post_any = method_segment.new('POST', String)
|
|
34
|
+
# route do |r|
|
|
35
|
+
# r.on('baz') do
|
|
36
|
+
# r.on(get_foo) do
|
|
37
|
+
# # GET method, /baz/foo prefix
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# r.is(post_any) do |seg|
|
|
41
|
+
# # for POST /baz/bar, seg is "bar"
|
|
42
|
+
# end
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# r.on('quux') do
|
|
46
|
+
# r.is(get_foo) do
|
|
47
|
+
# # GET method, /quux/foo route
|
|
48
|
+
# end
|
|
49
|
+
#
|
|
50
|
+
# r.on(post_any) do |seg|
|
|
51
|
+
# # for POST /quux/xyz, seg is "xyz"
|
|
52
|
+
# end
|
|
53
|
+
# end
|
|
54
|
+
# end
|
|
55
|
+
module CustomMatchers
|
|
56
|
+
def self.configure(app)
|
|
57
|
+
app.opts[:custom_matchers] ||= OPTS
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
module ClassMethods
|
|
61
|
+
def custom_matcher(match_class, &block)
|
|
62
|
+
custom_matchers = Hash[opts[:custom_matchers]]
|
|
63
|
+
meth = custom_matchers[match_class] = custom_matchers[match_class] || :"_custom_matcher_#{match_class}"
|
|
64
|
+
opts[:custom_matchers] = custom_matchers.freeze
|
|
65
|
+
self::RodaRequest.send(:define_method, meth, &block)
|
|
66
|
+
nil
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
module RequestMethods
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
# Try custom matchers before calling super
|
|
74
|
+
def unsupported_matcher(matcher)
|
|
75
|
+
roda_class.opts[:custom_matchers].each do |match_class, meth|
|
|
76
|
+
if match_class === matcher
|
|
77
|
+
return send(meth, matcher)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
super
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
register_plugin(:custom_matchers, CustomMatchers)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The default_headers plugin accepts a hash of headers,
|
|
7
|
+
# and overrides the default_headers method in the
|
|
8
|
+
# response class to be a copy of the headers.
|
|
9
|
+
#
|
|
10
|
+
# Note that when using this module, you should not
|
|
11
|
+
# attempt to mutate of the values set in the default
|
|
12
|
+
# headers hash.
|
|
13
|
+
#
|
|
14
|
+
# Example:
|
|
15
|
+
#
|
|
16
|
+
# plugin :default_headers, 'Content-Type'=>'text/csv'
|
|
17
|
+
#
|
|
18
|
+
# You can modify the default headers later by loading the
|
|
19
|
+
# plugin again:
|
|
20
|
+
#
|
|
21
|
+
# plugin :default_headers, 'Foo'=>'bar'
|
|
22
|
+
# plugin :default_headers, 'Bar'=>'baz'
|
|
23
|
+
module DefaultHeaders
|
|
24
|
+
# Merge the given headers into the existing default headers, if any.
|
|
25
|
+
def self.configure(app, headers={})
|
|
26
|
+
app.opts[:default_headers] = (app.default_headers || app::RodaResponse::DEFAULT_HEADERS).merge(headers).freeze
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module ClassMethods
|
|
30
|
+
# The default response headers to use for the current class.
|
|
31
|
+
def default_headers
|
|
32
|
+
opts[:default_headers]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Optimize the response class set_default_headers method if it hasn't been
|
|
36
|
+
# overridden and all default headers are strings.
|
|
37
|
+
def freeze
|
|
38
|
+
if (headers = opts[:default_headers]).all?{|k, v| k.is_a?(String) && v.is_a?(String)} &&
|
|
39
|
+
(self::RodaResponse.instance_method(:set_default_headers).owner == Base::ResponseMethods)
|
|
40
|
+
self::RodaResponse.class_eval(<<-END, __FILE__, __LINE__+1)
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def set_default_headers
|
|
44
|
+
h = @headers
|
|
45
|
+
#{headers.map{|k,v| "h[#{k.inspect}] ||= #{v.inspect}"}.join('; ')}
|
|
46
|
+
end
|
|
47
|
+
END
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
super
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
module ResponseMethods
|
|
55
|
+
# Get the default headers from the related roda class.
|
|
56
|
+
def default_headers
|
|
57
|
+
roda_class.default_headers
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
register_plugin(:default_headers, DefaultHeaders)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The default_status plugin accepts a block which should
|
|
7
|
+
# return a response status integer. This integer will be used as
|
|
8
|
+
# the default response status (usually 200) if the body has been
|
|
9
|
+
# written to, and you have not explicitly set a response status.
|
|
10
|
+
#
|
|
11
|
+
# Example:
|
|
12
|
+
#
|
|
13
|
+
# # Use 201 default response status for all requests
|
|
14
|
+
# plugin :default_status do
|
|
15
|
+
# 201
|
|
16
|
+
# end
|
|
17
|
+
module DefaultStatus
|
|
18
|
+
def self.configure(app, &block)
|
|
19
|
+
raise RodaError, "default_status plugin requires a block" unless block
|
|
20
|
+
if check_arity = app.opts.fetch(:check_arity, true)
|
|
21
|
+
unless block.arity == 0
|
|
22
|
+
if check_arity == :warn
|
|
23
|
+
RodaPlugins.warn "Arity mismatch in block passed to plugin :default_status. Expected Arity 0, but arguments required for #{block.inspect}"
|
|
24
|
+
end
|
|
25
|
+
b = block
|
|
26
|
+
block = lambda{instance_exec(&b)} # Fallback
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
app::RodaResponse.send(:define_method, :default_status, &block)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
register_plugin(:default_status, DefaultStatus)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
module DelayBuild
|
|
7
|
+
module ClassMethods
|
|
8
|
+
# No-op for backwards compatibility
|
|
9
|
+
def build!
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# RODA4: Remove plugin
|
|
15
|
+
# Only available for backwards compatibility, no longer needed
|
|
16
|
+
register_plugin(:delay_build, DelayBuild)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The delegate plugin allows you to easily setup instance methods in
|
|
7
|
+
# the scope of the route block that call methods on the related
|
|
8
|
+
# request, response, or class which may offer a simpler API in some cases.
|
|
9
|
+
# Roda doesn't automatically setup such delegate methods because
|
|
10
|
+
# it pollutes the application's method namespace, but this plugin
|
|
11
|
+
# allows the user to do so.
|
|
12
|
+
#
|
|
13
|
+
# Here's an example based on the README's initial example, using the
|
|
14
|
+
# request_delegate method to simplify the DSL:
|
|
15
|
+
#
|
|
16
|
+
# plugin :delegate
|
|
17
|
+
# request_delegate :root, :on, :is, :get, :post, :redirect
|
|
18
|
+
#
|
|
19
|
+
# route do |r|
|
|
20
|
+
# # GET / request
|
|
21
|
+
# root do
|
|
22
|
+
# redirect "/hello"
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# # /hello branch
|
|
26
|
+
# on "hello" do
|
|
27
|
+
# # Set variable for all routes in /hello branch
|
|
28
|
+
# @greeting = 'Hello'
|
|
29
|
+
#
|
|
30
|
+
# # GET /hello/world request
|
|
31
|
+
# get "world" do
|
|
32
|
+
# "#{@greeting} world!"
|
|
33
|
+
# end
|
|
34
|
+
#
|
|
35
|
+
# # /hello request
|
|
36
|
+
# is do
|
|
37
|
+
# # GET /hello request
|
|
38
|
+
# get do
|
|
39
|
+
# "#{@greeting}!"
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# # POST /hello request
|
|
43
|
+
# post do
|
|
44
|
+
# puts "Someone said #{@greeting}!"
|
|
45
|
+
# redirect
|
|
46
|
+
# end
|
|
47
|
+
# end
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
module Delegate
|
|
51
|
+
module ClassMethods
|
|
52
|
+
# Delegate the given methods to the class
|
|
53
|
+
def class_delegate(*meths)
|
|
54
|
+
meths.each do |meth|
|
|
55
|
+
define_method(meth){|*a, &block| self.class.public_send(meth, *a, &block)}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Delegate the given methods to the request
|
|
60
|
+
def request_delegate(*meths)
|
|
61
|
+
meths.each do |meth|
|
|
62
|
+
define_method(meth){|*a, &block| @_request.public_send(meth, *a, &block)}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Delegate the given methods to the response
|
|
67
|
+
def response_delegate(*meths)
|
|
68
|
+
meths.each do |meth|
|
|
69
|
+
define_method(meth){|*a, &block| @_response.public_send(meth, *a, &block)}
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
register_plugin(:delegate, Delegate)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The delete_empty_headers plugin deletes any headers whose
|
|
7
|
+
# value is set to the empty string. Because of how default headers are
|
|
8
|
+
# set in Roda, if you have a default header but don't want
|
|
9
|
+
# to set it for a specific request, you need to use this plugin
|
|
10
|
+
# and set the header value to the empty string, and Roda will automatically
|
|
11
|
+
# delete the header.
|
|
12
|
+
module DeleteEmptyHeaders
|
|
13
|
+
module ResponseMethods
|
|
14
|
+
# Delete any empty headers when calling finish
|
|
15
|
+
def finish
|
|
16
|
+
delete_empty_headers(super)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Delete any empty headers when calling finish_with_body
|
|
20
|
+
def finish_with_body(_)
|
|
21
|
+
delete_empty_headers(super)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
# Delete any empty headers from response
|
|
27
|
+
def delete_empty_headers(res)
|
|
28
|
+
res[1].delete_if{|_, v| v.is_a?(String) && v.empty?}
|
|
29
|
+
res
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
register_plugin(:delete_empty_headers, DeleteEmptyHeaders)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The direct_call plugin makes the call class method skip the middleware stack
|
|
7
|
+
# (app.call will still call the middleware).
|
|
8
|
+
# This can be used as an optimization, as the Roda class itself can be used
|
|
9
|
+
# as the callable, which is faster than using a lambda.
|
|
10
|
+
module DirectCall
|
|
11
|
+
def self.configure(app)
|
|
12
|
+
app.send(:build_rack_app)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ClassMethods
|
|
16
|
+
# Call the application without middlware.
|
|
17
|
+
def call(env)
|
|
18
|
+
new(env)._roda_handle_main_route
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
# If new_api is true, use the receiver as the base rack app for better
|
|
24
|
+
# performance.
|
|
25
|
+
def base_rack_app_callable(new_api=true)
|
|
26
|
+
if new_api
|
|
27
|
+
self
|
|
28
|
+
else
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
register_plugin(:direct_call, DirectCall)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
raise LoadError, "disallow_file_uploads plugin not supported on Rack <1.6" if Rack.release < '1.6'
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
class Roda
|
|
7
|
+
module RodaPlugins
|
|
8
|
+
# The disallow_file_uploads plugin raises a Roda::RodaPlugins::DisallowFileUploads::Error
|
|
9
|
+
# if there is an attempt to upload a file. This plugin is useful for applications where
|
|
10
|
+
# multipart file uploads are not expected and you want to remove the ability for rack
|
|
11
|
+
# to create temporary files. Example:
|
|
12
|
+
#
|
|
13
|
+
# plugin :disallow_file_uploads
|
|
14
|
+
#
|
|
15
|
+
# This plugin is only supported on Rack 1.6+. This plugin does not technically
|
|
16
|
+
# block users from uploading files, it only blocks the parsing of request bodies containing
|
|
17
|
+
# multipart file uploads. So if you do not call +r.POST+ (or something that calls it such as
|
|
18
|
+
# +r.params+), then Roda will not attempt to parse the request body, and an exception will not
|
|
19
|
+
# be raised.
|
|
20
|
+
module DisallowFileUploads
|
|
21
|
+
# Exception class used when a multipart file upload is attempted.
|
|
22
|
+
class Error < RodaError; end
|
|
23
|
+
|
|
24
|
+
NO_TEMPFILE = lambda{|_,_| raise Error, "Support for uploading files has been disabled"}
|
|
25
|
+
|
|
26
|
+
module RequestMethods
|
|
27
|
+
# HTML escape the input and return the escaped version.
|
|
28
|
+
def initialize(_, env)
|
|
29
|
+
env['rack.multipart.tempfile_factory'] = NO_TEMPFILE
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
register_plugin(:disallow_file_uploads, DisallowFileUploads)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The drop_body plugin automatically drops the body and
|
|
7
|
+
# Content-Type/Content-Length headers from the response if
|
|
8
|
+
# the response status indicates that the response should
|
|
9
|
+
# not include a body (response statuses 100, 101, 102, 204,
|
|
10
|
+
# and 304). For response status 205, the body and Content-Type
|
|
11
|
+
# headers are dropped, but the Content-length header is set to
|
|
12
|
+
# '0' instead of being dropped.
|
|
13
|
+
module DropBody
|
|
14
|
+
module ResponseMethods
|
|
15
|
+
DROP_BODY_STATUSES = [100, 101, 102, 204, 205, 304].freeze
|
|
16
|
+
RodaPlugins.deprecate_constant(self, :DROP_BODY_STATUSES)
|
|
17
|
+
|
|
18
|
+
DROP_BODY_RANGE = 100..199
|
|
19
|
+
private_constant :DROP_BODY_RANGE
|
|
20
|
+
|
|
21
|
+
# If the response status indicates a body should not be
|
|
22
|
+
# returned, use an empty body and remove the Content-Length
|
|
23
|
+
# and Content-Type headers.
|
|
24
|
+
def finish
|
|
25
|
+
r = super
|
|
26
|
+
case r[0]
|
|
27
|
+
when DROP_BODY_RANGE, 204, 304
|
|
28
|
+
r[2] = EMPTY_ARRAY
|
|
29
|
+
h = r[1]
|
|
30
|
+
h.delete(RodaResponseHeaders::CONTENT_LENGTH)
|
|
31
|
+
h.delete(RodaResponseHeaders::CONTENT_TYPE)
|
|
32
|
+
when 205
|
|
33
|
+
r[2] = EMPTY_ARRAY
|
|
34
|
+
empty_205_headers(r[1])
|
|
35
|
+
end
|
|
36
|
+
r
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
register_plugin(:drop_body, DropBody)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The each_part plugin adds an each_part method, which is a
|
|
7
|
+
# render_each-like method that treats all keywords as locals.
|
|
8
|
+
#
|
|
9
|
+
# # Can replace this:
|
|
10
|
+
# render_each(enum, :template, locals: {foo: 'bar'})
|
|
11
|
+
#
|
|
12
|
+
# # With this:
|
|
13
|
+
# each_part(enum, :template, foo: 'bar')
|
|
14
|
+
#
|
|
15
|
+
# On Ruby 2.7+, the part method takes a keyword splat, so you
|
|
16
|
+
# must pass keywords and not a positional hash for the locals.
|
|
17
|
+
#
|
|
18
|
+
# If you are using the :assume_fixed_locals render plugin option,
|
|
19
|
+
# template caching is enabled, you are using Ruby 3+, and you
|
|
20
|
+
# are freezing your Roda application, in addition to providing a
|
|
21
|
+
# simpler API, this also provides a performance improvement.
|
|
22
|
+
module EachPart
|
|
23
|
+
def self.load_dependencies(app)
|
|
24
|
+
app.plugin :render_each
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module ClassMethods
|
|
28
|
+
# When freezing, optimize the part method if assuming fixed locals
|
|
29
|
+
# and caching templates.
|
|
30
|
+
def freeze
|
|
31
|
+
if render_opts[:assume_fixed_locals] && !render_opts[:check_template_mtime]
|
|
32
|
+
include AssumeFixedLocalsInstanceMethods
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
super
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
module InstanceMethods
|
|
40
|
+
if RUBY_VERSION >= '2.7'
|
|
41
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
|
42
|
+
def each_part(enum, template, **locals, &block)
|
|
43
|
+
render_each(enum, template, :locals=>locals, &block)
|
|
44
|
+
end
|
|
45
|
+
RUBY
|
|
46
|
+
# :nocov:
|
|
47
|
+
else
|
|
48
|
+
def each_part(enum, template, locals=OPTS, &block)
|
|
49
|
+
render_each(enum, template, :locals=>locals, &block)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
# :nocov:
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
module AssumeFixedLocalsInstanceMethods
|
|
56
|
+
# :nocov:
|
|
57
|
+
if RUBY_VERSION >= '3.0'
|
|
58
|
+
# :nocov:
|
|
59
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
|
60
|
+
def each_part(enum, template, **locals, &block)
|
|
61
|
+
if optimized_method = _cached_render_each_template_method(template)
|
|
62
|
+
optimized_method = optimized_method[0]
|
|
63
|
+
as = render_each_default_local(template)
|
|
64
|
+
if defined?(yield)
|
|
65
|
+
enum.each do |v|
|
|
66
|
+
locals[as] = v
|
|
67
|
+
yield send(optimized_method, **locals)
|
|
68
|
+
end
|
|
69
|
+
nil
|
|
70
|
+
else
|
|
71
|
+
enum.map do |v|
|
|
72
|
+
locals[as] = v
|
|
73
|
+
send(optimized_method, **locals)
|
|
74
|
+
end.join
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
render_each(enum, template, :locals=>locals, &block)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
RUBY
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
register_plugin(:each_part, EachPart)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The early_hints plugin allows sending 103 Early Hints responses
|
|
7
|
+
# using the rack.early_hints environment variable.
|
|
8
|
+
# Early hints allow clients to preload necessary files before receiving
|
|
9
|
+
# the response.
|
|
10
|
+
module EarlyHints
|
|
11
|
+
module InstanceMethods
|
|
12
|
+
# Send given hash of Early Hints using the rack.early_hints environment variable,
|
|
13
|
+
# currenly only supported by puma. hash given should generally have the single
|
|
14
|
+
# key 'Link', and a string or array of strings for each of the early hints.
|
|
15
|
+
def send_early_hints(hash)
|
|
16
|
+
if eh_proc = env['rack.early_hints']
|
|
17
|
+
eh_proc.call(hash)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
register_plugin(:early_hints, EarlyHints)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The empty_root plugin makes +r.root+ match both on +/+ and
|
|
7
|
+
# on the empty string. This is mostly useful when using multiple
|
|
8
|
+
# rack applications, where the initial PATH_INFO has been moved
|
|
9
|
+
# to SCRIPT_NAME. For example, if you have the following
|
|
10
|
+
# applications:
|
|
11
|
+
#
|
|
12
|
+
# class App1 < Roda
|
|
13
|
+
# on "albums" do
|
|
14
|
+
# run App2
|
|
15
|
+
# end
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# class App2 < Roda
|
|
19
|
+
# plugin :empty_root
|
|
20
|
+
#
|
|
21
|
+
# route do |r|
|
|
22
|
+
# r.root do
|
|
23
|
+
# "root"
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# Then requests for both +/albums/+ and +/albums+ will return
|
|
29
|
+
# "root". Without this plugin loaded into App2, only requests
|
|
30
|
+
# for +/albums/+ will return "root", since by default, +r.root+
|
|
31
|
+
# matches only when the current PATH_INFO is +/+ and not when
|
|
32
|
+
# it is empty.
|
|
33
|
+
module EmptyRoot
|
|
34
|
+
module RequestMethods
|
|
35
|
+
# Match when the remaining path is the empty string,
|
|
36
|
+
# in addition to the default behavior of matching when
|
|
37
|
+
# the remaining path is +/+.
|
|
38
|
+
def root(&block)
|
|
39
|
+
super
|
|
40
|
+
if remaining_path.empty? && is_get?
|
|
41
|
+
always(&block)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
register_plugin(:empty_root, EmptyRoot)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The environments plugin adds a environment class accessor to get
|
|
7
|
+
# the environment for the application, 3 predicate class methods
|
|
8
|
+
# to check for the current environment (development?, test? and
|
|
9
|
+
# production?), and a class configure method that takes environment(s)
|
|
10
|
+
# and yields to the block if the given environment(s) match the
|
|
11
|
+
# current environment.
|
|
12
|
+
#
|
|
13
|
+
# The default environment for the application is based on
|
|
14
|
+
# <tt>ENV['RACK_ENV']</tt>.
|
|
15
|
+
#
|
|
16
|
+
# Example:
|
|
17
|
+
#
|
|
18
|
+
# class Roda
|
|
19
|
+
# plugin :environments
|
|
20
|
+
#
|
|
21
|
+
# environment # => :development
|
|
22
|
+
# development? # => true
|
|
23
|
+
# test? # => false
|
|
24
|
+
# production? # => false
|
|
25
|
+
#
|
|
26
|
+
# # Set the environment for the application
|
|
27
|
+
# self.environment = :test
|
|
28
|
+
# test? # => true
|
|
29
|
+
#
|
|
30
|
+
# configure do
|
|
31
|
+
# # called, as no environments given
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# configure :development, :production do
|
|
35
|
+
# # not called, as no environments match
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# configure :test do
|
|
39
|
+
# # called, as environment given matches current environment
|
|
40
|
+
# end
|
|
41
|
+
# end
|
|
42
|
+
module Environments
|
|
43
|
+
# Set the environment to use for the app. Default to ENV['RACK_ENV']
|
|
44
|
+
# if no environment is given. If ENV['RACK_ENV'] is not set and
|
|
45
|
+
# no environment is given, assume the development environment.
|
|
46
|
+
def self.configure(app, env=ENV["RACK_ENV"])
|
|
47
|
+
app.environment = (env || 'development').to_sym
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module ClassMethods
|
|
51
|
+
# If no environments are given or one of the given environments
|
|
52
|
+
# matches the current environment, yield the receiver to the block.
|
|
53
|
+
def configure(*envs)
|
|
54
|
+
if envs.empty? || envs.any?{|s| s == environment}
|
|
55
|
+
yield self
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The current environment for the application, which should be stored
|
|
60
|
+
# as a symbol.
|
|
61
|
+
def environment
|
|
62
|
+
opts[:environment]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Override the environment for the application, instead of using
|
|
66
|
+
# RACK_ENV.
|
|
67
|
+
def environment=(v)
|
|
68
|
+
opts[:environment] = v
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
[:development, :test, :production].each do |env|
|
|
72
|
+
define_method("#{env}?"){environment == env}
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
register_plugin(:environments, Environments)
|
|
78
|
+
end
|
|
79
|
+
end
|