tag:blogger.com,1999:blog-47963507650813175812023-11-15T10:00:46.726-08:00Just My ThoughtsAnonymoushttp://www.blogger.com/profile/05315723391769813524noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-4796350765081317581.post-22691090802158487162012-05-30T15:25:00.000-07:002012-05-30T15:26:07.082-07:00<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
*{margin:0;padding:0;}
body {
font:13.34px helvetica,arial,freesans,clean,sans-serif;
color:black;
line-height:1.4em;
background-color: #F8F8F8;
padding: 0.7em;
}
p {
margin:1em 0;
line-height:1.5em;
}
table {
font-size:inherit;
font:100%;
margin:1em;
}
table th{border-bottom:1px solid #bbb;padding:.2em 1em;}
table td{border-bottom:1px solid #ddd;padding:.2em 1em;}
input[type=text],input[type=password],input[type=image],textarea{font:99% helvetica,arial,freesans,sans-serif;}
select,option{padding:0 .25em;}
optgroup{margin-top:.5em;}
pre,code{font:12px Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;}
pre {
margin:1em 0;
font-size:12px;
background-color:#eee;
border:1px solid #ddd;
padding:5px;
line-height:1.5em;
color:#444;
overflow:auto;
-webkit-box-shadow:rgba(0,0,0,0.07) 0 1px 2px inset;
-webkit-border-radius:3px;
-moz-border-radius:3px;border-radius:3px;
}
pre code {
padding:0;
font-size:12px;
background-color:#eee;
border:none;
}
code {
font-size:12px;
background-color:#f8f8ff;
color:#444;
padding:0 .2em;
border:1px solid #dedede;
}
img{border:0;max-width:100%;}
abbr{border-bottom:none;}
a{color:#4183c4;text-decoration:none;}
a:hover{text-decoration:underline;}
a code,a:link code,a:visited code{color:#4183c4;}
h2,h3{margin:1em 0;}
h1,h2,h3,h4,h5,h6{border:0;}
h1{font-size:170%;border-top:4px solid #aaa;padding-top:.5em;margin-top:1.5em;}
h1:first-child{margin-top:0;padding-top:.25em;border-top:none;}
h2{font-size:150%;margin-top:1.5em;border-top:4px solid #e0e0e0;padding-top:.5em;}
h3{margin-top:1em;}
hr{border:1px solid #ddd;}
ul{margin:1em 0 1em 2em;}
ol{margin:1em 0 1em 2em;}
ul li,ol li{margin-top:.5em;margin-bottom:.5em;}
ul ul,ul ol,ol ol,ol ul{margin-top:0;margin-bottom:0;}
blockquote{margin:1em 0;border-left:5px solid #ddd;padding-left:.6em;color:#555;}
dt{font-weight:bold;margin-left:1em;}
dd{margin-left:2em;margin-bottom:1em;}
@media screen and (min-width: 768px) {
body {
width: 748px;
margin:10px auto;
}
}
</style>
<title>Working with models in patio</title>
</head>
<body>
<h1>Loading Models in Patio</h1>
<p>One question that I often get is how to work with models in <code>patio</code>. Models in <code>patio</code> are different in that they are not synchronous in the loading of them. The reason is because we load the schema when you define the model object.</p>
<p>The reason we did this when designing <code>patio</code> was that it allows for a clean seperation of database DDL. You may ask what difference does it make, well…</p>
<p>This can come in handy when you have multiple pieces of software reading from a single database.</p>
<p>Imagine you have a ruby implementation of your model and a javascript implementation, for whatever reason (maybe your migrating from ruby to javascript and you cannot do it all at once). Well if this is the case then with patio you can just add your models and not have to worry about schema design as patio will dynamically load it at run time.</p>
<p>This allows the javascript developers to focus on gettings things done rather than setting up their models to match the ruby schemas field for field!</p>
<h2>Getting started</h2>
<p>When I work with patio I typically follow the same basic directory structure</p>
<pre><code>- lib
- models
- Model1.js
- Model2.js
- Model3.js
- index.js
</code></pre>
<p>Then in index.js I have a method like the following</p>
<pre><code>(function(){
"use strict";
var path = require("path"),
comb = require("comb"),
patio = require("patio");
var CONNECT_URI = "mysql://test:testpass@localhost:3306/db?minConnections=1&maxConnections=5";
patio.connect(CONNECT_URI);
//add patio as an export so I dont have any
//module issues where I have the wrong instance of patio.
exports.patio = patio;
exports.load = (function(){
//create a shared promise so we only load the models once, and a loaded var to store if
//we have called load before
var loadPromise = new comb.Promise(), loaded = false;
return function(cb){
if(!loaded){
//we havent loaded yet so load the models directory at once then call the loadPromise
patio.import(path.resolve(__dirname, "./models")).then(loadPromise);
loaded = true;
}
if(cb){
//classic accepts a callback like a normal node callback i.e. function(err, result){};
loadPromise.classic(cb);
}
//return the promise incase you want to use the promise api
return loadPromise;
};
})();
})();
</code></pre>
<p>I usually have my model in its own module so I can use it accross services we’ll call our model package <code>my-model</code></p>
<p>So in other modules I add it as a dependency and use it like so</p>
<pre><code>(function(){
"use strict";
var models = require("my-model"),
patio = models.patio;
models.load(function(err){
if(err){
console.error(err.stack);
process.exit();
}else{
var Model1 = patio.getModel("model1"),
Model2 = patio.getModel("model2");
//do some thing with them
}
});
})();
</code></pre>
<h2>Inter-model Dependencies</h2>
<p>Sometimes you have models that are dependent among eachother to get around this the model has a <code>patio</code> property or you can just require <code>patio</code>. Then in the constructor of the model you can set up your dependencies.</p>
<p>So if Model2 needed Model1 for a query you can do the following</p>
<pre><code>
(function(){
"use strict";
var patio = require("patio"),
Model1;
patio.addModel("model2", {
instance : {
constructor : function(){
if(!Model1){
//now you can use it
Model1 = patio.getModel("model1");
}
}
},
static : {
someQueryMethod : function(){
//using the patio property
var Model1 = this.patio.getModel("model1");
//do something with it
}
}
});
});
</code></pre>
<h3>Wrapup</h3>
<p>Hopefully this boiler plate can help you get started with <code>patio</code> and the model loading pattern.</p>
<p>I have set up a repo at <a href="https://github.com/doug-martin/patio-boilerplate">https://github.com/doug-martin/patio-boilerplate</a></p>
</body>
</html>Anonymoushttp://www.blogger.com/profile/05315723391769813524noreply@blogger.com1tag:blogger.com,1999:blog-4796350765081317581.post-61020675046267165782012-05-23T19:56:00.002-07:002012-05-23T19:56:27.229-07:00Getting started with gofigure<style>
*{margin:0;padding:0;}
body {
font:13.34px helvetica,arial,freesans,clean,sans-serif;
color:black;
line-height:1.4em;
background-color: #F8F8F8;
padding: 0.7em;
}
p {
margin:1em 0;
line-height:1.5em;
}
table {
font-size:inherit;
font:100%;
margin:1em;
}
table th{border-bottom:1px solid #bbb;padding:.2em 1em;}
table td{border-bottom:1px solid #ddd;padding:.2em 1em;}
input[type=text],input[type=password],input[type=image],textarea{font:99% helvetica,arial,freesans,sans-serif;}
select,option{padding:0 .25em;}
optgroup{margin-top:.5em;}
pre,code{font:12px Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;}
pre {
margin:1em 0;
font-size:12px;
background-color:#eee;
border:1px solid #ddd;
padding:5px;
line-height:1.5em;
color:#444;
overflow:auto;
-webkit-box-shadow:rgba(0,0,0,0.07) 0 1px 2px inset;
-webkit-border-radius:3px;
-moz-border-radius:3px;border-radius:3px;
}
pre code {
padding:0;
font-size:12px;
background-color:#eee;
border:none;
}
code {
font-size:12px;
background-color:#f8f8ff;
color:#444;
padding:0 .2em;
border:1px solid #dedede;
}
img{border:0;max-width:100%;}
abbr{border-bottom:none;}
a{color:#4183c4;text-decoration:none;}
a:hover{text-decoration:underline;}
a code,a:link code,a:visited code{color:#4183c4;}
h2,h3{margin:1em 0;}
h1,h2,h3,h4,h5,h6{border:0;}
h1{font-size:170%;border-top:4px solid #aaa;padding-top:.5em;margin-top:1.5em;}
h1:first-child{margin-top:0;padding-top:.25em;border-top:none;}
h2{font-size:150%;margin-top:1.5em;border-top:4px solid #e0e0e0;padding-top:.5em;}
h3{margin-top:1em;}
hr{border:1px solid #ddd;}
ul{margin:1em 0 1em 2em;}
ol{margin:1em 0 1em 2em;}
ul li,ol li{margin-top:.5em;margin-bottom:.5em;}
ul ul,ul ol,ol ol,ol ul{margin-top:0;margin-bottom:0;}
blockquote{margin:1em 0;border-left:5px solid #ddd;padding-left:.6em;color:#555;}
dt{font-weight:bold;margin-left:1em;}
dd{margin-left:2em;margin-bottom:1em;}
@media screen and (min-width: 768px) {
body {
width: 748px;
margin:10px auto;
}
}
</style>
<title>gofigure</title>
</head>
<body>
<ul>
<li><a href="https://github.com/Pollenware/gofigure">github</a></li>
<li><a href="http://pollenware.github.com/gofigure/">webpage</a></li>
</ul>
<p><code>gofigure</code> is a configuration tool for node to help in the gathering and monitoring of configuration files in node.</p>
<h1>Installation</h1>
<pre><code>npm install gofigure
</code></pre>
<p>or</p>
<pre><code>git clone git@github.com:Pollenware/gofigure.git
</code></pre>
<h1>Getting Started</h1>
<ul>
<li><a href="#load">Loading A Configuration</a>
<ul>
<li><a href="#loadDir">Directories</a></li>
<li><a href="#loadFiles">Files</a></li>
</ul>
</li>
<li><a href="#monitoring">Monitoring Property Changes</a>
<ul>
<li><a href="#monitoringAll">Monitoring All Files</a></li>
<li><a href="#monitoringSome">Monitoring Certain Files</a></li>
<li><a href="#monitoringSyntax">Property Topic Syntax</a></li>
<li><a href="#monitoringCB">Property Change Callback</a></li>
</ul>
</li>
<li><a href="#environments">Environments</a></li>
</ul>
<p><a name="load"></a></p>
<h2>Loading configurations</h2>
<p><code>gofigure</code> currently handles the loading of JSON files for configurations.</p>
<p>To Get an instance of a configuration object use the <code>gofigure</code> method. The <code>gofigure</code> method takes an object that accepts the following options</p>
<ul>
<li><a href="#loadDir">locations</a> : an array of directories that contain your configurations.</li>
<li><a href="#loadFiles">files</a> : an array of files that contain your configurations.</li>
<li><a href="#monitoring">monitor</a> : set to true to monitor changes to configuration files.</li>
<li><code>ignoreMissing</code> : By default <code>gofigure</code> will ignore missing directories. Set this to false to prevent the ignoring of missing configuration directories.</li>
<li><a href="#environments">environment</a> : By default will look for <code>process.env.NODE_ENV</code> if this is not set then <code>gofigure</code> will read all properties. If you wish to explicity set the environment then set this property.</li>
</ul>
<pre><code>
var gofigure = require("gofigure");
//Loader for directory of configurations
var dirLoader = gofigure({
locations : [__dirname + "/configs"]
});
//Loader for files of configurations
var dirLoader = gofigure({
files : [process.env.HOME + "/configs/config1.json", __dirname + "/config1.json"]
});
</code></pre>
<p>You can load configurations asynchronously</p>
<pre><code>loader.load(function(err, config){
var PORT = config.port, HOST = config.host;
});
</code></pre>
<p>or synchronously</p>
<pre><code>var gofigure = require("gofigure");
var loader = gofigure({locations : [__dirname + "/configs"]});
var config = loader.loadSync();
</code></pre>
<p><a name="loadDir"></a></p>
<h3>Directories of configurations</h3>
<p>To load directories that contain configuration files in the options object provide locations property that is an array of directories than contain your configurations.</p>
<pre><code>
var gofigure = require("gofigure");
var loader = gofigure({locations : [__dirname + "/configs"]});
loader.load(function(err, config){
var PORT = config.port, HOST = config.host;
});
</code></pre>
<p>The order of the locations matter as it defines a precedence for files. For example suppose you have a directory of default configuration files, and on production you want to override those configuration with environment specific configurations with out changing your module or source controlled files.</p>
<pre><code>var gofigure = require("gofigure");
var loader = gofigure({locations : ["/prod/configs", __dirname + "/configs"]});
loader.load(function(err, config){
var PORT = config.port, HOST = config.host;
});
</code></pre>
<p>Here any production configuration files found in <code>/prod/configs</code> will override the properties in <code>__dirname + "/configs"</code>.</p>
<p>Another use case might be in development where you have default properties and instead of altering the source controlled files the developer can override them by putting them in their home directory.</p>
<pre><code>var gofigure = require("gofigure");
var HOME = process.env.HOME;
var loader = gofigure({locations : [ HOME + "/yourApp/configs", __dirname + "/configs"]});
loader.load(function(err, config){
var PORT = config.port, HOST = config.host;
});
</code></pre>
<p><a name="loadFiles"></a></p>
<h3>Files</h3>
<p>You may also load specific files rather than entire directories.</p>
<pre><code>var gofigure = require("gofigure");
var loader = gofigure({files : ["/prod/configs/config1.json", __dirname + "/config.json"]});
loader.load(function(err, config){
var PORT = config.port, HOST = config.host;
});
</code></pre>
<p>Again order matters <code>/prod/configs/config1.json</code> will override <code>__dirname + "/config.json"</code></p>
<p><a name="monitoring"></a></p>
<h2>Monitoring</h2>
<p><code>gofigure</code> supports the monitoring of changes to configuration files.</p>
<p><a name="monitoringAll"></a></p>
<h3>All files</h3>
<p>To enable monitoring you can specify monitor to true in the options.</p>
<pre><code>var gofigure = require("gofigure");
var loader = gofigure({monitor : true, files : ["/prod/configs/config1.json", __dirname + "/config.json"]});
var config = loader.loadSync();
loading.on("my.cool.property", function(newValue){
//...do something
});
</code></pre>
<p><a name="monitoringSome"></a></p>
<h3>Individual Files</h3>
<p>To monitor certain files you can use the files property and with object that have a <code>monitor : true</code> KV pair.</p>
<pre><code>var gofigure = require("gofigure");
var loader = gofigure({files : [
{
file : "/prod/configs/config1.json",
monitor : true
},
__dirname + "/config.json"
]});
var config = loader.loadSync();
loading.on("my.cool.property", function(newValue){
//...do something
});
</code></pre>
<p>Just <code>config1.json</code> will be monitored for changes.</p>
<p><a name="monitoringSyntax"></a></p>
<h3>Property topic syntax</h3>
<p>To listen to all properties</p>
<pre><code>loading.on(function(config){
//...do something
});
loading.on(function(nameOfPropertyChanged, config){
//...do something
});
loading.on(function(nameOfPropertyChanged, value, config){
//...do something
});
</code></pre>
<p>To listen to specific properties</p>
<pre><code>loading.on("my.cool.property", function(newValue){
//...do something
});
loading.on("my.cool.property", function(newValue, config){
//...do something
});
loading.on("my.cool.property", function(nameOfPropertyChanged, value, config){
//...do something
});
</code></pre>
<h3>Wild cards</h3>
<pre><code>
//listen to any property changed on the my.cool object
loading.on("my.cool.*", function(propName, newValue){
//...do something
});
//listen to the change of a property named 'property' on any object
//that is a member of my
loading.on("my.*.property", function(propName, newValue){
//...do something
});
//listen to the change of a property named 'property' that is
//a member of a property called cool
loading.on("*.cool.property", function(propName, newValue){
//...do something
});
//listen to the change of property or otherProperty on the my.cool object.
loading.on("my.cool.{property|otherProperty}", function(propName, newValue){
//...do something
});
//listen to the change of property or otherProperty on the my cool or
//notCool object.
loading.on("my.{cool|notCool}.{property|otherProperty}", function(propName, newValue){
//...do something
});
</code></pre>
<p><a name="monitoringCB"></a></p>
<h3>Callback Arguments</h3>
<p>The property change callback will pass in the following values depending on the arity of the callback.</p>
<p>If 1 argument is expected then just the callback invoked with the new value is a.</p>
<pre><code>
loading.on("my.cool.property", function(newValue){
//...do something
});
</code></pre>
<p>If two arguments are expected then it is invoked with the property name and the new value.</p>
<pre><code>
loading.on("my.cool.property", function(propName, newValue){
//...do something
});
</code></pre>
<p>Other wise the callback is invoked with the propertyName, newValue and the configuration object.</p>
<pre><code>
loading.on("my.cool.property", function(propName, newValue, configObject){
//...do something
});
</code></pre>
<p><a name="environments"></a></p>
<h2>Environments</h2>
<p><code>gofigure</code> also supports environments, by default it will look for <code>NODE_ENV</code> and if it is set then it will use it.</p>
<p>The following is an example configuration file</p>
<pre><code>
{
"development": {
"logging":{
"patio":{
"level":"DEBUG",
"appenders":[
{
"type":"RollingFileAppender",
"file":"/var/log/myApp/patio.log"
},
{
"type":"ConsoleAppender"
}
]
}
},
"app" : {
"host" : "localhost",
"port" : "8088"
},
"MYSQL_DB" : "mysql://test:testpass@localhost:3306/dev_db",
"MONGO_DB" : "mongodb://test:testpass@localhost:27017/dev_db"
},
"production": {
"logging":{
"patio":{
"level":"ERROR",
"appenders":[
{
"type":"RollingFileAppender",
"file":"/var/log/myApp/patio.log"
}
]
}
},
"app" : {
"host" : "prod.mydomain.com",
"port" : "80"
},
"MYSQL_DB" : "mysql://test:testpass@prod.mydomain.com:3306/prod_db",
"MONGO_DB" : "mongodb://test:testpass@prod.mydomain.com:27017/prd_db"
},
"test": {
"logging":{
"patio":{
"level":"INFO",
"appenders":[
{
"type":"RollingFileAppender",
"file":"/var/log/myApp/patio.log"
}
]
}
},
"app" : {
"host" : "test.mydomain.com",
"port" : "80"
},
"MYSQL_DB" : "mysql://test:testpass@test.mydomain.com:3306/test_db",
"MONGO_DB" : "mongodb://test:testpass@test.mydomain.com:27017/test_db"
}
}
</code></pre>
<p>To load just the development properties set the <code>environment</code> to development.</p>
<pre><code>
var gofigure = require("gofigure"),
patio = require("patio"),
mongoose = require("mongoose"),
comb = require("comb"),
DB, HOST, PORT;
var loader = gofigure({
files : [__dirname + "/config-env.json"],
environment : "development"
})
.on("MYSQL_DB", function(uri){
patio.connect(uri);
})
.on("MONGO_DB", function(uri){
mongoose.connect(uri);
})
.on("logging", function(logging){
new comb.logging.PropertyConfigurator().configure(logging);
patio.configureLogging(logging);
})
.on("app", function(app){
//...
})
.load(function(){
//do something
})
</code></pre>
<h1>Wrap up</h1>
<p>I hope this is useful is getting you started with <code>gofigure</code> and the potential uses of the library.</p>
<p>Please submit issues to <a href="https://github.com/Pollenware/gofigure/issues">github issues</a>.</p>
<p>As always pull requests are welcome!</p>
</body>Anonymoushttp://www.blogger.com/profile/05315723391769813524noreply@blogger.com2tag:blogger.com,1999:blog-4796350765081317581.post-53148455636837478112012-05-22T17:19:00.001-07:002012-05-23T14:42:53.045-07:00Getting started with nools<h2>
What is nools?</h2>
Nools is a rete based rules engine written entirely in javascript, with a target platform of node.js. <br />
Nools was written for Pollenware to allow them to status offers in their market clearing events in a more dynamic way.<br />
<h2>
Getting Started</h2>
To install nools run<br />
<pre class="brush:js">npm install nools</pre>
Or<br />
<pre class="brush:js">git clone git@github.com:Pollenware/nools.git</pre>
To run the tests<br />
<pre class="brush:js">make test</pre>
To run the benchmarks<br />
<pre class="brush:js">make benchmarks</pre>
<h2>
Terms</h2>
First lets start with a few terms that are used in nools.<br />
<ul>
<li><code>rule</code> - A collection of constraints that must be satisfied for in order for a <code>action</code> to occur.</li>
<li><code>action</code> - The code that will execute when a all of a <code>rule</code>'s constraints have been satisfied.</li>
<li><code>fact</code> - An object/item inserted into a session that the <code>rule</code>'s constraints match against.</li>
<li><code>flow</code> - This is container for rules that will be executed, you can think of it as a rule book.</li>
<li><code>session</code> - This is an "instance" of a flow used to match facts. Sessions are obtained from a flow.</li>
</ul>
<h2>
Writing rules</h2>
Nools includes a parser to parse <code>nools</code> files into a <code>flow</code>.<br />
Lets look at an example<br />
<pre class="brush:js">//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 && (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 && f2.sequence == s1 + 1 {sequence:s2};
f3 : Fibonacci f3.value == -1 && f3.sequence == s2 + 1;
r : Result
}
then {
modify(f3, function(){
this.value = r.result = f1.value + f2.value;
});
retract(f1);
}
}
</pre>
<h3>
Defining Objects</h3>
In the above flow we define two classes <code>Fibonacci</code> and <code>Result</code> Both of these classes can be referenced by name throughout the file you can also access them by through the <code>flow</code> by calling <code>getDefined</code>. <br />
In the nools language any valid <code>javascript</code> hash can be put inside of the define block,
however if you define a <code>constructor</code> property then that will override the default constructor<br />
For example we could change <code>Fibonacci</code> to to accept a sequence and value directly<br />
<pre class="brush:js">define Fibonacci{
constructor : function(sequence, value){
this.sequence = sequence || -1;
this.value = value || -1;
}
}
</pre>
You could then use the new constructor in your rules<br />
<pre class="brush:js">var fib = new Fibonacci(10, 1);</pre>
<h3>
Rule Definition</h3>
The rules <code>Recurse</code>, <code>Bootstrap</code> and <code>Calculate</code> use the nool rule syntax<br />
<pre class="brush:js">rule <name> {
when {<constraints>}
then {<action>}
}
</pre>
Lets look at the <code>Recurse</code> rule a little closer.<br />
<pre class="brush:js">//Define a rule recurse
rule Recurse {
//Give it a priority. The priority is 1 which is above all
//other rules as the default priority/salience is 0
priority:1,
//Our LHS when block
when {
//you can use not or or methods in here
//give the fact an alias of f and we checking that there is
//NOT a Fibonacci object with a sequence of 1
not(f : Fibonacci f.sequence == 1);
//look for a Fibonacci object who's sequence does not equal 1
f1 : Fibonacci f1.sequence != 1;
}
then {
//assert a new fact into the engine
assert(new Fibonacci({sequence : f1.sequence - 1}));
}
}
</pre>
<strong>Note</strong> In the when block each constraint must end with a <code>;</code><br />
<h4>
But my action is async</h4>
The actions also support async actions through a <code>next(err?)</code> call.<br />
<pre class="brush:js">rule Recurse {
priority:1,
when {
not(f : Fibonacci f.sequence == 1);
f1 : Fibonacci f1.sequence != 1;
}
then {
process.nextTick(function(){
assert(new Fibonacci({sequence : f1.sequence - 1}));
next();
});
}
}
</pre>
<strong>Note</strong> if next is called with an argument then it will be assumed to be an error
and the <code>session</code> execution will stop and an error will be passed into the callback.<br />
<h3>
Defining Helper Functions</h3>
Nools also allows the definition of helper functions, the function can be any valid javascript.<br />
<pre class="brush:js">function subtract(a, b){
return a, b;
}
function add(a, b){
return a + b;
}
function sum(){
var arr = Array.prototype.slice.call(arguments);
var sum = 0;
arr.forEach(function(a){sum += 0});
return sum;
}
</pre>
You can reference the methods in your actions or within other defined functions.<br />
<h2>
Working With Flows</h2>
The <code>flow</code> object is the container for all rules engines, a <code>flow</code> is created once and you can get multiple sessions from the flow. <br />
To get a flow for the above fibonacci rules<br />
<pre class="brush:js">//compile the file into a flow
var flow = nools.compile(__dirname + "/fibonacci.nools");
//Get defined classes
var Fibonacci = flow.getDefined("Fibonacci"),
Result = flow.getDefined("Result");
</pre>
<h3>
Sessions</h3>
The <code>flow</code> object is simply a conatainer for rules. To run the engine you need to obtain a <code>session</code>.<br />
<pre class="brush:js">var r1 = new Result(),
//Get a new session inserting a new Fibonacci object and a result to gather the
//final number
session1 = flow.getSession(new Fibonacci({sequence:10}), r1),
s1 = +(new Date());
//call match to execute the engine
session1.match(function(err){
if(err){
console.error(err);
}else{
console.log("%d [%dms]", r1.result, +(new Date()) - s1);
//cleanup the session
session1.dispose();
}
});
</pre>
<h4>
Session Events</h4>
Then <code>session</code> object also emits different events <br />
<ul>
<li><code>fire</code> - emitted when a new rule is fired. The event is emitted with the name of the rule
fired and associated facts.</li>
<li><code>assert</code> - emitted when a new fact is asserted</li>
<li><code>retract</code> - emitted when a fact is retracted(removed) from the session</li>
<li><code>modify</code> - emitted when a fact is modified</li>
</ul>
<h2>
Wrap Up</h2>
I hope this was a good introduction into nools for more information visit :<br />
<ul>
<li><a href="https://github.com/Pollenware/nools">github page</a> </li>
<li><a href="http://pollenware.github.com/nools/">nools webpage</a>.</li>
</ul>Anonymoushttp://www.blogger.com/profile/05315723391769813524noreply@blogger.com25tag:blogger.com,1999:blog-4796350765081317581.post-67961089698277387962012-01-14T15:04:00.000-08:002012-01-15T09:20:03.050-08:00OO with comb and Node.js<span style="font-family: Arial, Helvetica, sans-serif;">So, I decided last night that I want to blog. The more I thought about I realized there have been a lot of things I should have written about but didn't; so here is to writing about things I should.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<h4>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: x-large;">Comb</span></h4>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://github.com/Pollenware/comb">[github] https://github.com/Pollenware/comb</a></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="http://pollenware.github.com/comb/symbols/comb.html">[docs] http://pollenware.github.com/comb</a></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><b>A little about comb...</b></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;">Comb is a library that I have been working on for almost a year now and has recently seen some attention on DailyJs but other than that has stayed quiet. I have been racking my brain wondering why more people do not use it, and I think I know why...there is a lot of stuff in it and it can be daunting to find the gems in it. So my next couple of posts will be dedicated to going through some of the coolest features of comb and what makes it different.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><b>comb.define</b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="http://pollenware.github.com/comb/symbols/comb.html#.define">documentation</a></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Ok ok, I know what your thinking "oh man not another class system that tries to simulate OO, and hide the beauty of prototypal inheritance". Well...yes and no. I feel that one thing that is important in good software design is clearly and concisely organizing code into reusable blocks(e.g. classes). However, I do not like the java principle of single inheritance, the reason I do not care for single inheritance is that I often want to write a class that contains a set of features that can be exposed on other classes just by "mixing it in", so one of the first things I did when designing </span><a href="http://pollenware.github.com/comb/symbols/comb.html#.define" style="font-family: Arial, Helvetica, sans-serif;">comb.define</a><span style="font-family: Arial, Helvetica, sans-serif;"> was to account for multiple inheritance as well as addressing other issues that arrise with following OO patterns in javascript.</span><br />
<br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><b>Instance Methods </b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">When defining classes in <i style="font-weight: bold;"> comb</i> there are two root level properties you can define, <i style="font-weight: bold;"> instance</i> and <i><b> static</b>. </i></span><span style="font-family: Arial, Helvetica, sans-serif;">The optional <b><i>instance</i></b> object is used to define properties and methods on an instance of a class. The optional <b>static</b> property is used to define class level methods and properties than can be used without an instance of a class.</span><br />
<pre class="brush:js">comb.define(null, {
instance : {//Define your instance methods and properties}
static : {//Define your static methods and properties}
});</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><i><br /></i></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Lets start of by defining the class Mammal that will be used as the parent for other classes.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<pre class="brush:js">var Mammal = comb.define(null, {
instance : {
_type : "mammal",
_sound : " *** ",
constructor: function(options) {
options = options || {};
this._super(arguments);
var type = options.type, sound = options.mammal;
type && (this._type = type);
sound && (this._sound = sound);
},
speak : function() {
return "A mammal of type " + this._type;
}
}
});</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Next lets define two implementing classes, Wolf and Dog. This example is a little contrived as Dog could inherit from Wolf. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<pre class="brush:js">var Wolf = comb.define(Mammal, {
instance: {
_type : "wolf",
_sound : "howl",
speak : function() {
return this._super(arguments) + " that " + this._sound + "s";
},
howl : function(){
console.log("Hoooooooooooowl!")
}
}
});
var Dog = comb.define(Mammal, {
instance: {
_type : "dog",
_sound : "bark",
speak : function() {
return this._super(arguments) + ", thats domesticated";
},
woof : function(){
console.log("Wooooooof!")
}
}
});
</pre>
<div style="white-space: normal;">
<span style="font-family: Arial, Helvetica, sans-serif;">Ok, so... Wolf and Dog inherit from Mammal, which means that they are both an </span><i style="font-family: Arial, Helvetica, sans-serif;"><b>instanceof</b></i><span style="font-family: Arial, Helvetica, sans-serif;"> Mammal. </span><span style="font-family: Arial, Helvetica, sans-serif;">Notice that both Wolf and Dog override the Mammal default values type and sound with their own values. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<br />
<pre class="brush:js">speak : function() {
return this._super(arguments) + " that " + this._sound + "s";
}
</pre>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Wolf and Dog also override the <b><i>speak</i></b> method, in order to invoke the parents implementation the method </span><i style="font-family: Arial, Helvetica, sans-serif;"><span style="color: #0c343d;"><b>_super</b></span></i><span style="font-family: Arial, Helvetica, sans-serif;"> is invoked. <b><i>_super</i></b> traverses the inheritance chain and returns the value. So for both Dog and Wolf they called <b><i>_super</i></b> and</span><span style="font-family: Arial, Helvetica, sans-serif;"> appended their own message to their parents message.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
</div>
<pre class="brush:js">//1. Create a dog and make him speak
var myDog = new Dog();
myDog.woof() //prints Wooooooof!
myDog.speak();
//=> A mammal of type dog, thats domesticated
//2. Create a wolf and make him speak
var myWolf = new Wolf();
myWolf.howl() //prints "Hoooooooooooowl!"
myWolf.speak();
//=> A mammal of type wolf that howls
//3. Create a DogWolf that inherits from Dog, and mixes in Wolf
var DogWolf = comb.define([Dog, Wolf]);
var myDogWolf = new DogWolf();
myDogWolf.woof() //prints Wooooooof!
myDogWolf.howl() //prints "Hoooooooooooowl!"
myDogWolf.speak();
//=> A mammal of type wolf, thats domesticated that howls
//4. Create a WolfDog that inherits from Wolf, and mixes in Dog
var WolfDog = comb.define([Wolf, Dog]);
var myWolfDog = new WolfDog();
myWolfDog.woof() //prints Wooooooof!
myWolfDog.howl() //prints "Hoooooooooooowl!"
myWolfDog.speak();
//=> A mammal of type dog that barks, thats domesticated
</pre>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<span style="font-family: Arial, Helvetica, sans-serif;">What?!?!?!</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b>1 and 2</b> : We created instances of Dog and Wolf and made them speak. Notice that the return value of the <b><i>speak()</i></b> method is the return value of Mammal's speak method concatenated with the implementing classes own message.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b>3 and 4</b>. Ok, this is where it gets interesting, so lets break it down line by line.</span><br />
<br />
<pre class="brush:js">var DogWolf = comb.define([Dog, Wolf]);</pre>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">This line defines a new class aptly named DogWolf. The DogWolf class is an instanceof Dog but mixes in Wolf. What does that mean?</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<br />
<pre class="brush:js">var myDogWolf = new DogWolf();
myDogWolf instanceof Dog //=> true
myWolfDog instanceof Wolf //=> false
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">So Wolf is mixed so we can get the howl method. </span>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<pre class="brush:js">myDogWolf.speak();
//=> A mammal of type wolf, thats domesticated that howls
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">So when myDogWolf speaks it invokes the speak functionality of Wolf->Dog->Mammal. The order of inheritance is important to keep in mind when designing your classes the inheritance chain will happen in reverse, starting with the last mixin traversing the inheritance chain until either <i style="font-weight: bold;">_super</i> is not invoked or the parent of the <i style="font-weight: bold;">super </i><i>class</i><i style="font-weight: bold;"> </i>is reached, in this case Mammal. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">So lets add some public properties to Wolf and Dog.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<pre class="brush:js">var Wolf = comb.define(Mammal, {
instance:{
_type:"wolf",
_sound:"howl",
__color:"grey",
speak:function () {
return this._super(arguments) + " that " + this._sound + "s";
},
howl:function () {
console.log("Hoooooooooooowl!")
},
setters:{
color:function (color) {
if (comb.isString(color)) {
this.__color = color;
if (color === "white") {
this._sound = "LOUD howl";
}
}else{
throw new TypeError("Color must be a String");
}
}
},
getters:{
color:function () {
return this.__color;
}
}
}
});
var Dog = comb.define(Mammal, {
instance:{
_type:"dog",
_sound:"bark",
__breed:null,
constructor : function(opts){
opts = opts || {};
!comb.isUndefinedOrNull(opts.breed)
&& (this.breed = opts.breed);
this._super(arguments);
},
speak:function () {
return this._super(arguments) + ", thats domesticated";
},
woof:function () {
console.log("Wooooooof!")
},
setters:{
breed:function (breed) {
if (comb.isString(breed)) {
this.__breed = breed;
} else {
throw new TypeError("Breed must be a String");
}
}
},
getters:{
breed:function () {
return this.__breed;
},
foundOldManInWell:function () {
return "collie" === this.__breed;
}
}
}
});
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">So we added a setter and getter for <b><i> color</i></b> to the Wolf class. The advantage of adding setters and getters is that it allows you to add logic when setting/getting properties. When setting the <b><i>color</i></b> property on Wolf we check that it is a string and we change our sound depending on the color of the Wolf. If you supply a getter for a property and not a corresponding setter it will be read only(e.g. the Dogs <i><b>foundOldManInWell</b> </i>property is read only<i>),</i> the same applies for supplying only a setter<i>. </i>Lets try the getters and setters out.</span><br />
<i style="font-family: Arial, Helvetica, sans-serif;"><br /></i><br />
<pre class="brush:js">var myDog = new Dog({breed : "beagle"});
console.log(myDog.breed); //prints beagle
console.log(myDog.foundOldManInWell); //prints false
myDog.breed = "collie";
console.log(myDog.breed); //prints collie
console.log(myDog.foundOldManInWell); //prints true
try {
myDog.breed = false;
} catch (e) {
console.error(e); //prints [TypeError: Breed must be a String]
}
try {
new Dog({breed : false});
} catch (e) {
console.error(e); //prints [TypeError: Breed must be a String]
}
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">So now that we have defined some instance methods lets get our static on.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><b>Static Methods</b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">As stated above <i style="font-weight: bold;"> comb.define</i> looks for an optional <i style="font-weight: bold;">static </i> property on the prototype declaration of a class. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Lets modify Mammal to include static properties.</span>
<br />
<pre class="brush:js">var Mammal = comb.define(null, {
instance:{
_type:"mammal",
_sound:" *** ",
constructor:function (options) {
options = options || {};
this._super(arguments);
var myClass = this._static;
this._type = options.type || myClass.DEFAULT_TYPE;
this._sound = options.sound || myClass.DEFAULT_SOUND;
},
speak:function () {
return "A mammal of type " + this._type;
},
getter : {
type : function(){
return this._type;
}
}
},
static : {
DEFAULT_TYPE : "mammal",
DEFAULT_SOUND : " *** ",
soundOff : function() {
return "Im a mammal!!";
}
}
});
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">So we added two static properties to Mammal, <b><i>DEFAULT_TYPE</i></b> and <b><i>DEFAULT_SOUND</i></b>. These properties can be accessed by instances through the <b><i>_static</i></b> property. </span>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<pre class="brush:js">constructor:function (options) {
options = options || {};
this._super(arguments);
var myClass = this._static;
this._type = options.type || myClass.DEFAULT_TYPE;
this._type = options.sound || myClass.DEFAULT_SOUND;
}
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;">So we refactored the constructor function to leverage the new static properties when initializing itself. One example of using this initialization method is when you have properties that you want to be able to configure and apply to all instances of a class.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<br />
<pre class="brush:js">var myMammal = new Mammal();
console.log(myMammal.type); //prints mammal
Mammal.DEFAULT_TYPE = "whale";
myMammal = new Mammal();
console.log(myMammal.type); //prints whale
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b>Inhertance In Static Functions.</b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b><br /></b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">One neat thing about defining classes in <i style="font-weight: bold;">comb </i>is that you not only get the advantages of inheritance in instance methods but static methods as well. So lets modify Dog and Wolf to take advantage of that.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
<br />
<pre class="brush:js">var Wolf = comb.define(Mammal, {
instance:{
_type:"wolf",
_sound:"howl",
__color:"grey",
speak:function () {
return this._super(arguments) + " that " + this._sound + "s";
},
howl:function () {
console.log("Hoooooooooooowl!")
},
setters:{
color:function (color) {
if (comb.isString(color)) {
this.__color = color;
if (color === "white") {
this._sound = "LOUD howl";
}
} else {
throw new TypeError("Color must be a String");
}
}
},
getters:{
color:function () {
return this.__color;
}
}
},
static:{
soundOff:function () {
return comb.string.format("%s, %s", this._super(arguments), "I'm a Wolf");
}
}
});
var Dog = comb.define(Mammal, {
instance:{
_type:"dog",
_sound:"bark",
__breed:null,
constructor:function (opts) {
opts = opts || {};
!comb.isUndefinedOrNull(opts.breed) && (this.breed = opts.breed);
this._super(arguments);
},
speak:function () {
return this._super(arguments) + ", thats domesticated";
},
woof:function () {
console.log("Wooooooof!")
},
setters:{
breed:function (breed) {
if (comb.isString(breed)) {
this.__breed = breed;
} else {
throw new TypeError("Breed must be a String");
}
}
},
getters:{
breed:function () {
return this.__breed;
},
foundOldManInWell:function () {
return "collie" === this.__breed;
}
}
},
static:{
soundOff:function () {
return comb.string.format("%s, %s", this._super(arguments), "I'm a Dog");
}
}
});
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;">When executing soundOff.</span>
<br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<pre class="brush:js">console.log(Mammal.soundOff());
console.log(Wolf.soundOff());
console.log(Dog.soundOff());
console.log(DogWolf.soundOff());
console.log(WolfDog.soundOff());
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">As you can see inheritance within the static methods follows the same order as it does within the instance methods.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b>Static Getters and Setters</b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">Getters and setters are declared the same way in a static declaration as they are in an instance declaration.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b>Getting an Instance of my self.</b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><b><br /></b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">One nuance about prototypal inheritance is that the scope in which a function is called is not consistent. For example, lets add a reproduce method to Mammal.</span><br />
<pre class="brush:js">var Mammal = comb.define(null, {
instance:{
_type:"mammal",
_sound:" *** ",
constructor:function (options) {
options = options || {};
this._super(arguments);
var myClass = this._static;
this._type = options.type || myClass.DEFAULT_TYPE;
this._sound = options.sound || myClass.DEFAULT_SOUND;
},
speak:function () {
return "A mammal of type " + this._type;
},
reproduce : function(){
return new Mammal();
},
getters:{
type:function () {
return this._type;
}
}
},
static:{
DEFAULT_TYPE:"mammal",
DEFAULT_SOUND:" *** ",
soundOff:function () {
return comb.string.format("Im a %s!!", this.DEFAULT_TYPE);
}
}
});
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">This is great except that it will only work for instances of Mammal if we created a Dog and asked it to reproduce it would return a Mammal and not a Dog. Solution, change reproduce to:</span><br />
<pre class="brush:js">reproduce : function(){
return new this._static();
}
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">This guarantees that you create an instance of your type. The same applies if you want to check if something is an instance of your current type. For example lets add a sameSpecies method to Mammal.</span><br />
<pre class="brush:js">sameSpecies : function(obj){
return obj instanceof this._static;
}
</pre>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">This comes in handy when dealing with multiple inheritance, and wanting to check if an object is of the same concrete class.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif; font-size: large;"><b>Next time...</b></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;">In the next post Im going to go into detail about <a href="http://pollenware.github.com/comb/symbols/comb.Promise.html">Promises</a> in comb, some useful patterns to clean up the callback madness and a neat little method called <a href="http://pollenware.github.com/comb/symbols/comb.html#.executeInOrder">comb.executeInOrder</a> which allows you to write async code as if it were synchronous.</span>Anonymoushttp://www.blogger.com/profile/05315723391769813524noreply@blogger.com5