Foundations

Foundations is a loadable framework of utility JavaScript APIs that both Mojo and JavaScript service applications can use.

Component Description
Array Utilities Array operation calls. Right now, just one for clearing an array.
Assert Utilities Assert operation calls. Two versions are provided for each call: one that logs an error and one that throws an error.
Communication Utilities Wrappers for async Ajax calls and a Palm bus service call.
Control Utilities Utilities to implement asynchronous callbacks (Futures), finite state machines, and map reduce functionality.
Environment Utilities Run-time environment (runtime, browser, node) detection calls.
Object Utilities Object operation calls. Right now, just one for converting an object containing name/value pairs to a string.
String Utilities String operation calls -- converting, escaping, searching, and stripping (HTML).
Structure Utilities Wrapper for allocating error and class objects.

Including Foundations in Your Code

To include Foundations in your Mojo app code:

  • Include the following two script tags in your app's "index.html" file: >
    <script src="/usr/palm/frameworks/mojoloader.js" type="text/javascript"></script>
    
    
  • Load the Foundations library and create short-hand references (optional) in your JavaScript:

    var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
    var ArrayUtils  = libraries["foundations"].ArrayUtils;
    var AssertUtils = libraries["foundations"].Assert;  
    var EnvUtils    = libraries["foundations"].EnvironmentUtils; 
    var PalmCall    = libraries["foundations"].Comms.PalmCall; 
    var AjaxCall    = libraries["foundations"].Comms.AjaxCall; 
    var ObjUtils    = libraries["foundations"].ObjectUtils;
    var StringUtils = libraries["foundations"].StringUtils; 
    var Err         = libraries["foundations"].Err; 
    var Class       = libraries["foundations"].Class;  
    var DB          = libraries["foundations"].Data.DB;  // db8 JavaScript wrapper calls
    var Future      = libraries["foundations"].Control.Future;
    var FSM         = libraries["foundations"].Control.FSM;   
    var MapReduce   = libraries["foundations"].Control.mapReduce;    
    
    

To include Foundations in your service app code:

  • Import the Foundations library and create short-hand references (optional) in your JavaScript:

    var Foundations = IMPORTS.foundations;
    var ArrayUtils  = Foundations.ArrayUtils;
    var AssertUtils = Foundations.Assert;
    var EnvUtils    = Foundations.EnvironmentUtils;
    var PalmCall    = Foundations.Comms.PalmCall;
    var AjaxCall    = Foundations.Comms.AjaxCall;
    var ObjUtils    = Foundations.ObjectUtils;
    var StringUtils = Foundations.StringUtils;
    var Err         = Foundations.Err;
    var Class       = Foundations.Class;
    var DB          = Foundations.Data.DB;
    var Future      = Foundations.Control.Future;
    var FSM         = Foundations.Control.FSM;
    var MapReduce   = Foundations.Control.mapReduce;
    
    

    You can then reference methods using standard dot notation. For example: StringUtils.isBlank.


Array Utilities

This namespace contains functions that operate on arrays and is intended to replace Prototype library functions.


ArrayUtils.clear

Clears an array.

Syntax

    void ArrayUtils.clear(array);

Parameters

Argument Required Type Description
array Yes any array Array to be cleared.

Returns

None. Clears the passed array.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var ArrayUtils = libraries["foundations"].ArrayUtils;
var quote= new Array(5);
quote[0]="I like JavaScript.";
quote[1]="I used to like Java.";
quote[2]="JavaScript rules.";
quote[3]="Help! JavaScript Error!";
quote[4]="Just Kidding.";

ArrayUtils.clear(quote);

if (quote[0] !== undefined)
{
   Mojo.Log.info("quote[0]="+quote[0]); // No log message
}


Assert Utilities

Provides a set of Assert functions, for checking code pre-conditions and post-conditions.

Assert and Require Versions

For each function, there are two versions. For example:

  1. Assert.assertEqual(obj1, obj2, msg, params)
  2. Assert.requireEqual(obj1, obj2, msg, params)

If the assertion evaluates to false, the "assert" function logs an error message and returns false while the "require" one throws an exception.

Messages are logged to "/var/log/messages." You can use the "tail" utility to view messages in real-time.

To monitor logged messages in real-time:

  • Open a shell on the device and run:
tail -f /var/log/messages

The "-f" option causes tail to display the last 10 lines of messages
and append new lines to the display as they are added.

To show output for just your app:

  • Open a shell on the device and run:
tail -f /var/log/messages | grep packageid

Note that using "tail" like this works until the log file is rotated; then you will need to reissue the command.

Using the "msg" and "params" arguments

Each function can take optional "msg" and "params" arguments. The msg parameter is used when logging an error message or throwing an error. It can also contain "#{...}" placeholders for values from the params object. For example:

msg = "Expected a sum greater than #{count}, but it was #{amount}";

The params argument can then be used to situationally fill the placeholders. For example:

params = {count: 3, amount: 0};


Assert Functions

Function Description
Assert.assert Logs an error if the expression is not true.
Assert.assertArray Logs an error if the expression is not an array.
Assert.assertClass Logs an error if an object does not have a given constructor.
Assert.assertDefined Logs an error if the argument is not defined.
Assert.assertEqual Logs an error if the expressions are not equal (==).
Assert.assertError Logs an error if a function does not throw the expected error.
Assert.assertFalse Logs an error if the expression is not false.
Assert.assertFunction Logs an error if the argument is not a function.
Assert.assertIdentical Logs an error if the expressions are not identical (===), that is, if they do not have the same type and value.
Assert.assertJSONObject Logs an error if the argument does not evaluate (when run through Object.prototype.toString()) to '[object Object]' or '[object Array]' (an object of an array).
Assert.assertMatch Logs an error if a regular expression pattern has no matches in a given string.
Assert.assertNumber Logs an error if the argument is not a number.
Assert.assertObject Logs an error if the argument is not an object.
Assert.assertProperty Logs an error if the object does not have a particular property or properties.
Assert.assertString Logs an error if the argument is not a string.
Assert.require Throws an error if the expression is not true
Assert.requireArray Throws an error if the expression is not an array.
Assert.requireClass Throws an error if an object does not have a given constructor.
Assert.requireDefined Throws an error if the argument is not defined.
Assert.requireEqual Throws an error if the expressions are not equal (==).
Assert.requireError Throws an error if a function does not throw the expected error.
Assert.requireFalse Throws an error if the expression is not false.
Assert.requireFunction Throws an error if the argument is not a function.
Assert.requireIdentical Throws an error if the expressions are not identical (===), that is, if they do not have the same type and value.
Assert.requireJSONObject Throws an error if the argument does not evaluate (when run through Object.prototype.toString()) to '[object Object]' or '[object Array]' (an object of an array).
Assert.requireMatch Throws an error if the pattern does not match.
Assert.requireNumber Throws an error if the argument is not a number.
Assert.requireObject Throws an error if the argument is not an object.
Assert.requireProperty Throws an error if the object does not have a particular property or properties.
Assert.requireString Throws an error if the argument is not a string.

Assert.assert

Logs an error if the expression is not true.

Syntax

    Assert.assert(exp, msg, params);

Parameters

<tr">
Argument Required Type Description
exp Yes any Expression to test
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Returns the expression passed.

Logs an error if the expression does not evaluate to true.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var exp="";
var msg = "Does not evaluate to true";
Mojo.Log.info("assert = "+ AssertUtils.assert(exp, msg));

Example Output

Error: Does not evaluate to true
assert = ""


Assert.assertArray

Logs an error if the expression is not an array.

Syntax

    boolean Assert.assertArray(exp, msg, params);

Parameters

Argument Required Type Description
exp Yes any Expression to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the expression is not an array.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var ary = [{"a":"b"}];
var notAry = "this is a string";
var msg = "Not an array";
Mojo.Log.info("assert = "+ AssertUtils.assertArray(ary, msg));
Mojo.Log.info("assert = "+ AssertUtils.assertArray(notAry, msg));

Example Output

assert = true
Error: Not an array
assert = false


Assert.assertClass

Logs an error if an object does not have a given constructor.

Syntax

    boolean Assert.assertClass(obj, constructor, msg, params)

Parameters

Argument Required Type Description
obj Yes any Object to test for constructor.
constructor Yes any Asserted constructor.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the constructor is not the passed object's constructor.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
function cat(name) {
  this.name = name;
  this.talk = function() {
      alert( this.name + " say meeow!" );
  }
}

cat1 = new cat("felix");
Mojo.Log.info("assert = "+ AssertUtils.assertClass(cat1, cat));

Example Output

assert = true


Assert.assertDefined

Logs an error if the argument is not defined.

Syntax

    boolean Assert.assertDefined(exp, msg, params);

Parameters

Argument Required Type Description
exp Yes any Expression to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the argument is not defined.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var undefObj;
Mojo.Log.info("assert = "+ AssertUtils.assertDefined(undefObj, "Not defined"));

Example Output

Error: Not defined
assert = false


Assert.assertEqual

Logs an error if the expressions are not equal (==).

Syntax

    boolean Assert.assertEqual(exp1, exp2, msg, params);

