roda 3.22.0 → 3.23.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c75151c856c93ac28e9089018a1d04f40f479782cc4d2e96099d4182d993d81a
4
- data.tar.gz: 3190821d03128b656e573f8dc748fafcd753b55bfabd4d53c1c6c219ed0a340a
3
+ metadata.gz: 2229b19a7b47a63c8f953c9a225f094d9b6c1120893629e30fea16fe189c8462
4
+ data.tar.gz: 341a5222c9bdf0cdc1aa56b654dd1accdce94257a5f9a756c8a8d37cf5bd5af8
5
5
  SHA512:
6
- metadata.gz: cbf0bdcd577b6766483121f654b3e5139de674b81539fda0a43d949bb73d0092d7e280b1efd772409917a0f53a6fb877897126687060b4c6a14c8c9f5d152e75
7
- data.tar.gz: 33fa800abbe118922d05db9712bc35910e7d633fbe4f224083c79f4289e8a269dcca90f31b2ac07aa0bece05c3957e5afa3f08bf14bea005a1b93242bcb317c5
6
+ metadata.gz: c996fa5a43603f429fb061c84585a84dbe97719032893f3ae1fff22dcd8056fb1c71fb8fa103ea46fca1a50cbaf6156139e9b1ee03ac1151e7a33d576d08b724
7
+ data.tar.gz: 8eff9c58e5dc39d40e18445bb33a4dcba019034975c110382a9f143021ddaf6920b8e783cc031be07f431a295e2b973ed750cf9f71e064c0796822e51faa6145
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ = 3.23.0 (2019-08-13)
2
+
3
+ * Make roda/session_middleware work if type_routing plugin is loaded into Roda itself (jeremyevans) (#169)
4
+
5
+ * Handle requests with nothing before extension in the path in the type_routing plugin (jeremyevans) (#168)
6
+
7
+ * Always show line number in exception_page output in exception_page plugin (jeremyevans)
8
+
9
+ * Improve render/view performance up to 2x in development mode in the default case by calling compiled template methods directly (jeremyevans)
10
+
1
11
  = 3.22.0 (2019-07-12)
2
12
 
3
13
  * Improve render performance up to 4x in the default case by calling compiled template methods directly (jeremyevans)
@@ -0,0 +1,28 @@
1
+ = Improvements
2
+
3
+ * The render/view methods in the render plugin, when called with
4
+ a single string/symbol argument (the most common case), are now
5
+ up to 2x faster in cache: false mode by directly calling compiled
6
+ template methods. This takes the performance increase in 3.22.0
7
+ and applies it to cache: false mode in addition to cache: true
8
+ mode. If the template file has changed, the compiled method is
9
+ removed, and a new compiled method replaces it.
10
+
11
+ * Template modification detection in the render plugin now uses a
12
+ faster check for modification, which also avoids a race condition.
13
+
14
+ * The type_routing plugin now handles requests with nothing but the
15
+ extension in the request path. This fixes cases when you have
16
+ one app partially route a request, and send the request to another
17
+ app, and that app uses the type_routing plugin and has an r.is
18
+ call at the root level.
19
+
20
+ * The roda/session_middleware middleware now works correctly if the
21
+ type_routing plugin is loaded into Roda itself (as opposed to a
22
+ Roda subclass).
23
+
24
+ * The exception_page plugin now always shows the line number for
25
+ each line. Previously, it only showed the line number if it was
26
+ showing the content of the line, which complicated debugging in
27
+ cases where the content of the line was no longer retrievable
28
+ due to file system permissions or restrictions (e.g. chroot).
@@ -340,9 +340,12 @@ class Roda
340
340
  end
341
341
 
342
342
  # Load a new plugin into the current class. A plugin can be a module
343
- # which is used directly, or a symbol represented a registered plugin
343
+ # which is used directly, or a symbol representing a registered plugin
344
344
  # which will be required and then used. Returns nil.
345
345
  #
346
+ # Note that you should not load plugins into a Roda class after the
347
+ # class has been subclassed, as doing so can break the subclasses.
348
+ #
346
349
  # Roda.plugin PluginModule
347
350
  # Roda.plugin :csrf
348
351
  def plugin(plugin, *args, &block)
@@ -330,7 +330,7 @@ END
330
330
  <ul class="traceback">
331
331
  #{frames.map{|frame| id = frame[:id]; (<<END1)}.join
332
332
  <li class="frame">
333
- <code>#{h frame[:filename]}</code>: in <code>#{h frame[:function]}</code>
333
+ <code>#{h frame[:filename]}:#{frame[:lineno]}</code> in <code>#{h frame[:function]}</code>
334
334
 
335
335
  #{frame[:context_line] ? (<<END2) : '</li>'
336
336
  <div class="context" id="c#{id}">
@@ -161,20 +161,14 @@ class Roda
161
161
  end
162
162
  end
163
163
 
164
- if opts[:check_template_mtime]
165
- opts.delete(:template_method_cache)
166
- elsif COMPILED_METHOD_SUPPORT
167
- opts[:template_method_cache] = orig_method_cache || (opts[:cache_class] || RodaCache).new
168
- begin
169
- app.const_get(:RodaCompiledTemplates, false)
170
- rescue NameError
171
- compiled_templates_module = Module.new
172
- app.send(:include, compiled_templates_module)
173
- app.const_set(:RodaCompiledTemplates, compiled_templates_module)
174
- end
175
- opts[:template_method_cache] = orig_method_cache || (opts[:cache_class] || RodaCache).new
164
+ begin
165
+ app.const_get(:RodaCompiledTemplates, false)
166
+ rescue NameError
167
+ compiled_templates_module = Module.new
168
+ app.send(:include, compiled_templates_module)
169
+ app.const_set(:RodaCompiledTemplates, compiled_templates_module)
176
170
  end
177
-
171
+ opts[:template_method_cache] = orig_method_cache || (opts[:cache_class] || RodaCache).new
178
172
  opts[:cache] = orig_cache || (opts[:cache_class] || RodaCache).new
179
173
 
180
174
  opts[:layout_opts] = (opts[:layout_opts] || {}).dup
@@ -244,15 +238,68 @@ class Roda
244
238
  # If the template file exists and the modification time has
245
239
  # changed, rebuild the template file, then call render on it.
246
240
  def render(*args, &block)
247
- if File.file?(path = @path)
248
- mtime = File.mtime(path)
241
+ modified?
242
+ @template.render(*args, &block)
243
+ end
244
+
245
+ # If the template file has been updated, return true and update
246
+ # the template object and the modification time. Other return false.
247
+ def modified?
248
+ begin
249
+ mtime = File.mtime(path = @path)
250
+ rescue
251
+ # ignore errors
252
+ else
249
253
  if mtime != @mtime
250
254
  @mtime = mtime
251
255
  @template = @template_class.new(path, *@template_args)
256
+ return true
252
257
  end
253
258
  end
254
259
 
255
- @template.render(*args, &block)
260
+ false
261
+ end
262
+
263
+ if COMPILED_METHOD_SUPPORT
264
+ # Compile a method in the given module with the given name that will
265
+ # call the compiled template method, updating the compiled template method
266
+ def define_compiled_method(roda_class, method_name)
267
+ mod = roda_class::RodaCompiledTemplates
268
+ internal_method_name = :"_#{method_name}"
269
+ begin
270
+ mod.send(:define_method, internal_method_name, send(:compiled_method, OPTS))
271
+ rescue ::NotImplementedError
272
+ return false
273
+ end
274
+
275
+ mod.send(:private, internal_method_name)
276
+ mod.send(:define_method, method_name, &compiled_method_lambda(self, roda_class, internal_method_name))
277
+ mod.send(:private, method_name)
278
+
279
+ method_name
280
+ end
281
+
282
+ private
283
+
284
+ # Return the compiled method for the current template object.
285
+ def compiled_method(_)
286
+ @template.send(:compiled_method, OPTS)
287
+ end
288
+
289
+ # Return the lambda used to define the compiled template method. This
290
+ # is separated into its own method so the lambda does not capture any
291
+ # unnecessary local variables
292
+ def compiled_method_lambda(template, roda_class, method_name)
293
+ mod = roda_class::RodaCompiledTemplates
294
+ lambda do |_, &block|
295
+ if template.modified?
296
+ mod.send(:define_method, method_name, template.send(:compiled_method, OPTS))
297
+ mod.send(:private, method_name)
298
+ end
299
+
300
+ send(method_name, OPTS, &block)
301
+ end
302
+ end
256
303
  end
257
304
  end
258
305
 
@@ -459,18 +506,23 @@ class Roda
459
506
  template_opts = template_opts.merge(current_template_opts)
460
507
  end
461
508
 
509
+ define_compiled_method = COMPILED_METHOD_SUPPORT &&
510
+ (method_cache_key = opts[:template_method_cache_key]) &&
511
+ (method_cache = render_opts[:template_method_cache]) &&
512
+ (method_cache[method_cache_key] != false) &&
513
+ !opts[:inline]
514
+
462
515
  if render_opts[:check_template_mtime] && !opts[:template_block] && !cache
463
- TemplateMtimeWrapper.new(opts[:template_class], opts[:path], 1, template_opts)
516
+ template = TemplateMtimeWrapper.new(opts[:template_class], opts[:path], 1, template_opts)
517
+
518
+ if define_compiled_method
519
+ method_name = :"_roda_template_#{self.class.object_id}_#{method_cache_key}"
520
+ method_cache[method_cache_key] = template.define_compiled_method(self.class, method_name)
521
+ end
464
522
  else
465
523
  template = opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block])
