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,285 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'stringio'
4
+ require 'mail'
5
+
6
+ class Roda
7
+ module RodaPlugins
8
+ # The mailer plugin allows your Roda application to send emails easily.
9
+ #
10
+ # class Mailer < Roda
11
+ # plugin :render
12
+ # plugin :mailer
13
+ #
14
+ # route do |r|
15
+ # r.on "albums", Integer do |album_id|
16
+ # @album = Album[album_id]
17
+ #
18
+ # r.mail "added" do
19
+ # from 'from@example.com'
20
+ # to 'to@example.com'
21
+ # cc 'cc@example.com'
22
+ # bcc 'bcc@example.com'
23
+ # subject 'Album Added'
24
+ # add_file "path/to/album_added_img.jpg"
25
+ # render(:albums_added_email) # body
26
+ # end
27
+ # end
28
+ # end
29
+ # end
30
+ #
31
+ # The default method for sending a mail is +sendmail+:
32
+ #
33
+ # Mailer.sendmail("/albums/1/added")
34
+ #
35
+ # If you want to return the <tt>Mail::Message</tt> instance for further modification,
36
+ # you can just use the +mail+ method:
37
+ #
38
+ # mail = Mailer.mail("/albums/1/added")
39
+ # mail.from 'from2@example.com'
40
+ # mail.deliver
41
+ #
42
+ # The mailer plugin uses the mail gem, so if you want to configure how
43
+ # email is sent, you can use <tt>Mail.defaults</tt> (see the mail gem documentation for
44
+ # more details):
45
+ #
46
+ # Mail.defaults do
47
+ # delivery_method :smtp, address: 'smtp.example.com', port: 587
48
+ # end
49
+ #
50
+ # You can support multipart emails using +text_part+ and +html_part+:
51
+ #
52
+ # r.mail "added" do
53
+ # from 'from@example.com'
54
+ # to 'to@example.com'
55
+ # subject 'Album Added'
56
+ # text_part render('album_added.txt') # views/album_added.txt.erb
57
+ # html_part render('album_added.html') # views/album_added.html.erb
58
+ # end
59
+ #
60
+ # In addition to allowing you to use Roda's render plugin for rendering
61
+ # email bodies, you can use all of Roda's usual routing tree features
62
+ # to DRY up your code:
63
+ #
64
+ # r.on "albums", Integer do |album_id|
65
+ # @album = Album[album_id]
66
+ # from 'from@example.com'
67
+ # to 'to@example.com'
68
+ #
69
+ # r.mail "added" do
70
+ # subject 'Album Added'
71
+ # render(:albums_added_email)
72
+ # end
73
+ #
74
+ # r.mail "deleted" do
75
+ # subject 'Album Deleted'
76
+ # render(:albums_deleted_email)
77
+ # end
78
+ # end
79
+ #
80
+ # When sending a mail via +mail+ or +sendmail+, a RodaError will be raised
81
+ # if the mail object does not have a body. This is similar to the 404
82
+ # status that Roda uses by default for web requests that don't have
83
+ # a body. If you want to specifically send an email with an empty body, you
84
+ # can use the explicit empty string:
85
+ #
86
+ # r.mail do
87
+ # from 'from@example.com'
88
+ # to 'to@example.com'
89
+ # subject 'No Body Here'
90
+ # ""
91
+ # end
92
+ #
93
+ # If while preparing the email you figure out you don't want to send an
94
+ # email, call +no_mail!+:
95
+ #
96
+ # r.mail 'welcome', Integer do |id|
97
+ # no_mail! unless user = User[id]
98
+ # # ...
99
+ # end
100
+ #
101
+ # You can pass arguments when calling +mail+ or +sendmail+, and they
102
+ # will be yielded as additional arguments to the appropriate +r.mail+ block:
103
+ #
104
+ # Mailer.sendmail('/welcome/1', 'foo@example.com')
105
+ #
106
+ # r.mail 'welcome', Integer do |user_id, mail_from|
107
+ # from mail_from
108
+ # to User[user_id].email
109
+ # # ...
110
+ # end
111
+ #
112
+ # By default, the mailer uses text/plain as the Content-Type for emails.
113
+ # You can override the default by specifying a :content_type option when
114
+ # loading the plugin:
115
+ #
116
+ # plugin :mailer, content_type: 'text/html'
117
+ #
118
+ # For backwards compatibility reasons, the +r.mail+ method does not do
119
+ # a terminal match by default if provided arguments (unlike +r.get+ and
120
+ # +r.post+). You can pass the :terminal option to make +r.mail+ enforce
121
+ # a terminal match if provided arguments.
122
+ #
123
+ # The mailer plugin does support being used inside a Roda application
124
+ # that is handling web requests, where the routing block for mails and
125
+ # web requests is shared. However, it's recommended that you create a
126
+ # separate Roda application for emails. This can be a subclass of your main
127
+ # Roda application if you want your helper methods to automatically be
128
+ # available in your email views.
129
+ module Mailer
130
+ RESPONSE_INSTANCE_VARIABLES = [:@mail, :@mail_attachments].freeze
131
+
132
+ # Error raised when the using the mail class method, but the routing
133
+ # tree doesn't return the mail object.
134
+ class Error < ::Roda::RodaError; end
135
+
136
+ # Set the options for the mailer. Options:
137
+ # :content_type :: The default content type for emails (default: text/plain)
138
+ def self.configure(app, opts=OPTS)
139
+ app.opts[:mailer] = (app.opts[:mailer]||OPTS).merge(opts).freeze
140
+ end
141
+
142
+ module ClassMethods
143
+ # Return a Mail::Message instance for the email for the given request path
144
+ # and arguments. Any arguments given are yielded to the appropriate +r.mail+
145
+ # block after any usual match block arguments. You can further manipulate the
146
+ #returned mail object before calling +deliver+ to send the mail.
147
+ def mail(path, *args)
148
+ mail = ::Mail.new
149
+ catch(:no_mail) do
150
+ unless mail.equal?(new("PATH_INFO"=>path, 'SCRIPT_NAME'=>'', "REQUEST_METHOD"=>"MAIL", 'rack.input'=>StringIO.new, 'roda.mail'=>mail, 'roda.mail_args'=>args)._roda_handle_main_route)
151
+ raise Error, "route did not return mail instance for #{path.inspect}, #{args.inspect}"
152
+ end
153
+ mail
154
+ end
155
+ end
156
+ # :nocov:
157
+ ruby2_keywords(:mail) if respond_to?(:ruby2_keywords, true)
158
+ # :nocov:
159
+
160
+ # Calls +mail+ with given arguments and immediately sends the resulting mail.
161
+ def sendmail(*args)
162
+ if m = mail(*args)
163
+ m.deliver
164
+ end
165
+ end
166
+ # :nocov:
167
+ ruby2_keywords(:sendmail) if respond_to?(:ruby2_keywords, true)
168
+ # :nocov:
169
+ end
170
+
171
+ module RequestMethods
172
+ # Similar to routing tree methods such as +get+ and +post+, this matches
173
+ # only if the request method is MAIL (only set when using the Roda class
174
+ # +mail+ or +sendmail+ methods) and the rest of the arguments match
175
+ # the request. This yields any of the captures to the block, as well as
176
+ # any arguments passed to the +mail+ or +sendmail+ Roda class methods.
177
+ def mail(*args)
178
+ if @env["REQUEST_METHOD"] == "MAIL"
179
+ # RODA4: Make terminal match the default
180
+ send(roda_class.opts[:mailer][:terminal] ? :_verb : :if_match, args) do |*vs|
181
+ yield(*(vs + @env['roda.mail_args']))
182
+ end
183
+ end
184
+ end
185
+ end
186
+
187
+ module ResponseMethods
188
+ # The mail object related to the current request.
189
+ attr_accessor :mail
190
+
191
+ # If the related request was an email request, add any response headers
192
+ # to the email, as well as adding the response body to the email.
193
+ # Return the email unless no body was set for it, which would indicate
194
+ # that the routing tree did not handle the request.
195
+ def finish
196
+ if m = mail
197
+ header_content_type = @headers.delete(RodaResponseHeaders::CONTENT_TYPE)
198
+ m.headers(@headers)
199
+ m.body(@body.join) unless @body.empty?
200
+ mail_attachments.each do |a, block|
201
+ m.add_file(*a)
202
+ block.call if block
203
+ end
204
+
205
+ if content_type = header_content_type || roda_class.opts[:mailer][:content_type]
206
+ if mail.multipart?
207
+ if /multipart\/mixed/ =~ mail.content_type &&
208
+ mail.parts.length >= 2 &&
209
+ (part = mail.parts.find{|p| !p.attachment && (p.encoded; /text\/plain/ =~ p.content_type)})
210
+ part.content_type = content_type
211
+ end
212
+ else
213
+ mail.content_type = content_type
214
+ end
215
+ end
216
+
217
+ unless m.body.to_s.empty? && m.parts.empty? && @body.empty?
218
+ m
219
+ end
220
+ else
221
+ super
222
+ end
223
+ end
224
+
225
+ # The attachments related to the current mail.
226
+ def mail_attachments
227
+ @mail_attachments ||= []
228
+ end
229
+ end
230
+
231
+ module InstanceMethods
232
+ # Add delegates for common email methods.
233
+ [:from, :to, :cc, :bcc, :subject].each do |meth|
234
+ define_method(meth) do |*args|
235
+ env['roda.mail'].public_send(meth, *args)
236
+ nil
237
+ end
238
+ end
239
+ [:text_part, :html_part].each do |meth|
240
+ define_method(meth) do |*args|
241
+ _mail_part(meth, *args)
242
+ end
243
+ end
244
+
245
+ # If this is an email request, set the mail object in the response, as well
246
+ # as the default content_type for the email.
247
+ def initialize(env)
248
+ super
249
+ if mail = env['roda.mail']
250
+ res = @_response
251
+ res.mail = mail
252
+ res.headers.delete(RodaResponseHeaders::CONTENT_TYPE)
253
+ end
254
+ end
255
+
256
+ # Delay adding a file to the message until after the message body has been set.
257
+ # If a block is given, the block is called after the file has been added, and you
258
+ # can access the attachment via <tt>response.mail_attachments.last</tt>.
259
+ def add_file(*a, &block)
260
+ response.mail_attachments << [a, block]
261
+ nil
262
+ end
263
+
264
+ # Signal that no mail should be sent for this request.
265
+ def no_mail!
266
+ throw :no_mail
267
+ end
268
+
269
+ private
270
+
271
+ # Set the text_part or html_part (depending on the method) in the related email,
272
+ # using the given body and optional headers.
273
+ def _mail_part(meth, body, headers=nil)
274
+ env['roda.mail'].public_send(meth) do
275
+ body(body)
276
+ headers(headers) if headers
277
+ end
278
+ nil
279
+ end
280
+ end
281
+ end
282
+
283
+ register_plugin(:mailer, Mailer)
284
+ end
285
+ end
@@ -0,0 +1,48 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The map_matcher plugin allows you to provide a string-keyed
7
+ # hash during route matching, and match any of the keys in the hash
8
+ # as the next segment in the request path, yielding the corresponding
9
+ # value in the hash:
10
+ #
11
+ # class App < Roda
12
+ # plugin :map_matcher
13
+ #
14
+ # map = { "foo" => "bar", "baz" => "quux" }.freeze
15
+ #
16
+ # route do
17
+ # r.get map: map do |v|
18
+ # v
19
+ # # GET /foo => bar
20
+ # # GET /baz => quux
21
+ # end
22
+ # end
23
+ # end
24
+ module MapMatcher
25
+ module RequestMethods
26
+ private
27
+
28
+ # Match only if the next segment in the path is one of the keys
29
+ # in the hash, and yield the value of the hash.
30
+ def match_map(hash)
31
+ rp = @remaining_path
32
+ if key = _match_class_String
33
+ if value = hash[@captures[-1]]
34
+ @captures[-1] = value
35
+ true
36
+ else
37
+ @remaining_path = rp
38
+ @captures.pop
39
+ false
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ register_plugin(:map_matcher, MapMatcher)
47
+ end
48
+ end
@@ -0,0 +1,64 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The match_affix plugin allows changing the default prefix and suffix used for
7
+ # match patterns. Roda's default behavior for a match pattern like <tt>"albums"</tt>
8
+ # is to use the pattern <tt>/\A\/(?:albums)(?=\/|\z)/</tt>. This prefixes the pattern
9
+ # with +/+ and suffixes it with <tt>(?=\/|\z)</tt>. With the match_affix plugin, you
10
+ # can change the prefix and suffix to use. So if you want to be explicit and require
11
+ # a leading +/+ in patterns, you can set the prefix to <tt>""</tt>. If you want to
12
+ # consume a trailing slash instead of leaving it, you can set the suffix to <tt>(\/|\z)</tt>.
13
+ #
14
+ # You set the prefix and suffix to use by passing arguments when loading the plugin:
15
+ #
16
+ # plugin :match_affix, ""
17
+ #
18
+ # will load the plugin and use an empty prefix (instead of a slash).
19
+ #
20
+ # plugin :match_affix, "", /(\/|\z)/
21
+ #
22
+ # will use an empty prefix and change the suffix to consume a trailing slash.
23
+ #
24
+ # plugin :match_affix, nil, /(?:\/\z|(?=\/|\z))/
25
+ #
26
+ # will not modify the prefix and will change the suffix so that it consumes a trailing slash
27
+ # at the end of the path only.
28
+ #
29
+ # This plugin automatically loads the placeholder_string_matchers plugin.
30
+ module MatchAffix
31
+ def self.load_dependencies(app, _prefix, _suffix=nil)
32
+ app.plugin :placeholder_string_matchers
33
+ end
34
+
35
+ # Set the default prefix and suffix to use in match patterns, if a non-nil value
36
+ # is given.
37
+ def self.configure(app, prefix, suffix=nil)
38
+ app.opts[:match_prefix] = prefix if prefix
39
+ app.opts[:match_suffix] = suffix if suffix
40
+ end
41
+
42
+ module RequestClassMethods
43
+ private
44
+
45
+ # Use the match prefix and suffix provided when loading the plugin, or fallback
46
+ # to Roda's default prefix/suffix if one was not provided.
47
+ def consume_pattern(pattern)
48
+ /\A#{roda_class.opts[:match_prefix] || "/"}(?:#{pattern})#{roda_class.opts[:match_suffix] || "(?=\/|\z)"}/
49
+ end
50
+ end
51
+
52
+ module RequestMethods
53
+ private
54
+
55
+ # Use regexps for all string matches, so that the prefix and suffix matches work.
56
+ def _match_string(str)
57
+ consume(self.class.cached_matcher(str){Regexp.escape(str).gsub(/:(\w+)/){|m| _match_symbol_regexp($1)}})
58
+ end
59
+ end
60
+ end
61
+
62
+ register_plugin(:match_affix, MatchAffix)
63
+ end
64
+ end
@@ -0,0 +1,34 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The match_hook plugin adds hooks that are called upon a successful match
7
+ # by any of the matchers. The hooks do not take any arguments. If you would
8
+ # like hooks that pass the arguments/matchers and values yielded to the route block,
9
+ # use the match_hook_args plugin. This uses the match_hook_args plugin internally,
10
+ # but doesn't pass the matchers and values yielded.
11
+ #
12
+ # plugin :match_hook
13
+ #
14
+ # match_hook do
15
+ # logger.debug("#{request.matched_path} matched. #{request.remaining_path} remaining.")
16
+ # end
17
+ module MatchHook
18
+ def self.load_dependencies(app)
19
+ app.plugin :match_hook_args
20
+ end
21
+
22
+ module ClassMethods
23
+ # Add a match hook.
24
+ def match_hook(&block)
25
+ meth = define_roda_method("match_hook", 0, &block)
26
+ add_match_hook{|_,_| send(meth)}
27
+ nil
28
+ end
29
+ end
30
+ end
31
+
32
+ register_plugin :match_hook, MatchHook
33
+ end
34
+ end
@@ -0,0 +1,93 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The match_hook_args plugin adds hooks that are called upon a successful match
7
+ # by any of the matchers. It is similar to the match_hook plugin, but it allows
8
+ # for passing the matchers and block arguments for each match method.
9
+ #
10
+ # plugin :match_hook_args
11
+ #
12
+ # add_match_hook do |matchers, block_args|
13
+ # logger.debug("matchers: #{matchers.inspect}. #{block_args.inspect} yielded.")
14
+ # end
15
+ #
16
+ # # Term is an implicit matcher used for terminating matches, and
17
+ # # will be included in the array of matchers yielded to the match hook
18
+ # # if a terminating match is used.
19
+ # term = self.class::RodaRequest::TERM
20
+ #
21
+ # route do |r|
22
+ # r.root do
23
+ # # for a request for /
24
+ # # matchers: nil, block_args: nil
25
+ # end
26
+ #
27
+ # r.on 'a', ['b', 'c'], Integer do |segment, id|
28
+ # # for a request for /a/b/1
29
+ # # matchers: ["a", ["b", "c"], Integer], block_args: ["b", 1]
30
+ # end
31
+ #
32
+ # r.get 'd' do
33
+ # # for a request for /d
34
+ # # matchers: ["d", term], block_args: []
35
+ # end
36
+ # end
37
+ module MatchHookArgs
38
+ def self.configure(app)
39
+ app.opts[:match_hook_args] ||= []
40
+ end
41
+
42
+ module ClassMethods
43
+ # Freeze the array of hook methods when freezing the app
44
+ def freeze
45
+ opts[:match_hook_args].freeze
46
+ super
47
+ end
48
+
49
+ # Add a match hook that will be called with matchers and block args.
50
+ def add_match_hook(&block)
51
+ opts[:match_hook_args] << define_roda_method("match_hook_args", :any, &block)
52
+
53
+ if opts[:match_hook_args].length == 1
54
+ class_eval("alias _match_hook_args #{opts[:match_hook_args].first}", __FILE__, __LINE__)
55
+ else
56
+ class_eval("def _match_hook_args(v, a); #{opts[:match_hook_args].map{|m| "#{m}(v, a)"}.join(';')} end", __FILE__, __LINE__)
57
+ end
58
+
59
+ public :_match_hook_args
60
+
61
+ nil
62
+ end
63
+ end
64
+
65
+ module InstanceMethods
66
+ # Default empty method if no match hooks are defined.
67
+ def _match_hook_args(matchers, block_args)
68
+ end
69
+ end
70
+
71
+ module RequestMethods
72
+ private
73
+
74
+ # Call the match hook with matchers and block args if yielding to the block before yielding to the block.
75
+ def if_match(v)
76
+ super do |*a|
77
+ scope._match_hook_args(v, a)
78
+ yield(*a)
79
+ end
80
+ end
81
+
82
+ # Call the match hook with nil matchers and blocks before yielding to the block
83
+ def always
84
+ scope._match_hook_args(nil, nil)
85
+ super
86
+ end
87
+ end
88
+ end
89
+
90
+ register_plugin :match_hook_args, MatchHookArgs
91
+ end
92
+ end
93
+