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