roda 3.31.0 → 3.32.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: 2d6d28c0f8b5197ab3d2a74726150921a435ccdcd8f18c6eb2c9bbe4d1cb2a14
4
- data.tar.gz: f1464284c0cb20638bc7575769271c6ea39642ff3b1842fad33b92759db915cd
3
+ metadata.gz: 2a342192f0ab697bea9c4e5b55669644f06fe16e161539b1efc3d10f3c6b9947
4
+ data.tar.gz: cf01944fe14494efd606cd892cbbbae5b5128f5a1d83c5e411bd4c64cc6e4321
5
5
  SHA512:
6
- metadata.gz: 4fca0abe3d0072e0a3e7201a089fd708610933ce4d461496bb0c13cbf7d84d2d10010c4007c460953972070d782742dba4d88799fd608f3df1ef7cca58cecef1
7
- data.tar.gz: 189a647f809aa732baebc225ea313c59e543d0d0935c8008a85084694161753e0939a7cac4c1f9d010e03785ec792d49b6c3e5643925066e1cda12d0b7701237
6
+ metadata.gz: e5de72f1385942855bd2c8e1c0f6be5187430d7d83112d7400bc573f045456a445166edfdbb6a7f70779c7b008745e8063bd44274b0111dec95643f87cfe12fe
7
+ data.tar.gz: b69e2fb41045d19c1f9e79dd2d1a87ca691fcd8de975bd34e37456cd6c5183cd2a6ad6bb59a07594527588d2903ef1bceea5f356a809aef03c01e5f64415246b
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ = 3.32.0 (2020-05-15)
2
+
3
+ * Make :dependencies option in assets plugin work correctly with render plugin template caching (jeremyevans) (#191)
4
+
5
+ * Support render method :dependencies option for specifying which files to check for modification (jgarth, jeremyevans) (#192)
6
+
7
+ * Add each_partial to the partials plugin for rendering a partial for each element in an enumerable (jeremyevans)
8
+
9
+ * Make render_each in render_each plugin handle template names with directories and extensions (jeremyevans)
10
+
1
11
  = 3.31.0 (2020-04-15)
2
12
 
3
13
  * Add :relative option to path method in path plugin, for generating a method returning relative paths (jeremyevans)
@@ -418,6 +418,10 @@ You can provide an array to specify multiple request methods and match on any of
418
418
  {method: :post} # matches POST
419
419
  {method: ['post', 'patch']} # matches POST and PATCH
420
420
 
421
+ === true
422
+
423
+ If +true+ is given directly as a matcher, it always matches.
424
+
421
425
  === false, nil
422
426
 
423
427
  If +false+ or +nil+ is given directly as a matcher, it doesn't match anything.
@@ -1,6 +1,6 @@
1
1
  = New Features
2
2
 
3
- * A relative_paths plugin has been added, adding a relative_path
3
+ * A relative_path plugin has been added, adding a relative_path
4
4
  method that will take an absolute path and make it relative to the
5
5
  current request by prepending an appropriate prefix. This is
6
6
  helpful when using Roda as a static site generator to generate a
@@ -0,0 +1,42 @@
1
+ = New Features
2
+
3
+ * render_each in the render_each plugin now automatically handles
4
+ template names with subdirectories and extensions. Previously, these
5
+ caused issues unless the :local option was provided. So now you
6
+ can use:
7
+
8
+ render_each(foos, "items/foo")
9
+
10
+ instead of:
11
+
12
+ render_each(foos, "items/foo", :local=>:foo)
13
+
14
+ * each_partial has been added to the partials plugin. It operates
15
+ similarly to render_each, but uses the convention for partial
16
+ template naming. So this:
17
+
18
+ each_partial(foos, "items/foo")
19
+
20
+ is the same as:
21
+
22
+ render_each(foos, "items/_foo", :local=>:foo)
23
+
24
+ = Other Improvements
25
+
26
+ * The :dependencies option in the assets plugin now works correctly
27
+ with compiled templates in the render plugin in uncached mode
28
+ (the default in development). Previously, modifying a dependency
29
+ file would not result in recompiling the asset template when
30
+ requesting the main file.
31
+
32
+ * Method visibility issues in the following plugins have been fixed:
33
+
34
+ * content_security_policy
35
+ * default_headers
36
+ * indifferent_params
37
+ * placeholder_string_matchers
38
+ * symbol_matchers
39
+
40
+ Previously, these plugins made private methods public by mistake
41
+ when overriding them. Additionally, Roda.freeze no longer changes
42
+ the visibility of the set_default_headers private method.
@@ -197,6 +197,8 @@ class Roda
197
197
  if instance_method(:set_default_headers).owner == ResponseMethods &&
198
198
  instance_method(:default_headers).owner == ResponseMethods
199
199
 
200
+ private
201
+
200
202
  def set_default_headers
201
203
  @headers['Content-Type'] ||= 'text/html'
202
204
  end
@@ -8,6 +8,8 @@ class Roda
8
8
  # using a regexp.
9
9
  module SymbolRegexpMatchers
10
10
  module RequestMethods
11
+ private
12
+
11
13
  # The regular expression to use for matching symbols. By default, any non-empty
12
14
  # segment matches.
13
15
  def _match_symbol_regexp(s)
@@ -405,6 +405,11 @@ class Roda
405
405
  opts[s] ||= {}
406
406
  end
407
407
 
408
+ expanded_deps = opts[:expanded_dependencies] = {}
409
+ opts[:dependencies].each do |file, deps|
410
+ expanded_deps[File.expand_path(file)] = Array(deps)
411
+ end
412
+
408
413
  if headers = opts[:headers]
409
414
  opts[:css_headers] = headers.merge(opts[:css_headers])
410
415
  opts[:js_headers] = headers.merge(opts[:js_headers])
@@ -412,7 +417,7 @@ class Roda
412
417
  opts[:css_headers]['Content-Type'] ||= "text/css; charset=UTF-8".freeze
413
418
  opts[:js_headers]['Content-Type'] ||= "application/javascript; charset=UTF-8".freeze
414
419
 
415
- [:css_headers, :js_headers, :css_opts, :js_opts, :dependencies].each do |s|
420
+ [:css_headers, :js_headers, :css_opts, :js_opts, :dependencies, :expanded_dependencies].each do |s|
416
421
  opts[s].freeze
417
422
  end
418
423
  [:headers, :css, :js].each do |s|
@@ -732,7 +737,7 @@ class Roda
732
737
  content = if file.end_with?(".#{type}")
733
738
  ::File.read(file)
734
739
  else
735
- render_asset_file(file, :template_opts=>o[:"#{type}_opts"])
740
+ render_asset_file(file, :template_opts=>o[:"#{type}_opts"], :dependencies=>o[:expanded_dependencies][file])
736
741
  end
737
742
 
738
743
  o[:postprocessor] ? o[:postprocessor].call(file, type, content) : content
@@ -762,7 +767,7 @@ class Roda
762
767
  # other files, check the modification times of all dependencies and
763
768
  # return the maximum.
764
769
  def asset_last_modified(file)
765
- if deps = self.class.assets_opts[:dependencies][file]
770
+ if deps = self.class.assets_opts[:expanded_dependencies][file]
766
771
  ([file] + Array(deps)).map{|f| ::File.stat(f).mtime}.max
767
772
  else
768
773
  ::File.stat(file).mtime
@@ -304,6 +304,8 @@ class Roda
304
304
  @content_security_policy ||= roda_class.opts[:content_security_policy].dup
305
305
  end
306
306
 
307
+ private
308
+
307
309
  # Set the appropriate content security policy header.
308
310
  def set_default_headers
309
311
  super
@@ -31,6 +31,8 @@ class Roda
31
31
  if owner == Base::ResponseMethods || (owner == response_class && app.opts[:set_default_headers_overridder] == response_class)
32
32
  app.opts[:set_default_headers_overridder] = response_class
33
33
  response_class.class_eval(<<-END, __FILE__, __LINE__+1)
34
+ private
35
+
34
36
  def set_default_headers
35
37
  h = @headers
36
38
  #{headers.map{|k,v| "h[#{k.inspect}] ||= #{v.inspect}"}.join('; ')}
@@ -8,7 +8,7 @@ class Roda
8
8
  #
9
9
  # class App < Roda
10
10
  # hash_matcher(:foo) do |v|
11
- # self['foo'] == v
11
+ # params['foo'] == v
12
12
  # end
13
13
  #
14
14
  # route do
@@ -64,6 +64,8 @@ class Roda
64
64
  module RequestMethods
65
65
  QUERY_PARSER = Rack::Utils.default_query_parser = QueryParser.new(QueryParser::Params, 65536, 100)
66
66
 
67
+ private
68
+
67
69
  def query_parser
68
70
  QUERY_PARSER
69
71
  end
@@ -18,27 +18,54 @@ class Roda
18
18
  # render('_test')
19
19
  # render('dir/_test')
20
20
  #
21
- # Note that this plugin automatically loads the :render plugin.
21
+ # To render the same template once for each object in an enumerable,
22
+ # you can use the +render_partials+ method:
23
+ #
24
+ # each_partial([1,2,3], :foo) # uses _foo.erb
25
+ #
26
+ # This is basically equivalent to:
27
+ #
28
+ # render_each([1,2,3], "_foo", local: :foo)
29
+ #
30
+ # This plugin depends on the render and render_each plugins.
22
31
  module Partials
23
- # Depend on the render plugin, since this overrides
24
- # some of its methods.
32
+ # Depend on the render plugin, passing received options to it.
33
+ # Also depend on the render_each plugin.
25
34
  def self.load_dependencies(app, opts=OPTS)
26
35
  app.plugin :render, opts
36
+ app.plugin :render_each
27
37
  end
28
38
 
29
39
  module InstanceMethods
40
+ # For each object in the given enumerable, render the given
41
+ # template (prefixing the template filename with an underscore).
42
+ def each_partial(enum, template, opts=OPTS)
43
+ unless opts.has_key?(:local)
44
+ opts = Hash[opts]
45
+ opts[:local] = render_each_default_local(template)
46
+ end
47
+ render_each(enum, partial_template_name(template.to_s), opts)
48
+ end
49
+
30
50
  # Renders the given template without a layout, but
31
51
  # prefixes the template filename to use with an
32
52
  # underscore.
33
53
  def partial(template, opts=OPTS)
34
54
  opts = parse_template_opts(template, opts)
35
55
  if opts[:template]
36
- template = opts[:template].split('/')
37
- template[-1] = "_#{template[-1]}"
38
- opts[:template] = template.join('/')
56
+ opts[:template] = partial_template_name(opts[:template])
39
57
  end
40
58
  render_template(opts)
41
59
  end
60
+
61
+ private
62
+
63
+ # Prefix the template base filename with an underscore.
64
+ def partial_template_name(template)
65
+ segments = template.split('/')
66
+ segments[-1] = "_#{segments[-1]}"
67
+ segments.join('/')
68
+ end
42
69
  end
43
70
  end
44
71
 
@@ -27,6 +27,8 @@ class Roda
27
27
  end
28
28
 
29
29
  module RequestMethods
30
+ private
31
+
30
32
  def _match_string(str)
31
33
  if str.index(":")
32
34
  consume(self.class.cached_matcher(str){Regexp.escape(str).gsub(/:(\w+)/){|m| _match_symbol_regexp($1)}})
@@ -241,12 +241,13 @@ class Roda
241
241
  # template file has been modified. This is an internal class and
242
242
  # the API is subject to change at any time.
243
243
  class TemplateMtimeWrapper
244
- def initialize(template_class, path, *template_args)
244
+ def initialize(template_class, path, dependencies, *template_args)
245
245
  @template_class = template_class
246
246
  @path = path
247
247
  @template_args = template_args
248
+ @dependencies = ([path] + Array(dependencies)) if dependencies
248
249
 
249
- @mtime = (File.mtime(path) if File.file?(path))
250
+ @mtime = template_last_modified if File.file?(path)
250
251
  @template = template_class.new(path, *template_args)
251
252
  end
252
253
 
@@ -257,17 +258,28 @@ class Roda
257
258
  @template.render(*args, &block)
258
259
  end
259
260
 
261
+ # Return when the template was last modified. If the template depends on any
262
+ # other files, check the modification times of all dependencies and
263
+ # return the maximum.
264
+ def template_last_modified
265
+ if deps = @dependencies
266
+ deps.map{|f| File.mtime(f)}.max
267
+ else
268
+ File.mtime(@path)
269
+ end
270
+ end
271
+
260
272
  # If the template file has been updated, return true and update
261
273
  # the template object and the modification time. Other return false.
262
274
  def modified?
263
275
  begin
264
- mtime = File.mtime(path = @path)
276
+ mtime = template_last_modified
265
277
  rescue
266
278
  # ignore errors
267
279
  else
268
280
  if mtime != @mtime
269
281
  @mtime = mtime
270
- @template = @template_class.new(path, *@template_args)
282
+ @template = @template_class.new(@path, *@template_args)
271
283
  return true
272
284
  end
273
285
  end
@@ -576,7 +588,7 @@ class Roda
576
588
  !opts[:inline]
577
589
 
578
590
  if render_opts[:check_template_mtime] && !opts[:template_block] && !cache
579
- template = TemplateMtimeWrapper.new(opts[:template_class], opts[:path], 1, template_opts)
591
+ template = TemplateMtimeWrapper.new(opts[:template_class], opts[:path], opts[:dependencies], 1, template_opts)
580
592
 
581
593
  if define_compiled_method
582
594
  method_name = :"_roda_template_#{self.class.object_id}_#{method_cache_key}"
@@ -26,7 +26,9 @@ class Roda
26
26
  #
27
27
  # Will render the +foo+ template, but the local variable used inside
28
28
  # the template will be +bar+. You can use <tt>local: nil</tt> to
29
- # not set a local variable inside the template.
29
+ # not set a local variable inside the template. By default, the
30
+ # local variable name is based on the template name, with any
31
+ # directories and file extensions removed.
30
32
  module RenderEach
31
33
  # Load the render plugin before this plugin, since this plugin
32
34
  # calls the render method.
@@ -45,11 +47,11 @@ class Roda
45
47
  # set a local variable. If not set, uses the template name.
46
48
  def render_each(enum, template, opts=(no_opts = true; optimized_template = _cached_render_each_template_method(template); OPTS))
47
49
  if optimized_template
48
- return _optimized_render_each(enum, optimized_template, template.to_s.to_sym, {})
50
+ return _optimized_render_each(enum, optimized_template, render_each_default_local(template), {})
49
51
  elsif opts.has_key?(:local)
50
52
  as = opts[:local]
51
53
  else
52
- as = template.to_s.to_sym
54
+ as = render_each_default_local(template)
53
55
  if no_opts && optimized_template.nil? && (optimized_template = _optimized_render_method_for_locals(template, (locals = {as=>nil})))
54
56
  return _optimized_render_each(enum, optimized_template, as, locals)
55
57
  end
@@ -77,6 +79,12 @@ class Roda
77
79
 
78
80
  private
79
81
 
82
+ # The default local variable name to use for the template, if the :local option
83
+ # is not used when calling render_each.
84
+ def render_each_default_local(template)
85
+ File.basename(template.to_s).sub(/\..+\z/, '').to_sym
86
+ end
87
+
80
88
  if Render::COMPILED_METHOD_SUPPORT
81
89
  # If compiled method support is enabled in the render plugin, return the
82
90
  # method name to call to render the template. Return false if not given
@@ -6,7 +6,7 @@ class Roda
6
6
  # The symbol_matchers plugin allows you do define custom regexps to use
7
7
  # for specific symbols. For example, if you have a route such as:
8
8
  #
9
- # r.on :username do
9
+ # r.on :username do |username|
10
10
  # # ...
11
11
  # end
12
12
  #
@@ -28,7 +28,7 @@ class Roda
28
28
  # If the placeholder_string_matchers plugin is loaded, this feature also applies to
29
29
  # placeholders in strings, so the following:
30
30
  #
31
- # r.on "users/:username" do
31
+ # r.on "users/:username" do |username|
32
32
  # # ...
33
33
  # end
34
34
  #
@@ -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 = 31
7
+ RodaMinorVersion = 32
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
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.31.0
4
+ version: 3.32.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: 2020-04-15 00:00:00.000000000 Z
11
+ date: 2020-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -207,6 +207,7 @@ extra_rdoc_files:
207
207
  - doc/release_notes/3.29.0.txt
208
208
  - doc/release_notes/3.30.0.txt
209
209
  - doc/release_notes/3.31.0.txt
210
+ - doc/release_notes/3.32.0.txt
210
211
  files:
211
212
  - CHANGELOG
212
213
  - MIT-LICENSE
@@ -239,6 +240,7 @@ files:
239
240
  - doc/release_notes/3.3.0.txt
240
241
  - doc/release_notes/3.30.0.txt
241
242
  - doc/release_notes/3.31.0.txt
243
+ - doc/release_notes/3.32.0.txt
242
244
  - doc/release_notes/3.4.0.txt
243
245
  - doc/release_notes/3.5.0.txt
244
246
  - doc/release_notes/3.6.0.txt