Dig-in! (learn…)

This manual is a pre-release preview. Please follow Moonstalk on Twitter or Facebook to be notified of a public release.

Create

This section provides an an overview for the use of Moonstalk, and the basics of adapting it to common needs. See the develop page for detailed attributes, behaviours and functionality.

Lua

If you've not learned the basics of the Lua language yet, now might be a good time. Programming In Lua is an easy to understand and straight-to-the-point guide that'll introduce you to the essentials in just a couple of hours. If you know other languages you may well be able soldier on and extrapolate much of its syntax.

Bundles

Moonstalk hosts both sites and applications, and we refer to both generically as ‘bundles’. Each are defined by folders containing much the same set of files for their resources.

Creating a bundle is as simple as creating a folder, and putting some files in it. The following are files common to bundles (both sites and applications). All are optional and may define functionality indepedantly of each other, or in combination.

Any file not otherwise noted and having an extension, is considered to be static content and will be served directly by the web server. See the design page, and bundles reference section for specific details.

You may create subfolders and organise your files as you wish. However top-level sub-folders having the name of another application will extend (supplement) or override (replace) that application with its own contents.

Sites

Site bundles are created inside the Moonstalk sites folder, and each bundle (folder) defines an individual site, named with its primary domain.

The primary domain my be specified with or without the www prefix, but both are always handled, therefore ensure your DNS is setup with records for both.

See the Tenants application for details of how sites can be stored in a database (e.g. for SaaS).

Features

Files

Applications

Application bundles are created inside the Moonstalk applications folder, and each bundle defines an individual application, named with its ID.

Applications provide shared or generic functionality (such as a blog system) for use on multiple sites (disparate domains). Applications must typically be enabled in a site's settings in order to use them, refer to an application's own documentation for details of its behaviour, configuration, and usage. Moonstalk includes several bundled applications.

Features

Files

The generic server not-found and error pages are provided by the Generic application, see its documentation to customise them.

Applications are for installation by a server operator only, and should be audited for security.

Static resources

Moonstalk configures the webserver to serve any file accessed with a filename extension on a site's primary domain, straight from disk (or RAM if cached) and without processing by Moonstalk's Scribe backend.

If your visitors primarily come from more than a single country (or state) the use of a Content Delivery Network (CDN) is highly recommend for improved performance in preference to hosting your assets from your server itself.

Assets

These are files such as images, CSS, and Javascript that are referenced in and enhance HTML pages, and also PDFs, video and other downloadable files.

Typically you would group all your assets together inside an assets subfolder of your site. When you link to them in HTML you simply use the relative src or href "assets/myfile.type" and the assets will work both on and offline.

Pages

Moonstalk's primary purpose is serving content that is at least partly dynamic, however you may serve static pages (i.e. complete HTML files) in the same manner as other static assets.

Dynamic resources

Any requests for an address not containing a filename extension is considered a dynamic request, to be processed by Moonstalk's Scribe backend, which runs a sequence of functions to handle the request and provide a response.

Moonstalk provides built-in handling for dynamic pages, generated from a view file providing the primary layout and content (HTML markup), and optionally supplemented with a controller providing separate processing logic (Lua code).

Both views and controllers are transformed into functions that run with access to the same Lua environment and Moonstalk functions—the difference lies only in the file format (tags in views, code in controllers). See the develop page for details of the environment.

See the Content application for details of how static pages can be stored in a database.

Views

These are simply .html files, either complete HTML pages or fragments of formatted content for display, such as within a template. Views may utilise the following two forms of dynamic markup.

Expression tags

?( expression )

The expression tag is a macro for the write() function and is replaced in the page by the resulting value of a Lua expression.

An expression may be a variable name, function call (but only if returning a single parameter), concatenation operation, or a combination of these (grouped inside brackets). Code blocks such as if and while cannot be used. Expression tags may be used anywhere in your HTML file (including inside attributes).

Processing tags

<? code ?>

These may contain any valid Lua code including blocks, and are stripped out of the page, except for the result of any calls to the write() function which may be used to append output to the page. Code may be split across multiple tags such as to define conditional output.

<? if mytest then ?>
<b>mytest is true</b>
<? end ?>

Controllers

These are predominantly used to separate and protect the logic (Lua code) from the design layout in a view, thus avoiding placing complex server processing tags within a view's markup.

When paired with a view, a controller's code is placed in a .lua file of the same name. I.e. myfile.html is the view and myfile.lua is the controller. Controllers run before views and are used to process and prepare variables (such as from the request, or a database) for insertion as strings into a page, using expression or processing tags in the corresponding view.

Controllers may provide output before a view is run, using write[[<p>content</p>]] (typically using a Lua 'long-string' to avoid issues with escaping), and may thus also be used in place of a view entirely, particularly where a non-HTML response is required (e.g. a JSON or XML API).

Templates

With templates you can define the common layout or features of all pages, or groups of pages, such as providing a navigation menu, header, footer and so forth. A template wraps the content or layout (e.g. from a view) with its additional markup.

