roda 3.20.0 → 3.21.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: bce3cf55fdec3d303d3d78b6e190046b38619e9ab296b63575962864535339e5
4
- data.tar.gz: 874904308a03694809bd777c406ed94e1cefcc11bb9d7e748dd860a22c853d18
3
+ metadata.gz: 34a644ccaa69bc1913eb1f54315437ce4b215bd5925e82f720d0fda007895224
4
+ data.tar.gz: 9a85847e46720f4fa2f7a050febd5b0f6ef7db528c8fbd09836113148944f87c
5
5
  SHA512:
6
- metadata.gz: 0c08ac192ce7a3609b968404e4a3bf232ad7d12d1e70ed3e0c3306fea13ddf91bbf746bff47ec746acfc3481c5bfbaed3d7916dbf44c88c9b7f4d8855be64358
7
- data.tar.gz: c3e6e9d50efc13dcd202379a76fef8ad6305c29f38954c8ed340ce7bd274b0ffe792cecb69a8ec0ea37aebc0d9fe1aeda16ea87d50f0f8892c1d805121f635ee
6
+ metadata.gz: 739c2a26ea80aeca2bbb4b3b51c4cabf93100309956fe594b61cc66a72f6d3e2f23ab0356c81f12e4a461bf82eb1d7f9cc2d0dc5fecbef88348bd17aca17c33a
7
+ data.tar.gz: 65ef8401849ee398968ccfce12ccbf203914f7a76721c8cb0ef31b5ab9051fd7f8460361dd96abb495dfa25c5acb50141611448b7065a5be3340b8ca51cc70ff
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ = 3.21.0 (2019-06-14)
2
+
3
+ * Cache compiled templates in development mode, until the template files are modified (jeremyevans)
4
+
1
5
  = 3.20.0 (2019-05-16)
2
6
 
3
7
  * Set Content-Length header to 0 for empty 205 responses (jeremyevans)
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ VERS = lambda do
7
7
  require_relative 'lib/roda/version'
8
8
  Roda::RodaVersion
9
9
  end
10
- CLEAN.include ["#{NAME}-*.gem", "rdoc", "coverage", "www/public/*.html", "www/public/rdoc", "spec/assets/app.*.css", "spec/assets/app.*.js", "spec/assets/app.*.css.gz", "spec/assets/app.*.js.gz"]
10
+ CLEAN.include ["#{NAME}-*.gem", "rdoc", "coverage", "www/public/*.html", "www/public/rdoc", "spec/assets/app.*.css", "spec/assets/app.*.js", "spec/assets/app.*.css.gz", "spec/assets/app.*.js.gz", "spec/iv.erb"]
11
11
 
12
12
  # Gem Packaging and Release
13
13
 
@@ -0,0 +1,5 @@
1
+ = Improvements
2
+
3
+ * View rendering speed is significantly improved in development mode
4
+ by caching file-based templates until there has been a modification
5
+ to the template file.
@@ -48,8 +48,11 @@ class Roda
48
48
  #
49
49
  # :allowed_paths :: Set the template paths to allow. Attempts to render paths outside
50
50
  # of this directory will raise an error. Defaults to the +:views+ directory.
51
- # :cache :: nil/false to disable template caching by default. By default, caching
52
- # is disabled by default if RACK_ENV is development.
51
+ # :cache :: nil/false to explicitly disable premanent template caching. By default, permanent
52
+ # template caching is disabled by default if RACK_ENV is development. When permanent
53
+ # template caching is disabled, for templates with paths in the file system, the
54
+ # modification time of the file will be checked on every render, and if it has changed,
55
+ # a new template will be created for the current content of the file.
53
56
  # :cache_class :: A class to use as the template cache instead of the default.
54
57
  # :check_paths :: Can be set to false to turn off template path checking.
55
58
  # :engine :: The tilt engine to use for rendering, also the default file extension for
@@ -83,7 +86,7 @@ class Roda
83
86
  #
84
87
  # :cache :: Set to false to not cache this template, even when
85
88
  # caching is on by default. Set to true to force caching for
86
- # this template, even when the default is to not cache (e.g.
89
+ # this template, even when the default is to not permantently cache (e.g.
87
90
  # when using the :template_block option).
88
91
  # :cache_key :: Explicitly set the hash key to use when caching.
89
92
  # :content :: Only respected by +view+, provides the content to render