Parameters

Argument Required Type Description
exp1 Yes any Expression to test.
exp2 Yes any Expression to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the expressions are not equal (==).

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var str1 = "Separate but equal";
var str2 = "Separate but equal not";
Mojo.Log.info("assert = "+ AssertUtils.assertEqual(str1, str2));

Example Output

Error: Assert.assertEqual: Separate but equal != Separate but equal not
assert = false


Assert.assertError

Logs an error if the function does not throw the expected error.

Syntax

    boolean Assert.assertError(context, func, args, error, msg, params);

Parameters

Argument Required Type Description
context Yes any The "this" value for function. This is the first argument to an apply method. The apply() method invokes the passed function and passes context as the first parameter. The runtime uses this parameter for the this reference.
func Yes any Function to run.
args Yes any object Array of arguments. Second argument to apply() method.
error Yes any object Expected error.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the function does not throw the expected error.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var context = { errmsg1: "Err1", errmsg2: "Err2" };
var args = ["User message 1", "User message 2" ];
function f(message)
{
  throw this.errmsg1;
}

Mojo.Log.info("assert = "+ AssertUtils.assertError(context, f, args, "Err1" ));
Mojo.Log.info("assert = "+ AssertUtils.assertError(context, f, args, "UnknownErr" ));    

Example Output

assert = true
Error: Assert.assertError: error thrown was 'Err1', instead of 'UnknownErr'
assert = false


Assert.assertFalse

Logs an error if the expression is not false.

Syntax

    boolean Assert.assertFalse(exp, msg, params);

Parameters

Argument Required Type Description
exp Yes string Expression to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the expression is not false.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var expFalse = "";
var expTrue = "something";
var msg = "Does not evaluate to false";
Mojo.Log.info("assert = "+ AssertUtils.assertFalse(expFalse, msg));
Mojo.Log.info("assert = "+ AssertUtils.assertFalse(expTrue, msg));

Example Output

assert = true
Error: Does not evaluate to false
assert = false


Assert.assertFunction

Logs an error if the argument is not a function.

