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
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: fbbe1c7f2a3c43738c8c98358cc1ec12d792d3eef166171033f72c9404e5ae13
|
|
4
|
+
data.tar.gz: bb3d4c405cc6934a3f226af3bf21922b5d9ed39b33df4560cadc00eac183f0d9
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a4ee47127536f906c9ac92d330a60201444777884dd3055a798828994f4136911f6d0fd6b3c0d33fd4f62e066234d66e4cfaef9ab4101527a3571a4f2a858a7a
|
|
7
|
+
data.tar.gz: 9e85f412c5e1681ae67b2b26469525752b2fe4548abd8f53e7151bd18491ee150eae77b4812165b8ac6e9a680aed05abec3c2e43906ced905bb1e36f50b833fd
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Copyright (c) 2014-2026 Jeremy Evans and contributors
|
|
2
|
+
Copyright (c) 2010-2014 Michel Martens, Damian Janowski and Cyril David
|
|
3
|
+
Copyright (c) 2008-2009 Christian Neukirchen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
require "thread"
|
|
4
|
+
|
|
5
|
+
class Roda
|
|
6
|
+
# A thread safe cache class, offering only #[] and #[]= methods,
|
|
7
|
+
# each protected by a mutex.
|
|
8
|
+
class RodaCache
|
|
9
|
+
# Create a new thread safe cache.
|
|
10
|
+
def initialize
|
|
11
|
+
@mutex = Mutex.new
|
|
12
|
+
@hash = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Make getting value from underlying hash thread safe.
|
|
16
|
+
def [](key)
|
|
17
|
+
@mutex.synchronize{@hash[key]}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Make setting value in underlying hash thread safe.
|
|
21
|
+
def []=(key, value)
|
|
22
|
+
@mutex.synchronize{@hash[key] = value}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Return the frozen internal hash. The internal hash can then
|
|
26
|
+
# be accessed directly since it is frozen and there are no
|
|
27
|
+
# thread safety issues.
|
|
28
|
+
def freeze
|
|
29
|
+
@hash.freeze
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# Create a copy of the cache with a separate mutex.
|
|
35
|
+
def initialize_copy(other)
|
|
36
|
+
@mutex = Mutex.new
|
|
37
|
+
other.instance_variable_get(:@mutex).synchronize do
|
|
38
|
+
@hash = other.instance_variable_get(:@hash).dup
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The Integer_matcher_max plugin sets the maximum integer value
|
|
7
|
+
# value that the Integer class matcher will match by default.
|
|
8
|
+
# By default, loading this plugin sets the maximum value to
|
|
9
|
+
# 2**63-1, the largest signed 64-bit integer value:
|
|
10
|
+
#
|
|
11
|
+
# plugin :Integer_matcher_max
|
|
12
|
+
# route do |r|
|
|
13
|
+
# r.is Integer do
|
|
14
|
+
# # Matches /9223372036854775807
|
|
15
|
+
# # Does not match /9223372036854775808
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# To specify a different maximum value, you can pass a different
|
|
20
|
+
# maximum value when loading the plugin:
|
|
21
|
+
#
|
|
22
|
+
# plugin :Integer_matcher_max, 2**64-1
|
|
23
|
+
module IntegerMatcherMax
|
|
24
|
+
def self.configure(app, max=nil)
|
|
25
|
+
if max
|
|
26
|
+
app.class_eval do
|
|
27
|
+
meth = :_max_value_convert_class_Integer
|
|
28
|
+
define_method(meth){max}
|
|
29
|
+
alias_method meth, meth
|
|
30
|
+
private meth
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module InstanceMethods
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
# Do not have the Integer matcher max when over the maximum
|
|
39
|
+
# configured Integer value.
|
|
40
|
+
def _convert_class_Integer(value)
|
|
41
|
+
value = super
|
|
42
|
+
value if value <= _max_value_convert_class_Integer
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Use 2**63-1 as the default maximum value for the Integer
|
|
46
|
+
# matcher.
|
|
47
|
+
def _max_value_convert_class_Integer
|
|
48
|
+
9223372036854775807
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
register_plugin(:Integer_matcher_max, IntegerMatcherMax)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
module Base64_
|
|
7
|
+
class << self
|
|
8
|
+
if RUBY_VERSION >= '2.4'
|
|
9
|
+
def decode64(str)
|
|
10
|
+
str.unpack1("m0")
|
|
11
|
+
end
|
|
12
|
+
# :nocov:
|
|
13
|
+
else
|
|
14
|
+
def decode64(str)
|
|
15
|
+
str.unpack("m0")[0]
|
|
16
|
+
end
|
|
17
|
+
# :nocov:
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def urlsafe_encode64(bin)
|
|
21
|
+
str = [bin].pack("m0")
|
|
22
|
+
str.tr!("+/", "-_")
|
|
23
|
+
str
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def urlsafe_decode64(str)
|
|
27
|
+
decode64(str.tr("-_", "+/"))
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
register_plugin(:_base64, Base64_)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# Internal before hook module, not for external use.
|
|
7
|
+
# Allows for plugins to configure the order in which
|
|
8
|
+
# before processing is done by using _roda_before_*
|
|
9
|
+
# private instance methods that are called in sorted order.
|
|
10
|
+
# Loaded automatically by the base library if any _roda_before_*
|
|
11
|
+
# methods are defined.
|
|
12
|
+
module BeforeHook # :nodoc:
|
|
13
|
+
module InstanceMethods
|
|
14
|
+
# Run internal before hooks - Old Dispatch API.
|
|
15
|
+
def call(&block)
|
|
16
|
+
# RODA4: Remove
|
|
17
|
+
super do
|
|
18
|
+
_roda_before
|
|
19
|
+
instance_exec(@_request, &block) # call Fallback
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Run internal before hooks before running the main
|
|
24
|
+
# roda route.
|
|
25
|
+
def _roda_run_main_route(r)
|
|
26
|
+
_roda_before
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
# Default empty implementation of _roda_before, usually
|
|
33
|
+
# overridden by Roda.def_roda_before.
|
|
34
|
+
def _roda_before
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
register_plugin(:_before_hook, BeforeHook)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The _optimized_matching plugin is automatically used internally to speed
|
|
7
|
+
# up matching when a single argument String instance, String class, Integer
|
|
8
|
+
# class, or Regexp matcher is passed to +r.on+, +r.is_+, or a verb method
|
|
9
|
+
# such as +r.get+ or +r.post+.
|
|
10
|
+
#
|
|
11
|
+
# The optimization works by avoiding the +if_match+ method if possible.
|
|
12
|
+
# Instead of clearing the captures array on every call, and having the
|
|
13
|
+
# matching append to the captures, it checks directly for the match,
|
|
14
|
+
# and on succesful match, it yields directly to the block without using
|
|
15
|
+
# the captures array.
|
|
16
|
+
module OptimizedMatching
|
|
17
|
+
TERM = Base::RequestMethods::TERM
|
|
18
|
+
|
|
19
|
+
module RequestMethods
|
|
20
|
+
# Optimize the r.is method handling of a single string, String, Integer,
|
|
21
|
+
# regexp, or true, argument.
|
|
22
|
+
def is(*args, &block)
|
|
23
|
+
case args.length
|
|
24
|
+
when 1
|
|
25
|
+
_is1(args, &block)
|
|
26
|
+
when 0
|
|
27
|
+
always(&block) if @remaining_path.empty?
|
|
28
|
+
else
|
|
29
|
+
if_match(args << TERM, &block)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Optimize the r.on method handling of a single string, String, Integer,
|
|
34
|
+
# or regexp argument. Inline the related matching code to avoid the
|
|
35
|
+
# need to modify @captures.
|
|
36
|
+
def on(*args, &block)
|
|
37
|
+
case args.length
|
|
38
|
+
when 1
|
|
39
|
+
case matcher = args[0]
|
|
40
|
+
when String
|
|
41
|
+
always{yield} if _match_string(matcher)
|
|
42
|
+
when Class
|
|
43
|
+
if matcher == String
|
|
44
|
+
rp = @remaining_path
|
|
45
|
+
if rp.getbyte(0) == 47
|
|
46
|
+
if last = rp.index('/', 1)
|
|
47
|
+
@remaining_path = rp[last, rp.length]
|
|
48
|
+
always{yield rp[1, last-1]}
|
|
49
|
+
elsif (len = rp.length) > 1
|
|
50
|
+
@remaining_path = ""
|
|
51
|
+
always{yield rp[1, len]}
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
elsif matcher == Integer
|
|
55
|
+
rp = @remaining_path
|
|
56
|
+
if /\A\/(\d{1,100})(?=\/|\z)/.match?(rp)
|
|
57
|
+
if last = rp.index('/', 1)
|
|
58
|
+
value = rp[1, last-1]
|
|
59
|
+
rp = rp[last, rp.length]
|
|
60
|
+
else
|
|
61
|
+
value = rp[1, rp.length]
|
|
62
|
+
rp = ""
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if value = scope.send(:_convert_class_Integer, value)
|
|
66
|
+
@remaining_path = rp
|
|
67
|
+
always{yield(value)}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
else
|
|
71
|
+
path = @remaining_path
|
|
72
|
+
captures = @captures.clear
|
|
73
|
+
meth = :"_match_class_#{matcher}"
|
|
74
|
+
if respond_to?(meth, true)
|
|
75
|
+
# Allow calling private methods, as match methods are generally private
|
|
76
|
+
if send(meth, &block)
|
|
77
|
+
block_result(yield(*captures))
|
|
78
|
+
throw :halt, response.finish
|
|
79
|
+
else
|
|
80
|
+
@remaining_path = path
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
else
|
|
84
|
+
unsupported_matcher(matcher)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
when Regexp
|
|
88
|
+
if matchdata = self.class.cached_matcher(matcher){matcher}.match(@remaining_path)
|
|
89
|
+
@remaining_path = matchdata.post_match
|
|
90
|
+
always{yield(*matchdata.captures)}
|
|
91
|
+
end
|
|
92
|
+
when true
|
|
93
|
+
always(&block)
|
|
94
|
+
when false, nil
|
|
95
|
+
# nothing
|
|
96
|
+
else
|
|
97
|
+
path = @remaining_path
|
|
98
|
+
captures = @captures.clear
|
|
99
|
+
|
|
100
|
+
matched = case matcher
|
|
101
|
+
when Array
|
|
102
|
+
_match_array(matcher)
|
|
103
|
+
when Hash
|
|
104
|
+
_match_hash(matcher)
|
|
105
|
+
when Symbol
|
|
106
|
+
_match_symbol(matcher)
|
|
107
|
+
when Proc
|
|
108
|
+
matcher.call
|
|
109
|
+
else
|
|
110
|
+
unsupported_matcher(matcher)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
if matched
|
|
114
|
+
block_result(yield(*captures))
|
|
115
|
+
throw :halt, response.finish
|
|
116
|
+
else
|
|
117
|
+
@remaining_path = path
|
|
118
|
+
false
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
when 0
|
|
122
|
+
always(&block)
|
|
123
|
+
else
|
|
124
|
+
if_match(args, &block)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
# Optimize the r.get/r.post method handling of a single string, String, Integer,
|
|
131
|
+
# regexp, or true, argument.
|
|
132
|
+
def _verb(args, &block)
|
|
133
|
+
case args.length
|
|
134
|
+
when 0
|
|
135
|
+
always(&block)
|
|
136
|
+
when 1
|
|
137
|
+
_is1(args, &block)
|
|
138
|
+
else
|
|
139
|
+
if_match(args << TERM, &block)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Internals of r.is/r.get/r.post optimization. Inline the related matching
|
|
144
|
+
# code to avoid the need to modify @captures.
|
|
145
|
+
def _is1(args, &block)
|
|
146
|
+
case matcher = args[0]
|
|
147
|
+
when String
|
|
148
|
+
rp = @remaining_path
|
|
149
|
+
if _match_string(matcher)
|
|
150
|
+
if @remaining_path.empty?
|
|
151
|
+
always{yield}
|
|
152
|
+
else
|
|
153
|
+
@remaining_path = rp
|
|
154
|
+
nil
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
when Class
|
|
158
|
+
if matcher == String
|
|
159
|
+
rp = @remaining_path
|
|
160
|
+
if rp.getbyte(0) == 47 && !rp.index('/', 1) && (len = rp.length) > 1
|
|
161
|
+
@remaining_path = ''
|
|
162
|
+
always{yield rp[1, len]}
|
|
163
|
+
end
|
|
164
|
+
elsif matcher == Integer
|
|
165
|
+
rp = @remaining_path
|
|
166
|
+
if /\A\/(\d{1,100})\z/.match?(rp) && (value = scope.send(:_convert_class_Integer, rp[1, 101]))
|
|
167
|
+
@remaining_path = ''
|
|
168
|
+
always{yield(value)}
|
|
169
|
+
end
|
|
170
|
+
else
|
|
171
|
+
path = @remaining_path
|
|
172
|
+
captures = @captures.clear
|
|
173
|
+
meth = :"_match_class_#{matcher}"
|
|
174
|
+
if respond_to?(meth, true)
|
|
175
|
+
# Allow calling private methods, as match methods are generally private
|
|
176
|
+
if send(meth, &block) && @remaining_path.empty?
|
|
177
|
+
block_result(yield(*captures))
|
|
178
|
+
throw :halt, response.finish
|
|
179
|
+
else
|
|
180
|
+
@remaining_path = path
|
|
181
|
+
false
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
unsupported_matcher(matcher)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
when Regexp
|
|
188
|
+
if (matchdata = self.class.cached_matcher(matcher){matcher}.match(@remaining_path)) && matchdata.post_match.empty?
|
|
189
|
+
@remaining_path = ''
|
|
190
|
+
always{yield(*matchdata.captures)}
|
|
191
|
+
end
|
|
192
|
+
when true
|
|
193
|
+
always(&block) if @remaining_path.empty?
|
|
194
|
+
when false, nil
|
|
195
|
+
# nothing
|
|
196
|
+
else
|
|
197
|
+
path = @remaining_path
|
|
198
|
+
captures = @captures.clear
|
|
199
|
+
|
|
200
|
+
matched = case matcher
|
|
201
|
+
when Array
|
|
202
|
+
_match_array(matcher)
|
|
203
|
+
when Hash
|
|
204
|
+
_match_hash(matcher)
|
|
205
|
+
when Symbol
|
|
206
|
+
_match_symbol(matcher)
|
|
207
|
+
when Proc
|
|
208
|
+
matcher.call
|
|
209
|
+
else
|
|
210
|
+
unsupported_matcher(matcher)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
if matched && @remaining_path.empty?
|
|
214
|
+
block_result(yield(*captures))
|
|
215
|
+
throw :halt, response.finish
|
|
216
|
+
else
|
|
217
|
+
@remaining_path = path
|
|
218
|
+
false
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
register_plugin(:_optimized_matching, OptimizedMatching)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
module SymbolClassMatchers_
|
|
7
|
+
module ClassMethods
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
# Backend of symbol_matcher and class_matcher.
|
|
11
|
+
def _symbol_class_matcher(expected_class, obj, matcher, block, options=OPTS, &request_class_block)
|
|
12
|
+
unless obj.is_a?(expected_class)
|
|
13
|
+
raise RodaError, "Invalid type passed to class_matcher or symbol_matcher: #{matcher.inspect}"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if obj.is_a?(Symbol)
|
|
17
|
+
type = "symbol"
|
|
18
|
+
meth = :"match_symbol_#{obj}"
|
|
19
|
+
else
|
|
20
|
+
type = "class"
|
|
21
|
+
meth = :"_match_class_#{obj}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
case matcher
|
|
25
|
+
when Regexp
|
|
26
|
+
regexp = matcher
|
|
27
|
+
consume_regexp = self::RodaRequest.send(:consume_pattern, regexp)
|
|
28
|
+
when Symbol
|
|
29
|
+
unless opts[:symbol_matchers]
|
|
30
|
+
raise RodaError, "cannot provide Symbol matcher to class_matcher unless using symbol_matchers plugin: #{matcher.inspect}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
regexp, consume_regexp, convert_meth, consume_meth = opts[:symbol_matchers][matcher]
|
|
34
|
+
|
|
35
|
+
unless regexp
|
|
36
|
+
raise RodaError, "unregistered symbol matcher given to #{type}_matcher: #{matcher.inspect}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
block = _merge_matcher_blocks(type, obj, block, convert_meth)
|
|
40
|
+
when Class
|
|
41
|
+
unless opts[:class_matchers]
|
|
42
|
+
raise RodaError, "cannot provide Class matcher to symbol_matcher unless using class_matchers plugin: #{matcher.inspect}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
regexp, consume_regexp, convert_meth, consume_meth = opts[:class_matchers][matcher]
|
|
46
|
+
unless regexp
|
|
47
|
+
raise RodaError, "unregistered class matcher given to #{type}_matcher: #{matcher.inspect}"
|
|
48
|
+
end
|
|
49
|
+
block = _merge_matcher_blocks(type, obj, block, convert_meth)
|
|
50
|
+
else
|
|
51
|
+
raise RodaError, "unsupported matcher given to #{type}_matcher: #{matcher.inspect}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if block.is_a?(Symbol)
|
|
55
|
+
convert_meth = block
|
|
56
|
+
elsif block
|
|
57
|
+
convert_meth = :"_convert_#{type}_#{obj}"
|
|
58
|
+
define_method(convert_meth, &block)
|
|
59
|
+
private convert_meth
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
consume_meth ||= options[:segment] ? :_consume_single_segment : :consume
|
|
63
|
+
array = opts[:"#{type}_matchers"][obj] = [regexp, consume_regexp, convert_meth, consume_meth].freeze
|
|
64
|
+
|
|
65
|
+
self::RodaRequest.class_eval do
|
|
66
|
+
class_exec(meth, array, &request_class_block)
|
|
67
|
+
private meth
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# If both block and convert_meth are given,
|
|
74
|
+
# define a method for block, and then return a
|
|
75
|
+
# proc that calls convert_meth first, and only calls
|
|
76
|
+
# the newly defined method with the return values of convert_meth
|
|
77
|
+
# if matcher_method returns a truthy value.
|
|
78
|
+
# Otherwise, return convert_meth or block.
|
|
79
|
+
def _merge_matcher_blocks(type, obj, block, convert_meth)
|
|
80
|
+
if convert_meth
|
|
81
|
+
if block
|
|
82
|
+
convert_merge_meth = :"_convert_merge_#{type}_#{obj}"
|
|
83
|
+
define_method(convert_merge_meth, &block)
|
|
84
|
+
private convert_merge_meth
|
|
85
|
+
|
|
86
|
+
proc do |*a|
|
|
87
|
+
if captures = send(convert_meth, *a)
|
|
88
|
+
if captures.is_a?(Array)
|
|
89
|
+
send(convert_merge_meth, *captures)
|
|
90
|
+
else
|
|
91
|
+
send(convert_merge_meth, captures)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
convert_meth
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
block
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
register_plugin(:_symbol_class_matchers, SymbolClassMatchers_)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The _symbol_regexp_matchers plugin is designed for internal use by other plugins,
|
|
7
|
+
# for the historical behavior of a symbol matching an arbitrary segment by default
|
|
8
|
+
# using a regexp.
|
|
9
|
+
module SymbolRegexpMatchers
|
|
10
|
+
module RequestMethods
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
# The regular expression to use for matching symbols. By default, any non-empty
|
|
14
|
+
# segment matches.
|
|
15
|
+
def _match_symbol_regexp(s)
|
|
16
|
+
"([^\\/]+)"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
register_plugin(:_symbol_regexp_matchers, SymbolRegexpMatchers)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The additional_render_engines plugin allows for specifying additional render
|
|
7
|
+
# engines to consider for templates. When rendering a template, it will
|
|
8
|
+
# first try the default template engine specified in the render plugin. If the
|
|
9
|
+
# template file to be rendered does not exist, it will try each additional render
|
|
10
|
+
# engine specified in this plugin, in order, using the path to the first
|
|
11
|
+
# template file that exists in the file system. If no such path is found, it
|
|
12
|
+
# uses the default path specified by the render plugin.
|
|
13
|
+
#
|
|
14
|
+
# Example:
|
|
15
|
+
#
|
|
16
|
+
# plugin :render # default engine is 'erb'
|
|
17
|
+
# plugin :additional_render_engines, ['haml', 'str']
|
|
18
|
+
#
|
|
19
|
+
# route do |r|
|
|
20
|
+
# # Will check the following in order, using path for first
|
|
21
|
+
# # template file that exists:
|
|
22
|
+
# # * views/t.erb
|
|
23
|
+
# # * views/t.haml
|
|
24
|
+
# # * views/t.str
|
|
25
|
+
# render :t
|
|
26
|
+
# end
|
|
27
|
+
module AdditionalRenderEngines
|
|
28
|
+
def self.load_dependencies(app, render_engines)
|
|
29
|
+
app.plugin :render
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Set the additional render engines to consider.
|
|
33
|
+
def self.configure(app, render_engines)
|
|
34
|
+
app.opts[:additional_render_engines] = render_engines.dup.freeze
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module InstanceMethods
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# If the template path does not exist, try looking for the template
|
|
41
|
+
# using each of the render engines, in order, returning
|
|
42
|
+
# the first path that exists. If no template path exists for the
|
|
43
|
+
# default any or any additional engines, return the original path.
|
|
44
|
+
def template_path(opts)
|
|
45
|
+
orig_path = super
|
|
46
|
+
|
|
47
|
+
unless File.file?(orig_path)
|
|
48
|
+
self.opts[:additional_render_engines].each do |engine|
|
|
49
|
+
path = super(opts.merge(:engine=>engine))
|
|
50
|
+
return path if File.file?(path)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
orig_path
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
register_plugin(:additional_render_engines, AdditionalRenderEngines)
|
|
60
|
+
end
|
|
61
|
+
end
|