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,111 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The class_level_routing plugin adds routing methods at the class level, which can
|
|
7
|
+
# be used instead of or in addition to using the normal +route+ method to start the
|
|
8
|
+
# routing tree. If a request is not matched by the normal routing tree, the class
|
|
9
|
+
# level routes will be tried. This offers a more Sinatra-like API, while
|
|
10
|
+
# still allowing you to use a routing tree inside individual actions.
|
|
11
|
+
#
|
|
12
|
+
# Here's the first example from the README, modified to use the class_level_routing
|
|
13
|
+
# plugin:
|
|
14
|
+
#
|
|
15
|
+
# class App < Roda
|
|
16
|
+
# plugin :class_level_routing
|
|
17
|
+
#
|
|
18
|
+
# # GET / request
|
|
19
|
+
# root do
|
|
20
|
+
# request.redirect "/hello"
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# # GET /hello/world request
|
|
24
|
+
# get "hello/world" do
|
|
25
|
+
# "Hello world!"
|
|
26
|
+
# end
|
|
27
|
+
#
|
|
28
|
+
# # /hello request
|
|
29
|
+
# is "hello" do
|
|
30
|
+
# # Set variable for both GET and POST requests
|
|
31
|
+
# @greeting = 'Hello'
|
|
32
|
+
#
|
|
33
|
+
# # GET /hello request
|
|
34
|
+
# request.get do
|
|
35
|
+
# "#{@greeting}!"
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# # POST /hello request
|
|
39
|
+
# request.post do
|
|
40
|
+
# puts "Someone said #{@greeting}!"
|
|
41
|
+
# request.redirect
|
|
42
|
+
# end
|
|
43
|
+
# end
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# When using the class_level_routing plugin with nested routes, you may also want to use the
|
|
47
|
+
# delegate plugin to delegate certain instance methods to the request object, so you don't have
|
|
48
|
+
# to continually use +request.+ in your routing blocks.
|
|
49
|
+
#
|
|
50
|
+
# Note that class level routing is implemented via a simple array of routes, so routing performance
|
|
51
|
+
# will degrade linearly as the number of routes increases. For best performance, you should use
|
|
52
|
+
# the normal +route+ class method to define your routing tree. This plugin does make it simpler to
|
|
53
|
+
# add additional routes after the routing tree has already been defined, though.
|
|
54
|
+
module ClassLevelRouting
|
|
55
|
+
# Initialize the class_routes array when the plugin is loaded. Also, if the application doesn't
|
|
56
|
+
# currently have a routing block, setup an empty routing block so that things will still work if
|
|
57
|
+
# a routing block isn't added.
|
|
58
|
+
def self.configure(app)
|
|
59
|
+
app.opts[:class_level_routes] ||= []
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
module ClassMethods
|
|
63
|
+
# Define routing methods that will store class level routes.
|
|
64
|
+
[:root, :on, :is, :get, :post, :delete, :head, :options, :link, :patch, :put, :trace, :unlink].each do |request_meth|
|
|
65
|
+
define_method(request_meth) do |*args, &block|
|
|
66
|
+
meth = define_roda_method("class_level_routing_#{request_meth}", :any, &block)
|
|
67
|
+
opts[:class_level_routes] << [request_meth, args, meth].freeze
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Freeze the class level routes so that there can be no thread safety issues at runtime.
|
|
72
|
+
def freeze
|
|
73
|
+
opts[:class_level_routes].freeze
|
|
74
|
+
super
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
module InstanceMethods
|
|
79
|
+
def initialize(_)
|
|
80
|
+
super
|
|
81
|
+
@_original_remaining_path = @_request.remaining_path
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
# If the normal routing tree doesn't handle an action, try each class level route
|
|
87
|
+
# to see if it matches.
|
|
88
|
+
def _roda_after_10__class_level_routing(result)
|
|
89
|
+
if result && result[0] == 404 && (v = result[2]).is_a?(Array) && v.empty?
|
|
90
|
+
# Reset the response so it doesn't inherit the status or any headers from
|
|
91
|
+
# the original response.
|
|
92
|
+
@_response.send(:initialize)
|
|
93
|
+
@_response.status = nil
|
|
94
|
+
result.replace(_roda_handle_route do
|
|
95
|
+
r = @_request
|
|
96
|
+
opts[:class_level_routes].each do |request_meth, args, meth|
|
|
97
|
+
r.instance_variable_set(:@remaining_path, @_original_remaining_path)
|
|
98
|
+
r.public_send(request_meth, *args) do |*a|
|
|
99
|
+
send(meth, *a)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
nil
|
|
103
|
+
end)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
register_plugin(:class_level_routing, ClassLevelRouting)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The class_matchers plugin allows you do define custom regexps and
|
|
7
|
+
# conversion procs to use for specific classes. For example, if you
|
|
8
|
+
# have multiple routes similar to:
|
|
9
|
+
#
|
|
10
|
+
# r.on /(\d\d\d\d)-(\d\d)-(\d\d)/ do |y, m, d|
|
|
11
|
+
# date = Date.new(y.to_i, m.to_i, d.to_i)
|
|
12
|
+
# # ...
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# You can register a Date class matcher for that regexp:
|
|
16
|
+
#
|
|
17
|
+
# class_matcher(Date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
|
|
18
|
+
# Date.new(y.to_i, m.to_i, d.to_i)
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# And then use the Date class as a matcher, and it will yield a Date object:
|
|
22
|
+
#
|
|
23
|
+
# r.on Date do |date|
|
|
24
|
+
# # ...
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# This is useful to DRY up code if you are using the same type of pattern and
|
|
28
|
+
# type conversion in multiple places in your application. You can have the
|
|
29
|
+
# block return an array to yield multiple captures.
|
|
30
|
+
#
|
|
31
|
+
# If you have a segment match the passed regexp, but decide during block
|
|
32
|
+
# processing that you do not want to treat it as a match, you can have the
|
|
33
|
+
# block return nil or false. This is useful if you want to make sure you
|
|
34
|
+
# are using valid data:
|
|
35
|
+
#
|
|
36
|
+
# class_matcher(Date, /(\d\d\d\d)-(\d\d)-(\d\d)/) do |y, m, d|
|
|
37
|
+
# y = y.to_i
|
|
38
|
+
# m = m.to_i
|
|
39
|
+
# d = d.to_i
|
|
40
|
+
# Date.new(y, m, d) if Date.valid_date?(y, m, d)
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# The second argument to class_matcher can be a class already registered
|
|
44
|
+
# as a class matcher. This can DRY up code that wants a conversion
|
|
45
|
+
# performed by an existing class matcher:
|
|
46
|
+
#
|
|
47
|
+
# class_matcher Employee, Integer do |id|
|
|
48
|
+
# Employee[id]
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# With the above example, the Integer matcher performs the conversion to
|
|
52
|
+
# integer, so +id+ is yielded as an integer. The block then looks up the
|
|
53
|
+
# employee with that id. If there is no employee with that id, then
|
|
54
|
+
# the Employee matcher will not match.
|
|
55
|
+
#
|
|
56
|
+
# If using the symbol_matchers plugin, you can provide a recognized symbol
|
|
57
|
+
# matcher as the second argument to class_matcher, and it will work in
|
|
58
|
+
# a similar manner:
|
|
59
|
+
#
|
|
60
|
+
# symbol_matcher(:employee_id, /E-(\d{6})/) do |employee_id|
|
|
61
|
+
# employee_id.to_i
|
|
62
|
+
# end
|
|
63
|
+
# class_matcher Employee, :employee_id do |id|
|
|
64
|
+
# Employee[id]
|
|
65
|
+
# end
|
|
66
|
+
#
|
|
67
|
+
# Blocks passed to the class_matchers plugin are evaluated in route
|
|
68
|
+
# block context.
|
|
69
|
+
#
|
|
70
|
+
# When passing a regexp as a matcher, to class_matcher, you can provide a
|
|
71
|
+
# <tt>segment: true</tt> option to speed up the matching on Ruby 2.4+:
|
|
72
|
+
#
|
|
73
|
+
# symbol_matcher(:employee_id, /E-(\d{6})/, segment: true) do |employee_id|
|
|
74
|
+
# employee_id.to_i
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# Use of <tt>segment: true</tt> requires that the regexp not match more than
|
|
78
|
+
# one segment (i.e. it cannot match +/+). Additionally, the entire segment will
|
|
79
|
+
# be captured, so any capture groups in the regexp will be ignored.
|
|
80
|
+
#
|
|
81
|
+
# This plugin does not work with the params_capturing plugin, as it does not
|
|
82
|
+
# offer the ability to associate block arguments with named keys.
|
|
83
|
+
module ClassMatchers
|
|
84
|
+
def self.load_dependencies(app)
|
|
85
|
+
app.plugin :_symbol_class_matchers
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def self.configure(app)
|
|
89
|
+
app.opts[:class_matchers] ||= {
|
|
90
|
+
Integer=>[/(\d{1,100})/, /\A\/(\d{1,100})(?=\/|\z)/, :_convert_class_Integer].freeze,
|
|
91
|
+
String=>[/([^\/]+)/, nil, nil].freeze
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
module ClassMethods
|
|
96
|
+
# Set the matcher and block to use for the given class.
|
|
97
|
+
# The matcher can be a regexp, registered class matcher, or registered symbol
|
|
98
|
+
# matcher (if using the symbol_matchers plugin).
|
|
99
|
+
#
|
|
100
|
+
# If providing a regexp, the block given will be called with all regexp captures.
|
|
101
|
+
# If providing a registered class or symbol, the block will be called with the
|
|
102
|
+
# captures returned by the block for the registered class or symbol, or the regexp
|
|
103
|
+
# captures if no block was registered with the class or symbol. In either case,
|
|
104
|
+
# if a block is given, it should return an array with the captures to yield to
|
|
105
|
+
# the match block.
|
|
106
|
+
def class_matcher(klass, matcher, opts=OPTS, &block)
|
|
107
|
+
_symbol_class_matcher(Class, klass, matcher, block, opts) do |meth, (_, regexp, convert_meth, consume_meth)|
|
|
108
|
+
if regexp
|
|
109
|
+
if consume_meth == :_consume_single_segment
|
|
110
|
+
define_method(meth){_consume_single_segment(regexp, convert_meth)}
|
|
111
|
+
else
|
|
112
|
+
define_method(meth){consume(regexp, convert_meth)}
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
define_method(meth){_consume_segment(convert_meth)}
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Freeze the class_matchers hash when freezing the app.
|
|
121
|
+
def freeze
|
|
122
|
+
opts[:class_matchers].freeze
|
|
123
|
+
super
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
module RequestMethods
|
|
128
|
+
# Use faster approach for segment matching. This is used for
|
|
129
|
+
# matchers based on the String class matcher, and avoids the
|
|
130
|
+
# use of regular expressions for scanning.
|
|
131
|
+
def _consume_segment(convert_meth)
|
|
132
|
+
rp = @remaining_path
|
|
133
|
+
if _match_class_String
|
|
134
|
+
if convert_meth
|
|
135
|
+
if captures = scope.send(convert_meth, @captures.pop)
|
|
136
|
+
if captures.is_a?(Array)
|
|
137
|
+
@captures.concat(captures)
|
|
138
|
+
else
|
|
139
|
+
@captures << captures
|
|
140
|
+
end
|
|
141
|
+
else
|
|
142
|
+
@remaining_path = rp
|
|
143
|
+
nil
|
|
144
|
+
end
|
|
145
|
+
else
|
|
146
|
+
true
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
register_plugin(:class_matchers, ClassMatchers)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The common_logger plugin adds common logger support to Roda
|
|
7
|
+
# applications, similar to Rack::CommonLogger, with the following
|
|
8
|
+
# differences:
|
|
9
|
+
#
|
|
10
|
+
# * Better performance
|
|
11
|
+
# * Doesn't include middleware timing
|
|
12
|
+
# * Doesn't proxy the body
|
|
13
|
+
# * Doesn't support different capitalization of the Content-Length response header
|
|
14
|
+
# * Logs to +$stderr+ instead of <tt>env['rack.errors']</tt> if explicit logger not passed
|
|
15
|
+
#
|
|
16
|
+
# Example:
|
|
17
|
+
#
|
|
18
|
+
# plugin :common_logger
|
|
19
|
+
# plugin :common_logger, $stdout
|
|
20
|
+
# plugin :common_logger, Logger.new('filename')
|
|
21
|
+
# plugin :common_logger, Logger.new('filename'), method: :debug
|
|
22
|
+
module CommonLogger
|
|
23
|
+
MUTATE_LINE = RUBY_VERSION < '2.3' || RUBY_VERSION >= '3'
|
|
24
|
+
private_constant :MUTATE_LINE
|
|
25
|
+
|
|
26
|
+
def self.configure(app, logger=nil, opts=OPTS)
|
|
27
|
+
app.opts[:common_logger] = logger || app.opts[:common_logger] || $stderr
|
|
28
|
+
app.opts[:common_logger_meth] = app.opts[:common_logger].method(opts.fetch(:method){logger.respond_to?(:write) ? :write : :<<})
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
if RUBY_VERSION >= '2.1'
|
|
32
|
+
# A timer object for calculating elapsed time.
|
|
33
|
+
def self.start_timer
|
|
34
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
# :nocov:
|
|
38
|
+
def self.start_timer # :nodoc:
|
|
39
|
+
Time.now
|
|
40
|
+
end
|
|
41
|
+
# :nocov:
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
module InstanceMethods
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# Log request/response information in common log format to logger.
|
|
48
|
+
def _roda_after_90__common_logger(result)
|
|
49
|
+
return unless result && (status = result[0]) && (headers = result[1])
|
|
50
|
+
|
|
51
|
+
elapsed_time = if timer = @_request_timer
|
|
52
|
+
'%0.4f' % (CommonLogger.start_timer - timer)
|
|
53
|
+
else
|
|
54
|
+
'-'
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
env = @_request.env
|
|
58
|
+
|
|
59
|
+
line = "#{env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-"} - #{env["REMOTE_USER"] || "-"} [#{Time.now.strftime("%d/%b/%Y:%H:%M:%S %z")}] \"#{env["REQUEST_METHOD"]} #{env["SCRIPT_NAME"]}#{env["PATH_INFO"]}#{"?#{env["QUERY_STRING"]}" if ((qs = env["QUERY_STRING"]) && !qs.empty?)} #{@_request.http_version}\" #{status} #{((length = headers[RodaResponseHeaders::CONTENT_LENGTH]) && (length unless length == '0')) || '-'} #{elapsed_time} "
|
|
60
|
+
if MUTATE_LINE
|
|
61
|
+
line.gsub!(/[^[:print:]]/){|c| sprintf("\\x%x", c.ord)}
|
|
62
|
+
# :nocov:
|
|
63
|
+
else
|
|
64
|
+
line = line.gsub(/[^[:print:]]/){|c| sprintf("\\x%x", c.ord)}
|
|
65
|
+
# :nocov:
|
|
66
|
+
end
|
|
67
|
+
line[-1] = "\n"
|
|
68
|
+
opts[:common_logger_meth].call(line)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Create timer instance used for timing
|
|
72
|
+
def _roda_before_05__common_logger
|
|
73
|
+
@_request_timer = CommonLogger.start_timer
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
register_plugin(:common_logger, CommonLogger)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
class Roda
|
|
4
|
+
module RodaPlugins
|
|
5
|
+
# The conditional_sessions plugin loads the sessions plugin. However,
|
|
6
|
+
# it only allows sessions if the block passed to the plugin returns
|
|
7
|
+
# truthy. The block is evaluated in request context. This is designed for
|
|
8
|
+
# use in applications that want to use sessions for some requests,
|
|
9
|
+
# and want to be sure that sessions are not used for other requests.
|
|
10
|
+
# For example, if you want to make sure that sessions are not used for
|
|
11
|
+
# requests with paths starting with /static, you could do:
|
|
12
|
+
#
|
|
13
|
+
# plugin :conditional_sessions, secret: ENV["SECRET"] do
|
|
14
|
+
# !path_info.start_with?('/static')
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# The the request session, session_created_at, and session_updated_at methods
|
|
18
|
+
# raise a RodaError exception when sessions are not allowed. The request
|
|
19
|
+
# persist_session and route scope clear_session methods do nothing when
|
|
20
|
+
# sessions are not allowed.
|
|
21
|
+
module ConditionalSessions
|
|
22
|
+
# Pass all options to the sessions block, and use the block to define
|
|
23
|
+
# a request method for whether sessions are allowed.
|
|
24
|
+
def self.load_dependencies(app, opts=OPTS, &block)
|
|
25
|
+
app.plugin :sessions, opts
|
|
26
|
+
app::RodaRequest.class_eval do
|
|
27
|
+
define_method(:use_sessions?, &block)
|
|
28
|
+
alias use_sessions? use_sessions?
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module InstanceMethods
|
|
33
|
+
# Do nothing if not using sessions.
|
|
34
|
+
def clear_session
|
|
35
|
+
super if @_request.use_sessions?
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
module RequestMethods
|
|
40
|
+
# Raise RodaError if not using sessions.
|
|
41
|
+
def session
|
|
42
|
+
raise RodaError, "session called on request not using sessions" unless use_sessions?
|
|
43
|
+
super
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Raise RodaError if not using sessions.
|
|
47
|
+
def session_created_at
|
|
48
|
+
raise RodaError, "session_created_at called on request not using sessions" unless use_sessions?
|
|
49
|
+
super
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Raise RodaError if not using sessions.
|
|
53
|
+
def session_updated_at
|
|
54
|
+
raise RodaError, "session_updated_at called on request not using sessions" unless use_sessions?
|
|
55
|
+
super
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Do nothing if not using sessions.
|
|
59
|
+
def persist_session(headers, session)
|
|
60
|
+
super if use_sessions?
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
register_plugin(:conditional_sessions, ConditionalSessions)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen-string-literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
class Roda
|
|
5
|
+
module RodaPlugins
|
|
6
|
+
# The content_for plugin is designed to be used with the
|
|
7
|
+
# render plugin, allowing you to store content inside one
|
|
8
|
+
# template, and retrieve that content inside a separate
|
|
9
|
+
# template. Most commonly, this is so view templates
|
|
10
|
+
# can set content for the layout template to display outside
|
|
11
|
+
# of the normal content pane.
|
|
12
|
+
#
|
|
13
|
+
# In the template in which you want to store content, call
|
|
14
|
+
# content_for with a block:
|
|
15
|
+
#
|
|
16
|
+
# <% content_for :foo do %>
|
|
17
|
+
# Some content here.
|
|
18
|
+
# <% end %>
|
|
19
|
+
#
|
|
20
|
+
# or:
|
|
21
|
+
#
|
|
22
|
+
# <% content_for :foo do "Some content here." end %>
|
|
23
|
+
#
|
|
24
|
+
# You can also set the raw content as the second argument,
|
|
25
|
+
# instead of passing a block:
|
|
26
|
+
#
|
|
27
|
+
# <% content_for :foo, "Some content" %>
|
|
28
|
+
#
|
|
29
|
+
# In the template in which you want to retrieve content,
|
|
30
|
+
# call content_for without the block or argument:
|
|
31
|
+
#
|
|
32
|
+
# <%= content_for :foo %>
|
|
33
|
+
#
|
|
34
|
+
# Note that when storing content by calling content_for
|
|
35
|
+
# with a block and embedding template code, the return
|
|
36
|
+
# value of the block is used as the content (after being
|
|
37
|
+
# converted to a string). This can cause issues in some
|
|
38
|
+
# cases, such as:
|
|
39
|
+
#
|
|
40
|
+
# <% content_for :foo do %>
|
|
41
|
+
# <% [1,2,3].each do |i| %>
|
|
42
|
+
# Content <%= i %>
|
|
43
|
+
# <% end %>
|
|
44
|
+
# <% end %>
|
|
45
|
+
#
|
|
46
|
+
# In the above example, the return value of the block is
|
|
47
|
+
# <tt>[1,2,3]</tt>, as Array#each returns the receiver.
|
|
48
|
+
# If whitespace is not important, you can work around this by
|
|
49
|
+
# adding an empty line before the end of the content_for block.
|
|
50
|
+
#
|
|
51
|
+
# If content_for is used multiple times with the same key,
|
|
52
|
+
# by default, the last call will append previous calls.
|
|
53
|
+
# If you want to overwrite the previous content, pass the
|
|
54
|
+
# <tt>append: false</tt> option when loading the plugin:
|
|
55
|
+
#
|
|
56
|
+
# plugin :content_for, append: false
|
|
57
|
+
module ContentFor
|
|
58
|
+
# Depend on the capture_erb plugin, since it uses capture_erb
|
|
59
|
+
# to capture the content.
|
|
60
|
+
def self.load_dependencies(app, _opts = OPTS)
|
|
61
|
+
app.plugin :capture_erb
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Configure whether to append or overwrite if content_for
|
|
65
|
+
# is called multiple times with the same key.
|
|
66
|
+
def self.configure(app, opts = OPTS)
|
|
67
|
+
app.opts[:append_content_for] = opts.fetch(:append, true)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
module InstanceMethods
|
|
71
|
+
# If called with a block, store content enclosed by block
|
|
72
|
+
# under the given key. If called without a block, retrieve
|
|
73
|
+
# stored content with the given key, or return nil if there
|
|
74
|
+
# is no content stored with that key.
|
|
75
|
+
def content_for(key, value=nil, &block)
|
|
76
|
+
append = opts[:append_content_for]
|
|
77
|
+
|
|
78
|
+
if block || value
|
|
79
|
+
if block
|
|
80
|
+
value = capture_erb(&block)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
@_content_for ||= {}
|
|
84
|
+
|
|
85
|
+
if append
|
|
86
|
+
(@_content_for[key] ||= []) << value
|
|
87
|
+
else
|
|
88
|
+
@_content_for[key] = value
|
|
89
|
+
end
|
|
90
|
+
elsif @_content_for && (value = @_content_for[key])
|
|
91
|
+
if append
|
|
92
|
+
value = value.join
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
value
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
register_plugin(:content_for, ContentFor)
|
|
102
|
+
end
|
|
103
|
+
end
|