roda 3.21.0 → 3.22.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34a644ccaa69bc1913eb1f54315437ce4b215bd5925e82f720d0fda007895224
4
- data.tar.gz: 9a85847e46720f4fa2f7a050febd5b0f6ef7db528c8fbd09836113148944f87c
3
+ metadata.gz: c75151c856c93ac28e9089018a1d04f40f479782cc4d2e96099d4182d993d81a
4
+ data.tar.gz: 3190821d03128b656e573f8dc748fafcd753b55bfabd4d53c1c6c219ed0a340a
5
5
  SHA512:
6
- metadata.gz: 739c2a26ea80aeca2bbb4b3b51c4cabf93100309956fe594b61cc66a72f6d3e2f23ab0356c81f12e4a461bf82eb1d7f9cc2d0dc5fecbef88348bd17aca17c33a
7
- data.tar.gz: 65ef8401849ee398968ccfce12ccbf203914f7a76721c8cb0ef31b5ab9051fd7f8460361dd96abb495dfa25c5acb50141611448b7065a5be3340b8ca51cc70ff
6
+ metadata.gz: cbf0bdcd577b6766483121f654b3e5139de674b81539fda0a43d949bb73d0092d7e280b1efd772409917a0f53a6fb877897126687060b4c6a14c8c9f5d152e75
7
+ data.tar.gz: 33fa800abbe118922d05db9712bc35910e7d633fbe4f224083c79f4289e8a269dcca90f31b2ac07aa0bece05c3957e5afa3f08bf14bea005a1b93242bcb317c5
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ = 3.22.0 (2019-07-12)
2
+
3
+ * Improve render performance up to 4x in the default case by calling compiled template methods directly (jeremyevans)
4
+
1
5
  = 3.21.0 (2019-06-14)
2
6
 
3
7
  * Cache compiled templates in development mode, until the template files are modified (jeremyevans)
@@ -0,0 +1,24 @@
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 2.5x/4x faster by directly calling compiled template methods.
6
+ This works by extracting the UnboundMethod objects that Tilt
7
+ creates, and defining real methods for them, then calling those
8
+ methods using send. This avoids most of the overhead of the render
9
+ and view methods. The compiled template methods are defined inside
10
+ a module included in the Roda app's class, so this support works
11
+ even if the Roda app itself is frozen.
12
+
13
+ Some plugins, such as render_locals, do not work with this
14
+ optimization, and disable the use of it. The view_options plugin
15
+ does work with this optimization if you are using set_view_subdir or
16
+ append_view_subdir, but not if using set_view_options or
17
+ set_layout_options.
18
+
19
+ This optimization depends on Ruby 2.3+ and Tilt 1.2+, and will not
20
+ be used on earlier versions, or if an API change in Tilt is
21
+ detected.
22
+
23
+ * Session deserialization is now slightly faster in the sessions
24
+ plugin.
@@ -120,29 +120,27 @@ class Roda
120
120
  #
121
121
  # = Speeding Up Template Rendering
122
122
  #
123
- # By default, determining the cache key to use for the template can be a lot
124
- # of work. If you specify the +:cache_key+ option, you can save Roda from
125
- # having to do that work, which will make your application faster. However,
126
- # if you do this, you need to make sure you choose a correct key.
123
+ # The render/view method calls are optimized for usage with a single symbol/string
124
+ # argument specifying the template name. So for fastest rendering, pass only a
125
+ # symbol/string to render/view.
127
126
  #
128
- # If your application uses a unique template per path, in that the same
129
- # path never uses more than one template, you can use the +view_options+ plugin
130
- # and do:
131
- #
132
- # set_view_options cache_key: r.path_info
133
- #
134
- # at the top of your route block. You can even do this if you do have paths
135
- # that use more than one template, as long as you specify +:cache_key+
136
- # specifically when rendering in those paths.
137
- #
138
- # If you use a single layout in your application, you can also make layout
139
- # rendering faster by specifying +:cache_key+ inside the +:layout_opts+
140
- # plugin option.
127
+ # If you must pass a hash to render/view, either as a second argument or as the
128
+ # only argument, you can speed things up by specifying a +:cache_key+ option in
129
+ # the hash, making sure the +:cache_key+ is unique to the template you are
130
+ # rendering.
141
131
  module Render