Templates are identical to dynamic pages, having both a view and an optional controller, but are run after the page controller and view. Templates may thus have both layout and logic.

In a template you must specify where to insert the page content generated by the page controller and view, using the following command.

<? scribe.Insert "content" ?>

Templates may be defined in the following manner, the latter methods take precedence over any prior.

Sections

By default all output is placed into a section container named content, from which the page response is generated. You may define your own output sections, to capture output to insert into the page later in an arbitrary order. Use the following command to define a section.

<? section "name" ?>

All output following this will be captured, until another section is defined (or the page is generated). Templates use this same mechanism.

Once output is collected you must concatenate any custom sections into the page content. To combine your sections with the page, use the scribe.Insert command with the name of your previously defined section.

<? scribe.Insert "name" ?>

Chaining

You may include or run any view or controller in any other, by using the following commands, however bear in mind that the output response will be affected by the order that they run unless you use sections.

All application view and controller names are prefixed with the application name, e.g. appname/viewname. The current site's is accessed with just its name.

Chaining behaviour is akin to forwarding in J2EE, and should not be confused with HTTP redirection.

Redirection

To cause the user's browser to send a new request for a specified address use the following command, the redirect will occur after the current request has finished unless explicitly abandoned.

scribe.Redirect "address"

This is often used after successfully processing a submitted form to change the URL to a bookmarkable action ID, instead of simply displaying a different view at an unchanged address. The given address may be a path or an absolute URL.

Routing

To provide a response, a request's URL path must be mapped to a function (typically a controller) or content (typically a view). Moonstalk provides built-in mapping through its addressing mechanism, and ad-hoc routing through the chaining mechanism.

By default views in site bundles (but not applications) are automatically mapped to an address corresponding to their file names (without extension). E.g. the file sites/example.com/mypage.html would be accessed as http://example.com/mypage.

You may define your own mappings, by declaring an addresses array in a bundle's settings file. Each address in the array takes the following form, specifying one selector, one or more handlers, with optional attributes inherited by the page. (See addresses on the develop page for full usage.)

{selector="path", handler="name", attribute=value}

Authentication

Moonstalk has built-in generic handling for user access control. You may employ this either on addresses, or within your own functions (see develop). Addresses and pages may be defined as having restricted access using locks, and users may be granted access to such locked pages using keys. Locks and keys are simply names that denote membership of certain user 'groups' as desired.

An additional application is required to define behaviours for user and key management (i.e. assignment, retraction). Moonstalk includes the people application for managing users within the Teller database. No support is provided for hard-coded lists such as from .htaccess files, but would be easily implemented yourself.

To restrict a view to a particular key holder, add a locks attribute to the page, or to desired addresses in the settings.

{ matches="private/page", view="private-page", locks={ "Private", } }

A user requiring access to that address must then be granted a key with the corresponding name in their keychain.

By default all signed-in users have a default "Guest" key, you may therefore require sign-in on pages by adding a lock of the same name.

Internationalisation

Moonstalk includes built-in support for translated vocabularies (including handling plurals, and functions such as for ordinals), easily used via a simple key-prefix on localised names. Support for locales is also built-in and may be selectively used via formatter functions. Additional built-in behaviours such as Latin transliteration, and a report for untranslated terms, facilitate localisation improving both visitor and developer experience with projects requiring ‘i18n’.

When serving localised and translated pages, a user's preferred or profile-derived locale and language is used wherever possible, followed by the site's specified default locale and language, with fallbacks to the first or only language defined (such as if translation is incomplete or only has a single language defined).

If enabled GeoIP lookups are made using an in-memory dataset to supplement an unprofiled user's locale, and completely avoiding the additional latency of third-party API calls.

Address paths are normalised using case-insensitivity, and transliteration of latin accented characters to ASCII. Pages may be addressed with or without such characters, whilst the original (i.e. with accents if your file or page names contain them) is preserved as the canonical name (and address).

