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,998 @@
1
+ # frozen-string-literal: true
2
+
3
+ require "tilt"
4
+
5
+ class Roda
6
+ module RodaPlugins
7
+ # The render plugin adds support for template rendering using the tilt
8
+ # library. Two methods are provided for template rendering, +view+
9
+ # (which uses the layout) and +render+ (which does not).
10
+ #
11
+ # plugin :render
12
+ #
13
+ # route do |r|
14
+ # r.is 'foo' do
15
+ # view('foo') # renders views/foo.erb inside views/layout.erb
16
+ # end
17
+ #
18
+ # r.is 'bar' do
19
+ # render('bar') # renders views/bar.erb
20
+ # end
21
+ # end
22
+ #
23
+ # The +render+ and +view+ methods just return strings, they do not have
24
+ # side effects (unless the templates themselves have side effects).
25
+ # As Roda uses the routing block return value as the body of the response,
26
+ # in most cases you will call these methods as the last expression in a
27
+ # routing block to have the response body be the result of the template
28
+ # rendering.
29
+ #
30
+ # Because +render+ and +view+ just return strings, you can call them inside
31
+ # templates (i.e. for subtemplates/partials), or multiple times in the
32
+ # same route and combine the results together:
33
+ #
34
+ # route do |r|
35
+ # r.is 'foo-bars' do
36
+ # @bars = Bar.where(:foo).map{|b| render(:bar, locals: {bar: b})}.join
37
+ # view('foo')
38
+ # end
39
+ # end
40
+ #
41
+ # You can provide options to the plugin method:
42
+ #
43
+ # plugin :render, engine: 'haml', views: 'admin_views'
44
+ #
45
+ # = Plugin Options
46
+ #
47
+ # The following plugin options are supported:
48
+ #
49
+ # :allowed_paths :: Set the template paths to allow. Attempts to render paths outside
50
+ # of these paths will raise an error. Defaults to the +:views+ directory.
51
+ # :assume_fixed_locals :: Set if you are sure all templates in your application use fixed locals
52
+ # to allow for additional optimization. This is ignored unless both
53
+ # compiled methods and fixed locals are not supported.
54
+ # :cache :: nil/false to explicitly disable permanent template caching. By default, permanent
55
+ # template caching is disabled by default if RACK_ENV is development. When permanent
56
+ # template caching is disabled, for templates with paths in the file system, the
57
+ # modification time of the file will be checked on every render, and if it has changed,
58
+ # a new template will be created for the current content of the file.
59
+ # :cache_class :: A class to use as the template cache instead of the default.
60
+ # :check_paths :: Can be set to false to turn off template path checking.
61
+ # :engine :: The tilt engine to use for rendering, also the default file extension for
62
+ # templates, defaults to 'erb'.
63
+ # :escape :: Use Erubi as the ERB template engine, and enable escaping by default,
64
+ # which makes <tt><%= %></tt> escape output and <tt><%== %></tt> not escape output.
65
+ # If given, sets the <tt>escape: true</tt> option for all template engines, which
66
+ # can break some non-ERB template engines. You can use a string or array of strings
67
+ # as the value for this option to only set the <tt>escape: true</tt> option for those
68
+ # specific template engines.
69
+ # :layout :: The base name of the layout file, defaults to 'layout'. This can be provided as a hash
70
+ # with the :template or :inline options.
71
+ # :layout_opts :: The options to use when rendering the layout, if different from the default options.
72
+ # :template_opts :: The tilt options used when rendering all templates. defaults to:
73
+ # <tt>{outvar: '@_out_buf', default_encoding: Encoding.default_external}</tt>.
74
+ # :engine_opts :: The tilt options to use per template engine. Keys are
75
+ # engine strings, values are hashes of template options.
76
+ # :views :: The directory holding the view files, defaults to the 'views' subdirectory of the
77
+ # application's :root option (the process's working directory by default).
78
+ #
79
+ # = Render/View Method Options
80
+ #
81
+ # Most of these options can be overridden at runtime by passing options
82
+ # to the +view+ or +render+ methods:
83
+ #
84
+ # view('foo', engine: 'html.erb')
85
+ # render('foo', views: 'admin_views')
86
+ #
87
+ # There are additional options to +view+ and +render+ that are
88
+ # available at runtime:
89
+ #
90
+ # :cache :: Set to false to not cache this template, even when
91
+ # caching is on by default. Set to true to force caching for
92
+ # this template, even when the default is to not permantently cache (e.g.
93
+ # when using the :template_block option).
94
+ # :cache_key :: Explicitly set the hash key to use when caching.
95
+ # :content :: Only respected by +view+, provides the content to render
96
+ # inside the layout, instead of rendering a template to get
97
+ # the content.
98
+ # :inline :: Use the value given as the template code, instead of looking
99
+ # for template code in a file.
100
+ # :locals :: Hash of local variables to make available inside the template.
101
+ # :path :: Use the value given as the full pathname for the file, instead
102
+ # of using the :views and :engine option in combination with the
103
+ # template name.
104
+ # :scope :: The object in which context to evaluate the template. By
105
+ # default, this is the Roda instance.
106
+ # :template :: Provides the name of the template to use. This allows you
107
+ # pass a single options hash to the render/view method, while
108
+ # still allowing you to specify the template name.
109
+ # :template_block :: Pass this block when creating the underlying template,
110
+ # ignored when using :inline. Disables caching of the
111
+ # template by default.
112
+ # :template_class :: Provides the template class to use, instead of using
113
+ # Tilt or <tt>Tilt[:engine]</tt>.
114
+ #
115
+ # Here's an example of using these options:
116
+ #
117
+ # view(inline: '<%= @foo %>')
118
+ # render(path: '/path/to/template.erb')
119
+ #
120
+ # If you pass a hash as the first argument to +view+ or +render+, it should
121
+ # have either +:template+, +:inline+, +:path+, or +:content+ (for +view+) as
122
+ # one of the keys.
123
+ #
124
+ # = Fixed Locals in Templates
125
+ #
126
+ # By default, you can pass any local variables to any templates. A separate
127
+ # template method is compiled for each combination of locals. This causes
128
+ # multiple issues:
129
+ #
130
+ # * It is inefficient, especially for large templates that are called with
131
+ # many combinations of locals.
132
+ # * It hides issues if unused local variable names are passed to the template
133
+ # * It does not support default values for local variables
134
+ # * It does not support required local variables
135
+ # * It does not support cases where you want to pass values via a keyword splat
136
+ # * It does not support named blocks
137
+ #
138
+ # If you are using Tilt 2.6+, you can used fixed locals in templates, by
139
+ # passing the appropriate options in :template_opts. For example, if you
140
+ # are using ERB templates, the recommended way to use the render plugin is to
141
+ # use the +:extract_fixed_locals+ and +:default_fixed_locals+ template options:
142
+ #
143
+ # plugin :render, template_opts: {extract_fixed_locals: true, default_fixed_locals: '()'}
144
+ #
145
+ # This will default templates to not allowing any local variables to be passed.
146
+ # If the template requires local variables, you can specify them using a magic
147
+ # comment in the template, such as:
148
+ #
149
+ # <%# locals(required_local:, optional_local: nil) %>
150
+ #
151
+ # The magic comment is used as method parameters when defining the compiled template
152
+ # method.
153
+ #
154
+ # For better debugging of issues with invalid keywords being passed to templates that
155
+ # have not been updated to support fixed locals, it can be helpful to set
156
+ # +:default_fixed_locals+ to use a single optional keyword argument
157
+ # <tt>'(_no_kw: nil)'</tt>. This makes the error message show which keywords
158
+ # were passed, instead of showing that the takes no arguments (if you use <tt>'()'</tt>),
159
+ # or that no keywords are accepted (if you pass <tt>(**nil)</tt>).
160
+ #
161
+ # If you are sure your application works with all templates using fixed locals,
162
+ # set the :assume_fixed_locals render plugin option, which will allow the plugin
163
+ # to optimize cache lookup for renders with locals, and avoid duplicate compiled
164
+ # methods for templates rendered both with and without locals.
165
+ #
166
+ # See Tilt's documentation for more information regarding fixed locals.
167
+ #
168
+ # = Speeding Up Template Rendering
169
+ #
170
+ # The render/view method calls are optimized for usage with a single symbol/string
171
+ # argument specifying the template name. So for fastest rendering, pass only a
172
+ # symbol/string to render/view. Next best optimized are template calls with a
173
+ # single :locals option. Use of other options disables the compiled template
174
+ # method optimizations and can be significantly slower.
175
+ #
176
+ # If you must pass a hash to render/view, either as a second argument or as the
177
+ # only argument, you can speed things up by specifying a +:cache_key+ option in
178
+ # the hash, making sure the +:cache_key+ is unique to the template you are
179
+ # rendering.
180
+ #
181
+ # = Recommended +template_opts+
182
+ #
183
+ # Here are the recommended values of :template_opts for new applications (a couple
184
+ # are Erubi-specific and can be ignored if you are using other templates engines):
185
+ #
186
+ # plugin :render,
187
+ # assume_fixed_locals: true, # Optimize plugin by assuming all templates use fixed locals
188
+ # template_opts: {
189
+ # scope_class: self, # Always uses current class as scope class for compiled templates
190
+ # freeze: true, # Freeze string literals in templates
191
+ # extract_fixed_locals: true, # Support fixed locals in templates
192
+ # default_fixed_locals: '()', # Default to templates not supporting local variables
193
+ # escape: true, # For Erubi templates, escapes <%= by default (use <%== for unescaped
194
+ # chain_appends: true, # For Erubi templates, improves performance
195
+ # skip_compiled_encoding_detection: true, # Unless you need encodings explicitly specified
196
+ # }
197
+ #
198
+ # = Accepting Template Blocks in Methods
199
+ #
200
+ # If you are used to Rails, you may be surprised that this type of template code
201
+ # doesn't work in Roda:
202
+ #
203
+ # <%= some_method do %>
204
+ # Some HTML
205
+ # <% end %>
206
+ #
207
+ # The reason this doesn't work is that this is not valid ERB syntax, it is Rails syntax,
208
+ # and requires attempting to parse the <tt>some_method do</tt> Ruby code with a regular
209
+ # expression. Since Roda uses ERB syntax, it does not support this.
210
+ #
211
+ # In general, these methods are used to wrap the content of the block and
212
+ # inject the content into the output. To get similar behavior with Roda, you have
213
+ # a few different options you can use.
214
+ #
215
+ # == Use Erubi::CaptureBlockEngine
216
+ #
217
+ # Roda defaults to using Erubi for erb template rendering. Erubi 1.13.0+ includes
218
+ # support for an erb variant that supports blocks in <tt><%=</tt> and <tt><%==</tt>
219
+ # tags. To use it:
220
+ #
221
+ # require 'erubi/capture_block'
222
+ # plugin :render, template_opts: {engine_class: Erubi::CaptureBlockEngine}
223
+ #
224
+ # See the Erubi documentation for how to capture data inside the block. Make sure
225
+ # the method call (+some_method+ in the example) returns the output you want added
226
+ # to the rendered body.
227
+ #
228
+ # == Directly Inject Template Output
229
+ #
230
+ # You can switch from a <tt><%=</tt> tag to using a <tt><%</tt> tag:
231
+ #
232
+ # <% some_method do %>
233
+ # Some HTML
234
+ # <% end %>
235
+ #
236
+ # While this would output <tt>Some HTML</tt> into the template, it would not be able
237
+ # to inject content before or after the block. However, you can use the inject_erb_plugin
238
+ # to handle the injection:
239
+ #
240
+ # def some_method
241
+ # inject_erb "content before block"
242
+ # yield
243
+ # inject_erb "content after block"
244
+ # end
245
+ #
246
+ # If you need to modify the captured block before injecting it, you can use the
247
+ # capture_erb plugin to capture content from the template block, and modify that content,
248
+ # then use inject_erb to inject it into the template output:
249
+ #
250
+ # def some_method(&block)
251
+ # inject_erb "content before block"
252
+ # inject_erb capture_erb(&block).upcase
253
+ # inject_erb "content after block"
254
+ # end
255
+ #
256
+ # This is the recommended approach for handling this type of method, if you want to keep
257
+ # the template block in the same template.
258
+ #
259
+ # == Separate Block Output Into Separate Template
260
+ #
261
+ # By moving the <tt>Some HTML</tt> into a separate template, you can render that
262
+ # template inside the block:
263
+ #
264
+ # <%= some_method{render('template_name')} %>
265
+ #
266
+ # It's also possible to use an inline template:
267
+ #
268
+ # <%= some_method do render(:inline=><<-END)
269
+ # Some HTML
270
+ # END
271
+ # end %>
272
+ #
273
+ # This approach is useful if it makes sense to separate the template block into its
274
+ # own template. You lose the ability to use local variable from outside the
275
+ # template block inside the template block with this approach.
276
+ #
277
+ # == Separate Header and Footer
278
+ #
279
+ # You can define two separate methods, one that outputs the content before the block,
280
+ # and one that outputs the content after the block, and use those instead of a single
281
+ # call:
282
+ #
283
+ # <%= some_method_before %>
284
+ # Some HTML
285
+ # <%= some_method_after %>
286
+ #
287
+ # This is the simplest option to setup, but it is fairly tedious to use.
288
+ module Render
289
+ # Support for using compiled methods directly requires Ruby 2.3 for the
290
+ # method binding to work, and Tilt 1.2 for Tilt::Template#compiled_method.
291
+ tilt_compiled_method_support = defined?(Tilt::VERSION) && Tilt::VERSION >= '1.2' &&
292
+ ([1, -2].include?(((compiled_method_arity = Tilt::Template.instance_method(:compiled_method).arity) rescue false)))
293
+ NO_CACHE = {:cache=>false}.freeze
294
+ COMPILED_METHOD_SUPPORT = RUBY_VERSION >= '2.3' && tilt_compiled_method_support && ENV['RODA_RENDER_COMPILED_METHOD_SUPPORT'] != 'no'
295
+ FIXED_LOCALS_COMPILED_METHOD_SUPPORT = COMPILED_METHOD_SUPPORT && Tilt::Template.method_defined?(:fixed_locals?)
296
+
297
+ if FIXED_LOCALS_COMPILED_METHOD_SUPPORT
298
+ def self.tilt_template_fixed_locals?(template)
299
+ template.fixed_locals?
300
+ end
301
+ # :nocov:
302
+ else
303
+ def self.tilt_template_fixed_locals?(template)
304
+ false
305
+ end
306
+ end
307
+ # :nocov:
308
+
309
+ if compiled_method_arity == -2
310
+ def self.tilt_template_compiled_method(template, locals_keys, scope_class)
311
+ template.send(:compiled_method, locals_keys, scope_class)
312
+ end
313
+ # :nocov:
314
+ else
315
+ def self.tilt_template_compiled_method(template, locals_keys, scope_class)
316
+ template.send(:compiled_method, locals_keys)
317
+ end
318
+ # :nocov:
319
+ end
320
+
321
+ # Setup default rendering options. See Render for details.
322
+ def self.configure(app, opts=OPTS)
323
+ if app.opts[:render]
324
+ orig_cache = app.opts[:render][:cache]
325
+ orig_method_cache = app.opts[:render][:template_method_cache]
326
+ opts = app.opts[:render][:orig_opts].merge(opts)
327
+ end
328
+ app.opts[:render] = opts.dup
329
+ app.opts[:render][:orig_opts] = opts
330
+
331
+ opts = app.opts[:render]
332
+ opts[:engine] = (opts[:engine] || "erb").dup.freeze
333
+ opts[:views] = app.expand_path(opts[:views]||"views").freeze
334
+ opts[:allowed_paths] ||= [opts[:views]].freeze
335
+ opts[:allowed_paths] = opts[:allowed_paths].map{|f| app.expand_path(f, nil)}.uniq.freeze
336
+ opts[:check_paths] = true unless opts.has_key?(:check_paths)
337
+ opts[:assume_fixed_locals] &&= FIXED_LOCALS_COMPILED_METHOD_SUPPORT
338
+
339
+ unless opts.has_key?(:check_template_mtime)
340
+ opts[:check_template_mtime] = if opts[:cache] == false || opts[:explicit_cache]
341
+ true
342
+ else
343
+ ENV['RACK_ENV'] == 'development'
344
+ end
345
+ end
346
+
347
+ begin
348
+ app.const_get(:RodaCompiledTemplates, false)
349
+ rescue NameError
350
+ compiled_templates_module = Module.new
351
+ app.send(:include, compiled_templates_module)
352
+ app.const_set(:RodaCompiledTemplates, compiled_templates_module)
353
+ end
354
+ opts[:template_method_cache] = orig_method_cache || (opts[:cache_class] || RodaCache).new
355
+ opts[:template_method_cache][:_roda_layout] = nil if opts[:template_method_cache][:_roda_layout]
356
+ opts[:cache] = orig_cache || (opts[:cache_class] || RodaCache).new
357
+
358
+ opts[:layout_opts] = (opts[:layout_opts] || {}).dup
359
+ opts[:layout_opts][:_is_layout] = true
360
+ if opts[:layout_opts][:views]
361
+ opts[:layout_opts][:views] = app.expand_path(opts[:layout_opts][:views]).freeze
362
+ end
363
+
364
+ if layout = opts.fetch(:layout, true)
365
+ opts[:layout] = true
366
+
367
+ case layout
368
+ when Hash
369
+ opts[:layout_opts].merge!(layout)
370
+ when true
371
+ opts[:layout_opts][:template] ||= 'layout'
372
+ else
373
+ opts[:layout_opts][:template] = layout
374
+ end
375
+
376
+ opts[:optimize_layout] = (opts[:layout_opts][:template] if opts[:layout_opts].keys.sort == [:_is_layout, :template])
377
+ end
378
+ opts[:layout_opts].freeze
379
+
380
+ template_opts = opts[:template_opts] = (opts[:template_opts] || {}).dup
381
+ template_opts[:outvar] ||= '@_out_buf'
382
+ unless template_opts.has_key?(:default_encoding)
383
+ template_opts[:default_encoding] = Encoding.default_external
384
+ end
385
+
386
+ engine_opts = opts[:engine_opts] = (opts[:engine_opts] || {}).dup
387
+ engine_opts.to_a.each do |k,v|
388
+ engine_opts[k] = v.dup.freeze
389
+ end
390
+
391
+ if escape = opts[:escape]
392
+ require 'tilt/erubi'
393
+
394
+ case escape
395
+ when String, Array
396
+ Array(escape).each do |engine|
397
+ engine_opts[engine] = (engine_opts[engine] || {}).merge(:escape => true).freeze
398
+ end
399
+ else
400
+ template_opts[:escape] = true
401
+ end
402
+ end
403
+
404
+ template_opts.freeze
405
+ engine_opts.freeze
406
+ opts.freeze
407
+ end
408
+
409
+ # Wrapper object for the Tilt template, that checks the modified
410
+ # time of the template file, and rebuilds the template if the
411
+ # template file has been modified. This is an internal class and
412
+ # the API is subject to change at any time.
413
+ class TemplateMtimeWrapper
414
+ def initialize(roda_class, opts, template_opts)
415
+ @roda_class = roda_class
416
+ @opts = opts
417
+ @template_opts = template_opts
418
+ reset_template
419
+
420
+ @path = opts[:path]
421
+ deps = opts[:dependencies]
422
+ @dependencies = ([@path] + Array(deps)) if deps
423
+ @mtime = template_last_modified
424
+ end
425
+
426
+ # If the template file exists and the modification time has
427
+ # changed, rebuild the template file, then call render on it.
428
+ def render(*args, &block)
429
+ res = nil
430
+ modified = false
431
+ if_modified do
432
+ res = @template.render(*args, &block)
433
+ modified = true
434
+ end
435
+ modified ? res : @template.render(*args, &block)
436
+ end
437
+
438
+ # Return when the template was last modified. If the template depends on any
439
+ # other files, check the modification times of all dependencies and
440
+ # return the maximum.
441
+ def template_last_modified
442
+ if deps = @dependencies
443
+ deps.map{|f| File.mtime(f)}.max
444
+ else
445
+ File.mtime(@path)
446
+ end
447
+ end
448
+
449
+ # If the template file has been updated, return true and update
450
+ # the template object and the modification time. Other return false.
451
+ def if_modified
452
+ begin
453
+ mtime = template_last_modified
454
+ rescue
455
+ # ignore errors
456
+ else
457
+ if mtime != @mtime
458
+ reset_template
459
+ yield
460
+ @mtime = mtime
461
+ end
462
+ end
463
+ end
464
+
465
+ if COMPILED_METHOD_SUPPORT
466
+ # Whether the underlying template uses fixed locals.
467
+ def fixed_locals?
468
+ Render.tilt_template_fixed_locals?(@template)
469
+ end
470
+
471
+ # Compile a method in the given module with the given name that will
472
+ # call the compiled template method, updating the compiled template method
473
+ def define_compiled_method(roda_class, method_name, locals_keys=EMPTY_ARRAY)
474
+ mod = roda_class::RodaCompiledTemplates
475
+ internal_method_name = :"_#{method_name}"
476
+ begin
477
+ mod.send(:define_method, internal_method_name, compiled_method(locals_keys, roda_class))
478
+ rescue ::NotImplementedError
479
+ return false
480
+ end
481
+
482
+ mod.send(:private, internal_method_name)
483
+ mod.send(:define_method, method_name, &compiled_method_lambda(roda_class, internal_method_name, locals_keys))
484
+ mod.send(:private, method_name)
485
+
486
+ method_name
487
+ end
488
+
489
+ # Returns an appropriate value for the template method cache.
490
+ def define_compiled_method_cache_value(roda_class, method_name, locals_keys=EMPTY_ARRAY)
491
+ if compiled_method = define_compiled_method(roda_class, method_name, locals_keys)
492
+ [compiled_method, false].freeze
493
+ else
494
+ compiled_method
495
+ end
496
+ end
497
+
498
+ private
499
+
500
+ # Return the compiled method for the current template object.
501
+ def compiled_method(locals_keys=EMPTY_ARRAY, roda_class=nil)
502
+ Render.tilt_template_compiled_method(@template, locals_keys, roda_class)
503
+ end
504
+
505
+ # Return the lambda used to define the compiled template method. This
506
+ # is separated into its own method so the lambda does not capture any
507
+ # unnecessary local variables
508
+ def compiled_method_lambda(roda_class, method_name, locals_keys=EMPTY_ARRAY)
509
+ mod = roda_class::RodaCompiledTemplates
510
+ template = self
511
+ lambda do |locals, &block|
512
+ template.if_modified do
513
+ mod.send(:define_method, method_name, Render.tilt_template_compiled_method(template, locals_keys, roda_class))
514
+ mod.send(:private, method_name)
515
+ end
516
+
517
+ _call_optimized_template_method([method_name, Render.tilt_template_fixed_locals?(template)], locals, &block)
518
+ end
519
+ end
520
+ end
521
+
522
+ private
523
+
524
+ # Reset the template, done every time the template or one of its
525
+ # dependencies is modified.
526
+ def reset_template
527
+ @template = @roda_class.create_template(@opts, @template_opts)
528
+ end
529
+ end
530
+
531
+ module ClassMethods
532
+ if COMPILED_METHOD_SUPPORT
533
+ # If using compiled methods and there is an optimized layout, speed up
534
+ # access to the layout method to improve the performance of view.
535
+ def freeze
536
+ begin
537
+ _freeze_layout_method
538
+ rescue
539
+ # This is only for optimization, if any errors occur, they can be ignored.
540
+ # One possibility for error is the app doesn't use a layout, but doesn't
541
+ # specifically set the :layout=>false plugin option.
542
+ nil
543
+ end
544
+
545
+ # Optimize _call_optimized_template_method if you know all templates
546
+ # are going to be using fixed locals.
547
+ if render_opts[:assume_fixed_locals] && !render_opts[:check_template_mtime]
548
+ include AssumeFixedLocalsInstanceMethods
549
+ end
550
+
551
+ super
552
+ end
553
+ end
554
+
555
+ # Return an Tilt::Template object based on the given opts and template_opts.
556
+ def create_template(opts, template_opts)
557
+ opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block])
558
+ end
559
+
560
+ # A proc that returns content, used for inline templates, so that the template
561
+ # doesn't hold a reference to the instance of the class
562
+ def inline_template_block(content)
563
+ Proc.new{content}
564
+ end
565
+
566
+ # Copy the rendering options into the subclass, duping
567
+ # them as necessary to prevent changes in the subclass
568
+ # affecting the parent class.
569
+ def inherited(subclass)
570
+ super
571
+ opts = subclass.opts[:render] = subclass.opts[:render].dup
572
+ if COMPILED_METHOD_SUPPORT
573
+ opts[:template_method_cache] = (opts[:cache_class] || RodaCache).new
574
+ end
575
+ opts[:cache] = opts[:cache].dup
576
+ opts.freeze
577
+ end
578
+
579
+ # Return the render options for this class.
580
+ def render_opts
581
+ opts[:render]
582
+ end
583
+
584
+ private
585
+
586
+ # Precompile the layout method, to reduce method calls to look it up at runtime.
587
+ def _freeze_layout_method
588
+ if render_opts[:layout]
589
+ instance = allocate
590
+ # This needs to be called even if COMPILED_METHOD_SUPPORT is not set,
591
+ # in order for the precompile_templates plugin to work correctly.
592
+ instance.send(:retrieve_template, instance.send(:view_layout_opts, OPTS))
593
+
594
+ if COMPILED_METHOD_SUPPORT && (layout_template = render_opts[:optimize_layout]) && !opts[:render][:optimized_layout_method_created]
595
+ instance.send(:retrieve_template, :template=>layout_template, :cache_key=>nil, :template_method_cache_key => :_roda_layout)
596
+ layout_method = opts[:render][:template_method_cache][:_roda_layout]
597
+ define_method(:_layout_method){layout_method}
598
+ private :_layout_method
599
+ alias_method(:_layout_method, :_layout_method)
600
+ opts[:render] = opts[:render].merge(:optimized_layout_method_created=>true)
601
+ end
602
+ end
603
+ end
604
+ end
605
+
606
+ module InstanceMethods
607
+ # Render the given template. See Render for details.
608
+ def render(template, opts = (no_opts = true; optimized_template = _cached_template_method(template); OPTS), &block)
609
+ if optimized_template
610
+ _call_optimized_template_method(optimized_template, OPTS, &block)
611
+ elsif !no_opts && opts.length == 1 && (locals = opts[:locals]) && (optimized_template = _optimized_render_method_for_locals(template, locals))
612
+ _call_optimized_template_method(optimized_template, locals, &block)
613
+ else
614
+ opts = render_template_opts(template, opts)
615
+ retrieve_template(opts).render((opts[:scope]||self), (opts[:locals]||OPTS), &block)
616
+ end
617
+ end
618
+
619
+ # Return the render options for the instance's class.
620
+ def render_opts
621
+ self.class.render_opts
622
+ end
623
+
624
+ # Render the given template. If there is a default layout
625
+ # for the class, take the result of the template rendering
626
+ # and render it inside the layout. Blocks passed to view
627
+ # are passed to render when rendering the template.
628
+ # See Render for details.
629
+ def view(template, opts = (content = _optimized_view_content(template) unless defined?(yield); OPTS), &block)
630
+ if content
631
+ # First, check if the optimized layout method has already been created,
632
+ # and use it if so. This way avoids the extra conditional and local variable
633
+ # assignments in the next section.
634
+ if layout_method = _layout_method
635
+ return _call_optimized_template_method(layout_method, OPTS){content}
636
+ end
637
+
638
+ # If we have an optimized template method but no optimized layout method, create the
639
+ # optimized layout method if possible and use it. If you can't create the optimized
640
+ # layout method, fall through to the slower approach.
641
+ if layout_template = self.class.opts[:render][:optimize_layout]
642
+ retrieve_template(:template=>layout_template, :cache_key=>nil, :template_method_cache_key => :_roda_layout)
643
+ if layout_method = _layout_method
644
+ return _call_optimized_template_method(layout_method, OPTS){content}
645
+ end
646
+ end
647
+ else
648
+ opts = parse_template_opts(template, opts)
649
+ content = opts[:content] || render_template(opts, &block)
650
+ end
651
+
652
+ if layout_opts = view_layout_opts(opts)
653
+ content = render_template(layout_opts){content}
654
+ end
655
+
656
+ content
657
+ end
658
+
659
+ private
660
+
661
+ if COMPILED_METHOD_SUPPORT
662
+ # If there is an instance method for the template, return the instance
663
+ # method symbol. This optimization is only used for render/view calls
664
+ # with a single string or symbol argument.
665
+ def _cached_template_method(template)
666
+ case template
667
+ when String, Symbol
668
+ if (method_cache = render_opts[:template_method_cache])
669
+ _cached_template_method_lookup(method_cache, template)
670
+ end
671
+ end
672
+ end
673
+
674
+ # The key to use in the template method cache for the given template.
675
+ def _cached_template_method_key(template)
676
+ template
677
+ end
678
+
679
+ # Return the instance method symbol for the template in the method cache.
680
+ def _cached_template_method_lookup(method_cache, template)
681
+ method_cache[template]
682
+ end
683
+
684
+ # Return a symbol containing the optimized layout method
685
+ def _layout_method
686
+ self.class.opts[:render][:template_method_cache][:_roda_layout]
687
+ end
688
+
689
+ # Use an optimized render path for templates with a hash of locals. Returns the result
690
+ # of the template render if the optimized path is used, or nil if the optimized
691
+ # path is not used and the long method needs to be used.
692
+ def _optimized_render_method_for_locals(template, locals)
693
+ render_opts = self.render_opts
694
+ return unless method_cache = render_opts[:template_method_cache]
695
+
696
+ case template
697
+ when String, Symbol
698
+ if fixed_locals = render_opts[:assume_fixed_locals]
699
+ key = template
700
+ if optimized_template = _cached_template_method_lookup(method_cache, key)
701
+ return optimized_template
702
+ end
703
+ else
704
+ key = [:_render_locals, template]
705
+ if optimized_template = _cached_template_method_lookup(method_cache, key)
706
+ # Fixed locals case
707
+ return optimized_template
708
+ end
709
+
710
+ locals_keys = locals.keys.sort
711
+ key << locals_keys
712
+ if optimized_template = _cached_template_method_lookup(method_cache, key)
713
+ # Regular locals case
714
+ return optimized_template
715
+ end
716
+ end
717
+ else
718
+ return
719
+ end
720
+
721
+ if method_cache_key = _cached_template_method_key(key)
722
+ template_obj = retrieve_template(render_template_opts(template, NO_CACHE))
723
+ unless fixed_locals
724
+ key.pop if fixed_locals = Render.tilt_template_fixed_locals?(template_obj)
725
+ key.freeze
726
+ end
727
+ method_name = :"_roda_template_locals_#{self.class.object_id}_#{method_cache_key}"
728
+
729
+ method_cache[method_cache_key] = case template_obj
730
+ when Render::TemplateMtimeWrapper
731
+ template_obj.define_compiled_method_cache_value(self.class, method_name, locals_keys)
732
+ else
733
+ begin
734
+ unbound_method = Render.tilt_template_compiled_method(template_obj, locals_keys, self.class)
735
+ rescue ::NotImplementedError
736
+ false
737
+ else
738
+ self.class::RodaCompiledTemplates.send(:define_method, method_name, unbound_method)
739
+ self.class::RodaCompiledTemplates.send(:private, method_name)
740
+ [method_name, fixed_locals].freeze
741
+ end
742
+ end
743
+ end
744
+ end
745
+
746
+ # Get the content for #view, or return nil to use the unoptimized approach. Only called if
747
+ # a single argument is passed to view.
748
+ def _optimized_view_content(template)
749
+ if optimized_template = _cached_template_method(template)
750
+ _call_optimized_template_method(optimized_template, OPTS)
751
+ elsif template.is_a?(Hash) && template.length == 1
752
+ template[:content]
753
+ end
754
+ end
755
+
756
+ if RUBY_VERSION >= '3'
757
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
758
+ def _call_optimized_template_method((meth, fixed_locals), locals, &block)
759
+ if fixed_locals
760
+ send(meth, **locals, &block)
761
+ else
762
+ send(meth, locals, &block)
763
+ end
764
+ end
765
+ RUBY
766
+ # :nocov:
767
+ elsif RUBY_VERSION >= '2'
768
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
769
+ def _call_optimized_template_method((meth, fixed_locals), locals, &block)
770
+ if fixed_locals
771
+ if locals.empty?
772
+ send(meth, &block)
773
+ else
774
+ send(meth, **locals, &block)
775
+ end
776
+ else
777
+ send(meth, locals, &block)
778
+ end
779
+ end
780
+ RUBY
781
+ else
782
+ # Call the optimized template method. This is designed to be used with the
783
+ # method cache, which caches the method name and whether the method uses
784
+ # fixed locals. Methods with fixed locals need to be called with a keyword
785
+ # splat.
786
+ def _call_optimized_template_method((meth, fixed_locals), locals, &block)
787
+ send(meth, locals, &block)
788
+ end
789
+ end
790
+ # :nocov:
791
+ else
792
+ def _cached_template_method(_)
793
+ nil
794
+ end
795
+
796
+ def _cached_template_method_key(_)
797
+ nil
798
+ end
799
+
800
+ def _optimized_render_method_for_locals(_, _)
801
+ nil
802
+ end
803
+
804
+ def _optimized_view_content(template)
805
+ nil
806
+ end
807
+ end
808
+
809
+ # Convert template options to single hash when rendering templates using render.
810
+ def render_template_opts(template, opts)
811
+ parse_template_opts(template, opts)
812
+ end
813
+
814
+ # Private alias for render. Should be used by other plugins when they want to render a template
815
+ # without a layout, as plugins can override render to use a layout.
816
+ alias render_template render
817
+
818
+ # If caching templates, attempt to retrieve the template from the cache. Otherwise, just yield
819
+ # to get the template.
820
+ def cached_template(opts, &block)
821
+ if key = opts[:cache_key]
822
+ cache = render_opts[:cache]
823
+ unless template = cache[key]
824
+ template = cache[key] = yield
825
+ end
826
+ template
827
+ else
828
+ yield
829
+ end
830
+ end
831
+
832
+ # Given the template name and options, set the template class, template path/content,
833
+ # template block, and locals to use for the render in the passed options.
834
+ def find_template(opts)
835
+ render_opts = self.class.opts[:render]
836
+ engine_override = opts[:engine]
837
+ engine = opts[:engine] ||= render_opts[:engine]
838
+ if content = opts[:inline]
839
+ path = opts[:path] = content
840
+ template_class = opts[:template_class] ||= ::Tilt[engine]
841
+ opts[:template_block] = self.class.inline_template_block(content)
842
+ else
843
+ opts[:views] ||= render_opts[:views]
844
+ path = opts[:path] ||= template_path(opts)
845
+ template_class = opts[:template_class]
846
+ opts[:template_class] ||= ::Tilt
847
+ end
848
+
849
+ if (cache = opts[:cache]).nil?
850
+ cache = content || !opts[:template_block]
851
+ end
852
+
853
+ if cache
854
+ unless opts.has_key?(:cache_key)
855
+ template_block = opts[:template_block] unless content
856
+ template_opts = opts[:template_opts]
857
+
858
+ opts[:cache_key] = if template_class || engine_override || template_opts || template_block
859
+ [path, template_class, engine_override, template_opts, template_block]
860
+ else
861
+ path
862
+ end
863
+ end
864
+ else
865
+ opts.delete(:cache_key)
866
+ end
867
+
868
+ opts
869
+ end
870
+
871
+ # Return a single hash combining the template and opts arguments.
872
+ def parse_template_opts(template, opts)
873
+ opts = Hash[opts]
874
+ if template.is_a?(Hash)
875
+ opts.merge!(template)
876
+ else
877
+ if opts.empty? && (key = _cached_template_method_key(template))
878
+ opts[:template_method_cache_key] = key
879
+ end
880
+ opts[:template] = template
881
+ opts
882
+ end
883
+ end
884
+
885
+ # The default render options to use. These set defaults that can be overridden by
886
+ # providing a :layout_opts option to the view/render method.
887
+ def render_layout_opts
888
+ Hash[render_opts[:layout_opts]]
889
+ end
890
+
891
+ # Retrieve the Tilt::Template object for the given template and opts.
892
+ def retrieve_template(opts)
893
+ cache = opts[:cache]
894
+ if !opts[:cache_key] || cache == false
895
+ found_template_opts = opts = find_template(opts)
896
+ end
897
+ cached_template(opts) do
898
+ opts = found_template_opts || find_template(opts)
899
+ render_opts = self.class.opts[:render]
900
+ template_opts = render_opts[:template_opts]
901
+ if engine_opts = render_opts[:engine_opts][opts[:engine]]
902
+ template_opts = template_opts.merge(engine_opts)
903
+ end
904
+ if current_template_opts = opts[:template_opts]
905
+ template_opts = template_opts.merge(current_template_opts)
906
+ end
907
+
908
+ define_compiled_method = COMPILED_METHOD_SUPPORT &&
909
+ (method_cache_key = opts[:template_method_cache_key]) &&
910
+ (method_cache = render_opts[:template_method_cache]) &&
911
+ (method_cache[method_cache_key] != false) &&
912
+ !opts[:inline]
913
+
914
+ if render_opts[:check_template_mtime] && !opts[:template_block] && !cache
915
+ template = TemplateMtimeWrapper.new(self.class, opts, template_opts)
916
+
917
+ if define_compiled_method
918
+ method_name = :"_roda_template_#{self.class.object_id}_#{method_cache_key}"
919
+ method_cache[method_cache_key] = template.define_compiled_method_cache_value(self.class, method_name)
920
+ end
921
+ else
922
+ template = self.class.create_template(opts, template_opts)
923
+
924
+ if define_compiled_method && cache != false
925
+ begin
926
+ unbound_method = Render.tilt_template_compiled_method(template, EMPTY_ARRAY, self.class)
927
+ rescue ::NotImplementedError
928
+ method_cache[method_cache_key] = false
929
+ else
930
+ method_name = :"_roda_template_#{self.class.object_id}_#{method_cache_key}"
931
+ self.class::RodaCompiledTemplates.send(:define_method, method_name, unbound_method)
932
+ self.class::RodaCompiledTemplates.send(:private, method_name)
933
+ method_cache[method_cache_key] = [method_name, Render.tilt_template_fixed_locals?(template)].freeze
934
+ end
935
+ end
936
+ end
937
+
938
+ template
939
+ end
940
+ end
941
+
942
+ # The name to use for the template. By default, just converts the :template option to a string.
943
+ def template_name(opts)
944
+ opts[:template].to_s
945
+ end
946
+
947
+ # The template path for the given options.
948
+ def template_path(opts)
949
+ path = "#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
950
+ if opts.fetch(:check_paths){render_opts[:check_paths]}
951
+ full_path = self.class.expand_path(path)
952
+ unless render_opts[:allowed_paths].any?{|f| full_path.start_with?(f)}
953
+ raise RodaError, "attempt to render path not in allowed_paths: #{full_path} (allowed: #{render_opts[:allowed_paths].join(', ')})"
954
+ end
955
+ end
956
+ path
957
+ end
958
+
959
+ # If a layout should be used, return a hash of options for
960
+ # rendering the layout template. If a layout should not be
961
+ # used, return nil.
962
+ def view_layout_opts(opts)
963
+ if layout = opts.fetch(:layout, render_opts[:layout])
964
+ layout_opts = render_layout_opts
965
+
966
+ method_layout_opts = opts[:layout_opts]
967
+ layout_opts.merge!(method_layout_opts) if method_layout_opts
968
+
969
+ case layout
970
+ when Hash
971
+ layout_opts.merge!(layout)
972
+ when true
973
+ # use default layout
974
+ else
975
+ layout_opts[:template] = layout
976
+ end
977
+
978
+ layout_opts
979
+ end
980
+ end
981
+ end
982
+
983
+ module AssumeFixedLocalsInstanceMethods
984
+ # :nocov:
985
+ if RUBY_VERSION >= '3.0'
986
+ # :nocov:
987
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
988
+ def _call_optimized_template_method((meth,_), locals, &block)
989
+ send(meth, **locals, &block)
990
+ end
991
+ RUBY
992
+ end
993
+ end
994
+ end
995
+
996
+ register_plugin(:render, Render)
997
+ end
998
+ end