132
+ # Support for using compiled methods directly requires Ruby 2.3 for the
133
+ # method binding to work, and Tilt 1.2 for Tilt::Template#compiled_method.
134
+ COMPILED_METHOD_SUPPORT = RUBY_VERSION >= '2.3' &&
135
+ defined?(Tilt::VERSION) &&
136
+ Tilt::VERSION >= '1.2' &&
137
+ (Tilt::Template.instance_method(:compiled_method).arity rescue false) == 1
138
+
142
139
  # Setup default rendering options. See Render for details.
143
140
  def self.configure(app, opts=OPTS)
144
141
  if app.opts[:render]
145
142
  orig_cache = app.opts[:render][:cache]
143
+ orig_method_cache = app.opts[:render][:template_method_cache]
146
144
  opts = app.opts[:render][:orig_opts].merge(opts)
147
145
  end
148
146
  app.opts[:render] = opts.dup
@@ -163,6 +161,20 @@ class Roda
163
161
  end
164
162
  end
165
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
176
+ end
177
+
166
178
  opts[:cache] = orig_cache || (opts[:cache_class] || RodaCache).new
167
179
 
168
180
  opts[:layout_opts] = (opts[:layout_opts] || {}).dup
@@ -182,6 +194,8 @@ class Roda
182
194
  else
183
195
  opts[:layout_opts][:template] = layout
184
196
  end
197
+
198
+ opts[:optimize_layout] = (opts[:layout_opts][:template] if opts[:layout_opts].keys.sort == [:_is_layout, :template])
185
199
  end
186
200
  opts[:layout_opts].freeze
187
201
 
@@ -249,6 +263,9 @@ class Roda
249
263
  def inherited(subclass)
250
264
  super
251
265
  opts = subclass.opts[:render] = subclass.opts[:render].dup
266
+ if COMPILED_METHOD_SUPPORT
267
+ opts[:template_method_cache] = (opts[:cache_class] || RodaCache).new
268
+ end
252
269
  opts[:cache] = opts[:cache].dup
253
270
  opts.freeze
254
271
  end
@@ -261,9 +278,13 @@ class Roda
261
278
 
262
279
  module InstanceMethods
263
280
  # Render the given template. See Render for details.
264
- def render(template, opts = OPTS, &block)
265
- opts = render_template_opts(template, opts)
266
- retrieve_template(opts).render((opts[:scope]||self), (opts[:locals]||OPTS), &block)
281
+ def render(template, opts = (optimized_template = _cached_template_method(template); OPTS), &block)
282
+ if optimized_template
283
+ send(optimized_template, OPTS, &block)
284
+ else
285
+ opts = render_template_opts(template, opts)
286
+ retrieve_template(opts).render((opts[:scope]||self), (opts[:locals]||OPTS), &block)
287
+ end
267
288
  end
268
289
 
269
290
  # Return the render options for the instance's class.
@@ -274,9 +295,26 @@ class Roda
274
295
  # Render the given template. If there is a default layout
275
296
  # for the class, take the result of the template rendering
276
297
  # and render it inside the layout. See Render for details.
277
- def view(template, opts=OPTS)
278
- opts = parse_template_opts(template, opts)
279
- content = opts[:content] || render_template(opts)
298
+ def view(template, opts = (optimized_template = _cached_template_method(template); OPTS))
299
+ if optimized_template
300
+ content = send(optimized_template, OPTS)
301
+
302
+ render_opts = self.class.opts[:render]
303
+ if layout_template = render_opts[:optimize_layout]
304
+ method_cache = render_opts[:template_method_cache]
305
+ unless layout_method = method_cache[:_roda_layout]
306
+ retrieve_template(:template=>layout_template, :cache_key=>nil, :template_method_cache_key => :_roda_layout)
307
+ layout_method = method_cache[:_roda_layout]
308
+ end
309
+
310
+ if layout_method
311
+ return send(layout_method, OPTS){content}
312
+ end
313
+ end
314
+ else
315
+ opts = parse_template_opts(template, opts)
316
+ content = opts[:content] || render_template(opts)
317
+ end
280
318
 
