npm install elixir---

Elixir is based on a rewrite of
Director by
Flatiron. It depends solely
on RaptorJuice, which
is a lightweight (around 4.5k), self contained iterator and utility
library. RaptorJuice originated as the general utility functions for
Elixer.
At this point, Elixer is not intended to act as a drop-in replacement
for Director, though it could easily be extended to do so. Rather, it
should be viewed as refinement of the original logic which exists in
Director.
* The source.
* The docs.
* The devs.
Elixir is a flexible router which is:
* Based on regular expressions.
* Segmented by a customizable delimiter.
* Entirely asynchronous.
* Ensure that you have Node.js
on your system.
* Prepare your environment by executing the following commands:
```
git clone https://github.com/junglefresh/Elixir.js elixir
cd elixir
npm install
sudo npm install -g grunt-cli mocha
To automatically run tests upon saving changes to the source or tests
run the following:
``
mocha --reporter spec ./spec.js -w
* Upon execution of the following command, after each write:
* The unit tests will be confirmed.
To begin automatically building the project, run:
``
grunt watch
* Please note that a Java Runtime is required due to the jsdoc
dependency.
* By executing the following command, upon each write:
* The unit tests will be confirmed.
* Documentation will be regenerated if all tests pass.
Elixer is a router which treats any segmented string, such as the path
portion of a URL, as a trajectory into a tree structure. This
trajectory is defined by the segments of the path. A segment is
any portion of a path which lies between two delimiting sequence.
For a URL, the common delimiting sequence is a /, but with __Elixir__
it can be defined to suit your needs.
In summary, __Elixir__ projects a segmented string into its routing table.
__Elixir__ allows us to attach functions to any part of a route's tree
structure. A route is defined as a segmented string, so it is similar
to a path, yet its segments are regular expressions.
``
var potion = new Elixir();
potion.add('/test', 'on', function() {
Elixir.R.log('Hello world!');
});
Elixir.R.log(potion.table.segments);
First, we create a new __Elixir__ object and call it potion. Then, weon
add an state handler to the /test route in potions routingpotion
table. By logging the segments of s routing table in the laston
line of the example, you can see that the segments of the route were
created, and our handler was added to the state.
So what now? We've added an event handler to potion, lets trigger it
with a path that matches its route.
* Context...
``
potion.trigger('/test', null, { }, function() {
if(this.error) {
Elixir.R.log('Fout:' + this.error.message);
}
Elixir.R.log('Tot ziens, wereld!');
});
Well, it kinda works, but why isn't the callback with our goodbye message
being executed?
The answer lies in the fact that __Elixir__ has been built entirely
asynchronously. Every handler function in the routing table must call
the next function supplied with its context.
`
var potion = new Elixir();
potion.add('/test', 'on', function() {
Elixir.R.log('Hello world!');
this.next(); // The fix.
});
potion.trigger('/test', null, { }, function() {
if(this.error) {
Elixir.R.log('Fout:' + this.error.message);
}
Elixir.R.log('Tot ziens, wereld!');
});
`
By calling next without any arguments, we ensure that the proceedingtrigger
function on our trajectory is invoked. On the other hand, we can
diverge from our or trajectory and invoke the callback supplied to
immediately, by supplying any truthy value to next.
`
var potion = new Elixir();
potion.add('/test', 'on', function() {
Elixir.R.log('Hello world!');
this.next({ message : 'An error!' }); // The fix.
});
potion.trigger('/test', null, { }, function() {
if(this.error) {
Elixir.R.log('Fout: ' + this.error.message);
}
Elixir.R.log('Tot ziens, wereld!');
});
`
In this example, by passing an object to next, the error propertynext
of the triggered event's context is set to the argument supplied to
. Any subsequent handlers on our current trajectory (in this
case, there are none) will by bypassed.
To understand the structure of a routing table, we need to take a step
back and look at a path for what it really is. The segments of a
path (as described in the introduction) project onto a series of
nodes in a tree. This series of nodes, or projection, can then be
traversed in any method to achieve the desired order of event handlers.
`
var potion = new Elixir();
potion.add('/test', 'on', function() {
Elixir.R.log('I am test!');
});
potion.add('/test/ing', 'on', function() {
Elixir.R.log('I am ing!');
});
potion.trigger('/test');
potion.trigger('/test/ing');
`
The cool part about routes is that they are actually
regular expressions. What this means is that we can create generic
nodes or segments to handle a range of inputs.
`
potion.add('/test/ing/(\\d+)', 'on', function(numbers) {
Elixir.R.log('I am ' + numbers);
});
potion.trigger('/test/ing/123');
`
As an artifact of a route's basis an regular expressions, we can
create create segments which contain the delimiting sequence.
`
potion.add('/(test/ing/(\\d+))', 'on', function(match) {
Elixir.R.log('I am test-ing-' + match);
});
potion.trigger('/test/ing/123');
`
Notice two things. First, the route containing two occurances of the
delimiting sequence took precidence over the routes with fewer
occurances. Second, the entire match was presented as the parameter to
the handler, not the interion match.
The magic really starts to happen when we throw in some states. The
idea of states allow us to create structured routes and repeat
very littly code.
The default states are before, on and after, in that order.
`
var potion = new Elixir();
potion.add('/', 'before', function() {
this.output = 'I ';
this.next();
});
potion.add('/Jamaican', 'before', function() {
this.output += 'am ';
this.next();
});
potion.add('/Jamaican', 'on', function(match) {
this.output += match;
this.next();
});
potion.add('/Jamaican', 'after', function() {
this.output += ', maaaannn.';
this.next();
});
potion.add('/', 'after', function() {
Elixir.R.log(this.output);
this.next();
});
potion.trigger('/Jamaican');
`
We can add more routes and have them easily printed. Note that the
root segment is assumed in any route.
`
potion.add('/(fly/high)', 'before', function() {
this.output += '... Uhhh';
this.next();
});
potion.add('/(fly/high)', 'on', function() {
this.output += '... ';
this.next();
});
potion.add('/(fly/high)', 'after', function() {
this.output += 'What was I gonna say?';
this.next();
});
potion.trigger('fly/high');
`
Methods allow us to to perform more specific actions on a trajectory.
`
var potion = new Elixir({ methods : [ 'talk', 'speak' ] });
potion.add('/samson', 'before', function() {
this.output = 'I ';
this.next();
})
potion.add('/samson', 'before', function() {
this.output += 'wanna ';
this.next();
})
potion.add('/samson', 'talk', 'on', function() {
this.output += 'talk ';
this.next();
})
potion.add('/samson', 'speak', 'on', function() {
this.output += 'speak ';
this.next();
})
potion.add('/samson', 'after', function() {
this.output += 'to ';
this.next();
})
potion.add('/samson', 'after', function() {
this.output += 'Samson.';
Elixir.R.log(this.output);
this.next();
})
potion.trigger('/samson', 'talk');
potion.trigger('/samson', 'speak');
`
The previous example could have been more consisely written by grouping
our stacked handlers.
`
var potion = new Elixir({ methods : [ 'talk', 'speak' ] });
potion.add('/samson', 'before', [
function() {
this.output = 'I ';
this.next();
},
function() {
this.output += 'wanna ';
this.next();
}
]);
potion.add('/samson', 'talk', 'on', function() {
this.output += 'talk ';
this.next();
})
potion.add('/samson', 'speak', 'on', function() {
this.output += 'speak ';
this.next();
})
potion.add('/samson', 'after', [
function() {
this.output += 'to ';
this.next();
},
function() {
this.output += 'Samson.';
Elixir.R.log(this.output);
this.next();
}
])
potion.trigger('/samson', 'talk');
potion.trigger('/samson', 'speak');
`
Both methods and states can be customized on a per-router basis. Each
router has three state categories. We can change the states a router
uses upon initialization.
`
var potion = new Elixir({
methods : [ 'eightfold', 'path' ],
before : [ 'pre' ],
on : [ 'event' ],
after : [ 'post' ]
});
Elixir.R.log(potion.states);
Elixir.R.log(potion.methods);
`
As you might imagine, each state category can actually contain multiple
states and order is preserved.
`
var potion = new Elixir({
methods : [ 'eightfold', 'path' ],
before : [ 'pre', 'setup' ],
on : [ 'event', 'on' ],
after : [ 'destroy', 'post' ]
});
Elixir.R.log(potion.states);
Elixir.R.log(potion.methods);
``
__Elixir__ is a flexible, asynchronous, structured event handler. By
combining states and methods with routes and paths we can
drastically reduce code repitition.