466
524
 
467
- if COMPILED_METHOD_SUPPORT &&
468
- (method_cache_key = opts[:template_method_cache_key]) &&
469
- (method_cache = render_opts[:template_method_cache]) &&
470
- (method_cache[method_cache_key] != false) &&
471
- !opts[:inline] &&
472
- cache != false
473
-
525
+ if define_compiled_method && cache != false
474
526
  begin
475
527
  unbound_method = template.send(:compiled_method, OPTS)
476
528
  rescue ::NotImplementedError
@@ -482,9 +534,9 @@ class Roda
482
534
  method_cache[method_cache_key] = method_name
483
535
  end
484
536
  end
485
-
486
- template
487
537
  end
538
+
539
+ template
488
540
  end
489
541
  end
490
542
 
@@ -131,7 +131,7 @@ class Roda
131
131
  mimes.freeze
132
132
 
133
133
  type_keys = config[:types].keys
134
- config[:extension_regexp] = /(.+?)\.(#{Regexp.union(type_keys.map(&:to_s))})\z/
134
+ config[:extension_regexp] = /(.*?)\.(#{Regexp.union(type_keys.map(&:to_s))})\z/
135
135
 
136
136
  type_keys.each do |type|
137
137
  app::RodaRequest.send(:define_method, type) do |&block|
@@ -150,11 +150,18 @@ class RodaSessionMiddleware
150
150
  end
151
151
  end
152
152
 
153
+ module RequestMethods
154
+ # Work around for if type_routing plugin is loaded into Roda class itself.
155
+ def _remaining_path(_)
156
+ end
157
+ end
158
+
153
159
  # Setup the middleware, passing +opts+ as the Roda sessions plugin options.
154
160
  def initialize(app, opts)
155
161
  mid = Class.new(Roda)
156
162
  mid.plugin :sessions, opts
157
163
  @req_class = mid::RodaRequest
164
+ @req_class.send(:include, RequestMethods)
158
165
  @app = app
159
166
  end
160
167
 
@@ -4,7 +4,7 @@ class Roda
4
4
  RodaMajorVersion = 3
5
5
 
6
6
  # The minor version of Roda, updated for new feature releases of Roda.
7
- RodaMinorVersion = 22
7
+ RodaMinorVersion = 23
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
@@ -139,6 +139,17 @@ describe "exception_page plugin" do
139
139
  body.wont_include 'id="c0"'
140
140
  end
141
141
 
142
+ it "should still show line numbers if the line content cannot be displayed" do
143
+ app(:exception_page) do |r|
144
+ instance_eval('raise "foo"', 'foo-bar.rb', 4200+42) rescue exception_page($!)
145
+ end
146
+ body = body('HTTP_ACCEPT'=>'text/html')
147
+ body.must_include "RuntimeError: foo"
148
+ body.must_include "foo-bar.rb:#{4200+42}"
149
+ body.must_include __FILE__
150
+ body.wont_include 'id="c0"'
151
+ end
152
+
142
153
  it "should serve exception page assets" do
143
154
  app(:exception_page) do |r|
144
155
  r.exception_page_assets
@@ -261,157 +261,160 @@ describe "render plugin" do
261
261
  end
262
262
 
263
263
  if Roda::RodaPlugins::Render::COMPILED_METHOD_SUPPORT
264
- it "does not cache template renders when using a template library that doesn't support it" do
265
- begin
266
- require 'tilt/rdoc'
267
- rescue
268
- next
269
- end
270
-
271
- app(:bare) do
272
- plugin :render, :views=>'spec/views', :engine=>'rdoc'
273
- route do
274
- render('a')
264
+ [true, false].each do |cache_plugin_option|
265
+ multiplier = cache_plugin_option ? 1 : 2
266
+ it "does not cache template renders when using a template library that doesn't support it with plugin option :cache=>#{cache_plugin_option}" do
267
+ begin
268
+ require 'tilt/rdoc'
269
+ rescue
270
+ next
275
271
  end
276
- end
277
272
 
278
- app.render_opts[:template_method_cache]['a'].must_be_nil
279
- body.strip.must_equal "<p># a # * b</p>"
280
- app.render_opts[:template_method_cache]['a'].must_equal false
281
- body.strip.must_equal "<p># a # * b</p>"
282
- app.render_opts[:template_method_cache]['a'].must_equal false
283
- body.strip.must_equal "<p># a # * b</p>"
284
- app.render_opts[:template_method_cache]['a'].must_equal false
285
- app::RodaCompiledTemplates.private_instance_methods.length.must_equal 0
286
- end
287
-
288
- ['comp_test', :comp_test].each do |template|
289
- it "does not cache template renders when given a hash" do
290
273
  app(:bare) do
291
- plugin :render, :views=>'spec/views'
274
+ plugin :render, :views=>'spec/views', :engine=>'rdoc', :cache=>cache_plugin_option
292
275
  route do
293
- render(:template=>template)
276
+ render('a')
294
277
  end
295
278
  end
296
279
 
297
- app.render_opts[:template_method_cache][template].must_be_nil
298
- body.strip.must_equal "ct"
299
- app.render_opts[:template_method_cache][template].must_be_nil
300
- body.strip.must_equal "ct"
301
- app.render_opts[:template_method_cache][template].must_be_nil
302
- body.strip.must_equal "ct"
303
- app.render_opts[:template_method_cache][template].must_be_nil
280
+ app.render_opts[:template_method_cache]['a'].must_be_nil
281
+ body.strip.must_equal "<p># a # * b</p>"
282
+ app.render_opts[:template_method_cache]['a'].must_equal false
283
+ body.strip.must_equal "<p># a # * b</p>"
284
+ app.render_opts[:template_method_cache]['a'].must_equal false
285
+ body.strip.must_equal "<p># a # * b</p>"
286
+ app.render_opts[:template_method_cache]['a'].must_equal false
304
287
  app::RodaCompiledTemplates.private_instance_methods.length.must_equal 0
305
288
  end
306
289
 
307
- it "caches template renders when given a #{template.class}" do
308
- app(:bare) do
309
- plugin :render, :views=>'spec/views'
310
- route do
311
- render(template)
290
+ ['comp_test', :comp_test].each do |template|
291
+ it "does not cache template renders when given a hash with #{template.class} value with plugin option :cache=>#{cache_plugin_option}" do
292
+ app(:bare) do
293
+ plugin :render, :views=>'spec/views', :cache=>cache_plugin_option
294
+ route do
295
+ render(:template=>template)
296
+ end
312
297
  end
313
- end
314
298
 
315
- app.render_opts[:template_method_cache][template].must_be_nil
316
- body.strip.must_equal "ct"
317
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
318
- body.strip.must_equal "ct"
319
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
320
- body.strip.must_equal "ct"
321
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
322
- app::RodaCompiledTemplates.private_instance_methods.length.must_equal 1
323
- end
299
+ app.render_opts[:template_method_cache][template].must_be_nil
300
+ body.strip.must_equal "ct"
301
+ app.render_opts[:template_method_cache][template].must_be_nil
302
+ body.strip.must_equal "ct"
303
+ app.render_opts[:template_method_cache][template].must_be_nil
304
+ body.strip.must_equal "ct"
305
+ app.render_opts[:template_method_cache][template].must_be_nil
306
+ app::RodaCompiledTemplates.private_instance_methods.length.must_equal 0
307
+ end
324
308
 
325
- it "does not cache template views or layout when given a hash" do
326
- app(:bare) do
327
- layout = template.to_s.sub('test', 'layout')
328
- layout = layout.to_sym if template.is_a?(Symbol)
329
- plugin :render, :views=>'spec/views', :layout=>layout
330
- route do
331
- view(:template=>template)
309
+ it "caches template renders when given a #{template.class} with plugin option :cache=>#{cache_plugin_option}" do
310
+ app(:bare) do
311
+ plugin :render, :views=>'spec/views', :cache=>cache_plugin_option
312
+ route do
313
+ render(template)
314
+ end
332
315
  end
333
- end
334
316
 
335
- app.render_opts[:template_method_cache][template].must_be_nil
336
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
337
- body.strip.must_equal "act\nb"
338
- app.render_opts[:template_method_cache][template].must_be_nil
339
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
340
- body.strip.must_equal "act\nb"
341
- app.render_opts[:template_method_cache][template].must_be_nil
342
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
343
- body.strip.must_equal "act\nb"
344
- app.render_opts[:template_method_cache][template].must_be_nil
345
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
346
- app::RodaCompiledTemplates.private_instance_methods.length.must_equal 0
347
- end
317
+ app.render_opts[:template_method_cache][template].must_be_nil
318
+ body.strip.must_equal "ct"
319
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
320
+ body.strip.must_equal "ct"
321
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
322
+ body.strip.must_equal "ct"
323
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
324
+ app::RodaCompiledTemplates.private_instance_methods.length.must_equal multiplier
325
+ end
348
326
 
349
- it "caches template views with layout when given a #{template.class}" do
350
- app(:bare) do
351
- layout = template.to_s.sub('test', 'layout')
352
- layout = layout.to_sym if template.is_a?(Symbol)
353
- plugin :render, :views=>'spec/views', :layout=>layout
354
- route do
355
- view(template)
327
+ it "does not cache template views or layout when given a hash with #{template.class} value with plugin option :cache=>#{cache_plugin_option}" do
328
+ app(:bare) do
329
+ layout = template.to_s.sub('test', 'layout')
330
+ layout = layout.to_sym if template.is_a?(Symbol)
331
+ plugin :render, :views=>'spec/views', :layout=>layout, :cache=>cache_plugin_option
332
+ route do
333
+ view(:template=>template)
334
+ end
356
335
  end
336
+
337
+ app.render_opts[:template_method_cache][template].must_be_nil
338
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
339
+ body.strip.must_equal "act\nb"
340
+ app.render_opts[:template_method_cache][template].must_be_nil
341
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
342
+ body.strip.must_equal "act\nb"
343
+ app.render_opts[:template_method_cache][template].must_be_nil
344
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
345
+ body.strip.must_equal "act\nb"
346
+ app.render_opts[:template_method_cache][template].must_be_nil
347
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
348
+ app::RodaCompiledTemplates.private_instance_methods.length.must_equal 0
357
349
  end
358
350
 
359
- app.render_opts[:template_method_cache][template].must_be_nil
360
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
361
- body.strip.must_equal "act\nb"
362
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
363
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
364
- body.strip.must_equal "act\nb"
365
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
366
- app.render_opts[:template_method_cache][:_roda_layout].must_be_kind_of(Symbol)
367
- body.strip.must_equal "act\nb"
368
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
369
- app.render_opts[:template_method_cache][:_roda_layout].must_be_kind_of(Symbol)
370
- app::RodaCompiledTemplates.private_instance_methods.length.must_equal 2
371
- end
372
-
373
- it "caches template views without layout when additional layout options given when given a #{template.class}" do
374
- app(:bare) do
375
- plugin :render, :views=>'spec/views', :layout=>nil
376
- route do
377
- view(template)
351
+ it "caches template views with layout when given a #{template.class} with plugin option :cache=>#{cache_plugin_option}" do
352
+ app(:bare) do
353
+ layout = template.to_s.sub('test', 'layout')
354
+ layout = layout.to_sym if template.is_a?(Symbol)
355
+ plugin :render, :views=>'spec/views', :layout=>layout, :cache=>cache_plugin_option
356
+ route do
357
+ view(template)
358
+ end
378
359
  end
360
+
361
+ app.render_opts[:template_method_cache][template].must_be_nil
362
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
363
+ body.strip.must_equal "act\nb"
364
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
365
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
366
+ body.strip.must_equal "act\nb"
367
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
368
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_kind_of(Symbol)
369
+ body.strip.must_equal "act\nb"
370
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
371
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_kind_of(Symbol)
372
+ app::RodaCompiledTemplates.private_instance_methods.length.must_equal(2*multiplier)
379
373
  end
380
374
 
381
- app.render_opts[:template_method_cache][template].must_be_nil
382
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
383
- body.strip.must_equal "ct"
384
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
385
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
386
- body.strip.must_equal "ct"
387
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
388
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
389
- body.strip.must_equal "ct"
390
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
391
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
392
- app::RodaCompiledTemplates.private_instance_methods.length.must_equal 1
393
- end
394
-
395
- it "caches template views without layout when additional layout options given when given a #{template.class}" do
396
- app(:bare) do
397
- plugin :render, :views=>'spec/views', :layout_opts=>{:locals=>{:title=>"Home"}}
398
- route do
399
- view(template)
375
+ it "caches template views without layout when additional layout options given when given a #{template.class} with plugin option :cache=>#{cache_plugin_option}" do
376
+ app(:bare) do
377
+ plugin :render, :views=>'spec/views', :layout=>nil, :cache=>cache_plugin_option
378
+ route do
379
+ view(template)
380
+ end
400
381
  end
382
+
383
+ app.render_opts[:template_method_cache][template].must_be_nil
384
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
385
+ body.strip.must_equal "ct"
386
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
387
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
388
+ body.strip.must_equal "ct"
389
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
390
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
391
+ body.strip.must_equal "ct"
392
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
393
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
394
+ app::RodaCompiledTemplates.private_instance_methods.length.must_equal multiplier
401
395
  end
402
396
 
403
- app.render_opts[:template_method_cache][template].must_be_nil
404
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
405
- body.strip.must_equal "<title>Roda: Home</title>\nct"
406
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
407
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
408
- body.strip.must_equal "<title>Roda: Home</title>\nct"
409
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
410
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
411
- body.strip.must_equal "<title>Roda: Home</title>\nct"
412
- app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
413
- app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
414
- app::RodaCompiledTemplates.private_instance_methods.length.must_equal 1
397
+ it "caches template views without layout when additional layout options given when given a #{template.class} with plugin option :cache=>#{cache_plugin_option}" do
398
+ app(:bare) do
399
+ plugin :render, :views=>'spec/views', :layout_opts=>{:locals=>{:title=>"Home"}}, :cache=>cache_plugin_option
400
+ route do
401
+ view(template)
402
+ end
403
+ end
404
+
405
+ app.render_opts[:template_method_cache][template].must_be_nil
406
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
407
+ body.strip.must_equal "<title>Roda: Home</title>\nct"
408
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
409
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
410
+ body.strip.must_equal "<title>Roda: Home</title>\nct"
411
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
412
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
413
+ body.strip.must_equal "<title>Roda: Home</title>\nct"
414
+ app.render_opts[:template_method_cache][template].must_be_kind_of(Symbol)
415
+ app.render_opts[:template_method_cache][:_roda_layout].must_be_nil
416
+ app::RodaCompiledTemplates.private_instance_methods.length.must_equal multiplier
417
+ end
415
418
  end
416
419
  end
417
420
  end
@@ -63,6 +63,38 @@ describe "type_routing plugin" do
63
63
  body('/a.html', 'HTTP_ACCEPT' => 'application/xml').must_equal 'HTML: html'
64
64
  end
65
65
 
66
+ it "works correctly in sub apps when sub app also handles extensions on empty paths" do
67
+ sup_app = app
68
+ @app = Class.new(sup_app)
69
+ sup_app.route do |r|
70
+ r.is do
71
+ r.get do
72
+ r.html { 'a' }
73
+ r.json { '{b:1}' }
74
+ end
75
+ end
76
+
77
+ r.on 'test' do
78
+ r.get do
79
+ r.html { 'c' }
80
+ r.json { '{d:2}' }
81
+ end
82
+ end
83
+ end
84
+ app.route do |r|
85
+ r.on "subpath" do
86
+ r.run(sup_app)
87
+ end
88
+ end
89
+
90
+ body('/subpath').must_equal 'a'
91
+ body('/subpath.html').must_equal 'a'
92
+ body('/subpath.json').must_equal '{b:1}'
93
+ body('/subpath/test').must_equal 'c'
94
+ body('/subpath/test.html').must_equal 'c'
95
+ body('/subpath/test.json').must_equal '{d:2}'
96
+ end
97
+
66
98
  it "uses the default if neither file extension nor Accept header are given" do
67
99
  body('/a').must_equal 'HTML: html'
68
100
  header('Content-Type', '/a').must_equal 'text/html'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.22.0
4
+ version: 3.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-12 00:00:00.000000000 Z
11
+ date: 2019-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -219,6 +219,7 @@ extra_rdoc_files:
219
219
  - doc/release_notes/3.20.0.txt
220
220
  - doc/release_notes/3.21.0.txt
221
221
  - doc/release_notes/3.22.0.txt
222
+ - doc/release_notes/3.23.0.txt
222
223
  files:
223
224
  - CHANGELOG
224
225
  - MIT-LICENSE
@@ -277,6 +278,7 @@ files:
277
278
  - doc/release_notes/3.20.0.txt
278
279
  - doc/release_notes/3.21.0.txt
279
280
  - doc/release_notes/3.22.0.txt
281
+ - doc/release_notes/3.23.0.txt
280
282
  - doc/release_notes/3.3.0.txt
281
283
  - doc/release_notes/3.4.0.txt
282
284
  - doc/release_notes/3.5.0.txt