@@ -152,11 +155,11 @@ class Roda
152
155
  opts[:allowed_paths] = opts[:allowed_paths].map{|f| app.expand_path(f, nil)}.uniq.freeze
153
156
  opts[:check_paths] = true unless opts.has_key?(:check_paths)
154
157
 
155
- unless opts.has_key?(:explicit_cache)
156
- opts[:explicit_cache] = if opts.fetch(:cache, true)
157
- ENV['RACK_ENV'] == 'development'
158
- else
158
+ unless opts.has_key?(:check_template_mtime)
159
+ opts[:check_template_mtime] = if opts[:cache] == false || opts[:explicit_cache]
159
160
  true
161
+ else
162
+ ENV['RACK_ENV'] == 'development'
160
163
  end
161
164
  end
162
165
 
@@ -211,6 +214,34 @@ class Roda
211
214
  opts.freeze
212
215
  end
213
216
 
217
+ # Wrapper object for the Tilt template, that checks the modified
218
+ # time of the template file, and rebuilds the template if the
219
+ # template file has been modified.
220
+ class TemplateMtimeWrapper
221
+ def initialize(template_class, path, *template_args)
222
+ @template_class = template_class
223
+ @path = path
224
+ @template_args = template_args
225
+
226
+ @mtime = (File.mtime(path) if File.file?(path))
227
+ @template = template_class.new(path, *template_args)
228
+ end
229
+
230
+ # If the template file exists and the modification time has
231
+ # changed, rebuild the template file, then call render on it.
232
+ def render(*args, &block)
233
+ if File.file?(path = @path)
234
+ mtime = File.mtime(path)
235
+ if mtime != @mtime
236
+ @mtime = mtime
237
+ @template = @template_class.new(path, *@template_args)
238
+ end
239
+ end
240
+
241
+ @template.render(*args, &block)
242
+ end
243
+ end
244
+
214
245
  module ClassMethods
215
246
  # Copy the rendering options into the subclass, duping
216
247
  # them as necessary to prevent changes in the subclass
@@ -268,7 +299,7 @@ class Roda
268
299
  # If caching templates, attempt to retrieve the template from the cache. Otherwise, just yield
269
300
  # to get the template.
270
301
  def cached_template(opts, &block)
271
- if (!render_opts[:explicit_cache] || opts[:cache]) && (key = opts[:cache_key])
302
+ if key = opts[:cache_key]
272
303
  cache = render_opts[:cache]
273
304
  unless template = cache[key]
274
305
  template = cache[key] = yield
@@ -335,7 +366,8 @@ class Roda
335
366
 
336
367
  # Retrieve the Tilt::Template object for the given template and opts.
337
368
  def retrieve_template(opts)
338
- unless opts[:cache_key] && opts[:cache] != false
369
+ cache = opts[:cache]
370
+ if !opts[:cache_key] || cache == false
339
371
  found_template_opts = opts = find_template(opts)
340
372
  end
341
373
  cached_template(opts) do
@@ -347,7 +379,12 @@ class Roda
347
379
  if current_template_opts = opts[:template_opts]
348
380
  template_opts = template_opts.merge(current_template_opts)
349
381
  end
350
- opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block])
382
+
383
+ if render_opts[:check_template_mtime] && !opts[:template_block] && !cache
384
+ TemplateMtimeWrapper.new(opts[:template_class], opts[:path], 1, template_opts)
385
+ else
386
+ opts[:template_class].new(opts[:path], 1, template_opts, &opts[:template_block])
387
+ end
351
388
  end
352
389
  end
353
390
 
@@ -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 = 20
7
+ RodaMinorVersion = 21
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
@@ -61,6 +61,66 @@ describe "render plugin" do
61
61
  end
62
62
  end
63
63
 