You may use any desired encoding for your HTML and strings in Lua (but UTF-8 is recommended as this used by all Moonstalk's bundled applications), simply be sure to use the same encoding throughout, and ensure that the corresponding encoding is declared in your HTML.

Lua does not handle Unicode sorting, and you may need to use your own or third-party routines for this if needed.

Non-ASCII (e.g. UTF-8) encoded files must be saved without a BOM, otherwise they will fail to load. See the utilities section for some editors that won't muck this up, if yours does.

Views

Views saved as files may have multiple versions created to provide separate content for different target cultures (translations/localisations), simply by using the following naming convention for the files (of any supported view format).

Views that are not provided in this manner are assumed to either use the site's default culture, or to be dynamically translated and/or localised using vocabularies and formatters.

Views generated from other sources may have cultures specified directly, see the Content app and view table for details.

Locales

These define the formatting of numbers, currency, dates and so forth, with country/language variations. Moonstalk will always attempt to identify and honour a user's locale and language (see vocabularies below).

Values are displayed respecting a locale if you output them using Moonstalk's format functions.

Several locales are included with Moonstalk, whilst additions or corrections may be submitted to us. You may override them in the global environment from a settings file.

Vocabularies

These enable localisation, and store the translated text values (strings) for each translated language. If you don't expect to need to use localised content you may ignore this functionality and it will not affect the display of pages.

You may set localise=false for a site, address or page to completely disable all locations functionality for corresponding requests.

Applications, sites and pages may specify their own individual vocabularies (translations) that supplement each other.

Pages are displayed using the language matching a user's locale or request when available, otherwise it will be substituted with a regionally acceptable language, the site or application default, or finally English, when these are available in the vocabularies.

Partial translations are undesirable, as missing translation are replaced with alternate translations according to the user's locale, which results in pages being displayed in a mix of languages, therefore it is important to ensure all applications, sites, and pages support the desired languages.

In developer mode missing translations are not substituted with alternates, but are instead displayed as ⚑name to assist in identifying missing translations, whilst the /Manager/Localisation view provides a complete report of untranslated terms.

Individual translated words or phrases are represented by keys (untranslated names) for which one is defined for each language (using its language code as defined in globals/Attributes.lua) in the bundle settings file.

vocabulary = { en={}, fr={} }
vocabulary.en.aword = "a word"
vocabulary.fr.aword = "un mot"

In settings files vocabulary is typically abbreviated as v to simplify typing, by defining local v = vocabulary.

Vocabulary item names (keys) should be globally unique (amongst all applications) else will be replaced. Per-site and per-page vocabularies may be used to supplement or customise these definitions.

You may replace a key in any application scope from anywhere, however you may only replace a key for the site in a page, and you cannot replace a key defined in a page as it is the final scope.

Translated words from the active vocabulary (the current user's language) are accessed using a variable named correspondingly but prefixed l. (for the original word) or L. (reformats the word with an initial cap).

In views the translated value's variable may be used in a placeholder as with any other variable.

Plural forms for translated words are also supported, these are defined in the same manner as words above, but with the number of plural forms corresponding to the language per the Mozilla rules (all of which are supported) e.g. 2 forms for Germanic languages (defined as an array of two strings), or 1 form for Asian languages (defined as a single string not an array).

en.items = {"item","items"}

Once defined you can access the translated plural by calling the localised vocabulary function with the identifier and a number that specifies the correct plural form to be used.

l("items", number)

Additional functions may also be localised and assigned to the vocabulary and called simply using the

l.
prefix. Some are included such as the
l.Ordinal(number)
function that will return an appropriate suffix for an ordinal number.

Manage

Each individual server (virtual or dedicated) on which Moonstalk runs is called a node, and comprises the components inside the install folder. No other location is used for configuration or temporary files, withstanding the startup script.

Runner

This shell utility is your interface for managing a Moonstalk node. Run without any command it will provide you with its status. It will always report any application or site compilation (syntax) errors. All instructions are optional, accepted in any order and with several synonyms. For further usage instructions issue the help command.

The server control commands are:

These control commands may be accompanied by a server name:

To ./runner start web you must use super-user priveleges (sudo or login as root).

Configuration

The node configuration is stored in the data/configuration/Node.lua file and contains node-specific options for both Moonstalk and other applications. You may edit this directly, or for node attributes, you may use the runner to change it.

For production (non-development) servers, set a unique node ID that is between 101 and 999.

For development computers, you can enable development mode.

You may also need to set a FQDN if the default hostname is not adequate.

See the develop page for additional configuration options.

Manager

Moonstalk includes a web administration application called the Manager. This is enabled on the localhost site, which is also accessible on the server's default hostname. The Manager's user database is created with a default operator user, having a unique password that is the secret from the node configuration. The runner will notify you of these upon first use.

Updating

Moonstalk can be updated to the current release version with a single command on a non-development server (id~=100).

Your sites, applications and data will be untouched by this command, but be aware that updates to applications may require adjustments to your code or settings, therefore it is advisable to check the release notes before updating.

During the pre-release development phase please review the changelog for changes that may affect you. Subscribe by RSS, open your ~/moonstalk directory [repository] with a Mercurial GUI app after updating, or use your shell: cd ~/moonstalk; hg log | grep summary | more

Repositories

You may create your own repositories using your preferred CVS for each of your application and site folders, or one for the entire sites folder—but not the entire applications folder, unless you are not using Mercurial and exclude moonstalk.* from being tracked.

If you use Mercurial for your site and application repositories, Moonstalk's update command can also pull from them for you. Simply push your changes before attempting an update, and add your repository folder names to the node configuration.

Forking

As the moonstalk directory is a version-managed Mercurial repository, if you change any of Moonstalk's managed files, the changes will be lost when Moonstalk is updated.

You may however fork/clone Moonstalk's repository, and change Moonstalk's default respoitory in .hg/hgrc to your own forked repository. Once an initial installation pull has been made from your respository on each of your deployment servers, the Moonstalk update command may be used to pull from your repoisitory thereafter.

Develop…

Now that you've got a hang of the fundamentals, read the develop page to learn about data tables, configuration, functions and more that will enable you to develop your own solutions as desired.

Addendum

Questions

Useful libraries