Syntax

    boolean Assert.assertFunction(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes Function Object to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the argument is not a function.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var myFunc = new Function("5+2");
var myStr = "not a function";
var msg = "Is not a function";
Mojo.Log.info("assert = "+ AssertUtils.assertFunction(myFunc, msg));
Mojo.Log.info("assert = "+ AssertUtils.assertFunction(myStr, msg));

Example Output

assert = true
Error: Is not a function
asset = false


Assert.assertIdentical

Logs an error if the expressions are not identical (===). Both type and value have to be the same.

Syntax

    boolean Assert.assertIdentical(exp1, exp2, msg, params); 

Parameters

Argument Required Type Description
exp1 Yes any Expression to test.
exp2 Yes any Expression to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the expressions are not identical (===).

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var a = "3";
var b =  3;
var c = "3";
var d = new String("3");

Mojo.Log.info("assert = "+ AssertUtils.assertIdentical(a,c,"Not identical"));
Mojo.Log.info("assert = "+ AssertUtils.assertIdentical(a,b,"Not identical"));
Mojo.Log.info("assert = "+ AssertUtils.assertIdentical(a,d,"Not identical"));

Example Output

assert = true
Error: Not identical
assert = false
Error: Not identical
assert = false


Assert.assertJSONObject

Logs an error if the argument does not evaluate (when run through Object.prototype.toString()) to '[object Object]' or '[object Array]' (an object of an array).

Syntax

    boolean Assert.assertJSONObject(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes string Object to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the argument does not evaluate to '[object Object]' or '[object Array]' (an object of an array).

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var jobj = [{ "fname": "Mabel", "lname":"Syrup", "isMember":true}];
Mojo.Log.info("assert = "+ AssertUtils.assertJSONObject(jobj, "Not an object or object in an array"));
var notObj = "Not a valid object";
Mojo.Log.info("assert = "+ AssertUtils.assertJSONObject(notObj, "Not an object or object in an array"));

Example Output

assert = true
Error: Not an object or object in an array
assert = false


Assert.assertMatch

Logs an error if a regular expression pattern has no matches in a given string.

Syntax

    string Assert.assertMatch(str, pattern, msg, params);

Parameters

Argument Required Type Description
str Yes string String to match against.
pattern Yes string Pattern to match (regular expression).
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

String with comma-separated matches or null.

Logs an error if the pattern does not match.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var str="The rain in SPAIN stays mainly in the plain";
var patt1=/ain/gi; // Search entire string for "ain",  ignore case
Mojo.Log.info("assert = "+ AssertUtils.assertMatch(str, patt1, "Not a match"));

Example Output

assert = ain,AIN,ain,ain


Assert.assertNumber

Logs an error if the argument is not a number.

Syntax

    boolean Assert.assertNumber(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes any Object to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the argument is not a number.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var num=32;
Mojo.Log.info("assert = "+ AssertUtils.assertNumber(num, "Not a number"));
var str="this is a string";
Mojo.Log.info("assert = "+ AssertUtils.assertNumber(str, "Not a number"));

Example Output

assert = true
Error: Not a number
assert = false


Assert.assertObject

Logs an error if the argument is not an object.

Syntax

    boolean Assert.assertObject(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes any Object to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the argument is not an object.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var txt = new String("this is an object");
Mojo.Log.info("assert = "+ AssertUtils.assertObject(txt, "Not an object"));
var str="this is not an object";
Mojo.Log.info("assert = "+ AssertUtils.assertObject(str, "Not an object"));

Example Output

assert = true
Error: Not an object
assert = false


Assert.assertProperty

Logs an error if the object does not have a particular property or properties.

Syntax

    boolean Assert.assertProperty(obj, props, msg, params);

Parameters

Argument Required Type Description
obj Yes any object Object to test.
props Yes any object Object containing properties to validate: {property1:value1, property2:value2}.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the object does not have a particular property or properties.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var home = new Object;
home.type= "colonial";
home.status = "foreclosed";
var props = {"status":"foreclosed"};
Mojo.Log.info("assert = "+ AssertUtils.assertProperty(home, props, "Not a property"));
props = "foreclosed";
Mojo.Log.info("assert = "+ AssertUtils.assertProperty(home, props, "Not a property"));

Example Output

assert = true
Error: Not a property
assert = false


Assert.assertString

Logs an error if the argument is not a string.

Syntax

    boolean Assert.assertString(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes string Object to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

true or false

Logs an error if the argument is not a string.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var num=32;
Mojo.Log.info("assert = "+ AssertUtils.assertString(num, "Not a string"));
var str="this is a string";
Mojo.Log.info("assert = "+ AssertUtils.assertString(str, "Not a string"));

Example Output

Error: Not a string
assert = false
assert = true


Assert.require

Syntax

    Assert.require(exp, msg, params);

Parameters

Argument Required Type Description
exp Yes any Expression to test.
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the expression is not true.

Example

var exp = "";
try
{
  AssertUtils.require(exp, "Does not evaluate to true");
}
catch (err)
{
  Mojo.Log.info("Err = " + err);
}

Example Output

Err = Error: Does not evaluate to true


Assert.requireArray

Throws an error if the expression is not an array.

Syntax

    Assert.requireArray(exp, msg, params);

Parameters

Argument Required Type Description
exp Yes any Expression to test.
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the argument is not an array.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var ary = [{"a":"b"}];
var notAry = "this is a string";
var msg = "Not an array";
try
{
  AssertUtils.requireArray(ary, msg);
  Mojo.Log.info("ary is Array");
}
catch (err)
{
  Mojo.Log.info("Err = " + err); 
}
try
{
  AssertUtils.requireArray(notAry, msg);
  Mojo.Log.info("notAry is Array");
}
catch (err)
{
  Mojo.Log.info("Err = " + err);
}

Example Output

ary is Array
Err = Error: Not an array


Assert.requireClass

Syntax

    Assert.requireClass(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes any Object to test.
constructor Yes any Required constructor.
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the constructor is not the passed object's constructor.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
function cat(name) {
  this.name = name;
  this.talk = function() {
      alert( this.name + " say meeow!" );
  }
}

cat1 = new cat("felix");
try
{
  AssertUtils.requireClass(cat1, cat);
  Mojo.Log.info("cat1 has cat constructor");
}
catch (err)
{
  Mojo.Log.info("requireClass throws " + err);
}

Example Output

cat1 has cat constructor


Assert.requireDefined

Throws an error if the passed argument is not defined.

Syntax

    Assert.requireDefined(exp, msg, params);   

Parameters

Argument Required Type Description
exp Yes any Expression to test.
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the argument is not defined.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var undefObj;
try
{
  AssertUtils.requireDefined(indefObj, "Not defined");
  Mojo.Log.info("Object is defined");
}
catch (err)
{
  Mojo.Log.info("requireDefined throws " + err);
}

Example Output

requireDefined throws ReferenceError: indefObj is not defined


Assert.requireEqual

Throws an error if two arguments are not equal (==).

Syntax

    Assert.requireEqual(exp1, exp2, msg, params);

Parameters

Argument Required Type Description
exp1 Yes any Expression to test.
exp2 Yes any Expression to test.
msg No string message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the expressions are not equal (==).

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var str1 = "Separate but equal";
var str2 = "Separate but equal not";
try
{
  AssertUtils.requireEqual(str1, str2, "Not equal");
  Mojo.Log.info("Objects are equal");
}
catch (err)
{
  Mojo.Log.info("requireEqual throws " + err); 
}

Example Output

requireEqual throws Error: Not equal


Assert.requireError

Throws an error if a function does not throw an expected error.

Syntax

    Assert.requireError(context, func, args, error, msg, params);

Parameters

Argument Required Type Description
context Yes string The "this" value for function. This is the first argument to an apply method. The apply() method invokes the passed function and passes context as the first parameter. The runtime uses this parameter for the this reference.
func Yes string Function to run.
args Yes any Array of arguments
error Yes string Expected error
msg No string message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the function does not throw an expected error.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var context = { errmsg1: "Err1", errmsg2: "Err2" };
var args = ["User message 1", "User message 2" ];
function f(message)
{
  throw this.errmsg1;
}

try
{   
  AssertUtils.requireError(context, f, args, "Err1", "Does not throw expected error");
  Mojo.Log.info("Function throws expected error");
}
catch (err)
{
  Mojo.Log.info("requireError throws " + err);
}

Example Output

Function throws expected error


Assert.requireFalse

Throws an error if the expression does not evaluate to false.

Syntax

    Assert.requireFalse(exp, msg, params);

Parameters

Argument Required Type Description
exp Yes any Expression to test
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the expression is not false.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var expFalse = "";
var expTrue = "something";
var msg = "Does not evaluate to false";
try
{
  AssertUtils.requireFalse(expFalse, msg);
  Mojo.Log.info("Evaluates to false");
}
catch (err)
{
  Mojo.Log.info("requireFalse throws " + err);
}
try
{
  AssertUtils.requireFalse(expTrue, msg);
  Mojo.Log.info("Evaluates to false");
}
catch (err)
{
  Mojo.Log.info("requireFalse throws " + err);
}    

Example Output

Evaluates to false
requireFalse throws Error: Does not evaluate to false   


Assert.requireFunction

Syntax

    Assert.requireFunction(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes any Object to test.
msg Yes string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params Yes any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the argument is not a function.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var myFunc = new Function("5+2");
var myStr = "not a function";
var msg = "Is not a function";
try
{
  AssertUtils.requireFunction(myFunc, msg);
  Mojo.Log.info("Is a function.");
}
catch (err)
{
  Mojo.Log.info("requireFunction throws " + err);
}
try
{
  AssertUtils.requireFalse(myStr, msg);
  Mojo.Log.info("Is a function.");
}
catch (err)
{
  Mojo.Log.info("requireFunction throws " + err);
}

Example Output

Is a function.
requireFunction throws Error: Is not a function


Assert.requireIdentical

Throws an error if two expressions do not have the same value and type (===).

Syntax

    Assert.requireIdentical(exp1, exp2, msg, params);

Parameters

Argument Required Type Description
exp1 Yes string Expression to test.
exp2 Yes string Expression to test.
msg Yes string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params Yes any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the expressions are not identical (===).

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var a = "3";
var b =  3;
var c = "3";
var d = new String("3");

try
{
  AssertUtils.requireIdentical(a,c,"Not identical");
  Mojo.Log.info("Identical");
}
catch (err)
{
  Mojo.Log.info("requireIdentical throws " + err);
}

try
{
  AssertUtils.requireIdentical(a,b,"Not identical");
  Mojo.Log.info("Identical");
}
catch (err)
{
  Mojo.Log.info("requireIdentical throws " + err);
}

try
{
  AssertUtils.requireIdentical(a,d,"Not identical");
  Mojo.Log.info("Identical");
}
catch (err)
{
  Mojo.Log.info("requireIdentical throws " + err);
}

Example Output

Identical
requireIdentical throws Error: Not identical
requireIdentical throws Error: Not identical


Assert.requireJSONObject

Throws an error if the passed object, when run through Object.prototype.toString(), does not evaluate to '[object Object]' or '[object Array]'.

Syntax

    Assert.requireJSONObject(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes string Object to test.
msg No string Message to log. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the argument does not evaluate to '[object Object]' or '[object Array]' (an object of an array).

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
Mojo.Log.info("assert = "+ JSON.stringify(AssertUtils.assertJSONObject(jobj, "Not an object or object in an array")));
try
{
  AssertUtils.requireJSONObject(jobj, "Not an object or object in an array");
  Mojo.Log.info("Is an object or object in an array");
}
catch (err)
{
  Mojo.Log.info("requireJSONObject throws " + err);
}

var notObj = "Not a valid object";
try
{
  AssertUtils.requireJSONObject(notObj, "Not an object or object in an array");
  Mojo.Log.info("Is an object or object in an array");
}
catch (err)
{
  Mojo.Log.info("requireJSONObject throws " + err);
}

Example Output

Is an object or object in an array
requireJSONObject throws Error: Not an object or object in an array


Assert.requireMatch

Throws an error if there not a match between a regular expression and a string.

Syntax

    Assert.requireMatch(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes string Object to test.
obj Yes string Object to test.
pattern Yes string Pattern to match (regular expression).
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the pattern does not match.

Example

var AssertUtils = libraries["foundations"].Assert;
var str = "The rain in SPAIN stays mainly in the plain";
var patt1 = /ain/gi;

//... Search entire string for "ain", ignore case
try {
  AssertUtils.requireMatch(str, patt1, "Not match");
  Mojo.Log.info("Match");
}
catch (err) {
  Mojo.Log.info("requireMatch throws " + err);
}

Example Output

Match    


Assert.requireNumber

Throws an error if the argument is not a number.

Syntax

    Assert.requireNumber(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes any Object to test.
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the argument is not a number.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var num=32;
try
{
  AssertUtils.requireNumber(num, "Not a number");
  Mojo.Log.info("It is a number.");
}
catch (err)
{
  Mojo.Log.info("requireNumber throws " + err);
}
var str="this is a string";
try
{
  AssertUtils.requireNumber(str, "Not a number");
  Mojo.Log.info("It is a number.")
}
catch (err)
{
  Mojo.Log.info("requireNumber throws " + err);
}

Example Output

It is a number.
requireNumber throws Error: Not a number


Assert.requireObject

Throws an error if a passed argument is not an object.

Syntax

    Assert.requireObject(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes string Object to test.
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the argument is not an object.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var txt = new String("this is an object");
var str="this is not an object";

try
{
  AssertUtils.requireObject(txt, "Not an object");
  Mojo.Log.info("It is an object.");
}
catch (err)
{
  Mojo.Log.info("requireObject throws " + err);
}

try
{
  AssertUtils.requireObject(str, "Not an object");
  Mojo.Log.info("It is an object.");
}
catch (err)
{
  Mojo.Log.info("requireObject throws " + err);
}

Example Output

It is an object.
requireObject throws Error: Not an object


Assert.requireProperty

Syntax

    Assert.requireProperty(obj, props, msg, params);

Parameters

Argument Required Type Description
obj Yes string Object to test.
props Yes string An object containing properties to validate: {property1:value1, property2:value2}.
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the object does not have a particular property set as expected.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var home = new Object();
home.type= "colonial";
home.status = "foreclosed";
var props = {"status":"foreclosed"};

try
{
  AssertUtils.requireProperty(home, props, "Not a property");
  Mojo.Log.info("Property is there");
}
catch (err)
{
  Mojo.Log.info("requireProperty throws " + err);
}
props = "foreclosed";
try
{
  AssertUtils.requireProperty(home, props, "Not a property");
  Mojo.Log.info("Property is there");
}
catch (err)
{
  Mojo.Log.info("requireProperty throws " + err);
}

Example Output

Property is there
requireProperty throws ReferenceError: props is not defined
requireProperty throws Error: Not a property


Assert.requireString

Throws an error if the argument is not a string.

Syntax

    Assert.requireString(obj, msg, params);

Parameters

Argument Required Type Description
obj Yes string Object to test.
msg No string Message to throw. This can contain "#{...}" placeholders for values from the params object, i.e., "Expected a sum greater than #{count}, but it was #{amount}".
params No any object Parameters to fill in "msg" placeholders, i.e., {count: 3, amount: 0}.

Returns

Throws an error if the argument is not a string.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AssertUtils = libraries["foundations"].Assert;
var num=32;
try
{
  AssertUtils.requireString(num, "Not a string");
  Mojo.Log.info("Is a string");
}
catch (err)
{
  Mojo.Log.info("requireString throws " + err);
}
var str="this is a string";
try
{
  AssertUtils.requireString(str, "Not a string");
  Mojo.Log.info("Is a string");
}
catch (err)
{
  Mojo.Log.info("requireString throws " + err);
}

Example Output

requireString throws Error: Not a string
Is a string


Communication Utilities

Wrappers for async Ajax calls and a Palm bus service call. All calls are made asynchronously and are implemented using 'Futures', Palm's mechanism for async calls. See the Futures documentation for more information. The examples provided with each call demonstrate how Futures are used.

Options for Ajax calls

The Ajax calls detailed below can each take the following options object:

{
  "bodyEncoding"    : string,
  "customRequest"   : string,
  "headers"         : any object,
  "joinableHeaders" : string array,
  "nocompression"   : boolean   // not currently supported; "true" by default
}

Element Required Type Description
bodyEncoding No string Encoding of the body data. Can be either 'ascii' or 'utf8'; 'utf8' is the default.
customRequest No string Used to specify a custom request method such as "PROPFIND", instead of the usual "GET" or "POST".
headers No object array Array of headers to send in an Ajax POST request.
joinableHeaders No string array

Set of response headers joined as a comma-delimited list when more than one instance is received from a server, per RFC 2616 (Hypertext Transfer Protocol -- HTTP/1.1), section 4.2.

Example:
options = { "joinableHeaders": ['Set-Cookies']};
 
When received as:
    "Set-Cookies: YT-1300"
    "Set-Cookies: T-16"
will be packaged as:
    "Set-Cookies": "YT-1300, T-16"
noncompression No boolean If 'true', accepted response encodings do not include compressed formats. Compression is useful if a large amount of data is sent in the response.

AjaxCall.get

Syntax

    Future AjaxCall.get(url, options);

Parameters

Argument Required Type Description
url Yes string URL
options No object See details in Communication Utilities overview.

Returns

Text from server.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future = libraries["foundations"].Control.Future;
var AjaxCall = libraries["foundations"].Comms.AjaxCall;

var options = { "bodyEncoding":"utf8"};
var future1 = AjaxCall.get("http://www.w3schools.com/ajax/ajax_info.txt", options);
future1.then(function(future)
{
  if (future.result.status == 200) // 200 = Success
      Mojo.Log.info('Ajax get success ' + JSON.stringify(future.result));
  else Mojo.Log.info('Ajax get fail');
});

Example Output

Ajax get success 
{
  "readyState":4,
  "responseText":"<p>AJAX is not a new programming language.</p>\r\n<p>AJAX is a technique for creating fast and dynamic web pages.</p>",
  "onloadstart":null,
  "onerror":null,
  "onabort":null,
  "withCredentials":false,
  "status":200,
  "responseXML":null,
  "onload":null,
  "onprogress":null,
  "upload":{
      "onloadstart":null,
      "onabort":null,
      "onerror":null,
      "onload":null,
      "onprogress":null
  },
  "statusText":"",
  "_complete":true
}


AjaxCall.head

Returns only the meta-information contained in the HTTP headers.

Syntax

    Future AjaxCall.head(url, options);

Parameters

Argument Required Type Description
url Yes string URL
options No object See details in Communication Utilities overview

Returns

Response object from server.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future      = libraries["foundations"].Control.Future;
var AjaxCall = libraries["foundations"].Comms.AjaxCall;

var options = { "bodyEncoding":"utf8"};
var future1 = AjaxCall.head("http://www.w3schools.com/ajax/ajax_info.txt", options);
future1.then(function(future)
{
  if (future.result.status == 200)  // 200 = Success
      Mojo.Log.info('Ajax head success ' + JSON.stringify(future.result));
  else Mojo.Log.info('Ajax head fail');
});

Example Output

Ajax head success 
{
  "readyState":4,
  "responseText":"",
  "onloadstart":null,
  "onerror":null,
  "onabort":null,
  "withCredentials":false,
  "status":200,
  "responseXML":null,
  "onload":null,
  "onprogress":null,
  "upload":{
      "onloadstart":null,
      "onabort":null,
      "onerror":null,
      "onload":null,
  "onprogress":null
  },
  "statusText":"",
  "_complete":true
}


AjaxCall.post

A post request is different from a get request in the following ways:

  • A block of data is sent with the request in the message body. There are usually extra headers to describe this message body, like "Content-Type:" and "Content-Length:".
  • The request URI is not a resource to retrieve but, instead, a program to handle the data you are sending.
  • The HTTP response is normally program output, not a static file.

Syntax

    Future AjaxCall.post(url, body, options);

Parameters

Argument Required Type Description
url Yes string URL
body Yes any Additional data, i.e., form data.
options No object See details in Communication Utilities overview

Returns

Response object from server.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var AjaxCall    = libraries["foundations"].Comms.AjaxCall;
var Future      = libraries["foundations"].Control.Future;

var options = { "bodyEncoding":"utf8", "headers": [{"Content-type":"application/x-www-form-urlencoded"}]};
var url = "http://www.javascriptkit.com/dhtmltutors/basicform.php?name=HuggyBear&age=25";
var body = "";
var future1 = AjaxCall.post(url, body, options);
future1.then(function(future)
{
  if (future.result.status == 200) // Success
  Mojo.Log.info('Ajax post success ' + JSON.stringify(future.result));
  else Mojo.Log.info('Ajax post fail ='+ JSON.stringify(future.result));
});

Example Output

Ajax post success 
{
  "readyState":4,
  "responseText":"<span style='color:red'>Welcome <b>HuggyBear</b> to JavaScript Kit.
      So you're <b>25</b> years old eh?</span>",
  "onloadstart":null,
  "onerror":null,
  "onabort":null,
  "withCredentials":false,
  "status":200,
  "responseXML":null,
  "onload":null,
  "onprogress":null,
  "upload":{
      "onloadstart":null,
      "onabort":null,
      "onerror":null,
      "onload":null,
      "onprogress":null
  },
  "statusText":"",
  "_complete":true
}


PalmCall.call

PalmCall.call is a wrapper for making a call to a service on the Palm message bus. This can be done with or without a subscription.

Syntax

    future PalmCall.call(service, method, parameters);

Parameters

Argument Required Type Description
service Yes string Service to call, i.e., "com.palm.db"
method Yes string Service method to call.
parameters Yes object Service method parameters as JSON object.

Returns

Response object from service.

Example 1 - Get device's unique ID from system properties

The device ID, or nduid, is a 20-byte (160 bit) SHA-1 digest unique to each device. You can obtain it from the com.palm.preferences service.

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var PalmCall  = libraries["foundations"].Comms.PalmCall;

var future1 = PalmCall.call("palm://com.palm.preferences/systemProperties", "Get", {"key": "com.palm.properties.nduid" });
future1.then(function(future)
{
  var result = future.result;
  if (result.returnValue == true)
  {
      //** The "com.palm.properties.nduid" field contains periods, which makes object dot notation references problematic.
      //** Instead, since I know it is the first name/value field, I am going to "split" it out.
      var result1 = JSON.stringify(result);
      var resultArray = result1.split('"');
      Mojo.Log.info("Unique Device ID = " + resultArray[3]);
  }
  else Mojo.Log.info("Failure = " + JSON.stringify(result));
});

Example 1 Output

Unique Device ID = 8fe37d5a9c7793af12fc0f6a129470721027d81b

Example 2 - Subscribed service call

The following is a Triton script example that subscribes to the locations service, gets a few position fixes, then quits.

To handle a subscribed service call using PalmCall you need to make sure to add a new then() clause after each response comes in, and, to do that, you need to use a named function (rather than an anonymous function) as the argument to then().

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;   
var PalmCall  = libraries["foundations"].Comms.PalmCall;

function main(args) {
  startApplicationLoop();
  var fixCount=3;
  Mojo.Log.info("Getting "+fixCount+" position fixes");
  
  var fixFuture = PalmCall.call("palm://com.palm.location", "startTracking",
      {subscribe: true});
  
  fixFuture.onError(function(future) {
      Mojo.Log.info("Error: "+future.exception);
      future.then(function() {
          quit();
      });
  });
  fixFuture.then(function print_it(future) {
      Mojo.Log.info("Got a fix:");
      for (var key in future.result) {
          Mojo.Log.info("\t"+key+":\t"+future.result[key]);
      }
      if (--fixCount > 0) {
          //register a new "then" with this same function
          future.then(print_it);
      } else {
          // cancel service handle
          PalmCall.cancel(fixFuture);
          quit();
      }
  });
}


Control Utilities

Component Description
Finite State Machine Implements a Finite State Machine with "states" and "events". States are defined in an object and are transitioned to via events.
Futures A mechanism for implementing asychronous callbacks that handles results and exceptions in a more flexible way than traditional callback mechanisms.
Map Reduce A version of Map Reduce using Futures.

Finite State Machine

Implements a Finite State Machine (FSM) with "states" and "events". States are defined in an object and are transitioned to via events.

FSMs model behavior where responses to future events depend upon previous events. FSMs consist of:

  • Events that the app responds to.
  • States where the app waits between events.
  • Transitions between states in response to events.
  • Actions taken during transitions.
  • Variables that hold values needed by actions between events.

FSMs are most useful in situations where many different types of events drive behavior, and the response to a particular event depends on the sequence of previous events.

States are a way to remember previous events, and transitions are a way to organize responses to future events.

FSMs are typically represented in one of two ways:

  1. Directed graphs -- Balloons represent states, and arrows between them represent transitions, which are labeled with events and actions.
  2. Two-dimensional tables -- Rows and columns represent events and states, and cells contain actions and transitions.

A full discussion of FSMs is beyond the scope of this documentation, but there are numerous resources available on the Internet.

Implementing a Finite State Machine

Typically, to implement a FSM, you would create a "states" object that defines states, events, and transition processing similar to the following:

var states = {
  stateOne: {
      eventOne: function() {
          // Do some processing and transition to another state
      },
      eventTwo: function() {
      }
  },
  stateTwo: {
      eventThree: function() {
      },
      eventFour: function() {
      }
  },
  // ....
};

Allocating a Finite State Machine

The following is a simple example of allocating a FSM:

// Load Foundation libraries
var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });  

// Create reference to FSM code
var FSM = libraries["foundations"].FSM; 

// Create states, events, and transition processing object     
var states = {
  one: {
      gotoTwo: function() {
          // Event/Transition processing here...
          this.go("two");  // FSM method
      },
      gotoThree: function() {
          this.go("three");
      }
  },
  two: {
      gotoOne: function() {
          this.go("one");
      },
      gotoThree: function() {
          this.go("three");
      }
  },
  three: {
      gotoTwo: function() {
          this.go("two");
      },
      gotoOne: function() {
          this.go("one");
      }
  }
};
var context = {}; // some object

// Allocate FSM    
var fsm = new FSM(states, context); 

If no "context" is provided, then the states object is used as the context. If you only need one instance of a particular FSM, there is no reason for a separate context object.


FSM Methods

  • currentState -- Get FSM's current state.
  • event -- Calls the named event method for the current state.
  • go -- Transition from the current state to to the specified new state.

currentState

Get FSM's current state.

Syntax

FSM.currentState();

Parameters

None.

Returns

FSM current state.

Example

// Use example from "Allocating..."
var fsm = new FSM(states, context);

// Get initial state
Mojo.Log.info("fsm current state = "+ fsm.currentState());

Example Output

fsm current state = __uninitialized


event

Calls the named event method for the current state. This usually, but not always, results in a state transition.

Syntax

    boolean FSM.event(event, arguments);

Parameters

Argument Required Type Description
event Yes string Event to call.
arguments No any array Arguments to pass to event function.

Returns

true or false

Example

// Use example from "Allocating..."
fsm.go("three");   
Mojo.Log.info("fsm event gotoOne = "+ fsm.event("gotoOne"));   

Example Output

fsm event gotoOne = true


go

Transition from the current state to to the specified new state. Though used in the FSM implementation, calling this is not really necessary - in general, you would want to use an event to switch between states. If not already there, this method transitions the FSM to the named state.

Syntax

    FSM.go(nstate);

Parameters

Argument Required Type Description
nstate No any Name of state to transition to.

Returns

None.

Example

// Use example from "Allocating..."
fsm.go("two");
// Get new state
Mojo.Log.info("fsm current state = "+ fsm.currentState());

Example Output

fsm current state = two


Futures

A Future is a class that provides a mechanism for implementing asychronous callbacks. The advantage with using Futures is that it handles results and exceptions in a more flexible way than traditional callback mechanisms.

Allocating a Future

The following is a simple example of allocating a Future:

// Load Foundation libraries
var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });

// Create reference to Futures class
var Future = libraries["foundations"].Control.Future;

// Allocate Future
var f = new Future("Hello");  // Allocate Future

Every Future has a "result" property and the above allocation initializes its value to "Hello".

Future Model

The Future model is a series of stages: "Do this, then, when done, do this with the result". Each stage is created with an invocation of the Future object's "then" method. The "then" method registers a function that is invoked when the "result" property gets set.

Here is a simple example:

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" }); 
var Future = libraries["foundations"].Control.Future;
var f = new Future("Hello");

f.then(function(future) {
  if (future.result == "Hello") {
      // Do some processing...
      future.result = "Success";
  }
});

f.then(function(future) {
  if (future.result == "Success") {
      // Do some more processing...
      future.result = "Did stage 2";
  }
});

f.then(function(future) {
  if (future.exception) {
      future.result = false;
      // Log exception...
  }
  else {
      // Total operation success
      future.result = true;
  }
});

Here is a more involved example -- a Foundations AJAX call is made to retrieve a user's remote ID, which is then used to search the local db8 database for that user's contact information:

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future = libraries["foundations"].Control.Future;
var DB = libraries["foundations"].Data.DB;
var AjaxCall = libraries["foundations"].Comms.AjaxCall;

var f = AjaxCall.get("http://www.foobar.com/theAnswer");  // Returns a Future

f.then(this, function(future)
{
  var status = future.result.status;

  if (status === 200 ) // 200 = Success
  {
      var response = future.result.responseJSON;
      var id = response.id;
      var query = {
          from: "com.palm.contacts:1",
          where: [{ "prop": "remote_id", "op": "=", "val": id }]
      };
      return DB.find(query);  // Call returns a Future
  }
  future.result = { returnValue : false, status: status };
});

f.then(function(future) {
  if (future.result.returnValue === true)
  {
      var record = future.result.results[0];  // Get first record from query
      Mojo.Log.info("record =" + JSON.stringify(record));
      future.result = { returnValue: true };
  }
  else {
      future.result = { returnValue: false };
  }   
});

The following is happening here:

  • The AjaxCall creates a Future and returns it to the caller.

  • The returned Future calls its "then" method, which registers a scope ("this") and a function that is executed when the Future's "result" property gets set (from the AjaxCall).

  • The "then" function is called when the "result" gets set. The triggered Future is passed in as the only argument. Note that if "result" had been set before the "then" method was called, the registered function would have been immediately called.

  • In the registered function, the Future's "result" property is read. If the Future contains an "exception", rather than returning this, the "exception" is re-thrown here. See the next section on error handling for details.

  • The retrieved "id" value is used in a db8 find query to look up the user's record in the local db8 database. Since "DB.find" also returns a Future, we can return that result from the "then" to chain the two Futures together.

  • Finally, when the record has been retrieved from db8 storage, it is logged to the console.

Basic Usage

The following is the basic pattern for using Futures:

  • Create a Future or obtain one from a Foundations library call (i.e., Ajax calls (get, head or post) or PalmCall or the db8 wrapper APIs).

  • Call the Future's "then" method to set up a function to call when the Future has a result.

  • Do something that will cause the Future's result to get set.

Error Handling

If the function specified in a "then" throws an exception, the exception is logged and stored in the Future. The next time the Future's "result" property is accessed, it is re-thrown. This allows your app to defer error handling to the end of the chain, if desired. Note, however, that reading a Future's "exception" resets the mechanism that causes errors to be re-thrown.

Deferred error-handling example:

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future = libraries["foundations"].Control.Future;
var f = new Future("Hello");
f.then(function(future) {
  if (future.result == "Hello") {
      throw "Error";      
  }
  future.result = "Success";
});
f.then(function(future) {
  if (future.result == "Success") // Error is re-thrown on this access
  {
       Mojo.Log.info("In stage 2");
  }
  future.result = "Did stage 2";
});
f.then(function(future) {
  if (future.exception) {
      Mojo.Log.info("Stage 3 Exception");
      future.result = false;
  }
  else {
      future.result = true;
  }
});

Logged output:

Stage 3 Exception

Passing Error Functions

When calling "then", you can specify a function to run if the previous stage threw an error:

var f = new Future("Hello");
f.then(function(future) {
  if (future.result == "Hello") {
      throw "Error";
  }
  future.result = "Success";
});

f.then(function(future) {
  Mojo.Log.info("In stage 2");
  future.result = "Did stage 2";
},
function(future) {        // Pass this error handling function
  Mojo.Log.info("In error handler, error was "+future.exception);
  future.result = "Skipped stage 2";
});

As an alternative to this (since reading reading a Future's "exception" resets the mechanism that causes errors to be re-thrown), you could have the following code:

f.then(function(future) {
  if (future.exception) {
      // do some error recovery
  }
  future.result=true;
});

Creating a Future-wide Error Handler

The "onError" function establishes a Future-wide error handler that is invoked for every thrown error.

For example:

var f = new Future("Hello");
f.onError(function(future) {
  Mojo.Log.info("In error handler, error was: "+future.exception);
  future.result = true;
});
f.then(function(future) {
  future.result;
  throw("1");
});
f.then(function(future) {
  future.result;
  throw("2");
});
f.then(function(future) {
  future.result;
  throw("3");
});

Logged Output:

In error handler, error was: 1
In error handler, error was: 2
In error handler, error was: 3

Guidelines for Implementing Futures

  • "then" functions should read the Future's "result" property before doing anything.

    This allows errors to propagate correctly (see Error Handling).

  • "then" functions should always set the Future's "result" property.

    They should do this either directly, or as the result of a callback. It should do this exactly once, no matter what path the code takes.

  • Use a Finite State Machine (FSM) design.

    Imagine your Future chain or sequence as a Finite State Machine (FSM). Map out the states and state transitions ahead of time, and write your code accordingly.

    If your FSM has branches or cycles you can use a Future's "nest" method to handle these conditionally. It is not recommended you use "then" handlers for the same Future at different levels to do this.

  • Implement a flat hierarchy.

    Because their control flow is linear and declared up front, flat hierarchies are easier to understand than deep ones. Avoid making and using more Futures than are necessary.

    Attaching additional "then" handlers in nested functions is not recommended -- the execution order and response of "then" handlers at different levels is hard to anticipate.

  • Always access a future "result" before setting it again.

    Always read a Future's result before setting a new value. If the previous step resulted in an error, it aborts immediately and prevents unnecessary further processing.

    Always read a Future's result before using "nest" to tack on another step. These two should be done together in a "then". The one exception is if the "nest" is the first step in the sequence and there is no initial value.

  • Utility functions should return new objects.

    When designing utility APIs that use Futures, try to have them return new Future objects rather than accepting a client-provided Future object as a parameter. This gives more control to the caller and avoids letting the utility function clobber Future flow or make any assumptions.

    If you think of utility methods as complex and unrelated sub-sequences (see "nest" above), expecting them to return new Futures and connecting them with "nest" seems very logical.

    If you are writing a utility method and it needs to execute a conditional or branch, you should do one more step: since loops and branches usually mean deferred attachment of "then" functions, you should wrap this future sequence in a single outer future to return to the caller. This way, when the caller inevitably attaches "then" functions early, they will not break your private inner sequence.

  • Name your "then" functions.

    If your Future sequence has many steps, it could be helpful to name your "then" functions rather than leaving them anonymous. It is easier for someone else to follow a list of named steps than a long sequence of unrelated functions.


Future Properties

  • exception -- Contains the Future's exception, if there is one. Reading or writing this property is the same as accessing it with "getException" or "setException".
  • result -- Contains the Future's result. Reading or writing this property is the same as accessing it with "getResult" or "setResult".

Future Methods

  • callback -- Provides for a standard callback mechanism.
  • cancel -- Cancels any pending "then" stages.
  • getException -- Gets the Future's most recent exception captured in a "then" or "now" function.
  • getResult -- Get the Future's "result" property value.
  • nest -- Nest a Future inside the current Future.
  • now -- Calls the scope and function immediately in the Future's scope.
  • onError -- Defines a Future-wide error handler.
  • setException -- Sets the Future's "exception" property.
  • setResult -- Sets the Future's "result" property.
  • status -- Returns the Future's current status.
  • then -- Register a scope and function for execution when a Future has a result or exception set.
  • whilst -- Provides a Futures looping construct.

Code Sample Notes

The code samples for the "nest" and "then" methods require the following db8 database set-up:

// 1. Load and reference required libraries

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future = libraries["foundations"].Control.Future;
var DB = libraries["foundations"].Data.DB;

// 2. Create a db8 kind object

var testKind = { name: "dbtest:1",  owner: "com.palm.foundmain",
  indexes: [ //** create indexes
      {name:"name", props: [{name: "name"}]},
      {name:"profession", props:[{name: "profession"}]}   
  ]
};

// 3.  Create 5 test data objects

var testData =  [ { _kind: testKind.name, name: "Mark", age: 40, profession: "engineer" },
  {  _kind: testKind.name, name: "Yvette", age: 36,  profession: "trainer" },
  {  _kind: testKind.name, name: "Lenny", age: 45, profession: "engineer" },
  {  _kind: testKind.name, name: "Homer", age: 51, profession: "safety inspector"},
  {  _kind: testKind.name, name: "Marge", age: 48, profession: "homemaker" }
];

// 4. Use db8 JavaScript wrapper API calls to create the kind and test objects (no error checking)

DB.putKind(testKind.name, testKind.owner, testKind.indexes);
DB.put(testData); 

The above code creates a db8 kind and then puts 5 JSON data objects of that kind into db8 storage using db8 JavaScript wrapper API calls. See the db8 documentation for more information.


callback

Wraps and returns the scope and function pair in a new function that requires no arguments. Generally, this is used to interface the Futures mechanism to the common function callback schemes that Ajax and HTML5 databases use.

Syntax

    Future.callback(scope, func);

Parameters

Argument Required Type Description
scope No any object Call scope
func Yes Function Function to call.

Returns

None.

Example

In this example, a callback function is used in a "setTimeout" call.

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var f = new Future();

setTimeout(f.callback(this, function() {
  f.result = "passed";
}), 100);

f.then(function(future) {
  Mojo.Log.info("In then, f.result="+f.result);
});


cancel

Cancels any pending "then" clauses. The Future is marked as canceled. It is an error to set a new result or "then" for a canceled Future.

Syntax

Future.cancel();

Parameters

None.

Returns

None.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future = libraries["foundations"].Control.Future;
var f = new Future();
f.then( this, function(future) {
  future.cancel();
  future.result="DONE";
}
).then( this, function(future) {
  Mojo.Log.info("Should never get here");
}
);


getException

Gets the Future's most recent exception captured in a "then" or "now" function.

Syntax

Future.getException();

Parameters

None.

Returns

Exception value.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var AssertUtils = libraries["foundations"].Assert;
var f = new Future("Hello");

f.then(function(future) {
  future.exception = 2;
});

f.then(function(future) {
  var e = future.getException();
  AssertUtils.requireEqual(e, 2);
  future.setException(3);
});

f.then(function(future) {
  var e = future.getException();
  AssertUtils.requireEqual(e, 3);
  future.result = "Passed";       
  Mojo.Log.info("future.result = "+future.result);
});


getResult

Get the Future's result property value. Calling this does not stop the future's exception (if any) from being re-thrown.

Syntax

Future.getResult();

Parameters

None.

Returns

Future result value.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var AssertUtils = libraries["foundations"].Assert;    
var f = new Future(1);

f.then(function(future) {
  AssertUtils.requireEqual(1, future.result);
  future.result = 2;
});

f.then(function(future) {
  AssertUtils.requireEqual(2, future.getResult());
  future.setResult(3);
});

f.then(function(future) {
  AssertUtils.requireEqual(future.result, future.getResult());
  future.setResult("passed");
});


nest

Nest a Future inside the current Future. This is useful when one Future contains many other Futures (for example, when a Future is created, which contains a number of database operations, each of which returns a Future). When an inner-Future completes, any results it contains propagate to the outer-Future.

Nests are useful as a way to abstract a complex and unrelated sub-sequence from the main sequence. They ensure that the main sequence always resumes upon sub-sequence completion, whether or not the sub-sequence resulted in an error or valid result.

Syntax

    Future.nest(innerfuture);

Parameters

Argument Required Type Description
innerfuture Yes Future Future to nest within the current future.

Returns

None.

Example

Do a series of db8 database finds, each of which returns a Future, and aggregate the results. See "Code Sample Notes" above to see how this code sample is set up.

// Allocate Future
var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future = libraries["foundations"].Control.Future;
var DB = libraries["foundations"].Data.DB;
var f = new Future("hello");

// Retrieve and aggregate 3 records from db8 storage
var result1, result2, result3;
f.nest(DB.find({ "from": "dbtest:1", "limit":1, "where": [{ "prop":"profession", "op":"=", "val":"engineer"}]}).then( function(f)
{
  result1 = f.result.results[0];  
}));

f.nest(DB.find({ "from": "dbtest:1", "limit":1, "where": [{ "prop" :"profession", "op": "=", "val":"homemaker"}]}).then( function(f)
{
  result2 = f.result.results[0];
}));

f.nest(DB.find({"from":"dbtest:1", "limit":1, "where": [{ "prop" :"profession", "op": "=", "val":"trainer"}]}).then( function(f)
{
  result3 = f.result.results[0];
  f.result = {
      rec1:  result1,
      rec2:  result2,
      rec3:  result3
  };
  Mojo.Log.info("Final result="+JSON.stringify(f.result));
}));

Example Output

Final result=
{
  "rec1":{
      "_id":"++HJdTuywUsIfU6N",
      "_kind":"dbtest:1",
      "_rev":5074,
      "age":40,
      "name":"Mark",
      "profession":"engineer"
  },
  "rec2":{
      "_id":"++HJdTuz3o4ez4D3",
      "_kind":"dbtest:1",
      "_rev":5078,
      "age":48,
      "name":"Marge",
      "profession":"homemaker"
      },
  "rec3":{
      "_id":"++HJdTuyyN44nzZl",
      "_kind":"dbtest:1",
      "_rev":5075,
      "age":36,
      "name":"Yvette",
      "profession":"trainer"
  }
}


now

Calls the scope and function immediately in the current Future's scope. This behaves like "then" except the function is immediately executed rather than waiting for "result" to be set. Generally, this is useful if your app wants to capture any exceptions the "now" function might generate, and assign them to the Future.

Syntax

    Future.now(scope, func, errorFunc);

Parameters

Argument Required Type Description
scope No any Call scope
func Yes Function Function to call.
errorFunc No Function Error function to invoke on failure.

Returns

None.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var f = new Future("Hello");

f.then(function(future) {
  Mojo.Log.info("In first stage");
  if (future.result == "Hello") {
      setTimeout(function() { Mojo.Log.info("100 ms passed"); future.result = "Success"; }, 100);
  }
});

f.now(function(future) {
  if (future.result == "Success" )
      Mojo.Log.info("First then finished");
  else
      Mojo.Log.info("Finished stage 2 before stage 1");
  future.result="Stage 2 done";          
});

f.then(function(future) {
  Mojo.Log.info("In stage 3 ");
  if (future.exception)
      future.result = false;
  else
      future.result = true;
});

Example Output

In first stage
Finished stage 2 before stage 1
In stage 3
100 ms passed

If the "now" was a "then", you would see the following output:

In first stage
100 ms passed
First then finished
In stage 3


onError

Used to define a Future-wide error handler. This overrides the default error handling in a Future (which passes the exception through to the next then clause). Instead, all errors are passed to the function defined with this call.

Syntax

    Future.OnError(func);

Parameters

Argument Required Type Description
func Yes Function Function to call when error occurs.

Returns

None.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var f = new Future("Hello");

f.onError(function(future) {
  Mojo.Log.info("In error handler, error was: "+future.exception);
  future.result = false;
});


setException

Sets the exception for the Future.

Syntax

    Future.setException(value);

Parameters

Argument Required Type Description
value Yes any Value to set.

Returns

None.

Example

var libraries   = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future      = libraries["foundations"].Control.Future;
var AssertUtils = libraries["foundations"].Assert;

var f = new Future("Hello");

f.then(function(future) {
  future.exception = 2;
});

f.then(function(future) {
  var e = future.exception;
  AssertUtils.requireEqual(e, 2);
  future.setException(3);
});

f.then(function(future) {
  var e = future.exception;
  AssertUtils.requireEqual(e, 3);
  future.result = "Passed";
  Mojo.Log.info("future.result = "+future.result);
});


setResult

Sets the Future's "result" property. Calling this does not stop the future's exception (if any) from being re-thrown.

Syntax

    Future.setResult(value);

Parameters

Argument Required Type Description
value Yes any Value to set.

Returns

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var AssertUtils = libraries["foundations"].Assert;

var f = new Future(1);
f.then(function(future) {
  AssertUtils.requireEqual(1, future.result);
  future.result = 2;
});

f.then(function(future) {
  AssertUtils.requireEqual(2, future.getResult());
  future.setResult(3);
});

f.then(function(future) {
  AssertUtils.requireEqual(future.result, future.getResult());
  future.setResult("passed");
});


status

Returns the Future's current status.

Syntax

string Future.status();

Parameters

None.

Returns

One of the following:

  • cancelled -- A pending result or exception was cancelled.
  • exception -- An exception is pending.
  • none -- No result, exception, or cancellation is pending.
  • result -- A result is pending.

then

Register a scope and function for execution when a Future has a result or exception set. You can register multiple "thens" and they are organized in the order registered. One "then" function is called per "result" or "exception" set on the Future.

The function registered in the "then" should take the form:

function myThenFunc(future) { .... }

The Future passed as the argument is the one that triggered the function call, allowing the same function to be used in different Futures. The function is executed in the scope passed. If the function throws any exceptions that are not handled, the Future passes them to subsequent "then" handlers.

Syntax

    Future.then(scope, thenfunc, errorfunc);

Parameters

Argument Required Type Description
scope No any object Call scope
thenfunc Yes Function Function to call.
errorFunc No Function Error function to invoke on failure.

Returns

None.

Example

The following example invokes the JavaScript wrapper API (which returns a future) for the db8 "find" (query) call once each in three different "thens". The final "then" aggregrates the results of all three find/then calls.

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var DB        = libraries["foundations"].Data.DB;

var f = new Future("hello");
var result1, result2, result3;
f.then(DB.find({ "from": "dbtest:1", "limit":1, "where": [{ "prop":"profession", "op":"=", "val":"engineer"}]}).then( function(f)
{
  result1 = f.result.results[0];
}));

f.then(DB.find({ "from": "dbtest:1", "limit":1, "where": [{ "prop" :"profession", "op": "=", "val":"homemaker"}]}).then( function(f)
{
  result2 = f.result.results[0];
}));

f.then(DB.find({"from":"dbtest:1", "limit":1, "where": [{ "prop" :"profession", "op": "=", "val":"trainer"}]}).then( function(f)
{
  result3 = f.result.results[0];
  f.result = {
      rec1:  result1,
      rec2:  result2,
      rec3:  result3
  };
  Mojo.Log.info("Final result="+JSON.stringify(f.result));
}));

Example Output

Final result=
{
  "rec1":{
      "_id":"++HJdTuywUsIfU6N",
      "_kind":"dbtest:1",
      "_rev":5074,
      "age":40,
      "name":"Mark",
      "profession":"engineer"
  },
  "rec2":{
      "_id":"++HJdTuz3o4ez4D3",
      "_kind":"dbtest:1",
      "_rev":5078,
      "age":48,
      "name":"Marge",
      "profession":"homemaker"
  },
  "rec3":{
      "_id":"++HJdTuyyN44nzZl",
      "_kind":"dbtest:1",
      "_rev":5075,
      "age":36,
      "name":"Yvette",
      "profession":"trainer"
  }
}


whilst

Provides a Futures looping construct. Every time through the loop, "conditionfunc" is executed. If it returns a "true" value, then "func" is called using Future.now().

Syntax

    Future.whilst(scope, conditionfunc, func, errorfunc);

Parameters

Argument Required Type Description
scope No any object Call scope
conditionfunc Yes Function Function executed every time through loop.
func Yes Function Function to call.
errorFunc No Function Error function to invoke on failure.

Returns

None.

Example

The following will execute the "now" function once, the "whilst" 10 times and, finally, the "then" once.

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future = libraries["foundations"].Control.Future;
var f = new Future("Hello");

f.now( function(f)
  {
      f.result = 0;
  }
  ).whilst(this, function(f)
      {
          return f.result < 10;
      },
      function(f)
      {
          f.result++;
      }
      ).then( function(f)
          {
              if (f.result == 10) {
              f.result = "Done";
          } else {
              f.result = "Error, should have been 10, was "+f.result;
          }
      }
);


mapReduce

A version of MapReduce using Futures, Palm's mechanism for handling asynchronous callbacks.

  • Map -- The map function is applied iteratively to each passed dataset element and the results are sent to reduce. The map function must return a Future.

  • Reduce -- The reduce function takes map results and combines them for the final result. The reduce function must return a Future and accept an array of objects where each is:

{ item: <original data>, result: <normal result>, exception: <error result> }

Only "result" or "exception" is present, never both.

By default, any exceptions in map are propagated to reduce and the returned future. To suppress or otherwise override this behavior, implement reduce.

Syntax

    Future mapReduce(config, data)

Parameters

Argument Required Type Description
config Yes object Object containing map and reduce functions.
data Yes any array The map function is applied iteratively to each element in the dataset.

Returns

Future containing results.

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Future    = libraries["foundations"].Control.Future;
var mapReduce = libraries["foundations"].Control.mapReduce;
var data = [
  {name: "duck", say: "quack", after: 300},
  {name: "duck", say: "quack", after: 100},
  {name: "goose", say: "quark", after: 200}
];

function map(animal) {
  var f = new Future();
  setTimeout(function() {
      try {
          f.result = [animal.name, " has this much to say: ", animal.say].join();
      } catch (e) {
          f.exception = e;
      }
  }, animal.after);
  return f;
};

function reduce(results) {
  // do not throw errors, just pass them through
  return new Future().immediate(results);
};

var future = mapReduce( { map: map, reduce: reduce }, data);

future.then(function() {                
  var result = future.result;
  Mojo.Log.info("mapReduce ="+JSON.stringify(result));
});

Example Output

mapReduce =
[
  {
      "item":{
          "name":"duck",
          "say":"quack",
          "after":100
      },
      "result":"duck, has this much to say: ,quack"
  },
  {
      "item":{
          "name":"goose",
          "say":"quark",
          "after":200
      },
      "result":"goose, has this much to say: ,quark"
  },
  {
      "item":{
          "name":"duck",
          "say":"quack",
          "after":300
      },
      "result":"duck, has this much to say: ,quack"
  }
]


Environment Utilities

This namespace contains boolean functions about an app or service's environment.


EnvironmentUtils.runtime

Syntax

string EnvironmentUtils.runtime(); 

Parameters

None.

Returns

"node" (node.js) or "browser" (Mojo)


EnvironmentUtils.isBrowser

Syntax

EnvironmentUtils.isBrowser(); 

Parameters

None.

Returns

true or false


EnvironmentUtils.isNode

Syntax

EnvironmentUtils.isNode(); 

Parameters

None.

Returns

true or false


Object Utilities

This namespace contains functions that operate on objects.


ObjectUtils.toQueryString()

Takes an object of name/value pairs, for example:

{'key1': 'value one', 'key2': 'value 2' }

And turns it into a string, for example:

key1=value%20one&key2=value%20two

It replaces the Prototype function Object.toQueryString.

Note:

Does not handle object arrays.

Syntax

    ObjectUtils.toQueryString(obj)

Parameters

Argument Required Type Description
obj Yes any object Object to convert to string.

Returns

{
  object string : string
}

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var ObjectUtils = libraries["foundations"].ObjectUtils;
var ItemPrices = { "Item" : "drink", "price" : 2};
Mojo.Log.info("ItemPrices string = "+ ObjectUtils.toQueryString(ItemPrices));

Example Output

ItemPrices string = Item=drink&price=2


String Utilities

This namespace contains functions that operate on strings.

Function Description
StringUtils.camelize Takes a string with words separated by '-' and turns it into a CamelCase'd string.
StringUtils.endsWith Checks whether a string ends with a given substring.
StringUtils.escapeHTML Takes a string with HTML entity forms "<", ">" and "&" and replaces them with "&#38lt;", "&#38gt;" and "&#38amp;".
StringUtils.includes Checks whether a substring appears anywhere within a string.
StringUtils.isBlank Checks whether a string is blank. A string is considered blank when it consists entirely of zero or more whitespace characters.
StringUtils.parseQueryString Turns a string containing name/value pairs into an object containing name/value pairs.
StringUtils.startsWith Checks whether a string starts with a given substring.
StringUtils.stripScripts From a string, removes script tags and anything inside them.
StringUtils.stripTags Removes all HTML tags from a string and returns the result.
StringUtils.unescapeHTML Unescapes a string with HTML entity forms "&#38lt;", "&#38gt;" and "&#38amp;" and replaces them with "<", ">" and "&".

StringUtils.camelize()

Takes a string with words separated by '-' and turns it into a <a http://en.wikipedia.org/wiki/CamelCase" target="_blank">CamelCased string. For example:

"some-string"  becomes "someString"
"some-other-string" becomes "someOtherString"

Syntax

    string StringUtils.camelize(str)

Parameters

Argument Required Type Description
str Yes string String to camelize.

Returns

{
  str : string
}

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var notCamelStr = "string-to-camelize";
Mojo.Log.info("camelStr = "+ JSON.stringify(StringUtils.camelize(notCamelStr)));

Example Output

camelStr = "stringToCamelize"


StringUtils.endsWith()

Checks whether a string ends with a given substring.

Syntax

    boolean StringUtils.endsWith(str, subStr)

Parameters

Argument Required Type Description
str Yes string String to check.
subStr Yes string Substring to search for at end.

Returns

true or false

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var str = "stringToCheck";
var subStr = "Check";
Mojo.Log.info("endsWith = "+ StringUtils.endsWith(str, subStr));

Example Output

endsWith = true


StringUtils.escapeHTML()

Takes a string with HTML entity forms "<", ">" and "&" and replaces them with "&lt;", "&gt;" and "&amp;".

Syntax

    string StringUtils.escapeHTML(escStr)

Parameters

Argument Required Type Description
escStr Yes string String to escape.

Returns

escaped string

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var escStr = "string>To<Escape&";
Mojo.Log.info("escapeHTML = "+ StringUtils.escapeHTML(escStr));

Example Output

    escapeHTML = string&To&Escape&

StringUtils.includes()

Checks whether a substring appears anywhere within a string.

Syntax

boolean StringUtils.includes(str, subStr)

Parameters

Argument Required Type Description
str Yes string String to check.
subStr Yes string Substring to check for.

Returns

true or false

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var strInc = "StringToCheckForSubstring";
var subStrInc = "For";
Mojo.Log.info("inlcudes = "+ StringUtils.includes(strInc, subStrInc));

Example Output

includes = true


StringUtils.isBlank()

Checks whether a string is blank. A string is considered blank when it consists entirely of zero or more whitespace characters.

Syntax

    boolean StringUtils.isBlank(str)

Parameters

Argument Required Type Description
str Yes string String to check for blankness.

Returns

true or false

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var blankStr = "    ";
Mojo.Log.info("isBlank = "+ StringUtils.isBlank(blankStr));

Example Output

isBlank = true


StringUtils.parseQueryString()

Takes a string of the form:

key1=value%20one&key2=val2

And turns it into an object:

{"key1":"value one","key2":"val2"}

It replaces the Prototye function String#toQueryParams and its alias String#parseQuery.

Syntax

object StringUtils.parseQueryString(string)

Parameters

Argument Required Type Description
string Yes string String to convert to object.

Returns

{
  object : any
}

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var itemPriceStr = "Item=drink&price=2";
Mojo.Log.info("ItemPrice obj = "+ JSON.stringify(StringUtils.parseQueryString(itemPriceStr)));

Example Output

ItemPrice obj = {"Item":"drink","price":"2"}


StringUtils.startsWith()

Checks whether a string starts with a given substring. It can be thought of as another way of saying:

str.indexOf(substring) === 0

Syntax

    boolean StringUtils.startsWith(str, subStr)

Parameters

Argument Required Type Description
str Yes string String to check.
subStr Yes string Substring to search for at beginning.

Returns

true or false

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var str = "stringToCheck";
var subStr = "str";
Mojo.Log.info("startsWith = "+ StringUtils.startsWith(str, subStr));

Example Output

startsWith = true


StringUtils.stripScripts()

From a string, removes <script> tags and anything inside them.

Syntax

    string StringUtils.stripScripts(str);

Parameters

Argument Required Type Description
str Yes string String to strip.

Returns

{
    strippedString : string
}

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var scriptsStr = "Remove <script>Please remove me</script>this";
Mojo.Log.info("strippedScriptsStr = "+ StringUtils.stripScripts(scriptsStr));

Example Output

strippedScriptsStr = Remove this


StringUtils.stripTags()

This function removes all HTML tags from a string and returns the result.

Syntax

    string StringUtils.stripTags(tagsStr);

Parameters

Argument Required Type Description
tagsStr Yes string String to strip.

Returns

{
  strippedString : string
}

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var StringUtils = libraries["foundations"].StringUtils;
var tagsStr = "<table><tr><td>Let the good times roll</td></tr></table>";
Mojo.Log.info("strippedTagsStr = "+ StringUtils.stripTags(tagsStr));

Example Output

strippedTagsStr = Let the good times roll


StringUtils.unescapeHTML()

Unescapes a string with HTML entity forms "&lt;", "&gt;" and "&amp;" and replaces them with "<", ">" and "&".

Syntax

    StringUtils.unescapeHTML(unescStr)

Parameters

Argument Required Type Description
unescStr Yes string String to unescape.

Returns

true or false

Example

    var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
    var StringUtils = libraries["foundations"].StringUtils; 
    var unescStr = "string&To&unescape&";      
    Mojo.Log.info("unescapeHTML = "+ StringUtils.unescapeHTML(unescStr)); 

Example Output

    unescapeHTML = string>To<unescape&

Structure Utilities

This namespace contains methods that allocate error and class objects.


Class.create()

Creates class objects that can call their own initialize (contructor) methods.

If the first argument is a class, it is treated as the new class's superclass, and all its methods are inherited. Otherwise, any arguments passed are treated as objects, and their methods are copied over as instance methods of the new class.

Syntax

    Class.create(superclass, methods);

Parameters

Argument Required Type Description
superclass No object If no superclass, the passed methods are used in creating the new class.
methods No objects Methods to implement. If nothing is passed, methods are inherited from the superclass. Methods passed override methods in the superclass.

Returns

{
  Class Object
}

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Class = libraries["foundations"].Class; 
var Pet = Class.create(  {
  //our 'constructor'
  initialize: function(petName, age){
      this.name = petName;
      this.age = age;
  },

  log: function(){
      Mojo.Log.info("I do not know what I should say, but my name is " + this.name);
  }
});

var famousDog = new Pet("Santas Little Helper", 15);
famousDog.log();

Example Output

I do not know what I should say, but my name is Santas Little Helper


Err.create()

Allocates an object containing an error code, error message, inner error message and stack trace.

Syntax

    errObj Err.create(errorCode, errorMessage, innerError);

Parameters

Argument Required Type Description
errorCode No int Error code. Default is -1.
errorMessage No string Error message. Default is none.
innerError No string Inner error message containing additional information.

Returns

{
  Error Object
}

Example

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var Err = libraries["foundations"].Err; 
var newErr = Err.create(23, "main error message", "inner error message");
Mojo.Log.info("New Error="+JSON.stringify(newErr));

Example Output

New Error=
{
  "message":"main error message",
  "stack":"Error: main error message;
      innerError: \"inner error message\"\n
      at Object.create (palmfoundationsVersion1_0:104:372)\n
      at FirstAssistant.handleButtonPress (file:///media/cryptofs/apps/usr/palm/applications/com.palm.foundmain/app/assistants/first-assistant.js:47:21)\n
      at HTMLDivElement.<anonymous> (InstallPrototypeBuiltIn:282:23)\n
      at Object.send (palmInitFramework362:10035:9)\n
      at anonymous.sendTap (palmInitFramework362:11249:21)\n
      at anonymous.finish (palmInitFramework362:11329:6)\n
      at anonymous.mouseUp (palmInitFramework362:11346:6)\n
      at HTMLDocument.<anonymous> (palmInitFramework362:10809:16)",
  "errorCode":23,
  "innerError":"inner error message"
}