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:
- Assert.assertEqual(obj1, obj2, msg, params)
- 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. 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:
- Directed graphs -- Balloons represent states, and arrows between them represent transitions, which are labeled with events and actions.
- 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 "&lt;", "&gt;" and "&amp;". |
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 "&lt;", "&gt;" and "&amp;" 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 "<"
, ">"
and "&"
.
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.unescapeHTML()
Unescapes a string with HTML entity forms "<"
, ">"
and "&
" 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" }