lib/roda/plugins/path_rewriter.rb in roda-2.6.0 vs lib/roda/plugins/path_rewriter.rb in roda-2.7.0
- old
+ new
@@ -28,10 +28,18 @@
#
# rewrite_path /\A\/a\z/, '/b'
# # PATH_INFO '/a' => remaining_path '/b'
# # PATH_INFO '/a/c' => remaining_path '/a/c', no change
#
+ # Patterns can be rewritten dynamically by providing a block accepting a MatchData
+ # object and evaluating to the replacement.
+ #
+ # rewrite_path(/\A\/a/(\w+)/){|match| match[1].capitalize}
+ # # PATH_INFO '/a/moo' => remaining_path '/a/Moo'
+ # rewrite_path(/\A\/a/(\w+)/, :path_info => true){|match| match[1].capitalize}
+ # # PATH_INFO '/a/moo' => PATH_INFO '/a/Moo'
+ #
# All path rewrites are applied in order, so if a path is rewritten by one rewrite,
# it can be rewritten again by a later rewrite. Note that PATH_INFO rewrites are
# processed before remaining_path rewrites.
module PathRewriter
PATH_INFO = 'PATH_INFO'.freeze
@@ -52,27 +60,48 @@
super
end
# Record a path rewrite from path +was+ to path +is+. Options:
# :path_info :: Modify PATH_INFO, not just remaining path.
- def rewrite_path(was, is, opts=OPTS)
+ def rewrite_path(was, is = nil, opts=OPTS, &block)
+ if is.is_a? Hash
+ raise RodaError, "cannot provide two hashes to rewrite_path" unless opts.empty?
+ opts = is
+ is = nil
+ end
+
+ if block
+ raise RodaError, "cannot provide both block and string replacement to rewrite_path" if is
+ is = block
+ end
+
was = /\A#{Regexp.escape(was)}/ unless was.is_a?(Regexp)
array = @opts[opts[:path_info] ? :path_info_rewrites : :remaining_path_rewrites]
array << [was, is.dup.freeze].freeze
end
end
module RequestMethods
# Rewrite remaining_path and/or PATH_INFO based on the path rewrites.
def initialize(scope, env)
path_info = env[PATH_INFO]
- scope.class.opts[:path_info_rewrites].each do |was, is|
- path_info.sub!(was, is)
- end
+
+ rewrite_path(scope.class.opts[:path_info_rewrites], path_info)
super
remaining_path = @remaining_path = @remaining_path.dup
- scope.class.opts[:remaining_path_rewrites].each do |was, is|
- remaining_path.sub!(was, is)
+ rewrite_path(scope.class.opts[:remaining_path_rewrites], remaining_path)
+ end
+
+ private
+
+ # Rewrite the given path using the given replacements.
+ def rewrite_path(replacements, path)
+ replacements.each do |was, is|
+ if is.is_a?(Proc)
+ path.sub!(was){is.call($~)}
+ else
+ path.sub!(was, is)
+ end
end
end
end
end