require 'addressable/template' module Juxt module Sinatra # Allows for declared, named URI Templates in Sinatra applications, # for both routing and URI generation. # # The URI generation method (included as a Sinatra helper) modifies # the path of generated URIs with request.script_name, meaning the # URIs generated will still be valid if multiple Sinatra applications # are hosted in the same application, using Rack::Builder. # # Requires Addressable (http://github.com/sporkmonger/addressable/tree/master). # # == Example # # class MyApplication < Sinatra::Base # extend Juxt::Sinatra::URITemplates # # uri :index, '/' # uri :entry, '/entries/{id}' # # get :index do # "Hello" # end # # get :entry do # "The URI of this entry is #{uri(:entry, 'id' => params[:id])}" # end # end module URITemplates def reset_uri_templates! @uri_templates = {} end # Declare a named URI Template for use in this application, and # in subclasses of this application. def uri(name, template) @uri_templates[name] = Addressable::Template.new(template) end # Gets the merged URI Template collection for this application, # and all superclasses. def uri_templates if superclass.respond_to?(:uri_templates) superclass.uri_templates.merge(@uri_templates) else @uri_templates end end private # Override Sinatra route compilation (dirty). def compile(path) super(uri_templates[path] || path) end def inherited(subclass) subclass.reset_uri_templates! super end # Initialize the URI Template collection for the application # being extended, and add a Sinatra helper for expanding # templates, by name. def self.extended(base) base.reset_uri_templates! base.helpers do def uri(name, *args) template = self.class.uri_templates[name] if template.nil? return nil end args[0] ||= {} uri = template.expand(*args) uri.path = request.script_name + uri.path uri end end end end end end