class Roda
module RodaPlugins
# The path plugin adds support for named paths. Using the +path+ class method, you can
# easily create *_path instance methods for each named path. Those instance
# methods can then be called if you need to get the path for a form action, link,
# redirect, or anything else. Example:
#
# plugin :path
# path :foo, '/foo'
# path :bar do |bar|
# "/bar/#{bar.id}"
# end
#
# route do |r|
# r.post 'bar' do
# bar = Bar.create(r.params['bar'])
# r.redirect bar_path(bar)
# end
# end
#
# The path method accepts the following options:
#
# :add_script_name :: Prefix the path generated with SCRIPT_NAME.
# :name :: Provide a different name for the method, instead of using *_path.
# :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 *_url
# 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, this will also create a _*_path
# 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.
module Path
DEFAULT_PORTS = {'http' => 80, 'https' => 443}.freeze
OPTS = {}.freeze
module ClassMethods
# Create a new instance method for the named path. See plugin module documentation for options.
def path(name, path=nil, opts=OPTS, &block)
if path.is_a?(Hash)
raise RodaError, "cannot provide two option hashses to Roda.path" unless opts.empty?
opts = path
path = nil
end
raise RodaError, "cannot provide both path and block to Roda.path" if path && block
raise RodaError, "must provide either path or block to Roda.path" unless path || block
if path
path = path.dup.freeze
block = lambda{path}
end
meth = opts[:name] || "#{name}_path"
url = opts[:url]
add_script_name = opts[:add_script_name]
if add_script_name || url || opts[:url_only]
_meth = "_#{meth}"
define_method(_meth, &block)
end
unless opts[:url_only]
if add_script_name
define_method(meth) do |*a, &blk|
request.script_name.to_s + send(_meth, *a, &blk)
end
else
define_method(meth, &block)
end
end
if url || opts[:url_only]
url_meth = if url.is_a?(String) || url.is_a?(Symbol)
url
else
"#{name}_url"
end
url_block = lambda do |*a, &blk|
r = request
scheme = r.scheme
port = r.port
uri = ["#{scheme}://#{r.host}#{":#{port}" unless DEFAULT_PORTS[scheme] == port}"]
uri << request.script_name.to_s if add_script_name
uri << send(_meth, *a, &blk)
File.join(uri)
end
define_method(url_meth, &url_block)
end
nil
end
end
end
register_plugin(:path, Path)
end
end