lib/roda/plugins/path.rb in roda-3.17.0 vs lib/roda/plugins/path.rb in roda-3.18.0

- old
+ new

@@ -8,11 +8,11 @@ # methods can then be called if you need to get the path for a form action, link, # redirect, or anything else. # # Additionally, you can call the +path+ class method with a class and a block, and it will register # the class. You can then call the +path+ instance method with an instance of that class, and it will - # instance_exec the block with the arguments provided to path. + # execute the block in the context of the route block scope with the arguments provided to path. # # Example: # # plugin :path # path :foo, '/foo' @@ -58,23 +58,23 @@ # :url :: Create a url method in addition to the path method, which will prefix the string generated # with the appropriate scheme, host, and port. If true, creates a <tt>*_url</tt> # method. If a Symbol or String, uses the value as the url method name. # :url_only :: Do not create a path method, just a url method. # - # Note that if :add_script_name, :url, or :url_only is used, will also create a <tt>_*_path</tt> - # method. This is necessary in order to support path methods that accept blocks, as you can't pass - # a block to a block that is instance_execed. + # Note that if :add_script_name, :url, or :url_only is used, the path method will also create a + # <tt>_*_path</tt> private method. module Path DEFAULT_PORTS = {'http' => 80, 'https' => 443}.freeze # Initialize the path classes when loading the plugin. Options: # :by_name :: Register classes by name, which is friendlier when reloading code (defaults to # true in development mode) def self.configure(app, opts=OPTS) app.instance_eval do self.opts[:path_class_by_name] = opts.fetch(:by_name, ENV['RACK_ENV'] == 'development') self.opts[:path_classes] ||= {} + self.opts[:path_class_methods] ||= {} unless path_block(String) path(String){|str| str} end end end @@ -86,10 +86,11 @@ end # Freeze the path classes when freezing the app. def freeze path_classes.freeze + opts[:path_classes_methods].freeze super end # Create a new instance method for the named path. See plugin module documentation for options. def path(name, path=nil, opts=OPTS, &block) @@ -98,10 +99,11 @@ raise RodaError, "must provide a block when calling path with a class" unless block if self.opts[:path_class_by_name] name = name.name end path_classes[name] = block + self.opts[:path_class_methods][name] = define_roda_method("path_#{name}", :any, &block) return end if path.is_a?(Hash) raise RodaError, "cannot provide two option hashses to Roda.path" unless opts.empty? @@ -162,10 +164,11 @@ nil end # Return the block related to the given class, or nil if there is no block. def path_block(klass) + # RODA4: Remove if opts[:path_class_by_name] klass = klass.name end path_classes[klass] end @@ -173,17 +176,19 @@ module InstanceMethods # Return a path based on the class of the object. The object passed must have # had its class previously registered with the application. If the app's # :add_script_name option is true, this prepends the SCRIPT_NAME to the path. - def path(obj, *args) + def path(obj, *args, &block) app = self.class - unless blk = app.path_block(obj.class) + opts = app.opts + klass = opts[:path_class_by_name] ? obj.class.name : obj.class + unless meth = opts[:path_class_methods][klass] raise RodaError, "unrecognized object given to Roda#path: #{obj.inspect}" end - path = instance_exec(obj, *args, &blk) - path = request.script_name.to_s + path if app.opts[:add_script_name] + path = send(meth, obj, *args, &block) + path = request.script_name.to_s + path if opts[:add_script_name] path end end end