281
319
  if layout_opts = view_layout_opts(opts)
282
320
  content = render_template(layout_opts){content}
@@ -287,6 +325,41 @@ class Roda
287
325
 
288
326
  private
289
327
 
328
+ if COMPILED_METHOD_SUPPORT
329
+ # If there is an instance method for the template, return the instance
330
+ # method symbol. This optimization is only used for render/view calls
331
+ # with a single string or symbol argument.
332
+ def _cached_template_method(template)
333
+ case template
334
+ when String, Symbol
335
+ if (method_cache = render_opts[:template_method_cache])
336
+ _cached_template_method_lookup(method_cache, template)
337
+ end
338
+ end
339
+ end
340
+
341
+ # The key to use in the template method cache for the given template.
342
+ def _cached_template_method_key(template)
343
+ template
344
+ end
345
+
346
+ # Return the instance method symbol for the template in the method cache.
347
+ def _cached_template_method_lookup(method_cache, template)
348
+ method_cache[template]
349
+ end
350
+ else
351
+ # :nocov:
352
+ def _cached_template_method(template)
353
+ nil
354
+ end
355
+
356
+ def _cached_template_method_key(template)
357
+ nil
358
+ end
359
+ # :nocov:
360
+ end
361
+
362
+
290
363
  # Convert template options to single hash when rendering templates using render.
291
364
  def render_template_opts(template, opts)
292
365
  parse_template_opts(template, opts)
@@ -313,7 +386,7 @@ class Roda
313
386
  # Given the template name and options, set the template class, template path/content,
314
387
  # template block, and locals to use for the render in the passed options.
315
388
  def find_template(opts)
316
- render_opts = render_opts()
389
+ render_opts = self.class.opts[:render]
317
390
  engine_override = opts[:engine]
318
391
  engine = opts[:engine] ||= render_opts[:engine]
319
392
  if content = opts[:inline]
@@ -332,13 +405,15 @@ class Roda
332
405
  end
333
406
 
334
407
  if cache
335
- template_block = opts[:template_block] unless content
336
- template_opts = opts[:template_opts]
337
-
338
- opts[:cache_key] ||= if template_class || engine_override || template_opts || template_block
339
- [path, template_class, engine_override, template_opts, template_block]
340
- else
341
- path
408
+ unless opts.has_key?(:cache_key)
409
+ template_block = opts[:template_block] unless content
410
+ template_opts = opts[:template_opts]
411
+
412
+ opts[:cache_key] = if template_class || engine_override || template_opts || template_block
413
+ [path, template_class, engine_override, template_opts, template_block]
414
+ else
415
+ path
416
+ end
342
417
  end
343
418
  else
344
419
  opts.delete(:cache_key)
@@ -353,6 +428,9 @@ class Roda
353
428
  if template.is_a?(Hash)
354
429
  opts.merge!(template)
355
430
  else
431
+ if opts.empty? && (key = _cached_template_method_key(template))
432
+ opts[:template_method_cache_key] = key
433
+ end
356
434
  opts[:template] = template
357
435
  opts
358
436
  end
@@ -372,6 +450,7 @@ class Roda
372
450
  end
373
451
  cached_template(opts) do
374
452
  opts = found_template_opts || find_template(opts)
453
+ render_opts = self.class.opts[:render]
375
454
  template_opts = render_opts[:template_opts]
376
455
  if engine_opts = render_opts[:engine_opts][opts[:engine]]
377
456
  template_opts = template_opts.merge(engine_opts)
@@ -383,7 +462,28 @@ class Roda
383
462
  if render_opts[:check_template_mtime] && !opts[:template_block] && !cache
384
463
  TemplateMtimeWrapper.new(opts[:template_class], opts[:path], 1, template_opts)
385
464
  else
386
- opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block])
465
+ template = opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block])
466
+
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
+
474
+ begin
475
+ unbound_method = template.send(:compiled_method, OPTS)
476
+ rescue ::NotImplementedError
477
+ method_cache[method_cache_key] = false
478
+ else
479
+ method_name = :"_roda_template_#{self.class.object_id}_#{method_cache_key}"
480
+ self.class::RodaCompiledTemplates.send(:define_method, method_name, unbound_method)
481
+ self.class::RodaCompiledTemplates.send(:private, method_name)
482
+ method_cache[method_cache_key] = method_name
483
+ end
484
+ end
485
+
486
+ template
387
487
  end
