ultra-max-sys 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ultra-max-sys might be problematic. Click here for more details.

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