Noumenon

I did have a description of where the name Noumenon came from here, but it doesn't actually fit that well. Maybe I'll come up with a better reason for th name choice some day.

What is This Thing?

Noumenon is a web application based on Sinatra for constructing dynamic websites which use a Git repository for storing all content. It's designed to allow technical and non-technical teams to collaborate on development and populate of a content management system using the tools they are most comfortable with.

In the case of developers (and some designers) that's version control and text editors, while in the case of content editors thats more likely to be a web interface.

 Getting Started

If you want to skip the theory, and get on with the fun bit, follow these steps:

$ gem install noumenon thin bundler
$ noumenon my_site
$ cd my_site
$ bundle install
$ thin start

You're basic Noumenon site will be running at http://localhost:3000/ now. If you want to put it on the internet it should work straight out of the box on Heroku.

How it Works

Noumenon splits your site into three parts:

Themes

Themes define how your content should be presented, and can provide templates and assets. You can load a theme from any filesystem path in your config.ru file. In the near future Ruby Gem based themes will also be supported.

Assets

Assets such as images, stylesheets, and javascripts are placed in the "assets" directory, and are accessible from your application at http://example.org/themes/Theme Name/asset.png. The URL structure directly matches the directory structure of your assets directory.

Templates

The core of a theme is the templates it provides. Each template can list the fields that it supports, and mark some or all of them as being required. Templates also include a Liquid template which is used to transform the provided fields into a web page.

Templates should be placed in a "templates" sub-directory within your theme, and end with the extension .nou.html

title:
  required: true
  label: "Page title"

subtitle:
  required: false

body:
  required: true
  type: "text"
---
<h1>{{ title }}</h1>
{% if subtitile %}
  <h2>{{ subtitle }}</h2>
{% endif %}
{{ body }}

Currently the "label" and "type" attributes on a field are only present for documentation purposes, but they will be used in the future to automatically build the content management interface used by content editors to publish pages, so it's probably worth taking the time to include them.

If not specified the type defaults to "string", the label to a capitalised version of the name, and required to false.

Any fields provided to a template which aren't specified will still be available in the Liquid template part.

Templates are written using Liquid, and so all the standard tags and filters are available, as well as the ones documented at Noumenon::Template::CoreTags.

Layouts

Layouts are used to wrap a piece of content with the overall look and feel of your website, and are provided with a single field "content" containing the rendered content, along with any fields that were specified on the page being rendered.

Unless otherwise specified the layout "default" will be used, which is loaded from the path layouts/default.nou.html within your theme. To specify a different layout set the "layout" field on your content item.

content:
  required: true
  type: "text"
---
<html>
  <head>
    <link rel="stylesheet" href="/themes/example_theme/styles.css">
    <title>Enormicorp</title>
  </head>

  <body>
    <h1>Enormicorp</h1>
    <nav>
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/about">About</a></li>
        <li><a href="/contact">Contact</a></li>
      </ul>
    </nav>

    <section id="content">
      {{ content }}
    </section>

    <footer>Copyright &copy; 2011, Enormicorp Plc.</footer>
  </body>
</html>

 A Content Repository

The site's content is stored within a repository. Each piece of content is represented by a set of key/value pairs, something like this:

template: team_member
name: Jon Wood
position: Head Honcho of Awesomeness
description: Do you need a description after a position like that?

Currently the only available content repository uses YAML files to store your content, but shortly a MongoDB one will be created, and the API for content repositories is simple enough that just about any datastore could be used if you want to implement an adapater for it.

 An Asset Repository

The asset repository is used to store arbitrary files, such as images to embed within pages.

Any uploaded assets can usually be accessed from /assets/path/to/image.jpg, although in some cases it may be quicker to access them directly. To get the correct URL for an asset use the {% asset /path/to/image.jpg %} template tag, which will return the correct URL.

 Applications

If part of your site requires something other then rendering a piece of content within a static template then you can use a custom URL handler to provide that part of the site. In this example we'll provide a basic contact form.

The ContactForm Handler

class Noumenon::Applications::ContactForm < Noumenon::Core
  def initialize(options = {})
    @to = options[:to]
  end

  get '/' do
    Noumenon.theme.template("templates/contact/form.html")
  end

  post '/send' do
    require 'pony'
    Pony.send :to => @to, :body => params[:body], :from => params[:from]

    Noumenon.theme.template("templates/contact/thanks.html").render(body: params[:body], from: params[:from])
  end
end

The Content item

To mount an application you need to put a content item in the tree where you want it, so in this example we'll put this at "/contact":

type: application
application: Noumenon::Applications::ContactForm
to: [email protected]

Make sure you've loaded the file that defines Noumenon::Applications::ContactForm.

Getting Help and Contributing

If you're using Noumenon I'd love to know about it, especially if you're having trouble, since my aim is to make creating a site based on Noumenon as simple as possible. The best way to get in touch is to open an issue at http://github.com/Noumenon/noumenon/issues.

If you'd like to contribute fork this repository, and then submit a pull request when you're done. Please make sure to include some tests so that your feature doesn't get broken in the future.

There are full API docs available at http://rubydoc.info/gems/noumenon/ which are generated whenever a new version is published.

 License

Noumenon is released under the MIT license by Blank Pad Development.