Skip to content
/ pine Public

ClojureScript routing for universal applications

License

Notifications You must be signed in to change notification settings

telekid/pine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

50 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pine

Note: Pine is pre-alpha software. Please don't use it in production.

Clojars Project CircleCI Last Released

For a proof-of-concept re-frame application that makes use of pine, see Pine App.

Overview

Pine is a ClojureScript router designed for universal applications.

Motivation

Traditional routers compare URLs against a set of route definitions, and return a single handler (or keyword) when they find a match.

Pine works a bit differently. Rather than returning a single match result, Pine returns a Clojure set containing the matched route, along with all of its ancestors.

Let's look at an example. Here's a code snippet that defines a few routes in Bidi and then matches against them:

;; define three routes
(def routes
  ["" {"/users" {"" :users
                 ["/" :id] {"" :user
                            "/delete" :delete-user}}}])
                            
;; match a few routes
user> (match-route "/users" routes)
{:handler :users}

user> (match-route "/users/123" routes)
{:handler :user :route-params {:id 123}}

user> (match-route "/users/123/delete" routes)
{:handler :delete-user :route-params {:id 123}}

Note that Bidi returns the :handler (a keyword in this case) and its associated :route-params.

Pine's match-route function returns some additional information:

;; define three routes
;; (note: this API is subject to change)
(def routes [{:route-id :users
              :test-path "/users"
              :routes [{:route-id :user
                        :test-path ["/" :id]
                        :routes [{:route-id :delete-user
                                  :test-path "/delete"}]}]}])

;; match a few routes
user> (match-route "/users" routes)
{:active #{:users}}
user> (match-route "/users/123" routes)
{:active #{:users :user} :params {:user {:id 123}}}
user> (match-route "/users" routes)
{:active #{:users :user :delete-user} :params {:user {:id 123}}}

Note that :active (Pine's equivalent of Bidi's :handler) contains a set of all active routes.

Why is this helpful?

Retaining ancestors makes certain tasks much easier:

  • Automatically showing / hiding components in your view tree based on the current route.
  • Conditionally styling links based upon the "active" status of their descendents (a la UI Router's ui-sref-active directive.)
  • Dispatching leave/retain/enter events when transitioning across route tree states.

...and more! I just haven't had a chance to write them all up yet.

Additional Features

  • Pine supports bi-directional routing. In other words, it can both generate URLs from an active route and its params, and return a set of active routes and params from a given URL.
  • Routes are defined in data, not code. In larger applications, it should be convenient to store them in an EDN file.

Inspiration

Pine borrows heavily from and is inspired by the amazing Bidi and UI Router libraries.