64
+ describe "render plugin" do
65
+ file = 'spec/iv.erb'
66
+ before do
67
+ File.binwrite(file, File.binread('spec/views/iv.erb'))
68
+ end
69
+ after do
70
+ File.delete(file) if File.file?(file)
71
+ end
72
+
73
+ [{:cache=>false}, {:explicit_cache=>true}, {:check_template_mtime=>true}].each do |cache_plugin_opts|
74
+ it "checks mtime if #{cache_plugin_opts} plugin option is used" do
75
+ app(:bare) do
76
+ plugin :render, {:views=>"./spec"}.merge!(cache_plugin_opts)
77
+
78
+ route do |r|
79
+ @a = 'a'
80
+ render('iv')
81
+ end
82
+ end
83
+
84
+ t = Time.now
85
+ body.strip.must_equal "a"
86
+
87
+ File.binwrite(file, File.binread(file) + "b")
88
+ File.utime(t, t+1, file)
89
+ body.gsub("\n", '').must_equal "ab"
90
+
91
+ File.binwrite(file, File.binread(file) + "c")
92
+ File.utime(t, t+2, file)
93
+ body.gsub("\n", '').must_equal "abc"
94
+
95
+ mtime = File.mtime(file)
96
+ File.binwrite(file, File.binread(file) + "d")
97
+ File.utime(t, mtime, file)
98
+ body.gsub("\n", '').must_equal "abc"
99
+
100
+ File.delete(file)
101
+ body.gsub("\n", '').must_equal "abc"
102
+ end
103
+ end
104
+
105
+ it "does not check mtime if :cache render option is used" do
106
+ app(:bare) do
107
+ plugin :render, :views=>"./spec", :cache=>false
108
+
109
+ route do |r|
110
+ @a = 'a'
111
+ render('iv', :cache=>true)
112
+ end
113
+ end
114
+
115
+ t = Time.now+1
116
+ body.strip.must_equal "a"
117
+
118
+ File.binwrite(file, File.binread(file) + "b")
119
+ File.utime(t, t+1, file)
120
+ body.gsub("\n", '').must_equal "a"
121
+ end
122
+ end
123
+
64
124
  describe "render plugin" do
65
125
  it "simple layout support" do
66
126
  app(:bare) do
@@ -322,13 +382,13 @@ describe "render plugin" do
322
382
  body('/c').must_equal "3"
323
383
  end
324
384
 
325
- it "Default to :explicit_cache=>true in development mode" do
385
+ it "Default to :check_template_mtime=>true in development mode" do
326
386
  with_rack_env('development') do
327
387
  app(:render){}
328
388
  end
329
- app.render_opts[:explicit_cache].must_equal true
389
+ app.render_opts[:check_template_mtime].must_equal true
330
390
  app(:render){}
331
- app.render_opts[:explicit_cache].must_equal false
391
+ app.render_opts[:check_template_mtime].must_equal false
332
392
  end
333
393
 
334
394
  it "Support :cache=>false plugin option to disable template caching by default, except :cache=>true method option is given" do
@@ -365,7 +425,7 @@ describe "render plugin" do
365
425
  body('/a').strip.must_equal "a"
366
426
  app.render_opts[:cache][File.expand_path('spec/views/iv.erb')].must_be_nil
367
427
  body('/b').strip.must_equal "a"
368
- app.render_opts[:cache][File.expand_path('spec/views/iv.erb')].wont_equal nil
428
+ app.render_opts[:cache][File.expand_path('spec/views/iv.erb')].wont_be_nil
369
429
  end
370
430
 
371
431
  it "Support :cache=>false option to disable template caching even when :cache_key is given" do
@@ -382,41 +442,28 @@ describe "render plugin" do
382
442
  body('/a').strip.must_equal "a"
383
443
  app.render_opts[:cache][:foo].must_be_nil
384
444
  body('/b').strip.must_equal "a"
385
- app.render_opts[:cache][:foo].wont_equal nil
445
+ app.render_opts[:cache][:foo].wont_be_nil
386
446
  end
387
447
 
388
- it "Support :explicit_cache option to disable caching by default, but still allow caching on a per-call basis" do
389
- app(:bare) do
390
- plugin :render, :views=>"./spec/views", :explicit_cache=>true
391
-
392
- route do |r|
393
- @a = 'a'
394
- r.is('a'){render('iv')}
395
- render('iv', :cache=>true)
396
- end
397
- end
398
-
399
- body('/a').strip.must_equal "a"
400
- app.render_opts[:cache][File.expand_path('spec/views/iv.erb')].must_be_nil
401
- body('/b').strip.must_equal "a"
402
- app.render_opts[:cache][File.expand_path('spec/views/iv.erb')].wont_equal nil
403
- end
448
+ [{}, {:cache=>true}].each do |cache_val_opts|
449
+ [{}, {:cache_key=>:foo}].each do |cache_key_opts|
450
+ cache_opts = cache_key_opts.merge(cache_val_opts)
451
+ it "Support :explicit_cache plugin option with #{cache_opts} render option" do
452
+ app(:bare) do
453
+ plugin :render, :views=>"./spec/views", :explicit_cache=>true
404
454
 
