Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
A port of Framework One (FW/1) from CFML to Clojure
Clojure CSS
Tree: 67d9b1a9ee

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
examples/usermanager
src/framework
test
.gitignore
README.md
project.clj

README.md

FW/1 in Clojure

This is a port from CFML to Clojure of Framework One (FW/1).

FW/1 in Clojure is based on Ring and Enlive. FW/1 is a lightweight, convention-based MVC framework. Controller functions and views are automatically selected based on standard URL patterns - with site sections and items within each section. Layouts are applied, if provided, in a cascade from item to section to site.

The basic URL pattern is: /section/item/arg1/value1/arg2/value2?arg3=value3

The arg / value pairs from the URL are assembled into a map called the request context (and referred to as rc in the documentation).

The standard file structure for a FW/1 application is:

  • controllers/ - contains a .clj file for each section that needs business logic.
  • layouts/ - contains per-item, per-section and per-site layouts as needed.
  • views/ - contains a folder for each section, containing an HTML view for each item.

Controllers can have before(rc) and after(rc) handler functions that apply to all requests in a section.

A URL of /section/item will cause FW/1 to call:

  • controllers.section/before(rc), if defined.
  • controllers.section/item(rc), if defined.
  • controllers.section/after(rc), if defined.

A handler function should return the rc, updated as necessary.

Then FW/1 will look for an HTML view template:

  • views/section/item.html

If controllers.section/item-view(rc nodes) exists, FW/1 will call that as an Enlive transform on the view template. A view function should return the nodes, updated as necessary.

Then FW/1 looks for a cascade of layouts:

  • layouts/section/item.html, replacing an HTML element with the id "body" with the view, and then applying controllers.section/item-layout(rc nodes) as a transform, if it exists.
  • layouts/section.html, replacing an HTML element with the id "body" with the view so far, and then applying controllers.section/layout(rc nodes) as a transform, if it exists.
  • layouts/default.html, replacing an HTML element with the id "body" with the view so far, and then applying the function provided as the :layout element of the configuration as a transform, if it was specified.

Each of the layout functions should return the nodes, updated as necessary.

Any controller function also has access to the the FW/1 API:

  • redirect(rc url) - returns rc containing information to indicate a redirect to the specified url.
  • reload?(rc) - returns true if the current request includes URL parameters to force an application reload.
  • to-long(val) - converts val to a long, returning zero if it cannot be converted (values in rc come in as strings so this is useful when you need a number instead and zero can be a sentinel for "no value").

The following transforms from Enlive are exposed as aliases via the FW/1 API:

  • append, at, clone-for, content, do->, html-content, prepend, remove-class, set-attr, substitute

In addition FW/1 adds:

  • append-attr(attr v) - appends v to the value of the specified attribute attr (useful to append data to href links).

You can start the server on port 8080 with:

lein run -m usermanager.main

You can specify a different port like this:

PORT=8111 lein run -m usermanager.main

In fw1-test.core, the call to (fw1/start) can be passed a map of configuration parameters:

  • :application-key - the namespace prefix for the application, default none.
  • :default-section - the section used if none is present in the URL, default "main".
  • :default-item - the item used if none is present in the URL, default "default".
  • :home - the "section.item" pair used for the / URL, defaults to :default-section and :default-item values.
  • :password - specify a password for the application reload URL flag, default "secret" - see also :reload.
  • :reload - specify an rc key for the application reload URL flag, default :reload - see also :password.
  • :reload-application-on-every-request - boolean, whether to reload controller, view and layout components on every request (intended for development of applications).
  • :error - the action - "section.item" - to execute if an exception is thrown from the initial request, defaults to :default-section value and "error" [not yet implemented].
Something went wrong with that request. Please try again.