388
488
  end
389
489
  end
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require_relative 'render'
4
+
3
5
  #
4
6
  class Roda
5
7
  module RodaPlugins
@@ -41,6 +43,14 @@ class Roda
41
43
  module InstanceMethods
42
44
  private
43
45
 
46
+ if Render::COMPILED_METHOD_SUPPORT
47
+ # Disable use of cached templates, since it assumes a render/view call with no
48
+ # options will have no locals.
49
+ def _cached_template_method(template)
50
+ nil
51
+ end
52
+ end
53
+
44
54
  def render_locals
45
55
  opts[:render_locals]
46
56
  end
@@ -394,10 +394,11 @@ class Roda
394
394
 
395
395
  bitmap, created_at, updated_at = data.unpack('vVV')
396
396
  padding_bytes = bitmap & PADDING_MASK
397
- if (max = opts[:max_seconds]) && Time.now.to_i > created_at + max
397
+ now = Time.now.to_i
398
+ if (max = opts[:max_seconds]) && now > created_at + max
398
399
  return _session_serialization_error("Not returning session: maximum session time expired")
399
400
  end
400
- if (max = opts[:max_idle_seconds]) && Time.now.to_i > updated_at + max
401
+ if (max = opts[:max_idle_seconds]) && now > updated_at + max
401
402
  return _session_serialization_error("Not returning session: maximum session idle time expired")
402
403
  end
403
404
 
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require_relative 'render'
4
+
3
5
  #
4
6
  class Roda
5
7
  module RodaPlugins
@@ -124,6 +126,32 @@ class Roda
124
126
 
125
127
  private
126
128
 
129
+ if Render::COMPILED_METHOD_SUPPORT
130
+ # Return nil if using custom view or layout options.
131
+ # If using a view subdir, prefix the template key with the subdir.
132
+ def _cached_template_method_key(template)
133
+ return if @_view_options || @_layout_options
134
+
135
+ if subdir = @_view_subdir
136
+ template = [subdir, template]
137
+ end
138
+
139
+ super
140
+ end
141
+
142
+ # Return nil if using custom view or layout options.
143
+ # If using a view subdir, prefix the template key with the subdir.
144
+ def _cached_template_method_lookup(method_cache, template)
145
+ return if @_view_options || @_layout_options
146
+
147
+ if subdir = @_view_subdir
148
+ template = [subdir, template]
149
+ end
150
+
151
+ super
152
+ end
153
+ end
154
+
127
155
  # If view options or locals have been set and this
128
156
  # template isn't a layout template, merge the options
129
157
  # and locals into the returned hash.
@@ -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 = 21
7
+ RodaMinorVersion = 22
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
@@ -1,8 +1,10 @@
1
1
  require_relative "../spec_helper"
2
2
 
3
3
  begin
4
+ require 'tilt'
4
5
  require 'tilt/erb'
5
6
  require 'tilt/string'
7
+ require_relative '../../lib/roda/plugins/render'
6
8
  rescue LoadError
7
9
  warn "tilt not installed, skipping render plugin test"
8
10
  else
@@ -258,6 +260,162 @@ describe "render plugin" do
258
260
  app.render_opts[:views].must_equal File.join(Dir.pwd, 'bar')
259
261
  end
260
262
 
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')
275
+ end
276
+ end
277
+
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
+ app(:bare) do
291
+ plugin :render, :views=>'spec/views'
292
+ route do
293
+ render(:template=>template)
294
+ end
295
+ end
296
+
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
304
+ app::RodaCompiledTemplates.private_instance_methods.length.must_equal 0
305
+ end
306
+
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)
312
+ end
313
+ end
314
+
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
324
+
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)
332
+ end
333
+ end
334
+
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
348
+
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)
356
+ end
357
+ end
358
+
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)
378
+ end
379
+ end
380
+
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)
400
+ end
401
+ end
402
+
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
415
+ end
416
+ end
417
+ end
418
+
261
419
  it "inline layouts and inline views" do
262
420
  app(:render) do
