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