This file documents some low-level APIs which are provided by Infusion at the JavaScript level. Note that since Infusion's more overarching aim is to enable declarative programming based on JSON structures, by means of its IoC system, the documentation in this file doesn't cover very much of Infusion's real function. Please consult pages on Component Grades, Component Configuration Options, the Infusion Event System, etc. for coverage of these wider topics.
Type checking
fluid.isValue(value)
value {Any}
- Returns:
{Boolean}
Returns true
if the supplied value is other than null
or undefined
.
fluid.isPrimitive(value)
value {Any}
- Returns:
{Boolean}
Returns true
if the supplied value is of a primitive JavaScript type (recognized: String
, Boolean
, Number
,
Function
, and falsy values)
fluid.isArrayable(totest)
totest {Any}
- Returns:
{Boolean}
Returns true
if the supplied value can be treated as an array. The strategy used is an optimised
approach taken from an earlier version of jQuery - detecting whether the toString()
version
of the object agrees with the textual form [object Array]
, or else whether the object is a
jQuery object (the most common source of "fake arrays").
fluid.isPlainObject(totest[, strict])
totest {Any}
strict {Boolean}
[optional] Iftrue
, only accepts plain Objects- Returns:
{Boolean}
Returns true
if the supplied object is a plain JSON-forming container - that is, it is either a plain Object
or a plain Array. If the strict
argument holds true
, only returns true
if the supplied object is a plain Object.
This method will accept as plain objects coming from other contexts (e.g. iframes or V8 contexts) if they were
plain in that context.
fluid.typeCode(totest)
totest {Any}
- Returns:
{String}
Returns primitive
, array
or object
depending on whether the supplied object has
one of those types, by use of the fluid.isPrimitive
, fluid.isPlainObject
and fluid.isArrayable
utilities
fluid.isDOMNode(totest)
totest {Any}
- Returns:
{Boolean}
Returns true
if the supplied object is a DOM node.
fluid.isDOMish(totest)
totest {Any}
- Returns:
{Boolean}
Returns true
if the supplied object is a DOM node or a jQuery object.
fluid.isUncopyable(totest)
totest {Any}
- Returns:
{Boolean}
Returns true
if it would be unwise to copy the supplied object. The framework will not attempt to copy any material
which fails this test. An object which passes fluid.isPrimitive
, fluid.isDOMish
or fails fluid.isPlainObject
will
pass this test.
fluid.isComponent(totest)
totest {Any}
- Returns:
{Boolean}
Returns true
if the supplied object is an Infusion component.
fluid.isDestroyed(component)
component {Component}
- Returns:
{Boolean}
Returns true
if the supplied Infusion component has been destroyed.
fluid.hasGrade(options, gradeName)
options {Object}
gradeName {String}
- Returns:
{Boolean}
Returns true
if the supplied options (defaults) are the top-level options of a
component which has the supplied grade. These must be options which have already been through options merging, since the
test is a simpleminded one that simply checks whether the gradeNames
entry in the options contains the supplied
gradeName
.
fluid.componentHasGrade(component, gradeName)
component {Component}
gradeName {String}
- Returns:
{Boolean}
Returns true
if the supplied component has the supplied gradeName
as a parent grade. This is a rapid check which
uses the framework's internal data structures for the lookup.
Basic implementation atoms
fluid.identity(arg)
arg {Any}
- Returns:
{Any}
fluid.notImplemented()
A function which raises a failure if executed. This function name can also be used as a placeholder in Invokers and namespaced Listener to create abstract (noninstantiable) Component Grades.
fluid.each(source, func)
source {Array|Object}
A container to be iterated over (may be null)func {Function} (element {Any}, index {Number|String}) → Any
. This function will be invoked once on each member ofsource
and will receive the member and its key (either an integer for an array source, or a string for an object source)- Returns: none
Iterates over a supplied array or hash, invoking a function once for each member. Similar to
jQuery.each
only the arguments to func
are the right way round and the
function does not explode on nonvalues. fluid.each
on null
or undefined
is a no-op.
fluid.invokeLater(func)
func {Function}
A function accepting zero arguments which is to be invoked later- Returns: none
A standard utility to schedule the invocation of a function after the current function call stack returns. On browsers
this defaults to setTimeout(func, 1)
but in other environments can be customised - e.g. to process.nextTick
in
node.js. In future, this could be optimised in the browser to not dispatch into the event queue.
fluid.allocateGuid()
- Returns:
{String}
A string of about a dozen characters that has made moderate efforts to be globally unique.
Allocate a string value that will be unique within this Infusion instance (frame or process), and globally unique with
high probability (50% chance of collision after a million trials). This has the structure prefix-id
where prefix
is
the value of fluid.fluidInstance
identifying this Infusion instance, and id
is a increasing integer initialised at 1
when this infusion instance starts up.
fluid.add(a, b)
a {Number}
The first operand to be addedb {Number}
The second operand to be added- Returns:
{Number}
The value ofa + b
Returns the result of invoking the JavaScript operator +
on its two arguments. This is a function convenient to
supply, for example, to fluid.accumulate
to sum a list of numbers.
Creation, copying and destroying
fluid.freshContainer(tocopy)
tocopy {Object|Array}
- Returns:
{Object|Array}
Return an empty container as the same type as the argument (either an array or hash). To be wise, the supplied argument
should pass the fluid.isPlainObject
test.
fluid.copy(tocopy)
tocopy {Any}
- Returns:
{Any}
Performs a deep copy (clone) of its argument. This will guard against cloning a circular object by terminating if it
reaches a path depth greater than fluid.strategyRecursionBailout
. fluid.copy
will
not copy an object which passes fluid.isUncopyable
.
fluid.makeArray(arg)
arg {Any}
- Returns:
{Array}
Converts the supplied argument to an array (or copies it if it is already an array), by a variety of strategies:
- If it is even slightly arrayable (has a numeric
length
property), its elements will be copied into a fresh array - If it is not slightly arrayable, it will be placed into a 1-element array
- If it is undefined, a 0-element array will be returned
fluid.generate(n, generator[, applyFunc])
n {Integer}
The size of the array to be filledgenerator {Object|Function}
Either a value to be replicated or function to be called (if theapplyFunc
argument holdstrue
). In case of a function, the signature is(i {Integer}) → Any
, accepting the index position and returning the generated element.applyFunc {Boolean}
Iftrue
, thegenerator
value is to be treated as a function- Returns:
{Array}
An array of lengthn
holding the generated elements
Fills an array of given size with copies of a value or result of a function invocation
fluid.iota(n[, first])
n {Integer}
Size of the filled array to be returnedfirst {Number}
[optional, defaults to 0] First element to appear in the array- Returns:
{Array}
An array of lengthn
holding the generated elements
Returns an array of size n
, filled with increasing integers, starting at 0 or at the value specified by first
. The
name iota
originally stems from the
APL programming language.
fluid.clear(target)
target {Object|Array}
The target to be cleared- Returns:
{Undefined}
Clears an object or array of its contents. For objects, each property is deleted. The input argument will be destructively modified.
Transforming and filtering
fluid.transform(source, [fn1, fn2, ...])
source {Array|Object}
The initial container of objects to be transformed. If the source is neither an array nor an object, it will be returned untransformedfn_i {Function} (element {Any}, index {Number|String})→Any
(arbitrary number accepted) An arbitrary number of optional further arguments, all of typeFunction
, accepting the signature(element, index)
, whereelement
is the list member to be transformed, andindex
is its index. Each function will be applied in turn to each member, which will be replaced by the return value from the function.- Returns:
{Array|Object}
The finally transformed structure, where each member has been replaced by the original member acted on by the function or functions.
Return a list or hash of objects, transformed by one or more functions. Similar to
jQuery.map
, but accepts an arbitrary list of transformation functions and does
not explode on null sources. fluid.transform
on a non-array and non-object (e.g. null
) is a no-op.
fluid.accumulate(list, fn, initial)
list {Array}
The list of objects to be accumulated over.fn {Function: (object {Any}, total {Any-Total}, index {Integer}) → Any-Total}
An "accumulation function" accepting the signature(object, total, index)
whereobject
is the list member,total
is the "running total" object (which is the return value from the previous invocation offn
or elseinitial
), and index is the index number.arg {Any-Total}
The initial value for the "running total" object.- Returns:
{Any-Total}
The final running total object as returned from the final invocation of the function on the last list member.
Scan through a list of objects, "accumulating" a value over them (may be a straightforward "sum" or some other chained computation). "accumulate" is the name derived from the C++ STL, other names for this algorithm are "reduce" or "fold". Example:
var numbers = fluid.iota(4, 1); // numbers now holds [1, 2, 3, 4]
var sum = fluid.accumulate(numbers, fluid.add, 0); // sum now holds 10
Note that other common uses of fluid.accumulate
(maximum and minimum) can be achieved through the multi-arg versions
of Math.max
and Math.min
, e.g.
var max = Math.max.apply(null, numbers);
fluid.roundToDecimal(num, scale, method)
num {Number}
The number to be roundedscale {Number}
The maximum number of decimal places to round to. If the scale is invalid (i.e falsey, not a number, negative value), it is treated as 0. If the scale is a floating point number, it is rounded to an integer.method {String}
(optional) Request a rounding method to use ("round", "ceil", "floor"). If nothing or an invalid method is provided, it will default to "round".
Derived from Sindre Sorhus's round-to node module. (License: MIT)
Rounds the supplied number to at most the number of decimal places indicated by the scale, omitting any trailing 0s. There are three possible rounding methods described below: "round", "ceil", "floor".
"round"
: Numbers are rounded away from 0 (i.e 0.5 -> 1, -0.5 -> -1)."ceil"
: Numbers are rounded up"floor"
: Numbers are rounded down
var rounded = fluid.roundToDecimal(1.555, 2); // rounded now holds 1.56
var ceil = fluid.roundToDecimal(1.555, 2, "ceil"); // rounded now holds 1.56
var floor = fluid.roundToDecimal(1.555, 2, "floor"); // rounded now holds 1.55
fluid.remove_if(source, fn[, target])
source {Array|Object}
The array or hash of objects to be scanned over. This structure will be modified in place. Note that in the case this is an array, iteration will run from the end of the array towards the front, so that the index of elements yet to be removed will remain stable.fn {Function: (object {Any}, index {Number|String}) → Booleanish }
A predicate function determining whether an element should be removed. This accepts the standard signature(object, index)
. If the predicate returns a "truthy" value, the corresponding object will be removed from the source structure.target {Array|Object}
[optional] A target object of the same type assource
, which will receive any objects removed from it.- Returns:
{Array|Object}
Eithertarget
, containing the removed elements, if it was supplied, or elsesource
modified by the operation of removing the matched elements.
Scan through a list or hash of objects, removing those which match a predicate. The source structure will be modified in place.
fluid.getMembers(holder, path)
holder {Array|Object}
The container to be filteredpath {String|Array of String}
An EL path to be fetched from each top-level member- Returns:
{Array|Object}
A container of the same type asholder
, with the members ofholder
dereferenced bypath
.
Extracts a particular member from each top-level member of a container, returning a new container of the same type. Example:
var cattes = [
{ name: "Huggoe" },
{ name: "Arthur" },
{ name: "THER CATTE" }
];
var names = fluid.getMembers(cattes, "name");
// names now holds ["Huggoe", "Arthur", "THER CATTE"];
fluid.filterKeys(toFilter, keys[, exclude])
toFilter {Object}
The object to be filtered - this will be NOT modified by the operationkeys {String[]}
The list of keys to operate withexclude {Boolean}
[optional] Iftrue
, the keys listed are removed rather than included- Returns:
{Object}
the filtered object
Accepts an object to be filtered, and a list of keys. Either all keys not present in the list are removed (the default),
or all keys present in the list are removed (exclude: true
). The supplied object is not modified but will be
shallow cloned by this operation.
fluid.censorKeys(toCensor, keys)
toFilter {Object}
The object to be filtered - this will be NOT modified by the operationkeys {String[]}
The list of keys to be excluded- Returns:
{Object}
A shallow clone oftoFilter
with the supplied keys removed
A convenience wrapper for fluid.filterKeys
with the argument exclude
set to true
. Returns a shallow clone of the
supplied object with listed keys removed.
fluid.keys(object)
object {Object}
The object to have its keys listed- Returns:
{Array}
An array holding the keys of this object.
Return the keys in the supplied object as an array. Note that this will return keys found in the prototype chain as well
as "own properties", unlike the builtin
Object.keys()
fluid.values(object)
object {Object}
The object to have its values listed- Returns:
{Array}
An array holding the values of this object.
Return the values in the supplied object as an array. This will return values found in the prototype chain as well as those attached to "own properties".
fluid.arrayToHash(array)
array {Array of String}
The array to be converted to a hash- Returns:
{Object}
An object with valuetrue
for each key taken from a member ofarray
Converts an array into an object whose keys are the elements of the array, each with the value true
fluid.hashToArray(hash, keyName[, func])
hash {Array}
The hash to be transformed into an arraykeyName {String}
The name within the resulting array elements which will receive the string which used to form the element's key inhash
func {Function (newElement {Object), oldElement {Object}, key {String}) → Object }
[optional] receives(newElement, oldElement, key)
wherenewElement
is the freshly cloned element (a freshObject obj
which just hasobj[keyName] = key
),oldElement
is the original hash's element, andkey
is the key of the element in the hash. The function returns the final element that will be added to the array - it may ignorenewElement
if it pleases and make an unrelated return. If the function makes no return,newElement
will be used. If the function is not supplied, the old element is simply deep-cloned onto the new element (same effect as transformfluid.transforms.objectToArray
).
Converts a hash into an array by hoisting out the object's keys into an array element via the supplied String key
, and
then transforming the elements via an optional further function func
. Note that without some further means of sorting
the resulting array elements, the order of elements in the array will not be defined.
Example:
var hash = {
"Proailurus": 25000000,
"Pseudaelurus": 18500000,
"Felis attica": 12000000,
"Felis lunensis": 2500000,
"CATT": 50000
};
var CATTyears = fluid.hashToArray(hash, "species", function (newElement, oldElement) {
newElement.yearsAgo = oldElement;
});
// CATTyears now contains [ {
// species: "Proailurus",
// yearsAgo: 25000000
//}, { // etc.
fluid.flatten(array)
array {Array}
The array to be flattened- Returns:
{Array}
The flattened array.
Converts an array consisting of a mixture of arrays and non-arrays into the concatenation of any inner arrays with the
non-array elements. The original array will not be modified. See description of
mapcat or flat-map
.
fluid.freezeRecursive(tofreeze)
tofreeze {Array|Object}
The object to be frozen recursively- Returns:
{Array|Object}
The supplied argument, recursively frozen
Calls Object.freeze
at each level of containment of the supplied object. This function is a no-op if a primitive value is supplied.
fluid.pushArray(holder, member, topush)
holder {Array|Object}
The holding object whose member is to receive the pushed element(s).member {String}
The member of theholder
onto which the element(s) are to be pushedtopush {Array|Object}
If an array, these elements will be added to the end of the array usingArray.push.apply
. If an object, it will be pushed to the end of the array usingArray.push
.
Pushes an element or elements onto an array, initialising the array as a member of a holding object if it is not already
allocated. The member of the holding object should either be undefined
or hold an array at the time of the call.
Example:
var holder = {};
fluid.pushArray(holder, "array", 3); // holder.array now holds [3]
fluid.pushArray(holder, "array", [4, 5]); // holder.array now holds [3, 4, 5]
Sorting and searching
fluid.find(source, func[, deflt])
source {Arrayable|Object}
The list or hash of objects to be searched.func {Function: (element {Any}, index {Number|String}) → Any}
A predicate function, acting on a member. A predicate which returns any value which is notundefined
will terminate the search.deflt {Any}
[optional] A value to be returned in the case the predicate is not satisfied on any element a member. The default will be the natural value ofundefined
- Returns: The first return value from the predicate function which is not
undefined
Scan through a list or hash of objects, terminating on the first member which satisfies a predicate function. The return is the return value from the predicate.
fluid.find_if(source, func[, deflt])
source {Arrayable|Object}
The list or hash of objects to be searched.func {Function: (element {Any}, index {Number|String}) → Boolean}
A predicate function, acting on a member. A predicate which returns any value which is notfalse
will terminate the search.deflt {Any}
[optional] A value to be returned in the case no predicate function matches a member. The default will be the natural value ofundefined
- Returns: The first element for which the value of the predicate function is not
false
Scan through a list or hash of objects, terminating on the first member which matches a predicate function. The return
value is the first element itself for which the predicate returns other than false
.
fluid.contains(tosearch, value)
tosearch {Object|Array}
The structure to be searched for the supplied value,value {Any}
The value to be searched for- Returns:
{Boolean|Undefined}
Returnstrue
if the value was found in the container
Searches through the supplied structure, and returns true
if the supplied value can be found, using ===
equality
fluid.keyForValue(tosearch, value) {
tosearch {Object|Array}
The structure to be searched for the supplied valuevalue {Any}
The value to be found. This will be compared against the structure's members using===
equality.- Returns:
{String|Integer|Undefined}
The first key (anInteger
iftosearch
is anArray
) whose value matches the one supplied, orundefined
if no value matches
Searches through the supplied object for the first value which matches the one supplied.
fluid.stableSort(array, func)
array {Array of Any-Element}
The array to be sorted. This input array will be modified in place.func {Function: (a {Any-Element}, b {Any-Element}) → Number}
A comparator returning >0, 0, or <0 on pairs of elements representing their sort order (same contract as Array.sort comparator)
Applies a stable sorting algorithm to the supplied array and comparator (note that Array.sort in JavaScript is not specified to be stable). The algorithm used will be an insertion sort, which whilst quadratic in time, will perform well on small array sizes.
fluid.compareStringLength(ascending)
ascending {Booleanish}
true
if a comparator is to be returned which sorts strings in ascending order of length- Returns:
{Function: (a {String}, b {String}) → Number}
The comparator function to be used for sorting
Produces a comparator function suitable for use with Array.sort or fluid.stableSort to sort an array of strings by length
Parsing and rendering
fluid.parseInteger(string)
string {String}
A string to be converted to an integer- Returns:
{Integer|NaN}
The integer value, orNaN
if the string does not represent an integer
Returns the converted integer if the input string can be converted to an integer. Otherwise, returns NaN
.
fluid.stringTemplate(template, terms)
template {String}
A string with embedded tokens of the form%value
terms {Object: String → Stringable}
A hash which maps tokens to their required interpolated values
A simple string interpolation system. Accepts a template string with embedded tokens of the form %value
. Returns a new
string with the tokens replaced by the specified values. Keys and values can be of any data type that can be coerced
into a string. Tokens are not delimited in the template with any syntax - the implementation will replace the longest
token which can be sourced from terms
.
Handling models and paths
fluid.get(model, path)
model {Any}
The model object to be indirected into. This may beundefined
, etc. without triggering an error.path {String|Array of String}
Either a period-separated EL path representing a chain of properties to be navigated, or else an array of path segments representing this- Returns:
{Any}
The result of the indirection of the path into the supplied model
Accesses an element nested within a model object at the supplied (EL) path.
fluid.get
can operate various special behaviour in encountering particular kinds of material - for example, any object
with a function member named resolvePathSegment
will hand resolution of the next path segment to that function if
there is no corresponding concrete member. If fluid.get
navigates off the end of the available model material, this
will not trigger an error - all successive indirections will simply return undefined
. fluid.get
accepts various
esoteric piece of configuration allowing it to operate indirection rules encoded in arbitrary JSON material - these are
imperfectly supported, contact us if you are interested.
fluid.getImmediate(model, path)
model {Any}
The model object to be indirected into. This may beundefined
, etc. without triggering an error.path {Array of String}
An array of path segments representing representing a chain of properties to be navigated- Returns:
{Any}
The result of the indirection of the path into the supplied model
An extremely simplistic, high-performance variant of fluid.get
that supports none of the same bells and whistles - it
is only capable of navigating over concrete object properties that are actually present in the model, and the path must
have already been parsed out into an array of segments. It still, however, operates the same semantic as fluid.get
for
navigating over undefined values.
fluid.set(model, path, newValue)
Writes a new value into a model at a specified path. This is performed by directly modifying the penultimately
referenced model object (the one referenced by the first n-1
path segments in path
) by writing the value newValue
to its property named after the final path segment. Other approaches to this task are possible (see New New Notes on
the
ChangeApplier)
but the fundamental invariant to be respected is that
fluid.get(model, fluid.set(model, path, value), path); // === value
Even a functional programmer could admit that. A slight wrinkle, however, is the behaviour of the special path ""
or
[]
, attempting to write a value at the model root. This API is not capable of this and will fail in this case - since
it is hampered at the language level by being unable to rewrite the object reference model
which exists in the scope
of its caller. The ADD
message of the ChangeApplier
can be used to handle this case. Under its new semantics, the reference model
is at a known address in its parent
component which can be rebound.
If the path path
indirects beyond the range of concrete properties in model
, the implementation will fill in any
intermediate path levels with fresh instances of {}
(in the manner of
mkdirs
).
There are some esoteric extra arguments for fluid.set
which will allow this to be done in a schema-aware way, for
example filling in path levels with []
instead - contact
us if you are interested.
model {Object}
The model object to be indirected into. This must be anObject
.path {String|Array of String}
Either a period-separated EL path representing a chain of properties to be navigated, or else an array of path segments representing thisnewValue: {Any}
The value to be written intomodel
at the pathpath
fluid.modelPairToChanges(value, oldValue, changePathPrefix)
value {Any}
Model value to compareoldValue {Any}
Model value to comparechangePathPrefix {String|Array of String}
[optional] Path prefix to prepend to change request paths- Returns:
{Array of changeRequest}
An array ofchangeRequest
objects
Calculates the changes between the model values value
and oldValue
and
returns an array of
changeRequest
objects. The optional argument changePathPrefix
is prepended to the change
path of each request (this is useful for generating change requests to be
applied at a non-root path in a model).
The returned array of change request objects may be used with
fluid.fireChanges()
.
For example, if we call fluid.modelPairToChanges
with value
of {b: 2}
and oldValue
of {a: 1}
:
fluid.modelPairToChanges({b: 2}, {a:1});
we will receive this result:
[
{
path: [ "b" ],
value: 2,
type: "ADD"
},
{
path: [ "a" ],
value: null,
type: "DELETE"
}
]
Indicating that the property "b" was added with value 2 and that the property "a" was removed.
fluid.model.parseEL(EL)
EL {String}
The EL path to be parsed- Returns:
{Array of String}
The EL path parsed as an array of path segments
Parses a EL path expression by splitting it on the character .
. This is a fast, low-quality implementation which
assumes that no escaping of .
characters is necessary.
fluid.model.composeSegments([seg1, seg2, ...])
seg1 ... segn {String}
The path segments to be composed- Returns:
{String}
The EL path composed by concatenating the path segments.
Compose any number of path segments, none of which may be empty. The inverse to fluid.model.parseEL
- this is a fast,
low-quality implementation which does no escaping.
fluid.pathUtil.parseEL(EL)
EL {String}
The EL path to be parsed- Returns:
{Array of String}
The EL path parsed as an array of path segments
Parses a EL path expression by splitting it on the period character ".
". This is an analog of fluid.model.parseEL
that will escape the characters .
as \.
and \
as \\
, allowing all possible paths to be expressed. In modern
JavaScript VMs, it is not much slower than fluid.model.parseEL
and should be used in all applications where paths will
be accepted from external users.
fluid.pathUtil.composeSegments([seg1, seg2, ...])
seg1 ... segn {String}
The path segments to be composed- Returns:
{String}
The EL path composed by concatenating the path segments.
Compose any number of path segments, none of which may be empty. This is an analog of fluid.pathUtil.parseEL
that will
escape the characters .
as \.
and \
as \\
, allowing all possible paths to be expressed. In modern JavaScript
VMs, it is not much slower than fluid.pathUtil.composeSegments
and should be used in all applications where paths will
be accepted from external users.
Logging and error handling
fluid.log([logLevel, arg1, ... argn])
logLevel {LogLevel}
[optional] One of the members of thefluid.logLevel
structure or in general somefluid.marker
with a numeric value holding a priorityarg1 ... argn {Stringable}
A sequence of arguments to be logged. By default these will be handed unchanged to the multiple arguments ofconsole.log
. It is wise to convert these toString
yourself (e.g. byJSON.stringify
) if i) this is safe, and ii) you would not be satisfied by the environment's rendering.
Log a message to a suitable environmental console (in current implementations, console.log
). If the first argument to
fluid.log
is one of the members of the fluid.logLevel
structure, this will be taken as the
priority of the logged message - else it will default to fluid.logLevel.INFO
. If the logged message
priority does not exceed that set by the most recent call to the fluid.setLogging
function, the logging action will be suppressed.
fluid.logLevel
A hash of strings to LogLevel
constants, suitable for sending as the special, optional, first argument to fluid.log
.
These communicate a logging priority, with lower numbers of higher priority than higher numbers. The system maintains a
current "logging level" as an internal piece of state, updated by fluid.setLogging
and fluid.popLogging
- any
fluid.log
statements whose supplied priority does not exceed the logging level will be inactive.
LogLevel | Priority | Description |
---|---|---|
fluid.logLevel.FATAL |
0 | the very highest logging level, indicating that the process must now exit immediately due to a fatal error |
fluid.logLevel.FAIL |
5 | a very high logging priority, corresponding to an assertion failure, similar to that of fluid.fail - the system will terminate shortly if not immediately |
fluid.logLevel.WARN |
10 | a moderate logging priority, corresponding to a problem which most users would wish to be notified of, but is not sufficient to halt the system |
fluid.logLevel.IMPORTANT |
12 | a moderate logging priority, corresponding to standard debugging messages. This is the level set by fluid.setLogging(false) |
fluid.logLevel.INFO |
15 | a low logging level, corresponding to verbose debugging messages. This is the level set by fluid.setLogging(true) . |
fluid.logLevel.TRACE |
20 | a very low logging level, which if enabled would produce extremely voluminous output which would significantly slow execution and consume a lot of storage. This should only be enabled for short periods of time, perhaps conditional on some triggers surrounding an event of interest. |
fluid.setLogging(logLevel)
logLevel {Boolean|LogLevel}
The system logging level to be made current and to be pushed onto the top of the system's stack of logging levels.
Push a value onto the stack of the system's current logging levels. This will become the system's current logging level
until there is a corresponding call to fluid.popLogging
. The argument may either be a boolean, in which case one of
the standard logging levels (true: fluid.logLevel.INFO
/ false: fluid.logLevel.IMPORTANT
) will be selected, or else
one of the members of the fluid.logLevel
structure or a LogLevel
marker in general. The stack is initialised with a
single element of fluid.logLevel.IMPORTANT
.
fluid.popLogging()
Pops one LogLevel
value that was pushed onto the logging level stack by a previous call to fluid.setLogging
. This
will expose the previous element on top of the stack and restore the logging level that had previously been in effect.
If the stack has only its one original element, this call is a no-op.
fluid.passLogLevel(testLogLevel)
testLogLevel {LogLevel}
The log level against which the system's current logging level is to be checked.- Returns:
{Boolean}
-true
if a message supplied at that log priority would be logged at the current logging level.
Accepts one of the members of the fluid.logLevel
structure or a LogLevel
object in general. Returns true
if a
message supplied at that log priority would be logged at the current logging level. Clients who issue particularly
expensive log payload arguments are recommended to guard their logging statements with this
fluid.doLog([arg1, ... argn])
The actual implementation to which fluid.log
messages and other logging generated by the system are dispatched.
Implemented to forward to console.debug
and console.log
but may be monkey-patched by clients who require an
alternative implementation.
fluid.fail([arg1, ... argn])
The framework and clients can call this method in order to signal a hard assertion failure. The current contract of
fluid.fail
is that an implementation/log error has been discovered - the typical behaviour of the system is to halt or
at the very least propagate an unhandled exception to the top process level which is likely to make the system's
behaviour unstable. If this failure resulted from bad user or external input, do not call this function but instead
signal it in a milder, more implementation-specific way - for example by sending an HTTP status code or showing a user
message. As Infusion evolves to handle a more finely graded variety of dynamic authoring scenarios, this function will
be broken up into variants which can signal failures of different severities.
The current system behaviour is to throw a particular subclass of the standard Error
type, of type fluid.FluidError
.
The behaviour of fluid.fail
can be customised by contributing handlers to the standard event fluid.failureEvent
fluid.failureEvent
log
- the namespace for the listener which logs the failure to a suitable environment. By default this fires tofluid.logFailure
which forwards tofluid.log
before also logging the state of the IoC system by usingfluid.logActivity
fail
- the namespace for the listener which enacts any failure behaviour. By default this callsfluid.fail
but in a testing environment, for example, will react by failing any current test, or in an HTTP server by aborting the handling of any current request with a suitable HTTP status code and message.
Every call to fluid.fail
triggers a firing of this global event. This is a standard Infusion
Event with several handlers installed on startup to take on various functions. Extra handlers
are registered, and the builtin handlers overriden, to customise error handling behaviour in various contexts - for
example, when Infusion is running in node.js, is running a jqUnit test or is running in
Kettle etc. There are two currently standard namespaces for listeners to this
event:
fluid.strategyRecursionBailout
A positive integer (default value 50) above which depth the framework's processing of configuration will bail out,
assuming that it has become circularly linked. This can be customised by the user (although this is an unlikely
requirement), and is read by algorithms such as fluid.copy
and during options
expansion.
The global namespace
Infusion is unusual amongst modern JavaScript systems in that it maintains a single, global namespace of fully qualified
implementation names. For example, builtin Infusion grades are stored in this namespace at paths fluid.*
and each
project will in general allocate its own top-level name. Users are assisted to operate on this global namespace with
some utility functions. Any user of Infusion who has successfully resolved the fluid
object can access the root object
for this namespace as fluid.global
. In the browser, the root of this namespace coincides directly with the real global
namespace, which conventionally is addressed as window
. In a Web
Worker this object is
conventionally known as self
. In environments like node.js where a global namespace is discouraged (but not,
thankfully, actively prohibited) the global object is not directly accessible and users will need to use these utilities
or the helping reference fluid.global
. See fluid.setGlobalValue
for some
guidelines on the use of global names.
fluid.registerNamespace(path)
path {String|Array of String}
The global path at which the namespace is to be allocated- Returns:
{Any}
Any current value held at the supplied path - or a freshly allocated{}
to be held at that path if it was previously empty
Ensures that the supplied path has an object allocated in the global namespace, and retrieves the current value. If no
value is stored, a fresh {}
will be assigned at the path, and to all currently empty paths leading to the global
namespace root. Calls to fluid.registerNamespace
are very common at the start of Infusion-aware .js
files - they are
analogous to require
statements, only they do not cause any code to be loaded by themselves - but they can grant
access to implementations which have been loaded by others, or else provide an intermediate node at which to export
implementations to others.
fluid.getGlobalValue(path)
path {String|Array of String}
The global path from which the value is to be fetched- Returns:
{Any}
The value that was stored at the path, orundefined
if there is none.
Returns any value held at a particular global path. This may be an object or a function, depending on what has been stored there.
fluid.setGlobalValue(path, value)
path {String|Array of String}
The global path at which the value is to be set.value {Any}
The value to be written to the global path. This should in general be a function or other immutable value, and an existing value should not be overwritten. This rule can be overlooked in a genuine architectural emergency.
Write a value to a particular global path. Users are strongly discouraged from storing any mutable information at these paths, but it is accepted that in certain integration scenarios there can be little alternative. Please choose a properly qualified global path name that identifies your project (perhaps, derived from a domain name or npm package name) that you have control over. The Java package naming conventions have proved effective at heading off such problems in the past and we intend that Infusion global names should be handled in an analogous way.
fluid.invokeGlobalFunction(functionPath, args)
functionPath {String|Array of String}
The global path holding the function which is to be invokedargs {Array|Any}
The array of arguments to be supplied to the function. Ifargs
is not an array,fluid.makeArray
will be called on it first.- Returns:
{Any}
Any return value from the function which was invoked
Invokes a function held at a particular global path with the supplied arguments. Equivalent to fluid.getGlobalValue
followed by Function.apply(null, args)
.
fluid.invokeGradedFunction(name, spec)
name {String}
A global name which can be resolved to aFunction
. The defaults for this name must resolve onto a grade derived fromfluid.function
. The defaults record should also contain an entryargumentMap
, a hash of argument names onto indexes.spec {Object}
A hash where the keys are keys of the functionsargumentMap
, and the values are the argument values to be sent to the function. The keys will be looked up in theargumentMap
and the values resolved into a flat list of arguments.- Returns:
{Any}
The return value from the function
Invoke a global function by name and named arguments. A courtesy to allow declaratively encoded function calls to use
named arguments, with names encoded in the defaults for a fluid.function
, rather than bare
arrays.
Storing and retrieving defaults
Infusion's component system is organised around blocks of JSON which define grades - another way
of describing a grade is as a component's default options, which appeals to a slightly more old-fashioned notion of
what a component is. These options are registered into the system and read back from it by using the API
fluid.defaults
. If the options supplied to fluid.defaults
represent a component
grade, the framework will automatically construct and register a component creator
function in the global namespace at a path which matches the component's grade name. Note
that not all defaults correspond to a component - some of them are descended from fluid.function
in which case they
represent a function grade and hold metadata about it. Some defaults are not descended from a framework grade at
all, and are designed to be used as mixins to other grades.
fluid.defaults(gradeName[, options])
gradeName {String}
The fully-qualified name of the grade whose defaults are to be read or written.options {Object}
[optional] The defaults which are to be registered for the grade. If this argument is omitted, the existing defaults are read and returned.- Returns:
{Object}
If the function was called with 1 argument, any defaults already registered for the component. These read defaults will already have gone through options merging and have the contents of any parent grades resolved in them. If you want to read exactly the raw defaults information that was registered for this grade, instead usefluid.rawDefaults
fluid.rawDefaults(gradeName[, options])
gradeName {String}
The fully-qualified name of the grade whose defaults are to be read or written.options {Object}
[optional] The defaults which are to be registered for the grade. If this argument is omitted, the existing defaults are read and returned.- Returns:
{Object}
The raw defaults registered for this grade, without being resolved against parent grades by options merging.