Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

738 lines (631 sloc) 26.216 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>nools</title>
<link rel="stylesheet" href="./assets/css/bootstrap.css">
<link rel="stylesheet" href="./assets/css/prettify.css">
<style type="text/css">
/*.subnav-inner {*/
/*width: 100%;*/
/*height: 36px;*/
/*background-color: #EEE;*/
/*background-repeat: repeat-x;*/
/*background-image: -moz-linear-gradient(top, whiteSmoke 0%, #EEE 100%);*/
/*background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, whiteSmoke), color-stop(100%, #EEE));*/
/*background-image: -webkit-linear-gradient(top, whiteSmoke 0%, #EEE 100%);*/
/*background-image: -ms-linear-gradient(top, whiteSmoke 0%, #EEE 100%);*/
/*background-image: -o-linear-gradient(top, whiteSmoke 0%, #EEE 100%);*/
/*filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#f5f5f5', endColorstr = '#eeeeee', GradientType = 0);*/
/*background-image: linear-gradient(top, whiteSmoke 0%, #EEE 100%);*/
/*-webkit-border-radius: 4px;*/
/*-moz-border-radius: 4px;*/
/*border-radius: 4px;*/
/*}*/
/*.subnav .nav > li > a:hover {*/
/*color: black !important;*/
/*}*/
/*.subnav .nav li.dropdown .dropdown-toggle .caret,*/
/*.subnav .nav li.dropdown.open .caret {*/
/*border-top-color: #999 !important;*/
/*border-bottom-color: #999 !important;*/
/*}*/
/*.subnav-fixed {*/
/*position: fixed;*/
/*width : 90%;*/
/*margin-right: auto;*/
/*margin-left: auto;*/
/*top: 40px;*/
/*left: 0;*/
/*right: 0;*/
/*z-index: 1020;*/
/*border-color: #D5D5D5;*/
/*border-width: 0 0 1px;*/
/*-webkit-border-radius: 0;*/
/*-moz-border-radius: 0;*/
/*border-radius: 0;*/
/*-webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1);*/
/*-moz-box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1);*/
/*box-shadow: inset 0 1px 0 #fff, 0 1px 5px rgba(0,0,0,.1);*/
/*filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);*/
/*}*/
/*.navbar .nav .dropdown-menu {*/
/*max-height: 500px;*/
/*overflow: auto;*/
/*}​*/
</style>
<style type="text/css">
body {
padding: 90px;
}
.subnav{
margin-top: 40px;
margin-right: auto;
margin-left: auto;
z-index: 1000;
}
@media (max-width:979px) {
.subnav{
margin-top: auto;
}
}
</style>
<link rel="stylesheet" href="./assets/css/bootstrap-responsive.css">
<script type="text/javascript">
var init = (function () {
"use strict";
var processScroll = (function () {
var curr = null, prev = null;
return function (nav) {
var $win = $(window);
$('.subnav').each(function () {
var nav = $(this);
var navTop = $win.width() < 980 ? 0 : nav.offset().top - 40;
var scrollTop = $win.scrollTop();
if (scrollTop >= navTop && curr != nav) {
if(curr){
curr.removeClass('subnav-fixed')
prev = curr;
}
curr = nav;
curr.addClass('subnav-fixed')
} else if (curr == nav && scrollTop <= navTop) {
curr.removeClass('subnav-fixed');
prev.addClass('subnav-fixed');
curr = prev;
}else{
nav.removeClass('subnav-fixed');
}
});
};
})();
return function () {
window.prettyPrint && prettyPrint();
$(".collapse").collapse();
var $window = $(window);
//$(".subnav").affix ();
// fix sub nav on scroll
// processScroll();
// $(window).on('scroll', processScroll)
}
})();
</script>
</head>
<body onload="init()">
<div class="navbar navbar-fixed-top navbar-inverse">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"> </span>
</a>
<a href="./index.html" class="brand">nools</a>
<div class="nav-collapse">
<ul class="nav">
</ul>
<ul class="nav pull-right">
<li class="divider-vertical"></li>
<li><a href="https://github.com/C2FO/nools" target="#github" class="pull-right">github</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<a name="top"></a>
<div class="container">
<p><a href="http://travis-ci.org/C2FO/nools"><img src="https://secure.travis-ci.org/C2FO/nools.png" alt="Build Status"></a>
</p>
<h1>Nools</h1>
<p>Nools is a rules engine for node based on the <a href="http://en.wikipedia.org/wiki/Rete_algorithm">rete</a> network.
</p>
<h1>Installation</h1>
<p><code>npm install nools</code>
</p>
<h1>Usage</h1>
<ul>
<li>Flows<ul>
<li><a href="#flow">Defining A Flow</a></li>
<li><a href="#session">Sessions</a></li>
<li><a href="#facts">Facts</a></li>
<li><a href="#firing">Firing</a></li>
<li><a href="#disposing">Disposing</a></li>
</ul>
</li>
<li><a href="#defining-rule">Defining Rules</a><ul>
<li><a href="#rule-structure">Structure</a></li>
<li><a href="#constraints">Constraints</a></li>
<li><a href="#action">Actions</a></li>
</ul>
</li>
<li><a href="#fib">Fibonacci</a></li>
</ul>
<p>To get started with nools the <a href="https://github.com/doug-martin/nools/tree/master/examples">examples</a> and <a href="https://github.com/doug-martin/nools/tree/master/test">tests</a> are a
great place to get started.
</p>
<p><a name="flow"></a>
</p>
<h2>Defining a flow</h2>
<p>When using nools you define a <strong>flow</strong> which acts as a container for rules that can later be used to get
an <strong>engine session</strong>
</p>
<h3>Pragmatically</h3>
<pre class='prettyprint linenums lang-js'><code>var nools = require(&quot;nools&quot;);
var Message = function (message) {
this.message = message;
};
var flow = nools.flow(&quot;Hello World&quot;, function (flow) {
//find any message that start with hello
this.rule(&quot;Hello&quot;, [Message, &quot;m&quot;, &quot;m.message =~ /^hello(\\s*world)?$/&quot;], function (facts) {
facts.m.message = facts.m.message + &quot; goodbye&quot;;
this.modify(facts.m);
});
//find all messages then end in goodbye
this.rule(&quot;Goodbye&quot;, [Message, &quot;m&quot;, &quot;m.message =~ /.*goodbye$/&quot;], function (facts) {
console.log(facts.m.message);
});
});</code></pre>
<p>In the above flow definition 2 rules were defined
</p>
<ul>
<li>Hello<ul>
<li>Requires a Message</li>
<li>The messages&#39;s message must match the regular expression &quot;/^hello(\s*world)?$/&quot;</li>
<li>When matched the message&#39;s message is modified and then we let the engine know that we modified the message.</li>
</ul>
</li>
<li>Goodbye<ul>
<li>Requires a Message</li>
<li>The messages&#39;s message must match the regular expression &quot;/.*goodbye$/&quot;(anything that ends in goodbye)</li>
<li>When matched the resulting message is logged.</li>
</ul>
</li>
</ul>
<h3>Nools DSL</h3>
<p>You may also use the <code>nools</code> rules language to define your rules
</p>
<pre class='prettyprint linenums lang-js'><code>define Message {
message : &#39;&#39;,
constructor : function(message){
this.message = message;
}
}
rule Hello {
when {
m : Message m.message =~ /^hello(\\s*world)?$/;
}
then {
modify(m, function(){this.message += &quot; goodbye&quot;;});
}
}
rule Goodbye {
when {
m : Message m.message =~ /.*goodbye$/;
}
then {
console.log(m.message);
}
}</code></pre>
<p>To use the flow
</p>
<pre class='prettyprint linenums lang-js'><code>var flow = nools.compile(__dirname + &quot;/helloworld.nools&quot;),
Message = flow.getDefined(&quot;message&quot;);</code></pre>
<p><a name="session"></a>
</p>
<h2>Working with a session</h2>
<p>A session is an instance of the flow that contains a working memory and handles the assertion, modification, and retraction
of facts from the engine.
</p>
<p>To obtain an engine session from the flow invoke the <strong>getSession</strong> method.
</p>
<pre class='prettyprint linenums lang-js'><code>var session = flow.getSession();</code></pre>
<p><a name="facts"></a>
</p>
<h2>Working with facts</h2>
<p>Facts are items that the rules should try to match.
</p>
<p>To add facts to the session use <strong>assert</strong> method.
</p>
<pre class='prettyprint linenums lang-js'><code>session.assert(new Message(&quot;hello&quot;));
session.assert(new Message(&quot;hello world&quot;));
session.assert(new Message(&quot;goodbye&quot;));</code></pre>
<p>As a convenience any object passed into <strong>getSession</strong> will also be asserted.
</p>
<pre class='prettyprint linenums lang-js'><code>flow.getSession(new Message(&quot;hello&quot;), new Message(&quot;hello world&quot;), new Message(&quot;goodbye&quot;));</code></pre>
<p>To retract facts from the session use the <strong>retract</strong> method.
</p>
<pre class='prettyprint linenums lang-js'><code>var m = new Message(&quot;hello&quot;);
//assert the fact into the engine
session.assert(m);
//remove the fact from the engine
session.retract(m);</code></pre>
<p>To modify a fact use the <strong>modify</strong> method.
</p>
<p><strong>Note</strong> modify will not work with immutable objects (i.e. strings).
</p>
<pre class='prettyprint linenums lang-js'><code>
var m = new Message(&quot;hello&quot;);
session.assert(m);
m.message = &quot;hello goodbye&quot;;
session.modify(m);</code></pre>
<p><strong>assert</strong> is typically used pre engine execution and during the execution of the rules.
</p>
<p><strong>modify</strong> and <strong>retract</strong> are typically used during the execution of the rules.
</p>
<p><a name="firing"></a>
</p>
<h2>Firing the rules</h2>
<p>When you get a session from a <strong>flow</strong> no rules will be fired until the <strong>match</strong> method is called.
</p>
<pre class='prettyprint linenums lang-js'><code>var session = flow.getSession();
//assert your different messages
session.assert(new Message(&quot;goodbye&quot;));
session.assert(new Message(&quot;hello&quot;));
session.assert(new Message(&quot;hello world&quot;));
//now fire the rules
session.match(function(err){
if(err){
console.error(err);
}else{
console.log(&quot;done&quot;);
}
})</code></pre>
<p>The <strong>match</strong> method returns a promise that is invoked once there are no more rules to activate.
</p>
<p>Example of the promise api
</p>
<pre class='prettyprint linenums lang-js'><code>session.match().then(
function(){
console.log(&quot;Done&quot;);
},
function(err){
//uh oh an error occurred
console.error(err);
});</code></pre>
<p><a name="disposing"></a>
</p>
<h2>Disposing of the session</h2>
<p>When working with a lot of facts it is wise to call the <strong>dispose</strong> method which will purge the current session of
all facts, this will help prevent the process growing a large memory footprint.
</p>
<pre class='prettyprint linenums lang-js'><code> session.dispose();</code></pre>
<p><a name="defining-rule"></a>
</p>
<h1>Defining rules</h1>
<p><a name="rule structure"></a>
</p>
<h2>Rule structure</h2>
<p>Lets look at the &quot;Calculate&quot; rule in the <a href="#fib">Fibonacci</a> example
</p>
<pre class='prettyprint linenums lang-js'><code> //flow.rule(type[String|Function], constraints[Array|Array[[]]], action[Function]);
flow.rule(&quot;Calculate&quot;, [
//Type alias pattern store sequence to s1
[Fibonacci, &quot;f1&quot;, &quot;f1.value != -1&quot;, {sequence:&quot;s1&quot;}],
[Fibonacci, &quot;f2&quot;, &quot;f2.value != -1 &amp;&amp; f2.sequence == s1 + 1&quot;, {sequence:&quot;s2&quot;}],
[Fibonacci, &quot;f3&quot;, &quot;f3.value == -1 &amp;&amp; f3.sequence == s2 + 1&quot;],
[Result, &quot;r&quot;]
], function (facts) {
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
this.modify(f3);
this.retract(f1);
});</code></pre>
<p>Or using the nools DSL
</p>
<pre class='prettyprint linenums lang-js'><code>rule Calculate{
when {
f1 : Fibonacci f1.value != -1 {sequence:s1};
f2 : Fibonacci f2.value != -1 &amp;&amp; f2.sequence == s1 + 1 {sequence:s2};
f3 : Fibonacci f3.value == -1 &amp;&amp; f3.sequence == s2 + 1;
}
then {
modify(f3, function(){
this.value = f1.value + f2.value;
});
retract(f1);
}
}</code></pre>
<p><a name="constraints"></a>
</p>
<h3>Constraints</h3>
<p> Constraints define what facts the rule should match. The constraint is a array of either a single constraint (i.e. Bootstrap rule)
or an array of constraints(i.e. Calculate).
</p>
<p>Prgamatically
</p>
<pre class='prettyprint linenums lang-js'><code>[
//Type alias pattern store sequence to s1
[Fibonacci, &quot;f1&quot;, &quot;f1.value != -1&quot;, {sequence:&quot;s1&quot;}],
[Fibonacci, &quot;f2&quot;, &quot;f2.value != -1 &amp;&amp; f2.sequence == s1 + 1&quot;, {sequence:&quot;s2&quot;}],
[Fibonacci, &quot;f3&quot;, &quot;f3.value == -1 &amp;&amp; f3.sequence == s2 + 1&quot;],
[Result, &quot;r&quot;]
]</code></pre>
<p>Using nools DSL
</p>
<pre class='prettyprint linenums lang-js'><code>when {
f1 : Fibonacci f1.value != -1 {sequence:s1};
f2 : Fibonacci f2.value != -1 &amp;&amp; f2.sequence == s1 + 1 {sequence:s2};
f3 : Fibonacci f3.value == -1 &amp;&amp; f3.sequence == s2 + 1;
}</code></pre>
<ol>
<li>Type - is the Object type the rule should match. The available types are<ul>
<li><code>String</code> - &quot;string&quot;, &quot;String&quot;, String</li>
<li><code>Number</code> - &quot;number&quot;, &quot;Number&quot;, Number</li>
<li><code>Boolean</code> - &quot;boolean&quot;, &quot;Boolean&quot;, Boolean</li>
<li><code>Date</code> - &quot;date&quot;, &quot;Date&quot;, Date</li>
<li><code>RegExp</code> - &quot;regexp&quot;, &quot;RegExp&quot;, RegExp</li>
<li><code>Array</code> - &quot;array&quot;, &quot;Array&quot;, [], Array</li>
<li><code>Object</code> - &quot;object&quot;, &quot;Object&quot;, &quot;hash&quot;, Object</li>
<li>Custom - any custom type that you define</li>
</ul>
</li>
<li>Alias - the name the object should be represented as.</li>
<li><p>Pattern(optional) - The pattern that should evaluate to a boolean, the alias that was used should be used to reference the object in the pattern. Strings should be in single quotes, regular expressions are allowed. Any previously define alias/reference can be used within the pattern. Available operators are.</p>
<ul>
<li><code>&amp;&amp;</code>, <code>AND</code>, <code>and</code></li>
<li><code>||</code>, <code>OR</code>, <code>or</code></li>
<li><code>&gt;</code>, <code>&lt;</code>, <code>&gt;=</code>, <code>&lt;=</code>, <code>gt</code>, <code>lt</code>, <code>gte</code>, <code>lte</code></li>
<li><code>==</code>, <code>!=</code>, <code>=~</code>, <code>eq</code>, <code>neq</code>, <code>like</code></li>
<li><code>+</code>, <code>-</code>, <code>*</code>, <code>/</code></li>
<li><code>-</code> (unary minus)</li>
<li><code>.</code> (member operator)</li>
<li><code>in</code> (check inclusion in an array)</li>
<li>Defined helper functions<ul>
<li><code>now</code> - the current date</li>
<li><code>Date(year?, month?, day?, hour?, minute?, second?, ms?)</code> - creates a new <code>Date</code> object</li>
<li><code>lengthOf(arr, length)</code> - checks the length of an array</li>
<li><code>isTrue(something)</code> - check if something === true</li>
<li><code>isFalse(something)</code> - check if something === false</li>
<li><code>isRegExp(something)</code> - check if something is a <code>RegExp</code></li>
<li><code>isArray(something)</code> - check if something is an <code>Array</code></li>
<li><code>isNumber(something)</code> - check if something is an <code>Number</code></li>
<li><code>isHash(something)</code> - check if something is strictly an <code>Object</code></li>
<li><code>isObject(something)</code> - check if something is any type of <code>Object</code></li>
<li><code>isDate(something)</code> - check if something is a <code>Date</code></li>
<li><code>isBoolean(something)</code> - check if something is a <code>Boolean</code></li>
<li><code>isString(something)</code> - check if something is a <code>String</code></li>
<li><code>isUndefined(something)</code> - check if something is a <code>undefined</code></li>
<li><code>isDefined(something)</code> - check if something is <code>Defined</code></li>
<li><code>isUndefinedOrNull(something)</code> - check if something is a <code>undefined</code> or <code>null</code></li>
<li><code>isPromiseLike(something)</code> - check if something is a &quot;promise&quot; like (containing <code>then</code>, <code>addCallback</code>, <code>addErrback</code>)</li>
<li><code>isFunction(something)</code> - check if something is a <code>Function</code></li>
<li><code>isNull(something)</code> - check if something is <code>null</code></li>
<li><code>isNotNull(something)</code> - check if something is not null</li>
<li><code>dateCmp(dt1, dt2)</code> - compares two dates return 1, -1, or 0</li>
<li><code>years|months|days|hours|minutes|seconds``Ago</code>/<code>FromNow``(interval)</code> - adds/subtracts the date unit from the current time</li>
</ul>
</li>
</ul>
</li>
<li><p>Reference(optional) - An object where the keys are properties on the current object, and values are aliases to use. The alias may be used in succeeding patterns.</p>
</li>
</ol>
<p><a name="action"></a>
</p>
<h3>Action</h3>
<p>The action is a function that should be fired when all patterns in the rule match. The action is called in the scope
of the engine so you can use <strong>this</strong> to <strong>assert</strong>, <strong>modify</strong>, or <strong>retract</strong> facts. An object containing all facts and
references created by the alpha nodes is passed in as the first argument to the action.
</p>
<p>So calculate&#39;s action modifies f3 by adding the value of f1 and f2 together and modifies f3 and retracts f1.
</p>
<pre class='prettyprint linenums lang-js'><code>function (facts) {
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
this.modify(f3);
this.retract(f1);
}</code></pre>
<p>The engine is also passed in as a second argument so alternatively you could do the following.
</p>
<pre class='prettyprint linenums lang-js'><code>function (facts, engine) {
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
engine.modify(f3);
engine.retract(f1);
}</code></pre>
<p>If you have an async action that needs to take place an optional third argument can be passed in which is a function
to be called when the action is completed.
</p>
<pre class='prettyprint linenums lang-js'><code>function (facts, engine, next) {
//some async action
process.nextTick(function(){
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
engine.modify(f3);
engine.retract(f1);
next();
})
}</code></pre>
<p>If any arguments are passed into next it is assumed there was an error and the session will error out.
</p>
<p>To define the action with the nools DSL
</p>
<pre class='prettyprint linenums lang-js'><code>then {
modify(f3, function(){
this.value = f1.value + f2.value;
});
retract(f1);
}</code></pre>
<p>For rules defined using the rules language nools will automatically determine what parameters need to be passed in based on what is referenced in the action.
</p>
<h1>Examples</h1>
<p><a name="fib"></a>
</p>
<h2>Fibonacci</h2>
<pre class='prettyprint linenums lang-js'><code>&quot;use strict&quot;;
var nools = require(&quot;nools&quot;);
var Fibonacci = function (sequence, value) {
this.sequence = sequence;
this.value = value || -1;
};
var Result = function (result) {
this.result = result || -1;
};
var flow = nools.flow(&quot;Fibonacci Flow&quot;, function (flow) {
flow.rule(&quot;Recurse&quot;, {priority:1}, [
[&quot;not&quot;, Fibonacci, &quot;f&quot;, &quot;f.sequence == 1&quot;],
[Fibonacci, &quot;f1&quot;, &quot;f1.sequence != 1&quot;]
], function (facts) {
var f2 = new Fibonacci(facts.f1.sequence - 1);
this.assert(f2);
});
flow.rule(&quot;Bootstrap&quot;, [
Fibonacci, &quot;f&quot;, &quot;f.value == -1 &amp;&amp; (f.sequence == 1 || f.sequence == 2)&quot;
], function (facts) {
var f = facts.f;
f.value = 1;
this.modify(f);
});
flow.rule(&quot;Calculate&quot;, [
[Fibonacci, &quot;f1&quot;, &quot;f1.value != -1&quot;, {sequence:&quot;s1&quot;}],
[Fibonacci, &quot;f2&quot;, &quot;f2.value != -1 &amp;&amp; f2.sequence == s1 + 1&quot;, {sequence:&quot;s2&quot;}],
[Fibonacci, &quot;f3&quot;, &quot;f3.value == -1 &amp;&amp; f3.sequence == s2 + 1&quot;],
[Result, &quot;r&quot;]
], function (facts) {
var f3 = facts.f3, f1 = facts.f1, f2 = facts.f2;
var v = f3.value = f1.value + facts.f2.value;
facts.r.result = v;
this.modify(f3);
this.retract(f1);
});
});
var r1 = new Result(),
session1 = flow.getSession(new Fibonacci(10), r1),
s1 = new Date;
session1.match().then(function () {
console.log(&quot;%d [%dms]&quot;, r1.result, new Date - s1);
session1.dispose();
});
var r2 = new Result(),
session2 = flow.getSession(new Fibonacci(150), r2),
s2 = new Date;
session2.match().then(function () {
console.log(&quot;%d [%dms]&quot;, r2.result, new Date - s2);
session2.dispose();
});
var r3 = new Result(),
session3 = flow.getSession(new Fibonacci(1000), r3),
s3 = new Date;
session3.match().then(function () {
console.log(&quot;%d [%dms]&quot;, r3.result, new Date - s3);
session3.dispose();
});</code></pre>
<p>Output
</p>
<pre class='prettyprint linenums lang-js'><code>55 [43ms]
9.969216677189305e+30 [383ms]
4.346655768693743e+208 [3580ms]</code></pre>
<p>Fiboncci with nools DSL
</p>
<pre class='prettyprint linenums lang-js'><code>//Define our object classes, you can
//also declare these outside of the nools
//file by passing them into the compile method
define Fibonacci {
value:-1,
sequence:null
}
define Result {
value : -1
}
rule Recurse {
priority:1,
when {
//you can use not or or methods in here
not(f : Fibonacci f.sequence == 1);
//f1 is how you can reference the fact else where
f1 : Fibonacci f1.sequence != 1;
}
then {
assert(new Fibonacci({sequence : f1.sequence - 1}));
}
}
rule Bootstrap {
when {
f : Fibonacci f.value == -1 &amp;&amp; (f.sequence == 1 || f.sequence == 2);
}
then{
modify(f, function(){
this.value = 1;
});
}
}
rule Calculate {
when {
f1 : Fibonacci f1.value != -1 {sequence : s1};
//here we define constraints along with a hash so you can reference sequence
//as s2 else where
f2 : Fibonacci f2.value != -1 &amp;&amp; f2.sequence == s1 + 1 {sequence:s2};
f3 : Fibonacci f3.value == -1 &amp;&amp; f3.sequence == s2 + 1;
r : Result
}
then {
modify(f3, function(){
this.value = r.result = f1.value + f2.value;
});
retract(f1);
}
}</code></pre>
<p>And to run
</p>
<pre class='prettyprint linenums lang-js'><code>var flow = nools.compile(__dirname + &quot;/fibonacci.nools&quot;);
var Fibonacci = flow.getDefined(&quot;fibonacci&quot;), Result = flow.getDefined(&quot;result&quot;);
var r1 = new Result(),
session1 = flow.getSession(new Fibonacci({sequence:10}), r1),
s1 = +(new Date());
session1.match().then(function () {
console.log(&quot;%d [%dms]&quot;, r1.result, +(new Date()) - s1);
session1.dispose();
});
var r2 = new Result(),
session2 = flow.getSession(new Fibonacci({sequence:150}), r2),
s2 = +(new Date());
session2.match().then(function () {
console.log(&quot;%d [%dms]&quot;, r2.result, +(new Date()) - s2);
session2.dispose();
});
var r3 = new Result(),
session3 = flow.getSession(new Fibonacci({sequence:1000}), r3),
s3 = +(new Date());
session3.match().then(function () {
console.log(&quot;%d [%dms]&quot;, r3.result, +(new Date()) - s3);
session3.dispose();
});</code></pre>
<hr>
<h2>License</h2>
<p>MIT <a href="https://github.com/C2FO/nools/raw/master/LICENSE">https://github.com/C2FO/nools/raw/master/LICENSE</a>
</p>
<h2>Meta</h2>
<p>Code: <code>git clone git://github.com/C2FO/nools.git</code></p>
</div>
</div>
<script type="text/javascript" src="./assets/js/jquery.js"></script>
<script type="text/javascript" src="./assets/js/bootstrap.min.js"></script>
<script type="text/javascript" src="./assets/js/prettify.js"></script>
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.