263
421
  view({:inline=>'bar'}, :layout=>{:inline=>'Foo: <%= yield %>'})
@@ -21,12 +21,23 @@ describe "view_options plugin view subdirs" do
21
21
 
22
22
  r.on "about" do
23
23
  append_view_subdir 'views'
24
+ r.on 'test' do
25
+ append_view_subdir 'about'
26
+ r.is('view'){view("comp_test")}
27
+ r.is{render("comp_test")}
28
+ end
24
29
  render("about", :locals=>{:title => "About Roda"})
25
30
  end
26
31
 
27
32
  r.on "path" do
28
33
  render('spec/views/about', :locals=>{:title => "Path"}, :layout_opts=>{:locals=>{:title=>"Home"}})
29
34
  end
35
+
36
+ r.on 'test' do
37
+ set_view_subdir 'spec/views'
38
+ r.is('view'){view("comp_test")}
39
+ r.is{render("comp_test")}
40
+ end
30
41
  end
31
42
  end
32
43
  end
@@ -42,6 +53,22 @@ describe "view_options plugin view subdirs" do
42
53
  it "should not change behavior when subdir is not set" do
43
54
  body("/path").strip.must_equal "<h1>Path</h1>"
44
55
  end
56
+
57
+ it "should handle template compilation correctly" do
58
+ @app.plugin :render, :layout=>'./spec/views/comp_layout'
59
+ 3.times do
60
+ body("/test").strip.must_equal "ct"
61
+ body("/about/test").strip.must_equal "about-ct"
62
+ body("/test/view").strip.must_equal "act\nb"
63
+ body("/about/test/view").strip.must_equal "aabout-ct\nb"
64
+ end
65
+ if Roda::RodaPlugins::Render::COMPILED_METHOD_SUPPORT
66
+ method_cache = @app.opts[:render][:template_method_cache]
67
+ method_cache[['spec/views', 'comp_test']].must_be_kind_of(Symbol)
68
+ method_cache[['spec/views/about', 'comp_test']].must_be_kind_of(Symbol)
69
+ method_cache[:_roda_layout].must_be_kind_of(Symbol)
70
+ end
71
+ end
45
72
  end
46
73
 
47
74
  describe "view_options plugin" do
@@ -0,0 +1,2 @@
1
+ # a
2
+ # * b
@@ -0,0 +1 @@
1
+ about-ct
@@ -0,0 +1 @@
1
+ a<%= yield %>b
@@ -0,0 +1 @@
1
+ ct
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.21.0
4
+ version: 3.22.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-06-14 00:00:00.000000000 Z
11
+ date: 2019-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -218,6 +218,7 @@ extra_rdoc_files:
218
218
  - doc/release_notes/3.19.0.txt
219
219
  - doc/release_notes/3.20.0.txt
220
220
  - doc/release_notes/3.21.0.txt
221
+ - doc/release_notes/3.22.0.txt
221
222
  files:
222
223
  - CHANGELOG
223
224
  - MIT-LICENSE
@@ -275,6 +276,7 @@ files:
275
276
  - doc/release_notes/3.2.0.txt
276
277
  - doc/release_notes/3.20.0.txt
277
278
  - doc/release_notes/3.21.0.txt
279
+ - doc/release_notes/3.22.0.txt
278
280
  - doc/release_notes/3.3.0.txt
279
281
  - doc/release_notes/3.4.0.txt
280
282
  - doc/release_notes/3.5.0.txt
@@ -500,13 +502,17 @@ files:
500
502
  - spec/version_spec.rb
501
503
  - spec/views/_test.erb
502
504
  - spec/views/a.erb
505
+ - spec/views/a.rdoc
503
506
  - spec/views/about.erb
504
507
  - spec/views/about.str
505
508
  - spec/views/about/_test.css.gz
506
509
  - spec/views/about/_test.erb
507
510
  - spec/views/about/_test.erb.gz
511
+ - spec/views/about/comp_test.erb
508
512
  - spec/views/b.erb
509
513
  - spec/views/c.erb
514
+ - spec/views/comp_layout.erb
515
+ - spec/views/comp_test.erb
510
516
  - spec/views/content-yield.erb
511
517
  - spec/views/home.erb
512
518
  - spec/views/home.str