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