roda 3.49.0 → 3.53.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: 2d3b9688bae8b0013acedfc6a5bcb45c374e0a73fd30e56985f0ebeee942ef8c
4
- data.tar.gz: acb8215250d1615f007a2ec01d2b6546376414d2fea23a4f2341af9efd951110
3
+ metadata.gz: 90bdf6d366ffc4bff40aa51721176291fadb80f56d7904965fe46a1385fe4172
4
+ data.tar.gz: ab1bea5320b4049e918ebb23d1b081c26d5401000f11b02c5f85a1e1b30899c3
5
5
  SHA512:
6
- metadata.gz: 3a5434bdcb6926d6c5e656c25b46e16b035ad54d74ed16bdc1cf46005b8ef605b3371a628cae52d65803064aa3d2eac8a56c2e8e1e55b6f3a82c04a74c636855
7
- data.tar.gz: 9dc3773fae04325373adb8a7a57d52166bb65c238b959999adf6f6f17a3be29fcdedcea677eeeaaa84f6a01b5accb4aff2594817165b8a77a45106a3d4a9dea3
6
+ metadata.gz: 13bc3beb138174dc8cadfc309458bd1821cbe8b6f80f1cb704752979bf085710181d5fd9df71a3cc1fba2be3b258721f36c8758e202961f9389f23b7555ee78b
7
+ data.tar.gz: 7129008315908bf7ebd6c0115cd8eb531a6357617a5f9ce3a0ffae3703a5cd68793af0d43ac4703752e280a5cc6090234b60640fe25384c4fa8aabe8e04b94af
data/CHANGELOG CHANGED
@@ -1,3 +1,37 @@
1
+ = 3.53.0 (2022-02-14)
2
+
3
+ * Make indifferent_params plugin support rack main branch (jeremyevans)
4
+
5
+ * Add additional_view_directories plugin, for checking multiple view directories for templates (jeremyevans) (#229)
6
+
7
+ = 3.52.0 (2022-01-14)
8
+
9
+ * Fix return value of Roda.freeze when multi_route plugin is used (jeremyevans) (#240)
10
+
11
+ * Use faster OpenSSL::Digest instead of Digest for assets plugin SRI support (jeremyevans)
12
+
13
+ * Drop development dependency on haml (jeremyevans)
14
+
15
+ * Make the path method in the path plugin handle blocks that accept keyword arguments in Ruby 3+ (adam12) (#227)
16
+
17
+ * Support typecast_params :date_parse_input_handler plugin option for handling input to date parsing methods (jeremyevans)
18
+
19
+ = 3.51.0 (2021-12-15)
20
+
21
+ * Avoid method redefinition warning in error_handler plugin in verbose warning mode (jeremyevans)
22
+
23
+ * Allow run in multi_run plugin to be called without an app to remove existing handler (jeremyevans)
24
+
25
+ * Allow route in named_routes plugin to be called without a block to remove existing handler (jeremyevans)
26
+
27
+ = 3.50.0 (2021-11-12)
28
+
29
+ * Add capture_erb plugin for capturing ERB template blocks, instead of injecting them into the template output (jeremyevans)
30
+
31
+ * Add inject_erb plugin for injecting content directly into ERB template output (jeremyevans)
32
+
33
+ * Allow hash_branch and hash_path in hash_routes plugin to be called without a block to remove existing handler (jeremyevans)
34
+
1
35
  = 3.49.0 (2021-10-13)
2
36
 
3
37
  * Switch block_given? to defined?(yield) (jeremyevans)
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014-2021 Jeremy Evans
1
+ Copyright (c) 2014-2022 Jeremy Evans
2
2
  Copyright (c) 2010-2014 Michel Martens, Damian Janowski and Cyril David
3
3
  Copyright (c) 2008-2009 Christian Neukirchen
4
4
 
data/README.rdoc CHANGED
@@ -12,7 +12,8 @@ maintainable web applications in ruby.
12
12
  Website :: http://roda.jeremyevans.net
13
13
  Source :: http://github.com/jeremyevans/roda
14
14
  Bugs :: http://github.com/jeremyevans/roda/issues
15
- Google Group :: http://groups.google.com/group/ruby-roda
15
+ Discussion Forum (GitHub Discussions) :: https://github.com/jeremyevans/roda/discussions
16
+ Alternate Discussion Forum (Google Group) :: http://groups.google.com/group/ruby-roda
16
17
 
17
18
  == Goals
18
19
 
@@ -0,0 +1,21 @@
1
+ = New Features
2
+
3
+ * An inject_erb plugin has been added, adding an inject_erb method
4
+ that allows for injecting content directly into the template output
5
+ for the template currently being rendered. This allows you to more
6
+ easily wrap blocks in templates, by calling methods that accept
7
+ template blocks and injecting content before and after the block.
8
+
9
+ * A capture_erb plugin has been added, adding a capture_erb method
10
+ for capturing a template block in an erb template and returning
11
+ the content appended during the block as a string, instead of
12
+ having the content of the template block be included directly into
13
+ the template output. This can be combined with the inject_erb
14
+ plugin to inject modified versions of captured blocks into template
15
+ output.
16
+
17
+ * The hash_routes plugin now allows calling hash_branch and hash_path
18
+ without a block in order to remove the existing route handler. This
19
+ is designed to be used with code reloading libraries, so that if a
20
+ route file is deleted, the related hash branches/paths are also
21
+ removed, without having to reload all route files.
@@ -0,0 +1,20 @@
1
+ = New Features
2
+
3
+ * The named_routes plugin now allows calling route without a block
4
+ to remove the existing route handler. The multi_run plugin
5
+ now allows calling run without an app to remove an existing handler.
6
+ These changes are designed to better support code reloading
7
+ libraries, so that if the related file is deleted, the related
8
+ handlers are also removed, without having to reload the entire
9
+ application.
10
+
11
+ = Other Improvements
12
+
13
+ * The error_handler plugin now avoids a method redefinition warning
14
+ in verbose warning mode.
15
+
16
+ = Other
17
+
18
+ * Roda's primary discussion forum is now GitHub Discussions. The
19
+ ruby-roda Google Group is still available for users who would
20
+ prefer to use that instead.
@@ -0,0 +1,20 @@
1
+ = New Features
2
+
3
+ * The typecast_params plugin now supports a :date_parse_input_handler
4
+ option that will be called with all input that will be passed to
5
+ the date parsing methods. You can use this option to automatically
6
+ truncate input, if that is perferable to raising an error (which is
7
+ how recent versions of Ruby handle too-long input).
8
+
9
+ = Other Improvements
10
+
11
+ * The path helper methods added by the path plugin now support
12
+ blocks that use keyword arguments on Ruby 3+.
13
+
14
+ * The assets plugin now uses OpenSSL::Digest instead of Digest (if
15
+ available) for calculating SRI digests. This is faster on Ruby 3+,
16
+ where Digest no longer uses the faster OpenSSL::Digest automatically
17
+ if available.
18
+
19
+ * Roda.freeze now returns self when the multi_route plugin is used.
20
+ This was broken (not returning self) starting in 3.48.0.
@@ -0,0 +1,14 @@
1
+ = New Features
2
+
3
+ * An additional_view_directories plugin has been added, which allows
4
+ you to specify additional directories to look in for templates.
5
+ If the template path does not exist when using the default view
6
+ directory, then each additional view directory will be checked,
7
+ returning the first path that exists:
8
+
9
+ plugin :additional_view_directories, ['admin_views', 'public_views']
10
+
11
+ = Other Improvements
12
+
13
+ * The indifferent_params plugin now avoids a deprecation warning when
14
+ using the rack main branch, which will become Rack 3.
@@ -0,0 +1,68 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The additional_view_directories plugin allows for specifying additional view
7
+ # directories to look in for templates. When rendering a template, it will
8
+ # first try the :views directory specified in the render plugin. If the template
9
+ # file to be rendered does not exist in that directory, it will try each additional
10
+ # view directory specified in this plugin, in order, using the path to the first
11
+ # template file that exists in the file system. If no such path is found, it
12
+ # uses the default path specified by the render plugin.
13
+ #
14
+ # Example:
15
+ #
16
+ # plugin :render, :views=>'dir'
17
+ # plugin :additional_view_directories, ['dir1', 'dir2', 'dir3']
18
+ #
19
+ # route do |r|
20
+ # # Will check the following in order, using path for first
21
+ # # template file that exists:
22
+ # # * dir/t.erb
23
+ # # * dir1/t.erb
24
+ # # * dir2/t.erb
25
+ # # * dir3/t.erb
26
+ # render :t
27
+ # end
28
+ module AdditionalViewDirectories
29
+ # Depend on the render plugin, since this plugin only makes
30
+ # sense when the render plugin is used.
31
+ def self.load_dependencies(app, view_dirs)
32
+ app.plugin :render
33
+ end
34
+
35
+ # Set the additional view directories to look in. Each additional view directory
36
+ # is also added as an allowed path.
37
+ def self.configure(app, view_dirs)
38
+ view_dirs = app.opts[:additional_view_directories] = view_dirs.map{|f| app.expand_path(f, nil)}.freeze
39
+ opts = app.opts[:render]
40
+ app.opts[:render] = opts.merge(:allowed_paths=>(opts[:allowed_paths] + view_dirs).uniq.freeze)
41
+ opts.freeze
42
+ end
43
+
44
+ module InstanceMethods
45
+ private
46
+
47
+ # If the template path does not exist, try looking for the template
48
+ # in each of the additional view directories, in order, returning
49
+ # the first path that exists. If no additional directory includes
50
+ # the template, return the original path.
51
+ def template_path(opts)
52
+ orig_path = super
53
+
54
+ unless File.file?(orig_path)
55
+ self.opts[:additional_view_directories].each do |view_dir|
56
+ path = super(opts.merge(:views=>view_dir))
57
+ return path if File.file?(path)
58
+ end
59
+ end
60
+
61
+ orig_path
62
+ end
63
+ end
64
+ end
65
+
66
+ register_plugin(:additional_view_directories, AdditionalViewDirectories)
67
+ end
68
+ end
@@ -641,9 +641,17 @@ class Roda
641
641
  # a different digest type or to return a static string if you don't
642
642
  # want to use a unique value.
643
643
  def asset_digest(content)
644
- require 'digest/sha2'
645
644
  algo = assets_opts[:sri] || :sha256
646
- ::Digest.const_get(algo.to_s.upcase).hexdigest(content)
645
+ digest = begin
646
+ require 'openssl'
647
+ ::OpenSSL::Digest
648
+ # :nocov:
649
+ rescue LoadError
650
+ require 'digest/sha2'
651
+ ::Digest
652
+ # :nocov:
653
+ end
654
+ digest.const_get(algo.to_s.upcase).hexdigest(content)
647
655
  end
648
656
  end
649
657
 
@@ -0,0 +1,41 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The capture_erb plugin allows you to capture the content of a block
7
+ # in an ERB template, and return it as a value, instead of
8
+ # injecting the template block into the template output.
9
+ #
10
+ # <% value = capture_erb do %>
11
+ # Some content here.
12
+ # <% end %>
13
+ #
14
+ # +capture_erb+ can be used inside other methods that are called
15
+ # inside templates. It can be combined with the inject_erb plugin
16
+ # to wrap template blocks with arbitrary output and then inject the
17
+ # wrapped output into the template.
18
+ module CaptureERB
19
+ def self.load_dependencies(app)
20
+ app.plugin :render
21
+ end
22
+
23
+ module InstanceMethods
24
+ # Temporarily replace the ERB output buffer
25
+ # with an empty string, and then yield to the block.
26
+ # Return the value of the block, converted to a string.
27
+ # Restore the previous ERB output buffer before returning.
28
+ def capture_erb
29
+ outvar = render_opts[:template_opts][:outvar]
30
+ buf_was = instance_variable_get(outvar)
31
+ instance_variable_set(outvar, String.new)
32
+ yield.to_s
33
+ ensure
34
+ instance_variable_set(outvar, buf_was) if outvar && buf_was
35
+ end
36
+ end
37
+ end
38
+
39
+ register_plugin(:capture_erb, CaptureERB)
40
+ end
41
+ end
@@ -55,10 +55,10 @@ class Roda
55
55
  #
56
56
  # plugin :content_for, append: false
57
57
  module ContentFor
58
- # Depend on the render plugin, since this plugin only makes
59
- # sense when the render plugin is used.
58
+ # Depend on the capture_erb plugin, since it uses capture_erb
59
+ # to capture the content.
60
60
  def self.load_dependencies(app, _opts = OPTS)
61
- app.plugin :render
61
+ app.plugin :capture_erb
62
62
  end
63
63
 
64
64
  # Configure whether to append or overwrite if content_for
@@ -72,18 +72,12 @@ class Roda
72
72
  # under the given key. If called without a block, retrieve
73
73
  # stored content with the given key, or return nil if there
74
74
  # is no content stored with that key.
75
- def content_for(key, value=nil)
75
+ def content_for(key, value=nil, &block)
76
76
  append = opts[:append_content_for]
77
77
 
78
- if defined?(yield) || value
79
- if defined?(yield)
80
- outvar = render_opts[:template_opts][:outvar]
81
- buf_was = instance_variable_get(outvar)
82
-
83
- # Use temporary output buffer for ERB-based rendering systems
84
- instance_variable_set(outvar, String.new)
85
- value = yield.to_s
86
- instance_variable_set(outvar, buf_was)
78
+ if block || value
79
+ if block
80
+ value = capture_erb(&block)
87
81
  end
88
82
 
89
83
  @_content_for ||= {}
@@ -62,6 +62,7 @@ class Roda
62
62
  # the exception in the scope of the Roda instance.
63
63
  def error(&block)
64
64
  define_method(:handle_error, &block)
65
+ alias_method(:handle_error, :handle_error)
65
66
  private :handle_error
66
67
  end
67
68
  end
@@ -394,20 +394,32 @@ class Roda
394
394
  dsl
395
395
  end
396
396
 
397
- # Add branch handler for the given namespace and segment.
397
+ # Add branch handler for the given namespace and segment. If called without
398
+ # a block, removes the existing branch handler if it exists.
398
399
  def hash_branch(namespace='', segment, &block)
399
400
  segment = "/#{segment}"
400
401
  routes = opts[:hash_branches][namespace] ||= {}
401
- routes[segment] = define_roda_method(routes[segment] || "hash_branch_#{namespace}_#{segment}", 1, &convert_route_block(block))
402
+ if block
403
+ routes[segment] = define_roda_method(routes[segment] || "hash_branch_#{namespace}_#{segment}", 1, &convert_route_block(block))
404
+ elsif meth = routes[segment]
405
+ routes.delete(segment)
406
+ remove_method(meth)
407
+ end
402
408
  end
403
409
 
404
410
  # Add path handler for the given namespace and path. When the
405
411
  # r.hash_paths method is called, checks the matching namespace
406
412
  # for the full remaining path, and dispatch to that block if
407
- # there is one.
413
+ # there is one. If called without a block, removes the existing
414
+ # path handler if it exists.
408
415
  def hash_path(namespace='', path, &block)
409
416
  routes = opts[:hash_paths][namespace] ||= {}
410
- routes[path] = define_roda_method(routes[path] || "hash_path_#{namespace}_#{path}", 1, &convert_route_block(block))
417
+ if block
418
+ routes[path] = define_roda_method(routes[path] || "hash_path_#{namespace}_#{path}", 1, &convert_route_block(block))
419
+ elsif meth = routes[path]
420
+ routes.delete(path)
421
+ remove_method(meth)
422
+ end
411
423
  end
412
424
  end
413
425
 
@@ -52,17 +52,29 @@ class Roda
52
52
  end
53
53
 
54
54
  class Params < Rack::QueryParser::Params
55
- def initialize(limit = Rack::Utils.key_space_limit)
56
- @limit = limit
57
- @size = 0
58
- @params = Hash.new(&INDIFFERENT_PROC)
55
+ # :nocov:
56
+ if Rack.release >= '2.3'
57
+ def initialize
58
+ @size = 0
59
+ @params = Hash.new(&INDIFFERENT_PROC)
60
+ end
61
+ else
62
+ # :nocov:
63
+ def initialize(limit = Rack::Utils.key_space_limit)
64
+ @limit = limit
65
+ @size = 0
66
+ @params = Hash.new(&INDIFFERENT_PROC)
67
+ end
59
68
  end
60
69
  end
61
70
 
62
71
  end
63
72
 
64
73
  module RequestMethods
65
- QUERY_PARSER = Rack::Utils.default_query_parser = QueryParser.new(QueryParser::Params, 65536, 100)
74
+ # :nocov:
75
+ query_parser = Rack.release >= '2.3' ? QueryParser.new(QueryParser::Params, 32) : QueryParser.new(QueryParser::Params, 65536, 32)
76
+ # :nocov:
77
+ QUERY_PARSER = Rack::Utils.default_query_parser = query_parser
66
78
 
67
79
  private
68
80
 
@@ -0,0 +1,33 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The inject_erb plugin allows you to inject content directly
7
+ # into the template output:
8
+ #
9
+ # <% inject_erb("Some HTML Here") %>
10
+ #
11
+ # This will inject <tt>Some HTML Here</tt> into the template output,
12
+ # even though the tag being used is <tt><%</tt> and not <tt><%=</tt>.
13
+ #
14
+ # This method can be used inside methods, such as to wrap calls to
15
+ # methods that accept template blocks, to inject code before and after
16
+ # the template blocks.
17
+ module InjectERB
18
+ def self.load_dependencies(app)
19
+ app.plugin :render
20
+ end
21
+
22
+ module InstanceMethods
23
+ # Inject into the template output for the template currently being
24
+ # rendered.
25
+ def inject_erb(value)
26
+ instance_variable_get(render_opts[:template_opts][:outvar]) << value.to_s
27
+ end
28
+ end
29
+ end
30
+
31
+ register_plugin(:inject_erb, InjectERB)
32
+ end
33
+ end
@@ -98,6 +98,7 @@ class Roda
98
98
  self::RodaRequest.named_route_regexp(k)
99
99
  end
100
100
  self::RodaRequest.instance_variable_get(:@namespaced_route_regexps).freeze
101
+ self
101
102
  end
102
103
 
103
104
  # Copy the named routes into the subclass when inheriting.
@@ -45,6 +45,9 @@ class Roda
45
45
  # subtrees, multi_run is a better approach, but it does not let you set instance
46
46
  # variables in the main Roda app and have those instance variables usable in
47
47
  # the routing subtrees.
48
+ #
49
+ # To handle development environments that reload code, you can call the
50
+ # +run+ class method without an app to remove dispatching for the prefix.
48
51
  module MultiRun
49
52
  # Initialize the storage for the dispatched applications
50
53
  def self.configure(app)
@@ -67,8 +70,12 @@ class Roda
67
70
 
68
71
  # Add a rack application to dispatch to for the given prefix when
69
72
  # r.multi_run is called.
70
- def run(prefix, app)
71
- multi_run_apps[prefix.to_s] = app
73
+ def run(prefix, app=nil)
74
+ if app
75
+ multi_run_apps[prefix.to_s] = app
76
+ else
77
+ multi_run_apps.delete(prefix.to_s)
78
+ end
72
79
  self::RodaRequest.refresh_multi_run_regexp!
73
80
  end
74
81
  end
@@ -38,6 +38,9 @@ class Roda
38
38
  # Note that in multi-threaded code, you should not attempt to add a
39
39
  # named route after accepting requests.
40
40
  #
41
+ # To handle development environments that reload code, you can call the
42
+ # +route+ class method without a block to remove an existing named route.
43
+ #
41
44
  # == Routing Files
42
45
  #
43
46
  # The convention when using the named_routes plugin is to have a single
@@ -124,7 +127,7 @@ class Roda
124
127
  # The names for the currently stored named routes
125
128
  def named_routes(namespace=nil)
126
129
  unless routes = opts[:namespaced_routes][namespace]
127
- raise RodaError, "unsupported multi_route namespace used: #{namespace.inspect}"
130
+ raise RodaError, "unsupported named_routes namespace used: #{namespace.inspect}"
128
131
  end
129
132
  routes.keys
130
133
  end
@@ -140,7 +143,12 @@ class Roda
140
143
  def route(name=nil, namespace=nil, &block)
141
144
  if name
142
145
  routes = opts[:namespaced_routes][namespace] ||= {}
143
- routes[name] = define_roda_method(routes[name] || "multi_route_#{namespace}_#{name}", 1, &convert_route_block(block))
146
+ if block
147
+ routes[name] = define_roda_method(routes[name] || "named_routes_#{namespace}_#{name}", 1, &convert_route_block(block))
148
+ elsif meth = routes[name]
149
+ routes.delete(name)
150
+ remove_method(meth)
151
+ end
144
152
  else
145
153
  super(&block)
146
154
  end
@@ -41,12 +41,12 @@ class Roda
41
41
  # end
42
42
  #
43
43
  # r.post 'baz' do
44
- # bar = Baz[1]
44
+ # baz = Baz[1]
45
45
  # r.redirect path(baz, 'c', 'd') # /baz/1/c/d
46
46
  # end
47
47
  #
48
48
  # r.post 'quux' do
49
- # bar = Quux[1]
49
+ # quux = Quux[1]
50
50
  # r.redirect url(quux, '/bar') # http://example.com/quux/1/bar
51
51
  # end
52
52
  # end
@@ -148,11 +148,17 @@ class Roda
148
148
  # Allow calling private _method to get path
149
149
  relative_path(request.script_name.to_s + send(_meth, *a, &blk))
150
150
  end
151
+ # :nocov:
152
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
153
+ # :nocov:
151
154
  elsif add_script_name
152
155
  define_method(meth) do |*a, &blk|
153
156
  # Allow calling private _method to get path
154
157
  request.script_name.to_s + send(_meth, *a, &blk)
155
158
  end
159
+ # :nocov:
160
+ ruby2_keywords(meth) if respond_to?(:ruby2_keywords, true)
161
+ # :nocov:
156
162
  else
157
163
  define_method(meth, &block)
158
164
  end
@@ -171,6 +177,9 @@ class Roda
171
177
  end
172
178
 
173
179
  define_method(url_meth, &url_block)
180
+ # :nocov:
181
+ ruby2_keywords(url_meth) if respond_to?(:ruby2_keywords, true)
182
+ # :nocov:
174
183
  end
175
184
 
176
185
  nil
@@ -47,7 +47,7 @@ class Roda
47
47
  # The following plugin options are supported:
48
48
  #
49
49
  # :allowed_paths :: Set the template paths to allow. Attempts to render paths outside
50
- # of this directory will raise an error. Defaults to the +:views+ directory.
50
+ # of these paths will raise an error. Defaults to the +:views+ directory.
51
51
  # :cache :: nil/false to explicitly disable premanent template caching. By default, permanent
52
52
  # template caching is disabled by default if RACK_ENV is development. When permanent
53
53
  # template caching is disabled, for templates with paths in the file system, the
@@ -59,9 +59,9 @@ class Roda
59
59
  # templates, defaults to 'erb'.
60
60
  # :escape :: Use Erubi as the ERB template engine, and enable escaping by default,
61
61
  # which makes <tt><%= %></tt> escape output and <tt><%== %></tt> not escape output.
62
- # If given, sets the <tt>:escape=>true</tt> option for all template engines, which
62
+ # If given, sets the <tt>escape: true</tt> option for all template engines, which
63
63
  # can break some non-ERB template engines. You can use a string or array of strings
64
- # as the value for this option to only set the <tt>:escape=>true</tt> option for those
64
+ # as the value for this option to only set the <tt>escape: true</tt> option for those
65
65
  # specific template engines.
66
66
  # :layout :: The base name of the layout file, defaults to 'layout'. This can be provided as a hash
67
67
  # with the :template or :inline options.
@@ -130,6 +130,84 @@ class Roda
130
130
  # only argument, you can speed things up by specifying a +:cache_key+ option in
131
131
  # the hash, making sure the +:cache_key+ is unique to the template you are
132
132
  # rendering.
133
+ #
134
+ # = Accepting Template Blocks in Methods
135
+ #
136
+ # If you are used to Rails, you may be surprised that this type of template code
137
+ # doesn't work in Roda:
138
+ #
139
+ # <%= some_method do %>
140
+ # Some HTML
141
+ # <% end %>
142
+ #
143
+ # The reason this doesn't work is that this is not valid ERB syntax, it is Rails syntax,
144
+ # and requires attempting to parse the <tt>some_method do</tt> Ruby code with a regular
145
+ # expression. Since Roda uses ERB syntax, it does not support this.
146
+ #
147
+ # In general, these methods are used to wrap the content of the block and
148
+ # inject the content into the output. To get similar behavior with Roda, you have
149
+ # a few different options you can use.
150
+ #
151
+ # == Directly Inject Template Output
152
+ #
153
+ # You can switch from a <tt><%=</tt> tag to using a <tt><%</tt> tag:
154
+ #
155
+ # <% some_method do %>
156
+ # Some HTML
157
+ # <% end %>
158
+ #
159
+ # While this would output <tt>Some HTML</tt> into the template, it would not be able
160
+ # to inject content before or after the block. However, you can use the inject_erb_plugin
161
+ # to handle the injection:
162
+ #
163
+ # def some_method
164
+ # inject_erb "content before block"
165
+ # yield
166
+ # inject_erb "content after block"
167
+ # end
168
+ #
169
+ # If you need to modify the captured block before injecting it, you can use the
170
+ # capture_erb plugin to capture content from the template block, and modify that content,
171
+ # then use inject_erb to inject it into the template output:
172
+ #
173
+ # def some_method(&block)
174
+ # inject_erb "content before block"
175
+ # inject_erb capture_erb(&block).upcase
176
+ # inject_erb "content after block"
177
+ # end
178
+ #
179
+ # This is the recommended approach for handling this type of method, if you want to keep
180
+ # the template block in the same template.
181
+ #
182
+ # == Separate Block Output Into Separate Template
183
+ #
184
+ # By moving the <tt>Some HTML</tt> into a separate template, you can render that
185
+ # template inside the block:
186
+ #
187
+ # <%= some_method{render('template_name')} %>
188
+ #
189
+ # It's also possible to use an inline template:
190
+ #
191
+ # <%= some_method do render(:inline=><<-END)
192
+ # Some HTML
193
+ # END
194
+ # end %>
195
+ #
196
+ # This approach is useful if it makes sense to separate the template block into its
197
+ # own template. You lose the ability to use local variable from outside the
198
+ # template block inside the template block with this approach.
199
+ #
200
+ # == Separate Header and Footer
201
+ #
202
+ # You can define two separate methods, one that outputs the content before the block,
203
+ # and one that outputs the content after the block, and use those instead of a single
204
+ # call:
205
+ #
206
+ # <%= some_method_before %>
207
+ # Some HTML
208
+ # <%= some_method_after %>
209
+ #
210
+ # This is the simplest option to setup, but it is fairly tedious to use.
133
211
  module Render
134
212
  # Support for using compiled methods directly requires Ruby 2.3 for the
135
213
  # method binding to work, and Tilt 1.2 for Tilt::Template#compiled_method.
@@ -6,8 +6,7 @@ class Roda
6
6
  # The status_303 plugin sets the default redirect status to be 303
7
7
  # rather than 302 when the request is not a GET and the
8
8
  # redirection occurs on an HTTP 1.1 connection as per RFC 7231.
9
- # The author knows of no cases where this actually matters in
10
- # practice.
9
+ # There are some frontend frameworks that require this behavior.
11
10
  #
12
11
  # Example:
13
12
  #
@@ -265,6 +265,23 @@ class Roda
265
265
  # If you would like to skip this check and allow null bytes in param string values,
266
266
  # you can do by passing the <tt>:allow_null_bytes</tt> option when loading the plugin.
267
267
  #
268
+ # You can use the :date_parse_input_handler option to specify custom handling of date
269
+ # parsing input. Modern versions of Ruby and the date gem internally raise if the input to
270
+ # date parsing methods is too large to prevent denial of service. If you are using an
271
+ # older version of Ruby, you can use this option to enforce the same check:
272
+ #
273
+ # plugin :typecast_params, date_parse_input_handler: proc {|string|
274
+ # raise ArgumentError, "too big" if string.bytesize > 128
275
+ # string
276
+ # }
277
+ #
278
+ # You can also use this option to modify the input, such as truncating it to the first
279
+ # 128 bytes:
280
+ #
281
+ # plugin :typecast_params, date_parse_input_handler: proc {|string|
282
+ # string.b[0, 128]
283
+ # }
284
+ #
268
285
  # By design, typecast_params only deals with string keys, it is not possible to use
269
286
  # symbol keys as arguments to the conversion methods and have them converted.
270
287
  module TypecastParams
@@ -384,6 +401,14 @@ class Roda
384
401
  end
385
402
  end
386
403
 
404
+ module DateParseInputHandler
405
+ # Pass input string to date parsing through handle_date_parse_input.
406
+ def _string_parse!(klass, v)
407
+ v = handle_date_parse_input(v)
408
+ super
409
+ end
410
+ end
411
+
387
412
  # Class handling conversion of submitted parameters to desired types.
388
413
  class Params
389
414
  # Handle conversions for the given type using the given block.
@@ -999,11 +1024,16 @@ class Roda
999
1024
  when ''
1000
1025
  nil
1001
1026
  when String
1002
- klass.parse(v)
1027
+ _string_parse!(klass, v)
1003
1028
  else
1004
1029
  raise Error, "unexpected value received: #{v.inspect}"
1005
1030
  end
1006
1031
  end
1032
+
1033
+ # Handle parsing for string values passed to parse!.
1034
+ def _string_parse!(klass, v)
1035
+ klass.parse(v)
1036
+ end
1007
1037
  end
1008
1038
 
1009
1039
  # Set application-specific Params subclass unless one has been set,
@@ -1019,6 +1049,14 @@ class Roda
1019
1049
  if opts[:allow_null_bytes]
1020
1050
  app::TypecastParams.send(:include, AllowNullByte)
1021
1051
  end
1052
+ if opts[:date_parse_input_handler]
1053
+ app::TypecastParams.class_eval do
1054
+ include DateParseInputHandler
1055
+ define_method(:handle_date_parse_input, &opts[:date_parse_input_handler])
1056
+ private :handle_date_parse_input
1057
+ alias handle_date_parse_input handle_date_parse_input
1058
+ end
1059
+ end
1022
1060
  end
1023
1061
 
1024
1062
  module ClassMethods
data/lib/roda/version.rb CHANGED
@@ -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 = 49
7
+ RodaMinorVersion = 53
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.49.0
4
+ version: 3.53.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: 2021-10-13 00:00:00.000000000 Z
11
+ date: 2022-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -94,20 +94,6 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: haml
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
97
  - !ruby/object:Gem::Dependency
112
98
  name: rack_csrf
113
99
  requirement: !ruby/object:Gem::Requirement
@@ -221,6 +207,10 @@ extra_rdoc_files:
221
207
  - doc/release_notes/3.48.0.txt
222
208
  - doc/release_notes/3.49.0.txt
223
209
  - doc/release_notes/3.5.0.txt
210
+ - doc/release_notes/3.50.0.txt
211
+ - doc/release_notes/3.51.0.txt
212
+ - doc/release_notes/3.52.0.txt
213
+ - doc/release_notes/3.53.0.txt
224
214
  - doc/release_notes/3.6.0.txt
225
215
  - doc/release_notes/3.7.0.txt
226
216
  - doc/release_notes/3.8.0.txt
@@ -277,6 +267,10 @@ files:
277
267
  - doc/release_notes/3.48.0.txt
278
268
  - doc/release_notes/3.49.0.txt
279
269
  - doc/release_notes/3.5.0.txt
270
+ - doc/release_notes/3.50.0.txt
271
+ - doc/release_notes/3.51.0.txt
272
+ - doc/release_notes/3.52.0.txt
273
+ - doc/release_notes/3.53.0.txt
280
274
  - doc/release_notes/3.6.0.txt
281
275
  - doc/release_notes/3.7.0.txt
282
276
  - doc/release_notes/3.8.0.txt
@@ -288,12 +282,14 @@ files:
288
282
  - lib/roda/plugins/_before_hook.rb
289
283
  - lib/roda/plugins/_optimized_matching.rb
290
284
  - lib/roda/plugins/_symbol_regexp_matchers.rb
285
+ - lib/roda/plugins/additional_view_directories.rb
291
286
  - lib/roda/plugins/all_verbs.rb
292
287
  - lib/roda/plugins/assets.rb
293
288
  - lib/roda/plugins/assets_preloading.rb
294
289
  - lib/roda/plugins/backtracking_array.rb
295
290
  - lib/roda/plugins/branch_locals.rb
296
291
  - lib/roda/plugins/caching.rb
292
+ - lib/roda/plugins/capture_erb.rb
297
293
  - lib/roda/plugins/chunked.rb
298
294
  - lib/roda/plugins/class_level_routing.rb
299
295
  - lib/roda/plugins/class_matchers.rb
@@ -329,6 +325,7 @@ files:
329
325
  - lib/roda/plugins/hooks.rb
330
326
  - lib/roda/plugins/host_authorization.rb
331
327
  - lib/roda/plugins/indifferent_params.rb
328
+ - lib/roda/plugins/inject_erb.rb
332
329
  - lib/roda/plugins/json.rb
333
330
  - lib/roda/plugins/json_parser.rb
334
331
  - lib/roda/plugins/mail_processor.rb
@@ -402,7 +399,7 @@ metadata:
402
399
  bug_tracker_uri: https://github.com/jeremyevans/roda/issues
403
400
  changelog_uri: http://roda.jeremyevans.net/rdoc/files/CHANGELOG.html
404
401
  documentation_uri: http://roda.jeremyevans.net/documentation.html
405
- mailing_list_uri: https://groups.google.com/forum/#!forum/ruby-roda
402
+ mailing_list_uri: https://github.com/jeremyevans/roda/discussions
406
403
  source_code_uri: https://github.com/jeremyevans/roda
407
404
  post_install_message:
408
405
  rdoc_options: []
@@ -419,7 +416,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
419
416
  - !ruby/object:Gem::Version
420
417
  version: '0'
421
418
  requirements: []
422
- rubygems_version: 3.2.22
419
+ rubygems_version: 3.3.3
423
420
  signing_key:
424
421
  specification_version: 4
425
422
  summary: Routing tree web toolkit