405
- it "Support :explicit_cache plugin option with :cache_key render option" do
406
- app(:bare) do
407
- plugin :render, :views=>"./spec/views", :explicit_cache=>true
455
+ route do |r|
456
+ @a = 'a'
457
+ render('iv', cache_opts)
458
+ end
459
+ end
408
460
 
409
- route do |r|
410
- @a = 'a'
411
- r.is('a'){render('iv', :cache_key=>:foo)}
412
- render('iv', :cache=>true, :cache_key=>:foo)
461
+ body('/a').strip.must_equal "a"
462
+ template = app.render_opts[:cache][cache_opts[:cache_key] || File.expand_path("spec/views/iv.erb")]
463
+ template.must_be_kind_of(cache_val_opts.empty? ? Roda::RodaPlugins::Render::TemplateMtimeWrapper : Tilt::Template)
464
+ body('/a').strip.must_equal "a"
413
465
  end
414
466
  end
415
-
416
- body('/a').strip.must_equal "a"
417
- app.render_opts[:cache][:foo].must_be_nil
418
- body('/b').strip.must_equal "a"
419
- app.render_opts[:cache][:foo].wont_equal nil
420
467
  end
421
468
 
422
469
  it "Support :cache=>true option to enable template caching when :template_block is used" do
@@ -445,7 +492,7 @@ describe "render plugin" do
445
492
  body('/a').strip.must_equal "iv-a"
446
493
  app.render_opts[:cache][['iv', c, nil, nil, proca]].must_be_nil
447
494
  body('/b').strip.must_equal "iv-a"
448
- app.render_opts[:cache][['iv', c, nil, nil, proca]].wont_equal nil
495
+ app.render_opts[:cache][['iv', c, nil, nil, proca]].wont_be_nil
449
496
  end
450
497
 
451
498
  it "Support :cache_key option to force the key used when caching, unless :cache=>false option is used" do
@@ -500,17 +547,17 @@ describe "render plugin" do
500
547
  c = Class.new(Roda)
501
548
  c.plugin :render
502
549
  cache = c.render_opts[:cache]
503
- c.render_opts[:explicit_cache].must_equal false
550
+ c.render_opts[:check_template_mtime].must_equal false
504
551
  c.plugin :render
505
552
  c.render_opts[:cache].must_be_same_as cache
506
- c.render_opts[:explicit_cache].must_equal false
553
+ c.render_opts[:check_template_mtime].must_equal false
507
554
 
508
555
  c.plugin :render, :cache=>false
509
556
  c.render_opts[:cache].must_be_same_as cache
510
- c.render_opts[:explicit_cache].must_equal true
557
+ c.render_opts[:check_template_mtime].must_equal true
511
558
  c.plugin :render
512
559
  c.render_opts[:cache].must_be_same_as cache
513
- c.render_opts[:explicit_cache].must_equal true
560
+ c.render_opts[:check_template_mtime].must_equal true
514
561
  end
515
562
 
516
563
  it "render plugin call should not override existing options" do
@@ -530,7 +577,7 @@ describe "render plugin" do
530
577
  end
531
578
 
532
579
  body("/inline").strip.must_equal "Hello Agent Smith"
533
- Class.new(app).render_opts[:cache][:a].must_be_nil
580
+ Class.new(app).render_opts[:check_template_mtime].must_equal true
534
581
  end
535
582
 
536
583
  it "with :check_paths=>true plugin option used" do
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.20.0
4
+ version: 3.21.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-05-16 00:00:00.000000000 Z
11
+ date: 2019-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -217,6 +217,7 @@ extra_rdoc_files:
217
217
  - doc/release_notes/3.18.0.txt
218
218
  - doc/release_notes/3.19.0.txt
219
219
  - doc/release_notes/3.20.0.txt
220
+ - doc/release_notes/3.21.0.txt
220
221
  files:
221
222
  - CHANGELOG
222
223
  - MIT-LICENSE
@@ -273,6 +274,7 @@ files:
273
274
  - doc/release_notes/3.19.0.txt
274
275
  - doc/release_notes/3.2.0.txt
275
276
  - doc/release_notes/3.20.0.txt
277
+ - doc/release_notes/3.21.0.txt
276
278
  - doc/release_notes/3.3.0.txt
277
279
  - doc/release_notes/3.4.0.txt
278
280
  - doc/release_notes/3.5.0.txt