' Adds two numbers.
' @since 0.0.21
' @category Math
' @param {Dynamic} augend - The first number in an addition
' @param {Dynamic} addend - The second number in an addition
' @returns {Dynamic} Returns the total
' @example
' rodash.add(1, 2) // => 3
function add(augend, addend)
value = 0
if (type(augend) = "Integer" OR type(augend) = "roInt" OR type(augend) = "roInteger" OR type(augend) = "LongInteger" OR type(augend) = "Float" OR type(augend) = "roFloat" OR type(augend) = "Double" OR type(augend) = "roDouble" OR type(augend) = "roIntrinsicDouble") then
value += augend
end if
if (type(addend) = "Integer" OR type(addend) = "roInt" OR type(addend) = "roInteger" OR type(addend) = "LongInteger" OR type(addend) = "Float" OR type(addend) = "roFloat" OR type(addend) = "Double" OR type(addend) = "roDouble" OR type(addend) = "roIntrinsicDouble") then
value += addend
end if
return value
end function
' Returns a formatted version of the current time/date.
' @since 0.0.21
' @category Date
' @param {String} format - The date format
' @param {Boolean} asLocal - Whether to get the local date. Default is false.
' @returns {String} value - Returns a formatted version of the current time/date
function asDateString(format = "long-date" as String, asLocal = false as Boolean) as String
return internal_getDateObject(asLocal).asDateString(format)
end function
' Returns the current time in seconds.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local time. Default is false.
' @returns {Integer} value - Returns the current time in seconds
function asSeconds(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).asSeconds()
end function
' Assigns own enumerable string keyed properties of source objects to the destination object. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
' This method mutates object and is loosely based on lodash Object.assign.
' @since 0.0.21
' @category Object
' @param {Dynamic} baseAA - The destination object
' @params {Object} sources - The source objects
' @params {Dynamic} Mutaded baseAA
' @returns {Dynamic} Returns the destination object
' @example
' rodash.assign({ 'a': 0 }, { 'b': 1 }, { 'a': 2 }) // => { 'a': 2, 'b': 1 }
function assign(baseAA as Dynamic, sources = Invalid as Dynamic) as Dynamic
if NOT (type(baseAA) = "roAssociativeArray") then
return Invalid
end if
if (type(sources) = "roArray" AND NOT sources.isEmpty()) then
for each source in sources
if (type(source) = "roAssociativeArray" AND source.keys().count() > 0) then
baseAA.append(source)
end if
end for
end if
return baseAA
end function
' Creates an array of values corresponding to paths of object.
' @since 0.0.21
' @category Object
' @param {AssocArray} obj - The object to iterate over.
' @param {Array} paths - The property paths to pick.
' @returns {Array} Returns the picked values.
' @example
' rodash.at({a: {b: 2}}, ["a.b"])
' // [2]
' rodash.at({a: {b: 2}}, ["a.b", "a.c"])
' // [2, invalid]
function at(obj as Object, paths as Object)
if NOT (type(obj) = "roAssociativeArray" AND obj.keys().count() > 0) OR NOT (type(paths) = "roArray" AND NOT paths.isEmpty()) then
return CreateObject("roArray", 0, true)
end if
returnArray = CreateObject("roArray", paths.count(), true)
for each path in paths
result = get(obj, path)
returnArray.push(result)
end for
return returnArray
end function
' Converts a string to camel case. Removes special characters and spaces.
' @since 0.0.21
' @category String
' @param {String} value - The string to convert.
' @returns {String} The camel case string.
' @example
' rodash.camelCase("Foo Bar") // => "fooBar"
' rodash.camelCase("foo/bar") // => "fooBar"
function camelCase(value = "" as String)
regex = CreateObject("roRegex", "[^a-zA-Z0-9\s]", "")
value = regex.ReplaceAll(value.trim(), "")
valueArray = value.split(" ")
responseValue = ""
for i = 0 to valueArray.count() - 1
valueString = valueArray[i]
if i = 0 then
responseValue += lcase(valueString)
else
responseValue += capitalize(valueString)
end if
end for
return responseValue
end function
' Capitalizes the first letter of a string.
' @since 0.0.21
' @category String
' @param {String} value - The string to capitalize.
' @returns {String} The capitalized string.
' @example
' rodash.capitalize("foo bar") // => "Foo bar"
function capitalize(value = "" as String)
if value = " " then
return value
end if
value = value.trim()
valueArray = value.split("")
responseValue = ""
for i = 0 to valueArray.count() - 1
valueString = valueArray[i]
if i = 0 then
responseValue += ucase(valueString)
else
responseValue += lcase(valueString)
end if
end for
return responseValue
end function
' Computes number rounded up to precision.
' @since 0.0.21
' @category Math
' @param {Integer} number - The number to round up
' @param {Integer} precision - The precision to round up to
' @returns {Integer} Returns the rounded up number
' @example
' rodash.ceil(4.006) // => 5
' rodash.ceil(0.056789, 4) // => 0.0568
function ceil(number = 0, precision = 0 as Dynamic) as Dynamic
return abs(int(-number * 10 ^ precision)) / 10 ^ precision
end function
' Creates an array of elements split into groups the length of size. If array can't be split evenly, the final chunk will be the remaining elements.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to process
' @param {Integer} chunkSize - The length of each chunk
' @returns {Array} Returns the new array of chunks
' @example
' rodash.chunk([1, 2, 3, 4, 5], 2) // => [[1, 2], [3, 4], [5]]
' rodash.chunk([1, 2, 3, 4, 5], 3) // => [[1, 2, 3], [4, 5]]
function chunk(array as Object, chunkSize = 1 as Integer) as Object
if NOT (type(array) = "roArray" AND NOT array.isEmpty()) then
return CreateObject("roArray", 0, true)
end if
array = clone(array)
numberOfChunks = floor(array.count() / chunkSize)
returnArray = CreateObject("roArray", numberOfChunks, true)
arrayIndex = 0
for index = 0 to numberOfChunks
chunkArray = CreateObject("roArray", chunkSize, true)
for i = 0 to chunkSize - 1
chunkArray.push(array[arrayIndex])
arrayIndex++
if arrayIndex = array.count() then
exit for
end if
end for
returnArray[index] = chunkArray
if arrayIndex = array.count() then
exit for
end if
end for
return returnArray
end function
' Clamps number within the inclusive lower and upper bounds.
' @since 0.0.21
' @category Number
' @param {Integer} number - The number to clamp
' @param {Integer} lower - The lower bound
' @param {Integer} upper - The upper bound
' @returns {Integer} Returns the clamped number
' @example
' rodash.clamp(-10, -5, 5) // => -5
' rodash.clamp(10, -5, 5) // => 5
function clamp(number, lower, upper) as Dynamic
return (maxBy([
lower
min([
upper
number
])
]))
end function
' Creates a shallow clone of value.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value - The value to be cloned
' @returns {Dynamic} The cloned value
function clone(value = Invalid as Dynamic) as Dynamic
if (type(value) = "<uninitialized>" OR value = Invalid)
return Invalid
end if
clonedValue = Invalid
if (type(value) = "roArray") then
clonedValue = CreateObject("roArray", value.count(), true)
clonedValue.append(value)
else if (type(value) = "roAssociativeArray") then
clonedValue = CreateObject("roAssociativeArray")
clonedValue.append(value)
else if isNode(value) then
clonedValue = value.clone(true)
else if (type(value) = "String" OR type(value) = "roString") then
clonedValue = "" + value
else if (type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger" OR type(value) = "Float" OR type(value) = "roFloat" OR type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble") then
clonedValue = 0 + value
else if (type(value) = "Boolean" OR type(value) = "roBoolean") then
clonedValue = false OR value
end if
return clonedValue
end function
' Creates an array with all falsey values removed. The values false, 0, "", and invalid are falsey.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to compact
' @returns {Array} Returns the new array of filtered values
' @example
' rodash.compact([0, 1, false, 2, '', 3]) // => [1, 2, 3]
function compact(array as Object) as Object
returnArray = CreateObject("roArray", 0, true)
if (type(array) = "roArray" AND NOT array.isEmpty()) then
for each item in array
shallPass = true
typeName = type(item)
if (type(item) = "<uninitialized>" OR item = Invalid) then
shallPass = false
else if (isString(item) AND item.isEmpty()) then
shallPass = false
else if (type(item) = "Integer" OR type(item) = "roInt" OR type(item) = "roInteger" OR type(item) = "LongInteger" OR type(item) = "Float" OR type(item) = "roFloat" OR type(item) = "Double" OR type(item) = "roDouble" OR type(item) = "roIntrinsicDouble") then
if item = 0 then
shallPass = false
end if
else if (type(item) = "Boolean" OR type(item) = "roBoolean") then
shallPass = item
end if
if shallPass then
returnArray.push(item)
end if
end for
end if
return returnArray
end function
' Creates a new array concatenating array with any additional arrays and/or values.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to concatenate
' @param {Array} values - The values to concatenate
' @returns {Array} Returns the new concatenated array
' @example
' rodash.concat([1], [2, [3], [[4]]]) // => [1, 2, [3], [[4]]]
function concat(array as Object, values as Object) as Object
if NOT (type(array) = "roArray") then
return CreateObject("roArray", 0, true)
end if
if NOT (type(values) = "roArray") then
return array
end if
returnArray = clone(array)
for each value in values
if (type(value) = "roArray") then
returnArray.append(value)
else
returnArray.push(value)
end if
end for
return returnArray
end function
' Creates a new roSGNode object with the specified nodeType and fields. Passed fields are set after the node is created and init() method is called.
' @since 0.0.32
' @category Node
' @param {String} nodeType - The type of node to create
' @param {Object} fields - The fields to set on the node
' @returns {Object} Returns the new roSGNode object
' @example
' rodash.createNode("Rectangle", { id: "myRectangle" }) // => <Rectangle: roSGNode>
' rodash.createNode("Label", { id: "myLabel" }) // => <Label: roSGNode>
function createNode(nodeType = "Node" as String, fields = {} as Dynamic) as Object
node = createObject("roSGNode", nodeType)
if isNode(node, nodeType) then
if (type(fields) = "roAssociativeArray" AND fields.keys().count() > 0) OR (type(fields) = "roArray" AND NOT fields.isEmpty()) then
node.update(fields, true)
end if
return node
end if
return Invalid
end function
' Invokes func after wait milliseconds. Any additional arguments are provided to func when it's invoked.
' @since 0.0.22
' @category Function
' @param {Sub} callback - The function sub to be called after a set delay
' @param {Float} [wait] - The number of milliseconds to delay
' @param {Object} options - The options object
' @param {Dynamic} options[context] - The context to be used when calling the callback
' @param {Float} options[maxWait] - The maximum time the sub is allowed to be delayed before it's invoked.
sub debounce(callback as Function, wait = 0 as dynamic, options = {
maxWait: -1
} as object)
id = "__debounce_" + callback.toStr()
duration = bslib_ternary(wait = 0, 0.001, wait / 1000)
if m[id] = invalid then
timer = createObject("RoSGNode", "Timer")
timer.update({
duration: duration
id: id
}, true)
m[id] = {
callback: callback
timer: timer
timespan: CreateObject("roTimeSpan")
context: get(options, "context", {})
}
m[id].timespan.mark()
timer.observeFieldScoped("fire", (sub(event as object)
id = event.getRoSgNode().id
container = m[id]
callback = container.callback
callback(container.context)
container.timer.unobserveFieldScoped("fire")
m.delete(id)
end sub).toStr().mid(10))
end if
if m[id] <> invalid then
maxWait = get(options, "maxWait", -1)
if maxWait > 0 and m[id].timespan.TotalMilliseconds() >= maxWait then
m[id].timespan.mark()
container = m[id]
callback = container.callback
callback(container.context)
container.timer.unobserveFieldScoped("fire")
m.delete(id)
else
timer = m[id].timer
timer.duration = duration
timer.control = "start"
end if
end if
end sub
' Deburrs string by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing combining diacritical marks.
' @since 0.0.30
' @category String
' @param {String} input - The string to deburr
' @returns {String} Returns the deburred string
' @example
' deburr("déjà vu") ' => "deja vu"
function deburr(input = "" as String)
' Create an associative array (dictionary) to map accented characters to basic Latin letters
latinMap = {}
latinMap.SetModeCaseSensitive()
latinMap.append({
"À": "A"
"Á": "A"
"Â": "A"
"Ã": "A"
"Ä": "A"
"Å": "A"
"Æ": "Ae"
"Ç": "C"
"È": "E"
"É": "E"
"Ê": "E"
"Ë": "E"
"Ì": "I"
"Í": "I"
"Î": "I"
"Ï": "I"
"Ð": "D"
"Ñ": "N"
"Ò": "O"
"Ó": "O"
"Ô": "O"
"Õ": "O"
"Ö": "O"
"Ø": "O"
"Ù": "U"
"Ú": "U"
"Û": "U"
"Ü": "U"
"Ý": "Y"
"Þ": "TH"
"ß": "ss"
"à": "a"
"á": "a"
"â": "a"
"ã": "a"
"ä": "a"
"å": "a"
"æ": "ae"
"ç": "c"
"è": "e"
"é": "e"
"ê": "e"
"ë": "e"
"ì": "i"
"í": "i"
"î": "i"
"ï": "i"
"ð": "d"
"ñ": "n"
"ò": "o"
"ó": "o"
"ô": "o"
"õ": "o"
"ö": "o"
"ø": "o"
"ù": "u"
"ú": "u"
"û": "u"
"ü": "u"
"ý": "y"
"þ": "th"
"ÿ": "y"
"Ā": "A"
"ā": "a"
"Ă": "A"
"ă": "a"
"Ą": "A"
"ą": "a"
"Ć": "C"
"ć": "c"
"Ĉ": "C"
"ĉ": "c"
"Ċ": "C"
"ċ": "c"
"Č": "C"
"č": "c"
"Ď": "D"
"ď": "d"
"Đ": "D"
"đ": "d"
"Ē": "E"
"ē": "e"
"Ĕ": "E"
"ĕ": "e"
"Ė": "E"
"ė": "e"
"Ę": "E"
"ę": "e"
"Ě": "E"
"ě": "e"
"Ĝ": "G"
"ĝ": "g"
"Ğ": "G"
"ğ": "g"
"Ġ": "G"
"ġ": "g"
"Ģ": "G"
"ģ": "g"
"Ĥ": "H"
"ĥ": "h"
"Ħ": "H"
"ħ": "h"
"Ĩ": "I"
"ĩ": "i"
"Ī": "I"
"ī": "i"
"Ĭ": "I"
"ĭ": "i"
"Į": "I"
"į": "i"
"İ": "I"
"ı": "i"
"IJ": "IJ"
"ij": "ij"
"Ĵ": "J"
"ĵ": "j"
"Ķ": "K"
"ķ": "k"
"ĸ": "k"
"Ĺ": "L"
"ĺ": "l"
"Ļ": "L"
"ļ": "l"
"Ľ": "L"
"ľ": "l"
"Ŀ": "L"
"ŀ": "l"
"Ł": "L"
"ł": "l"
"Ń": "N"
"ń": "n"
"Ņ": "N"
"ņ": "n"
"Ň": "N"
"ň": "n"
"ʼn": "n"
"Ō": "O"
"ō": "o"
"Ŏ": "O"
"ŏ": "o"
"Ő": "O"
"ő": "o"
"Œ": "OE"
"œ": "oe"
"Ŕ": "R"
"ŕ": "r"
"Ŗ": "R"
"ŗ": "r"
"Ř": "R"
"ř": "r"
"Ś": "S"
"ś": "s"
"Ŝ": "S"
"ŝ": "s"
"Ş": "S"
"ş": "s"
"Š": "S"
"š": "s"
"Ţ": "T"
"ţ": "t"
"Ť": "T"
"ť": "t"
"Ŧ": "T"
"ŧ": "t"
"Ũ": "U"
"ũ": "u"
"Ū": "U"
"ū": "u"
"Ŭ": "U"
"ŭ": "u"
"Ů": "U"
"ů": "u"
"Ű": "U"
"ű": "u"
"Ų": "U"
"ų": "u"
"Ŵ": "W"
"ŵ": "w"
"Ŷ": "Y"
"ŷ": "y"
"Ÿ": "Y"
"Ź": "Z"
"ź": "z"
"Ż": "Z"
"ż": "z"
"Ž": "Z"
"ž": "z"
})
normalizedString = ""
' Iterate over each character, checking if it needs replacement
for i = 0 to len(input) - 1
char = mid(input, i + 1, 1) ' Use i+1 to correctly get the current character
if latinMap.doesExist(char)
normalizedString = normalizedString + latinMap[char]
else
normalizedString = normalizedString + char
end if
end for
return normalizedString
end function
' Invokes sub after wait milliseconds. Any additional arguments are provided to subwhen it's invoked.
' @since 0.0.22
' @category Function
' @param {Sub} callback - The sub to be called after a set delay
' @param {Float} [wait] - The number of milliseconds to delay invocation
' @param {Dynamic} context - a single item of data to be passed into the callback when invoked
sub delay(callback as Function, wait = 0 as float, context = invalid as dynamic)
duration = bslib_ternary(wait = 0, 0.0001, wait / 1000)
timer = createObject("RoSGNode", "Timer")
timer.update({
duration: duration
repeat: false
id: "__delay_" + createObject("roDeviceInfo").getRandomUUID()
})
m[timer.id] = {
timer: timer
callback: callback
context: context
}
timer.observeFieldScoped("fire", (sub(event as object)
delayId = event.getNode()
options = m[delayId]
callback = options.callback
try
callback(options.context)
catch e
print "Crash during utils.delay:"
print e
end try
m[delayId].timer.unobserveFieldScoped("fire")
m.delete(delayId)
end sub).toStr().mid(10))
timer.control = "start"
end sub
' Creates an array of array values not included in the other given arrays using SameValueZero for equality comparisons. The order and references of result values are determined by the first array.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to inspect
' @param {Array} values - The values to exclude
' @returns {Array} Returns the new array of filtered values
' @example
' rodash.difference([2, 1], [2, 3]) // => [1]
function difference(array = CreateObject("roArray", 0, true) as Object, values = CreateObject("roArray", 0, true) as Object) as Object
return differenceBy(array, values)
end function
' This method is like rodash.difference except that it accepts iteratee which is invoked for each element of array and values to generate the criterion by which they're compared. The order and references of result values are determined by the first array. The iteratee is invoked with one argument:(value).
' @since 0.0.21
' @category Array
' @param {Array} array - The array to inspect
' @param {Array} values - The values to exclude
' @param {Dynamic} iteratee - The iteratee invoked per element
' @returns {Array} Returns the new array of filtered values
' @example
' rodash.differenceBy([2.1, 1.2], [2.3, 3.4], rodash.floor) // => [1.2]
' rodash.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x') // => [{ 'x': 2 }]
function differenceBy(array = CreateObject("roArray", 0, true) as Object, values = CreateObject("roArray", 0, true) as Object, iteratee = Invalid) as Object
iterateeIsFunction = isFunction(iteratee)
iterateeIsProperty = NOT iterateeIsFunction AND (type(iteratee) = "String" OR type(iteratee) = "roString")
returnArray = CreateObject("roArray", 0, true)
for each item in array
convertedItem = item
if iterateeIsFunction then
convertedItem = iteratee(item)
else if iterateeIsProperty then
convertedItem = item[iteratee]
end if
found = false
for each valueToMatch in values
if iterateeIsFunction then
valueToMatch = iteratee(valueToMatch)
else if iterateeIsProperty
valueToMatch = valueToMatch[iteratee]
end if
if convertedItem = valueToMatch then
found = true
exit for
end if
end for
if NOT found then
returnArray.push(item)
end if
end for
return returnArray
end function
' This method is like rodash.difference except that it accepts comparator which is invoked to compare elements of array to values. The order and references of result values are determined by the first array. The comparator is invoked with two arguments: (arrVal, othVal).
' @since 0.0.21
' @category Array
' @param {Array} array - The array to inspect
' @param {Array} values - The values to exclude
' @param {Dynamic} iteratee - The iteratee invoked per element
' @returns {Array} Returns the new array of filtered values
' @example
' objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
' rodash.differenceWith(objects, [{ 'x': 1, 'y': 2 }], rodash.isEqual)
' // => [{ 'x': 2, 'y': 1 }]
function differenceWith(array = CreateObject("roArray", 0, true) as Object, values = CreateObject("roArray", 0, true) as Object, comparator = Invalid) as Object
returnArray = CreateObject("roArray", 0, true)
if isFunction(comparator) then
for i = 0 to array.count() - 1
itemOne = array[0]
itemTwo = array[1]
if (type(itemOne) <> "<uninitialized>" AND itemOne <> Invalid) AND (type(itemTwo) <> "<uninitialized>" AND itemTwo <> Invalid) AND NOT isEqual(itemOne, itemTwo) then
returnArray.push(itemOne)
end if
end for
end if
return returnArray
end function
' Divides two numbers
' @since 0.0.21
' @category Math
' @param {Dynamic} dividend - The first number in a division
' @param {Dynamic} divisor - The second number in a division
' @returns {Integer} Returns the quotient
' @example
' rodash.divide(6, 4) // => 1.5
function divide(dividend as Dynamic, divisor as Dynamic) as Dynamic
if (NOT isNumber(dividend)) OR (NOT isNumber(divisor))
return 0
end if
if (divisor <= 0) then
return dividend
end if
return dividend / divisor
end function
' Creates a slice of array with n elements dropped from the beginning.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to query
' @param {Integer} n - The number of elements to drop
' @returns {Array} Returns the slice of array
' @example
' rodash.drop([1, 2, 3], 1) // => [2, 3]
function drop(array = CreateObject("roAssociativeArray") as Object, n = 1 as Integer)
array = clone(array)
for i = 0 to n - 1
array.shift()
if array.count() = 0 then
exit for
end if
end for
return array
end function
' Creates a slice of array with n elements dropped from the end.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to query
' @param {Integer} n - The number of elements to drop
' @returns {Array} Returns the slice of array
' @example
' rodash.dropRight([1, 2, 3], 1) // => [1, 2]
function dropRight(array = CreateObject("roAssociativeArray") as Object, n = 1 as Integer)
array = clone(array)
array.reverse()
array = drop(array, n)
array.reverse()
return array
end function
' Creates a slice of array excluding elements dropped from the end. Elements are dropped until predicate returns falsey. The predicate is invoked with three arguments: (value, index, array).
' @since 0.0.21
' @category Array
' @param {Array} array - The array to query
' @param {Dynamic} predicate - The function invoked per iteration
' @returns {Array} Returns the slice of array
function dropRightWhile(array = CreateObject("roAssociativeArray") as Object, predicate = Invalid)
array = clone(array)
array.reverse()
array = dropWhile(array, predicate)
array.reverse()
return array
end function
' Creates a slice of array excluding elements dropped from the beginning. Elements are dropped until predicate returns falsey. The predicate is invoked with three arguments: (value, index, array).
' @since 0.0.21
' @category Array
' @param {Array} array - The array to query
' @param {Dynamic} predicate - The function invoked per iteration
' @returns {Array} Returns the slice of array
function dropWhile(array = CreateObject("roArray", 0, true) as Object, predicate = Invalid)
array = clone(array)
for i = 0 to array.count() - 1
item = array[i]
if isFunction(predicate) then
if NOT predicate(item) then
return slice(array, i)
end if
else if (type(predicate) = "roAssociativeArray") then
if NOT isEqual(item, predicate) then
return slice(array, i)
end if
else if (type(predicate) = "roArray") then
if NOT isEqual(item[predicate[0]], predicate[1]) then
return slice(array, i)
end if
else if (type(predicate) = "String" OR type(predicate) = "roString") then
if NOT item[predicate] then
return slice(array, i)
end if
end if
end for
return array
end function
' Checks if `string` ends with the given target string.
' @since 0.0.21
' @category String
' @param {String} source - The string to search.
' @param {String} target - The string to search for.
' @param {Number} position - The position to search up to.
' @returns {Boolean} Returns `true` if `string` ends with `target`, else `false`.
' @example
' rodash.endsWith("abc", "c") // => true
' rodash.endsWith("abc", "b") // => false
function endsWith(source = "" as String, target = "" as String, position = Invalid as Dynamic)
if (type(position) = "<uninitialized>" OR position = Invalid) then
position = source.len()
end if
return source.endsWith(target, position)
end function
' Checks if two values are equivalent.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value - The value to compare.
' @param {Dynamic} other - The other value to compare.
' @returns {Boolean} Returns `true` if the values are equivalent, else `false`.
' @example
' rodash.eq(1, 1) // => true
' rodash.eq(1, 2) // => false
function eq(value as Dynamic, other as Dynamic)
return isEqual(value, other)
end function
' Escapes a string for insertion into HTML, replacing &, <, >, ", `, and ' characters.
' @since 0.0.21
' @category String
' @param {String} source - The string to escape.
' @returns {String} The escaped string.
' @example
' rodash.escape("fred, barney, & pebbles") // => 'fred, barney, & pebbles'
function escape(source = "" as String)
return source.escape()
end function
' Escapes a string for insertion into a regular expression.
' @since 0.0.21
' @category String
' @param {String} source - The string to escape.
' @returns {String} The escaped string.
function escapeRegExp(source = "" as String)
replaceArray = [
"^"
"$"
""
"."
"*"
"+"
"?"
"("
")"
"["
"]"
"{"
"}"
"|"
]
for each char in replaceArray
source = source.replace(char, "\" + char)
end for
return source.replace("\/\/", "//")
end function
' Fills elements of array with value from start up to, but not including, end.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to fill
' @param {Dynamic} value - The value to fill array with
' @param {Integer} startPos - The start position
' @param {Integer} endPos - The end position
' @returns {Array} Returns the mutated array
' @example
' rodash.fill([1, 2, 3], "a", 1, 2) // => [1, "a", 3]
' rodash.fill([1, 2, 3], "a") // => ["a", "a", "a"]
' rodash.fill([1, 2, 3], "a", 1) // => [1, "a", "a"]
function fill(array = CreateObject("roArray", 0, true) as Object, value = "" as Dynamic, startPos = Invalid, endPos = Invalid)
if (type(startPos) = "<uninitialized>" OR startPos = Invalid) then
startPos = 0
end if
if (type(endPos) = "<uninitialized>" OR endPos = Invalid) then
endPos = array.count()
end if
endPos = endPos - 1
for i = startPos to endPos
array[i] = value
end for
return array
end function
' Iterates over elements of collection, returning an array of all elements predicate returns truthy for.
' @since 0.0.35
' @category Collection
' @param {Array} sourceArray - The array to inspect
' @param {Function} predicate - The function invoked per iteration
' @returns {Array} Returns the matched elements
' @example
' users = [
' { "user": "barney", "active": false, "age": 50 },
' { "user": "fred", "active": false, "age": 40 },
' { "user": "pebbles", "active": true, "age": 10 }
' ]
'
' rodash.filter(users, function(o)
' return o.active
' end function)
' // => [{ "user": "pebbles", "active": true, "age": 10 }]
'
' rodash.filter(users, { "age": 40 })
' // => [{ "user": "fred", "active": false, "age": 40 }]
function filter(sourceArray as Object, predicate as Dynamic) as Object
' Create a new array to hold filtered results
filteredArray = []
validPredicate = false
if (type(sourceArray) = "roArray" AND NOT sourceArray.isEmpty()) then
' Iterate through the source array
for each item in sourceArray
' Apply the predicate to each item
if isFunction(predicate) then
if predicate(item) then
' Add item to filteredArray if predicate returns true
filteredArray.push(item)
end if
validPredicate = true
else if (type(predicate) = "roAssociativeArray" AND predicate.keys().count() > 0) then
' Check if the item matches the predicate
matches = true
for each key in predicate
if item[key] <> predicate[key] then
matches = false
exit for
end if
end for
' Add item to filteredArray if it matches the predicate
if matches then
filteredArray.push(item)
end if
validPredicate = true
else if (type(predicate) = "roArray" AND NOT predicate.isEmpty()) then
if predicate.count() <= 2 then
' Add item to filteredArray if it matches the predicate
if item[predicate[0]] = predicate[1] then
filteredArray.push(item)
end if
validPredicate = true
end if
else if ((type(predicate) = "String" OR type(predicate) = "roString") AND NOT predicate.isEmpty()) then
' Add item to filteredArray if it matches the predicate
if (type(item[predicate]) = "Boolean" OR type(item[predicate]) = "roBoolean") then
if item[predicate] then
filteredArray.push(item)
end if
validPredicate = true
end if
end if
end for
end if
if NOT validPredicate then
' If the predicate is invalid, return the source array
return sourceArray
end if
' Return the new filtered array
return filteredArray
end function
' Iterates over elements of collection, returning the first element predicate returns truthy for. The predicate is invoked with three arguments: (value, index|key, collection).
' @since 0.0.22
' @category Collection
' @param {Array} array - The array to inspect
' @param {Dynamic} predicate - The function invoked per iteration
' @param {Integer} fromIndex - The index to search from
' @returns {Dymanic} Returns the matched element, else invalid.
' @example
' users = [
' { "user": "barney", "active": false },
' { "user": "fred", "active": false },
' { "user": "pebbles", "active": true }
' ]
'
' rodash.find(users, function(o)
' return o.user = "barney"
' end function)
' // => { "user": "barney", "active": false }
function find(array, predicate = Invalid as Dynamic, fromIndex = 0 as Integer) as Dynamic
if NOT (type(array) = "roArray") then
return Invalid
end if
foundIndex = findIndex(array, predicate, fromIndex)
if foundIndex = -1 then
return Invalid
end if
return array[foundIndex]
end function
' This method is like rodash.find except that it returns the index of the first element predicate returns truthy for instead of the element itself.
' By default, when comparing arrays and associative arrays the function will compare the values on the elements. If the strict parameter is set to true, the function will compare the references of the AA and Array elements.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to inspect
' @param {Dynamic} predicate - The function invoked per iteration
' @param {Integer} fromIndex - The index to search from
' @param {Boolean} strict - If true, the function will compare the references of the AA and Array elements
' @returns {Integer} Returns the index of the found element, else -1
function findIndex(array, predicate = Invalid as Dynamic, fromIndex = 0 as Integer, strict = false as Boolean) as Integer
for index = fromIndex to array.count() - 1
item = array[index]
if internal_canBeCompared(item, predicate) then
if isEqual(item, predicate) then
return index
end if
else if isFunction(predicate) then
if predicate(item) then
return index
end if
else if (type(predicate) = "roAssociativeArray") then
if isEqual(item, predicate, strict) then
return index
end if
else if (type(predicate) = "roArray") then
if isEqual(item[predicate[0]], predicate[1], strict) then
return index
end if
if (type(item) = "roArray") AND isEqual(item, predicate, strict) then
return index
end if
else if (type(item) = "roAssociativeArray") AND (type(predicate) = "String" OR type(predicate) = "roString") AND item.doesExist(predicate) then
if item[predicate] then
return index
end if
end if
end for
return -1
end function
' This method is like rodash.findIndex except that it iterates over elements of collection from right to left.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to inspect
' @param {Dynamic} predicate - The function invoked per iteration
' @param {Integer} fromIndex - The index to search from
' @returns {Integer} Returns the index of the found element, else -1
function findLastIndex(array, predicate = Invalid, fromIndex = 0 as Integer)
array = clone(array)
array.reverse()
foundIndex = findIndex(array, predicate, fromIndex)
if foundIndex = -1 then
return -1
end if
return array.count() - 1 - foundIndex
end function
' An alias to the head function.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to query
' @returns {Dynamic} Returns the first element of array
' @example
' rodash.first([1, 2, 3]) // => 1
' rodash.first([]) // => Invalid
function first(array = CreateObject("roArray", 0, true))
return (array[0])
end function
' Flattens array a single level deep.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to flatten
' @returns {Dynamic} Returns the new flattened array
' @example
' rodash.flatten([1, [2, [3, [4]], 5]]) // => [1, 2, [3, [4]], 5]
function flatten(array = CreateObject("roArray", 0, true) as Object) as Object
returnArray = CreateObject("roArray", 0, true)
for each item in array
if type(item) = "roArray" then
returnArray.append(item)
else
returnArray.push(item)
end if
end for
return returnArray
end function
' Recursively flattens array.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to flatten
' @returns {Dynamic} Returns the new flattened array
' @example
' rodash.flattenDeep([1, [2, [3, [4]], 5]]) ' => [1, 2, 3, 4, 5]
' rodash.flattenDeep([1, [2, [3, [4]], 5], 6]) ' => [1, 2, 3, 4, 5, 6]
function flattenDeep(array = CreateObject("roArray", 0, true))
returnArray = CreateObject("roArray", 0, true)
for each item in array
if type(item) = "roArray" then
returnArray.append(flattenDeep(item))
else
returnArray.push(item)
end if
end for
return returnArray
end function
' Recursively flatten array up to depth times.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to flatten
' @param {Integer} depth - The maximum recursion depth
' @returns {Dynamic} Returns the new flattened array
function flattenDepth(array = Invalid, depth = 1 as Integer)
returnArray = CreateObject("roArray", 0, true)
if NOT (type(array) = "roArray") then
return array
end if
for i = 0 to array.count() - 1
item = array[i]
if (depth > 1) then
item = flattenDepth(item, depth - 1)
if (type(item) = "roArray") then
returnArray.append(item)
else
returnArray.push(item)
end if
else
if (type(item) = "roArray") then
returnArray.append(item)
else
returnArray.push(item)
end if
end if
end for
return returnArray
end function
' Computes number rounded down to precision
' @since 0.0.21
' @category Math
' @param {Integer} number - The number to round down
' @param {Integer} precision - The precision to round down to
' @returns {Integer} Returns the rounded down number
' @example
' rodash.floor(4.006) // => 4
' rodash.floor(0.046, 2) // => 0.04
' rodash.floor(4060, -2) // => 4000
function floor(number = 0, precision = 0 as Dynamic) as Dynamic
return abs(int(number * 10 ^ precision)) / 10 ^ precision
end function
' Iterates over elements of collection and invokes iteratee for each element. The iteratee is invoked with three arguments: (value, index|key, collection). Iteratee functions may exit iteration early by explicitly returning false.
' Note: As with other "Collections" methods, objects with a "length" property are iterated like arrays. To avoid this behavior use rodash.forIn or rodash.forOwn for object iteration.
' @since 0.0.21
' @category Collection
' @param {Dynamic} collection - The collection to iterate over
' @param {Dynamic} iteratee - The function invoked per iteration
' @returns {Dynamic} Returns collection
' @example
' rodash.forEach([1, 2], function(value)
' print value
' end function)
' // => Logs `1` then `2`
function forEach(collection = Invalid as Dynamic, iteratee = Invalid as Dynamic)
return internal_baseForEach(collection, iteratee)
end function
' This method is like rodash.forEach except that it iterates over elements of collection from right to left.
' @since 0.0.21
' @category Collection
' @param {Dynamic} collection - The collection to iterate over
' @param {Dynamic} iteratee - The function invoked per iteration
' @returns {Dynamic} Returns collection
' @example
' rodash.forEachRight([1, 2], function(value)
' print value
' end function)
' // => Logs `2` then `1`
function forEachRight(collection = Invalid as Dynamic, iteratee = Invalid as Dynamic)
return internal_baseForEach(collection, iteratee, "right")
end function
' Iterates over own and inherited enumerable string keyed properties of an object and invokes iteratee for each property. The iteratee is invoked with three arguments: (value, key, object). Iteratee functions may exit iteration early by explicitly returning false.
' @since 0.0.21
' @category Object
' @param {Dynamic} obj - The object to iterate over
' @param {Dynamic} iteratee - The function invoked per iteration
' @returns {Object} Returns object
function forIn(obj = CreateObject("roAssociativeArray") as Object, iteratee = Invalid as Dynamic)
return internal_baseForEach(obj, iteratee, "left", "omit")
end function
' This method is like rodash.forIn except that it iterates over properties of object in the opposite order.
' @since 0.0.21
' @category Object
' @param {Dynamic} obj - The object to iterate over
' @param {Dynamic} iteratee - The function invoked per iteration
' @returns {Object} Returns object
' @example
' rodash.forInRight({ 'a': 1, 'b': 2 }, function(value, key)
' print key
' end function)
' // => Logs `b` then `a`
function forInRight(obj = CreateObject("roAssociativeArray") as Object, iteratee = Invalid as Dynamic)
return internal_baseForEach(obj, iteratee, "right", "omit")
end function
' Iterates over own enumerable string keyed properties of an object and invokes iteratee for each property. The iteratee is invoked with three arguments: (value, key, object). Iteratee functions may exit iteration early by explicitly returning false.
' @since 0.0.21
' @category Object
' @param {Dynamic} obj - The object to iterate over
' @param {Dynamic} iteratee - The function invoked per iteration
' @returns {Object} Returns object
function forOwn(obj = CreateObject("roAssociativeArray") as Object, iteratee = Invalid as Dynamic)
return internal_baseForEach(obj, iteratee, "left", "omit")
end function
' This method is like rodash.forOwn except that it iterates over properties of object in the opposite order.
' @since 0.0.21
' @category Object
' @param {Dynamic} obj - The object to iterate over
' @param {Dynamic} iteratee - The function invoked per iteration
' @returns {Object} Returns object
function forOwnRight(obj = CreateObject("roAssociativeArray") as Object, iteratee = Invalid as Dynamic)
return internal_baseForEach(obj, iteratee, "right", "omit")
end function
' Converts an ISO 8601 string to a date object.
' @since 0.0.21
' @category Date
' @param {String} dateString - The date string to convert.
' @param {Boolean} asLocal - Whether to get the local date. Default is false.
' @returns {Object} The date object.
function fromISO8601String(dateString = "" as String, asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).fromISO8601String(dateString)
end function
' The inverse of rodash.toPairs; this method returns an object composed from key-value pairs.
' @since 0.0.24
' @category Array
' @param {Array} pairs - And array of arrays to be converted to an object
' @returns {Object} Returns the new object
function fromPairs(pairs = CreateObject("roArray", 0, true) as Object) as Object
returnObject = CreateObject("roAssociativeArray")
if NOT (type(pairs) = "roArray") then
return returnObject
end if
for each pair in pairs
if (type(pair) = "roArray") AND pair.count() = 2 then
returnObject[pair[0]] = pair[1]
end if
end for
return returnObject
end function
' Converts a number of seconds to a date object.
' @since 0.0.21
' @category Date
' @param {Number} numSeconds - The number of seconds to convert.
' @param {Boolean} asLocal - Whether to get the local date. Default is false.
' @returns {Object} The date object.
function fromSeconds(numSeconds = 0 as Integer, asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).fromSeconds(numSeconds)
end function
' TODO: Rewrite this due to scoping issue
' @ignore
' Creates an array of function property names from own enumerable properties of object.
' @category Object
' @param {Dynamic} obj - The object to iterate over
' @returns {Object} Returns object
function functions(obj = CreateObject("roAssociativeArray") as Object)
' return rodash.base.forEach.baseForEach(obj, invalid, "left", "only")
return []
end function
' TODO: Rewrite this due to scoping issue
' @ignore
' Creates an array of function property names from own and inherited enumerable properties of object.
' @param {Dynamic} obj - The object to iterate over
' @returns {Object} Returns object
function functionsIn(obj = CreateObject("roAssociativeArray") as Object)
' return rodash.base.forEach.baseForEach(obj, invalid, "left", "only")
return []
end function
' Gets the value at path of object. If the resolved value is undefined, the defaultValue is returned in its place.
' @since 0.0.21
' @category Object
' @param {Object} aa - Object to drill down into.
' @param {String} keyPath - A dot notation based string to the expected value.
' @param {Dynamic} fallback - A return fallback value if the requested field could not be found or did not pass the validator function.
' @param {Function} validator - A function used to validate the output value matches what you expected.
' @returns {Dynamic} The result of the drill down process
' @example
' rodash.get({a: {b: {c: 3}}}, 'a.b.c') ' => 3
' rodash.get({a: {b: {c: 3}}}, 'a.b.d') ' => invalid
' rodash.get({a: {b: {c: 3}}}, 'a.b.d', 'default') ' => 'default'
' rodash.get({a: {b: {c: 3}}}, 'a.b.c', -1, rodash.isNumber) ' => 3
' rodash.get({a: {b: {c: 3}}}, 'a.b.d', -1, rodash.isNumber) ' => -1
function get(aa as Object, keyPath as String, fallback = Invalid as Dynamic, validator = isNotInvalid as Function) as Dynamic
nextValue = aa
lookupSucceeded = true
for each key in keyPath.tokenize(".")
if (getInterface(nextValue, "ifAssociativeArray") <> Invalid) then
nextValue = nextValue[key]
else if (type(nextValue) = "roArray" AND NOT nextValue.isEmpty()) then
index = 0
if (type(key) = "String" OR type(key) = "roString") then
if key.instr(".") > -1 then
index = val(key)
else
index = val(key, 10)
end if
else if (type(key) = "Integer" OR type(key) = "roInt" OR type(key) = "roInteger" OR type(key) = "LongInteger" OR type(key) = "Float" OR type(key) = "roFloat" OR type(key) = "Double" OR type(key) = "roDouble" OR type(key) = "roIntrinsicDouble") then
index = key
else if (type(key) = "Boolean" OR type(key) = "roBoolean") then
if key then
index = 1
end if
index = 0
end if
nextValue = nextValue[index]
else
lookupSucceeded = false
exit for
end if
end for
if lookupSucceeded AND validator(nextValue) then
return nextValue
end if
return fallback
end function
' Gets the AA value at path of object. Calls rodash.get with the isAA validator function.
' @since 0.0.25
' @category Object
' @param {Object} aa - Object to drill down into.
' @param {String} keyPath - A dot notation based string to the expected value.
' @param {Assocarray} fallback - A return fallback value if the requested field could not be found or did not pass the validator function.
' @returns {Assocarray} The result of the drill down process
' @example
' rodash.getAA({a: {b: {c: 3}}}, 'a.b') ' => {c: 3}
' rodash.getAA({a: {b: {c: 3}}}, 'a.b.d') ' => {}
' rodash.getAA({a: {b: {c: 3}}}, 'a.b.c') ' => {}
' rodash.getAA({a: {b: {c: 3}}}, 'a.b.d', {d: 4}) ' => {d: 4}
function getAA(aa as Object, keyPath as String, fallback = CreateObject("roAssociativeArray") as Object) as Object
return get(aa, keyPath, fallback, isAA)
end function
' Gets the Array value at path of object. Calls rodash.get with the isArray validator function.
' @since 0.0.25
' @category Object
' @param {Object} aa - Object to drill down into.
' @param {String} keyPath - A dot notation based string to the expected value.
' @param {Array} fallback - A return fallback value if the requested field could not be found or did not pass the validator function.
' @returns {Array} The result of the drill down process
' @example
' rodash.getArray({a: {b: {c: [1, 2, 3]}}}, 'a.b.c') ' => [1, 2, 3]
' rodash.getArray({a: {b: {c: 3}}}, 'a.b.d') ' => []
' rodash.getArray({a: {b: {c: 3}}}, 'a.b.c') ' => []
' rodash.getArray({a: {b: {c: 3}}}, 'a.b.d', [1, 2, 3]) ' => [1, 2, 3]
function getArray(aa as Object, keyPath as String, fallback = CreateObject("roArray", 0, true) as Object) as Object
return get(aa, keyPath, fallback, isArray)
end function
' Gets the boolean value at path of object. Calls rodash.get with the isBoolean validator function.
' @since 0.0.25
' @category Object
' @param {Object} aa - Object to drill down into.
' @param {String} keyPath - A dot notation based string to the expected value.
' @param {Boolean} fallback - A return fallback value if the requested field could not be found or did not pass the validator function.
' @returns {Boolean} The result of the drill down process
' @example
' rodash.getBoolean({a: {b: {c: true}}}, 'a.b.c') ' => true
' rodash.getBoolean({a: {b: {c: 3}}}, 'a.b.d') ' => false
' rodash.getBoolean({a: {b: {c: 3}}}, 'a.b.c') ' => false
' rodash.getBoolean({a: {b: {c: 3}}}, 'a.b.d', true) ' => true
function getBoolean(aa as Object, keyPath as String, fallback = false as Boolean) as Boolean
return get(aa, keyPath, fallback, isBoolean)
end function
' Gets the day of the month.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local day of the month. Default is false.
' @returns {Integer} The day of the month.
function getDayOfMonth(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getDayOfMonth()
end function
' Gets the day of the week.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local day of the week. Default is false.
' @returns {Integer} The day of the week.
function getDayOfWeek(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getDayOfWeek()
end function
' Gets the function name from a function object.
' @since 0.0.26
' @category Lang
' @param {Object} call - function
' @returns {String} The function string name
function getFunctionName(call as Object) as String
if isFunction(call) then
return call.toStr().tokenize(" ").peek()
end if
return ""
end function
' Gets the hours.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local hours. Default is false.
' @Returns {Integer} The hours.
function getHours(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getHours()
end function
' Gets the last day of the month.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local last day of the month. Default is false.
' @returns {Integer} The last day of the month.
function getLastDayOfMonth(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getLastDayOfMonth()
end function
' Gets the milliseconds.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local milliseconds. Default is false.
' @returns {Integer} The milliseconds.
function getMilliseconds(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getMilliseconds()
end function
' Gets the minutes.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local minutes. Default is false.
' @returns {Integer} The minutes.
function getMinutes(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getMinutes()
end function
' Gets the month.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local month. Default is false.
' @returns {Integer} The month.
function getMonth(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getMonth()
end function
' Gets the children of a node.
' @since 0.0.32
' @category Node
' @param {Object} node - The node to get the children of
' @returns {Object} Returns the children of the node
function getNodeChildren(node as Object) as Object
if isNode(node) then
return node.getChildren(-1, 0)
end if
return []
end function
' Gets the last child of a node.
' @since 0.0.32
' @category Node
' @param {Object} node - The node to get the last child of
' @returns {Object} Returns the last child of the node
function getNodeLastChild(node as Object) as Object
children = getNodeChildren(node)
if children.count() > 0 then
return children[children.count() - 1]
end if
return Invalid
end function
' Gets the number value at path of object. Calls rodash.get with the isNumber validator function.
' @since 0.0.25
' @category Object
' @param {Object} aa - Object to drill down into.
' @param {String} keyPath - A dot notation based string to the expected value.
' @param {Number} fallback - A return fallback value if the requested field could not be found or did not pass the validator function.
' @returns {Number} The result of the drill down process
' @example
' rodash.getNumber({a: {b: {c: 3}}}, 'a.b.c') ' => 3
' rodash.getNumber({a: {b: {c: 3}}}, 'a.b.d') ' => 0
' rodash.getNumber({a: {b: {c: 3}}}, 'a.b.c') ' => 3
' rodash.getNumber({a: {b: {c: 3}}}, 'a.b.d', 25) ' => 25
function getNumber(aa as Object, keyPath as String, fallback = 0 as Dynamic) as Dynamic
return get(aa, keyPath, fallback, isNumber)
end function
' Gets the seconds.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local seconds. Default is false.
' @returns {Integer} The seconds.
function getSeconds(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getSeconds()
end function
' Gets the String value at path of object. Calls rodash.get with the isString validator function.
' @since 0.0.25
' @category Object
' @param {Object} aa - Object to drill down into.
' @param {String} keyPath - A dot notation based string to the expected value.
' @param {String} fallback - A return fallback value if the requested field could not be found or did not pass the validator function.
' @returns {String} The result of the drill down process
' @example
' rodash.getString({a: {b: {c: 'hello'}}}, 'a.b.c') ' => 'hello'
' rodash.getString({a: {b: {c: 3}}}, 'a.b.d') ' => ''
' rodash.getString({a: {b: {c: 3}}}, 'a.b.c') ' => ''
' rodash.getString({a: {b: {c: 3}}}, 'a.b.d', 'fallback') ' => 'fallback'
function getString(aa as Object, keyPath as String, fallback = "" as String) as String
return get(aa, keyPath, fallback, isString)
end function
' Gets the year.
' @since 0.0.21
' @category Date
' @param {Boolean} asLocal - Whether to get the local year. Default is false.
' @returns {Integer} The year.
function getYear(asLocal = false as Boolean) as Integer
return internal_getDateObject(asLocal).getYear()
end function
' Creates an object composed of keys generated from the results of running each element of collection thru iteratee. The order of grouped values is determined by the order they occur in collection. The corresponding value of each key is an array of elements responsible for generating the key. The iteratee is invoked with one argument: (value).
' @since 0.0.23
' @category Collection
' @param {Object} collection - The collection to iterate over.
' @param {Function|String} iteratee - The iteratee to transform keys.
' @returns {Object} Returns the composed aggregate object.
function groupBy(collection as Object, iteratee = Invalid as Dynamic) as Object
if NOT (type(collection) = "roArray") then
return CreateObject("roAssociativeArray")
end if
collection = clone(collection)
acc = CreateObject("roAssociativeArray")
if isFunction(iteratee) then
for each value in collection
key = toString(iteratee(value))
if acc.doesExist(key)
acc[key].push(value)
else
acc[key] = [
value
]
end if
end for
else if (type(iteratee) = "String" OR type(iteratee) = "roString") then
for each value in collection
if (type(value) = "roAssociativeArray") AND value.doesExist(iteratee) then
key = toString(value[iteratee])
if acc.doesExist(key)
acc[key].push(value)
else
acc[key] = [
value
]
end if
end if
end for
end if
return acc
end function
' Checks if value is greater than other.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value - The value to compare.
' @param {Dynamic} other - The other value to compare.
' @returns {Boolean} - Returns `true` if value is greater than other, else `false`.
' @example
' rodash.gt(3, 1) ' => true
' rodash.gt(3, 3) ' => false
' rodash.gt(1, 3) ' => false
function gt(value as Dynamic, other as Dynamic)
return value > other
end function
' Checks if value is greater than or equal to other.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value - The value to compare.
' @param {Dynamic} other - The other value to compare.
' @returns {Boolean} - Returns `true` if value is greater than or equal to other, else `false`.
' @example
' rodash.gte(3, 1) ' => true
' rodash.gte(3, 3) ' => true
' rodash.gte(1, 3) ' => false
function gte(value as Dynamic, other as Dynamic)
return value >= other
end function
' Checks if first level of the supplied AssociativeArray contains the Array of key strings.
' @since 0.0.21
' @category Object
' @param {Dynamic} aaValue - AssociativeArray to be checked
' @param {Array} keys - Array of key strings
' @returns {Boolean} - Returns `true` if first level of the supplied AssociativeArray contains the Array of key strings, else `false`.
' @example
' rodash.hasKeys({a: 1, b: 2, c: 3}, ["a", "b"]) ' => true
' rodash.hasKeys({a: 1, b: 2, c: 3}, ["a", "d"]) ' => false
' rodash.hasKeys({a: 1, b: 2, c: 3}, ["a", "b", "c"]) ' => true
' rodash.hasKeys([1,2,3], ["a", "b", "d"]) ' => false
function hasKeys(aaValue as Dynamic, keys as Dynamic) as Boolean
if NOT (getInterface(aaValue, "ifAssociativeArray") <> Invalid) OR aaValue.isEmpty() OR NOT (type(keys) = "roArray") OR keys.isEmpty() then
return false
end if
for each key in keys
if NOT aaValue.doesExist(key) then
return false
end if
end for
return true
end function
' Gets the first element of array.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to query
' @returns {Dynamic} Returns the first element of array
' @example
' rodash.head([1, 2, 3]) // => 1
function head(array = CreateObject("roArray", 0, true) as Object) as Dynamic
return array[0]
end function
' Checks if number is between start and up to, but not including, end. If end is not specified, it's set to start with start then set to 0.
' @since 0.0.21
' @category Number
' @param {Number} number - The number to check.
' @param {Number} [startPos=0] - The start of the range.
' @param {Number} [endPos=startPos] - The end of the range.
' @returns {Boolean} - Returns `true` if number is in the range, else `false`.
function inRange(number as dynamic, startPos = 0 as dynamic, endPos = invalid as dynamic)
if ((type(endPos) = "<uninitialized>" OR endPos = Invalid)) then
endPos = startPos
startPos = 0
end if
if (startPos > endPos) then
startPosTemp = startPos
endPosTemp = endPos
startPos = endPosTemp
endPos = startPosTemp
end if
return (number >= startPos) AND (number < endPos)
end function
' Gets the index at which the first occurrence of value is found in array using SameValueZero for equality comparisons. If fromIndex is negative, it's used as the offset from the end of array.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to inspect
' @param {Dynamic} value - The value to search for
' @param {Integer} fromIndex - The index to search from
' @returns {Integer} Returns the index of the matched value, else -1
function indexOf(array = CreateObject("roArray", 0, true) as Object, value = Invalid, fromIndex = Invalid)
if NOT (type(array) = "roArray") then
return -1
end if
if (type(fromIndex) = "<uninitialized>" OR fromIndex = Invalid) then
fromIndex = 0
end if
for index = fromIndex to array.count() - 1
item = array[index]
if isEqual(item, value) then
return index
end if
end for
return -1
end function
' Gets all but the last element of array.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to query
' @returns {Array} Returns the slice of array
function initial(array = CreateObject("roArray", 0, true) as Object)
if NOT (type(array) = "roArray") then
return []
end if
return slice(array, 0, array.count() - 1)
end function
' @ignore
' Attempts to convert the supplied value to a string.
' @since 0.0.21
' @category Internal
' @param {Dynamic} value - The value to convert.
' @returns {String} Results of the conversion.
function internal_aaToString(aa as Object) as String
description = "{"
for each key in aa
description += key + ": " + toString(aa[key]) + ", "
end for
description = description.left(description.len() - 2) + "}"
return description
end function
' @ignore
' Attempts to convert the supplied value to a string.
' @since 0.0.21
' @category Internal
' @param {Dynamic} value The value to convert.
' @returns {String} Results of the conversion.
function internal_arrayToString(array as Object) as String
description = "["
for each item in array
description += toString(item) + ", "
end for
description = description.left(description.len() - 2) + "]"
return description
end function
' @ignore
' The base implementation of `forEach`.
' @since 0.0.21
' @category Internal
' @param {Array|Object} - collection The collection to iterate over
' @param {Function} iteratee The function invoked per iteration
' @param {String} direction - the direction to traverse the collection
' @param {String} funcValueRule - Filters functions from collection. `allow`, `omit`, `only`.
' @returns {Array|Object} Returns `collection`
function internal_baseForEach(collection = Invalid as Dynamic, iteratee = Invalid as Dynamic, direction = "left", funcValueRule = "allow" as String)
if (type(collection) = "<uninitialized>" OR collection = Invalid) OR collection.isEmpty() then
return Invalid
end if
isRight = direction = "right"
if (type(collection) = "roAssociativeArray") then
keys = collection.keys()
if isRight then
keys.reverse()
end if
for each key in keys
item = collection[key]
if isFunction(iteratee) then
valueIsFunction = isFunction(item)
allowValue = false
if valueIsFunction AND NOT isEqual(funcValueRule, "omit")
allowValue = true
else if NOT valueIsFunction AND NOT isEqual(funcValueRule, "only")
allowValue = true
end if
if allowValue then
iteratee(item, key)
end if
end if
end for
else
if isRight then
collection.reverse()
end if
for each item in collection
if isFunction(iteratee) then
iteratee(item)
end if
end for
if isRight then
collection.reverse()
end if
end if
return collection
end function
' @ignore
' Attempts to convert the supplied value to a string.
' @since 0.0.21
' @category Internal
' @param {Dynamic} value The value to convert.
' @returns {String} Results of the conversion.
function internal_booleanToString(bool as Boolean) as String
if bool then
return "true"
end if
return "false"
end function
' @ignore
' Checks if the supplied values can be compared in a if statement.
' @since 0.0.21
' @category Internal
' @param {Dynamic} valueOne - First value
' @param {Dynamic} valueTwo - Second value
' @returns {Boolean} True if the values can be compared in a if statement
function internal_canBeCompared(valueOne as Dynamic, valueTwo as Dynamic) as Boolean
valueOneType = type(valueOne)
valueTwoType = type(valueTwo)
if (valueOneType = "String" OR valueOneType = "roString") then
if (valueTwoType = "String" OR valueTwoType = "roString") then
return true
end if
else if (valueOneType = "Integer" OR valueOneType = "roInt" OR valueOneType = "roInteger" OR valueOneType = "LongInteger" OR valueOneType = "Float" OR valueOneType = "roFloat" OR valueOneType = "Double" OR valueOneType = "roDouble" OR valueOneType = "roIntrinsicDouble") then
if (valueTwoType = "Integer" OR valueTwoType = "roInt" OR valueTwoType = "roInteger" OR valueTwoType = "LongInteger" OR valueTwoType = "Float" OR valueTwoType = "roFloat" OR valueTwoType = "Double" OR valueTwoType = "roDouble" OR valueTwoType = "roIntrinsicDouble") then
return true
end if
else if (valueOneType = "Boolean" OR valueOneType = "roBoolean") then
if (valueTwoType = "Boolean" OR valueTwoType = "roBoolean") then
return true
end if
else if (valueOneType = "<uninitialized>" OR valueOne = Invalid) then
if (valueTwoType = "<uninitialized>" OR valueTwo = Invalid) then
return true
end if
end if
return false
end function
' @ignore
function internal_getConstants()
return {
BrightScriptErrorCodes: {
' runtime errors
ERR_OKAY: &hFF
ERR_NORMAL_END: &hFC ' normal, but terminate execution. END, shell "exit", window closed, etc.
ERR_VALUE_RETURN: &hE2 ' return executed, and a value returned on the stack
ERR_INTERNAL: &hFE ' A condition that shouldn't occur did
ERR_UNDEFINED_OPCD: &hFD ' A opcode that we don't handle
ERR_UNDEFINED_OP: &hFB ' An expression operator that we don't handle
ERR_MISSING_PARN: &hFA
ERR_STACK_UNDER: &hF9 ' nothing on stack to pop
ERR_BREAK: &hF8 ' scriptBreak() called
ERR_STOP: &hF7 ' stop statement executed
ERR_RO0: &hF6 ' bscNewComponent failed because object class not found
ERR_RO1: &hF5 ' ro function call does not have the right number of parameters
ERR_RO2: &hF4 ' member function not found in object or interface
ERR_RO3: &hF3 ' Interface not a member of object
ERR_TOO_MANY_PARAM: &hF2 ' Too many function parameters to handle
ERR_WRONG_NUM_PARAM: &hF1 ' Incorect number of function parameters
ERR_RVIG: &hF0 ' Function returns a value, but is ignored
ERR_NOTPRINTABLE: &hEF ' Non Printable value
ERR_NOTWAITABLE: &hEE ' Tried to Wait on a function that does not have MessagePort interface
ERR_MUST_BE_STATIC: &hED ' interface calls from type rotINTERFACE must by static
ERR_RO4: &hEC ' . operator used on a variable that does not contain a legal object or interface reference
ERR_NOTYPEOP: &hEB ' operation on two typless operands attempted
ERR_USE_OF_UNINIT_VAR: &hE9 ' illegal use of uninited var
ERR_TM2: &hE8 ' non-numeric index to array
ERR_ARRAYNOTDIMMED: &hE7
ERR_USE_OF_UNINIT_BRSUBREF: &hE6 ' used a reference to SUB that is not initilized
ERR_MUST_HAVE_RETURN: &hE5
ERR_INVALID_LVALUE: &hE4 ' invalid left side of expression
ERR_INVALID_NUM_ARRAY_IDX: &hE3 ' invalid number of array indexes
ERR_UNICODE_NOT_SUPPORTED: &hE1
ERR_NOTFUNOPABLE: &hE0
ERR_STACK_OVERFLOW: &hDF
ERR_THROWN_EXCEPTION_ON_STACK: &hDE '(Internal use only)
ERR_SYNTAX: &h02
ERR_DIV_ZERO: &h14
ERR_MISSING_LN: &h0E
ERR_OUTOFMEM: &h0C
ERR_STRINGTOLONG: &h1C
ERR_TM: &h18 ' Type Mismatch (string / numeric operation mismatch)
ERR_OS: &h1A ' out of string space
ERR_RG: &h04 ' Return without Gosub
ERR_NF: &h00 ' Next without For
ERR_FC: &h08 ' Invalid parameter passed to function/array (e.g neg matrix dim or squr root)
ERR_DD: &h12 ' Attempted to redimension an array
ERR_BS: &h10 ' Array subscript out of bounds
ERR_OD: &h06 ' Out of Data (READ)
ERR_CN: &h20 ' Continue Not Allowed
ERR_BITSHIFT_BAD: &h1E ' Invalid Bitwise Shift
ERR_EXECUTION_TIMEOUT: &h23 ' Timeout on critical thread
ERR_CONSTANT_OVERFLOW: &h22 ' Constant Out Of Range
ERR_FORMAT_SPECIFIER: &h24 ' Invalid Format Specifier
ERR_BAD_THROW: &h26 ' Invalid argument to Throw
ERR_USER: &h28 ' User-specified exception
' compiler errors
ERR_NW: &hBF ' EndWhile with no While
ERR_MISSING_ENDWHILE: &hBE ' While Statement is missing a matching EndWhile
ERR_MISSING_ENDIF: &hBC ' end of code reached without finding ENDIF
ERR_NOLN: &hBB ' no line number found
ERR_LNSEQ: &hBA ' Line number sequence error
ERR_LOADFILE: &hB9 ' Error loading a file
ERR_NOMATCH: &hB8 ' "Match" statement did not match
ERR_UNEXPECTED_EOF: &hB7 ' End of string being compiled encountered when not expected (missing end of block usually)
ERR_FOR_NEXT_MISMATCH: &hB6 ' Variable on a NEXT does not match that for the FOR
ERR_NO_BLOCK_END: &hB5
ERR_LABELTWICE: &hB4 ' Label defined more than once
ERR_UNTERMED_STRING: &hB3 ' litteral string does not have ending quote
ERR_FUN_NOT_EXPECTED: &hB2
ERR_TOO_MANY_CONST: &hB1
ERR_TOO_MANY_VAR: &hB0
ERR_EXIT_WHILE_NOT_IN_WHILE: &hAF
ERR_INTERNAL_LIMIT_EXCEDED: &hAE
ERR_SUB_DEFINED_TWICE: &hAD
ERR_NOMAIN: &hAC
ERR_FOREACH_INDEX_TM: &hAB
ERR_RET_CANNOT_HAVE_VALUE: &hAA
ERR_RET_MUST_HAVE_VALUE: &hA9
ERR_FUN_MUST_HAVE_RET_TYPE: &hA8
ERR_INVALID_TYPE: &hA7
ERR_NOLONGER: &hA6 ' no longer supported
ERR_EXIT_FOR_NOT_IN_FOR: &hA5
ERR_MISSING_INITILIZER: &hA4
ERR_IF_TOO_LARGE: &hA3
ERR_RO_NOT_FOUND: &hA2
ERR_TOO_MANY_LABELS: &hA1
ERR_VAR_CANNOT_BE_SUBNAME: &hA0
ERR_INVALID_CONST_NAME: &h9F
ERR_CONST_FOLDING: &h9E
ERR_BUILTIN_FUNCTION: &h9D
ERR_FUNCTION_NOT_IN_NAMESPACE: &h91
ERR_EVAL_UNSUPPORTED: &h90
ERR_LABEL_INSIDE_TRY: &h8F
}
MAX_INT: 2147483647
MIN_INT: -2147483648
}
end function
' @ignore
function internal_getDateObject(asLocal = false as Boolean) as Object
dateObj = CreateObject("roDateTime")
if asLocal then
dateObj.toLocalTime()
end if
return dateObj
end function
' @ignore
' Checks if the supplied value allows for key field access
' @since 0.0.21
' @category Internal
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function internal_isKeyedValueType(value as Dynamic) as Boolean
return getInterface(value, "ifAssociativeArray") <> Invalid
end function
' @ignore
' Attempts to converts a nodes top level fields to an AssociativeArray.
' @since 0.0.21
' @category Internal
' @param {Dynamic} value - The variable to be converted.
' @param {Boolean} removeId - If set to true the nodes ID will also be stripped.
' @param {Object} removeFields - List of keys that need to be removed from the node.
' @returns {Dynamic} Results of the conversion.
function internal_nodeToAA(value as Object, removeId = false as Boolean, removeFields = Invalid as Dynamic) as Object
if isNode(value) then
fields = value.getFields()
fields.delete("change")
fields.delete("focusable")
fields.delete("focusedChild")
fields.delete("ready")
if removeId then
fields.delete("id")
end if
'Looping through any additional fields if passed.
if (type(removeFields) = "roArray" AND NOT removeFields.isEmpty()) then
for each field in removeFields
fields.delete(field)
end for
end if
return fields
else if (type(value) = "roAssociativeArray") then
return value
end if
return {}
end function
' @ignore
' Attempts to convert the supplied value to a string.
' @since 0.0.21
' @category Internal
' @param {Dynamic} value The value to convert.
' @returns {String} Results of the conversion.
function internal_nodeToString(node as Object) as String
if NOT isNode(node) then
return ""
end if
description = node.subtype()
if node.isSubtype("Group") then
' accessing properties from anywhere but the render thread is too expensive to include here
id = node.id
if id <> "" then
description += " (" + id + ")" + internal_aaToString(internal_nodeToAA(node))
end if
end if
return description
end function
' @ignore
' Attempts to convert the supplied value to a string.
' @param {Dynamic} value The value to convert.
' @returns {String} Results of the conversion.
function internal_numberToString(value as Dynamic) as String
return value.toStr()
end function
' @ignore
function internal_orderByCompare(item1 as Object, item2 as Object, keys as Object, orders as Object) as Boolean
' Iterate through the keys and corresponding orders
for i = 0 to keys.Count() - 1
key = keys[i]
order = orders[i]
if order = invalid then
order = "asc"
end if
value1 = item1[key]
value2 = item2[key]
' Compare the values based on the current key
if value1 <> value2
if order = "asc"
return value1 > value2
else if order = "desc"
return value1 < value2
end if
end if
end for
' If all values are equal, maintain original order
return false
end function
' @ignore
function internal_sanitizeKeyPath(value = "" as String)
regex = createObject("roRegex", "\[(.*?)\]", "i")
matches = regex.matchAll(value)
if (type(matches) <> "<uninitialized>" AND matches <> Invalid) then
for each match in matches
if (type(match) <> "<uninitialized>" AND match <> Invalid) then
value = value.replace(match[0], "." + match[1])
end if
end for
end if
return value
end function
' Creates an array of unique values that are included in all given arrays using SameValueZero for equality comparisons. The order and references of result values are determined by the first array.
' @since 0.0.21
' @category Array
' @param {Array} mainArray - The main array to inspect
' @param {Array} inspect - The array to find matches
' @returns {Array} Returns the new array of intersecting values
function intersection(mainArray = CreateObject("roArray", 0, true) as Object, inspectArray = CreateObject("roArray", 0, true) as Object) as Object
return intersectionBy(mainArray, inspectArray)
end function
' This method is like rodash.intersection except that it accepts iteratee which is invoked for each element of each arrays to generate the criterion by which they're compared. The order and references of result values are determined by the first array. The iteratee is invoked with one argument:(value).
' @since 0.0.21
' @category Array
' @param {Array} mainArray - The main array to inspect
' @param {Array} inspect - The array to find matches
' @param {Dynamic} iteratee - The iteratee invoked per element
' @returns {Array} Returns the new array of intersecting values
function intersectionBy(mainArray = CreateObject("roArray", 0, true) as Object, inspectArray = CreateObject("roArray", 0, true) as Object, iteratee = Invalid) as Object
intersectArray = CreateObject("roArray", 0, true)
mainArray = clone(mainArray)
inspectArray = clone(inspectArray)
if (type(iteratee) = "<uninitialized>" OR iteratee = Invalid) then
if (type(mainArray) = "roArray" AND NOT mainArray.isEmpty()) then
for each item in mainArray
if NOT isEqual(indexOf(inspectArray, item), -1) then
intersectArray.push(item)
end if
end for
end if
else if isFunction(iteratee) then
for i = 0 to inspectArray.count() - 1
inspectArray[i] = iteratee(inspectArray[i])
end for
for each item in mainArray
if NOT isEqual(indexOf(inspectArray, iteratee(item)), -1) then
intersectArray.push(item)
end if
end for
else if (type(iteratee) = "String" OR type(iteratee) = "roString") then
for each item in mainArray
findKey = item[iteratee]
if (type(findKey) <> "<uninitialized>" AND findKey <> Invalid) then
matchValue = CreateObject("roAssociativeArray")
matchValue[iteratee] = findKey
if NOT isEqual(findIndex(inspectArray, matchValue), -1) then
intersectArray.push(item)
end if
end if
end for
end if
return intersectArray
end function
' This method is like rodash.intersection except that it accepts comparator which is invoked to compare elements of arrays. The order and references of result values are determined by the first array. The comparator is invoked with two arguments: (arrVal, othVal).
' @since 0.0.21
' @category Array
' @param {Array} mainArray - The main array to inspect
' @param {Array} inspect - The array to find matches
' @param {Dynamic} comparator - The comparator invoked per element
' @returns {Array} Returns the new array of intersecting values
function intersectionWith(mainArray = CreateObject("roArray", 0, true) as Object, inspectArray = CreateObject("roArray", 0, true) as Object, comparator = Invalid) as Object
if NOT isFunction(comparator) then
return []
end if
return intersectionBy(mainArray, inspectArray, comparator)
end function
' Creates an object composed of the inverted keys and values of `object`.
' If `object` contains duplicate values, subsequent values overwrite property assignments of previous values.
' As AssocArrays are sorted, the order of the aa keys is not preserved.
' @since 0.0.22
' @category Object
' @param {Object} object The object to invert.
' @returns {Object} Returns the new inverted object.
' @example
' *
' const object = { 'a': 1, 'b': 2, 'c': 1 }
' rodash.invert(object)
' // { '1': 'c', '2': 'b' }
function invert(originalAA as Object) as Dynamic
if not (type(originalAA) = "roAssociativeArray") then
return invalid
end if
' Initialize an empty associative array to hold the inverted key-value pairs
invertedAA = CreateObject("roAssociativeArray")
' Iterate over each key-value pair in the original associative array
for each key in originalAA.keys()
' Assign the value as the new key and the key as the new value in the inverted array
invertedAA[toString(originalAA[toString(key)])] = key
end for
' Return the newly created inverted associative array
return invertedAA
end function
' Checks if the supplied value is a valid AssociativeArray type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isAA({}) // => true
' rodash.isAA([]) // => false
function isAA(value as Dynamic) as Boolean
return type(value) = "roAssociativeArray"
end function
' Checks if the supplied value is a roAppMemoryMonitorEvent type
' @since 0.0.26
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isAppMemoryMonitorEvent(value as Dynamic) as Boolean
return type(value) = "roAppMemoryNotificationEvent"
end function
' Checks if the supplied value is a valid Array type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isArray([]) // => true
' rodash.isArray({}) // => false
' rodash.isArray("") // => false
function isArray(value as Dynamic) as Boolean
return type(value) = "roArray"
end function
' Checks if value is array-like. A value is considered array-like if it is an array, a string, or an node with children.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isArrayLike([]) // => true
' rodash.isArrayLike({}) // => false
function isArrayLike(value as Dynamic) as Boolean
return (type(value) = "roArray") OR (type(value) = "String" OR type(value) = "roString") OR isNodeWithChildren(value)
end function
' Checks if the supplied value is a valid Boolean type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isBoolean(true) // => true
' rodash.isBoolean(false) // => true
' rodash.isBoolean(1) // => false
' rodash.isBoolean("true") // => false
function isBoolean(value as Dynamic) as Boolean
return type(value) = "Boolean" OR type(value) = "roBoolean"
end function
' Checks if the supplied value is a valid ByteArray type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isByteArray(value as Dynamic)
return type(value) = "roByteArray"
end function
' Alias to isDate function
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isDate(value as Dynamic) as Boolean
return (type(value) = "roDateTime")
end function
' Checks if the supplied value is a valid date time type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isDateTime(value as Dynamic) as Boolean
return type(value) = "roDateTime"
end function
' Checks if the supplied value is a roDeviceInfo type
' @since 0.0.26
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isDeviceInfoEvent(value as Dynamic) as Boolean
return type(value) = "roDeviceInfoEvent"
end function
' Checks if the supplied value is a valid Double type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isDouble(1) // => false
' rodash.isDouble(1.0#) // => true
' rodash.isDouble(1.0!) // => false
function isDouble(value as Dynamic) as Boolean
return type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble"
end function
' Alias to isNode function
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @param {String} subType An optional subType parameter to further refine the check
' @returns {Boolean} Results of the check
function isElement(value as Dynamic, subType = "" as String) as Boolean
return isNode(value, subtype)
end function
' Checks if a value is empty.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isEmpty("") // => true
' rodash.isEmpty([]) // => true
' rodash.isEmpty({}) // => true
' rodash.isEmpty(0) // => true
' rodash.isEmpty(false) // => true
' rodash.isEmpty(invalid) // => true
' rodash.isEmpty("Hello") // => false
function isEmpty(value as Dynamic)
if (type(value) = "<uninitialized>" OR value = Invalid) OR (type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger" OR type(value) = "Float" OR type(value) = "roFloat" OR type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble") OR (type(value) = "Boolean" OR type(value) = "roBoolean") then
return true
else
return value.isEmpty()
end if
return true
end function
' Checks if the supplied value is a valid String type and is not empty
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isEmptyString("") // => true
' rodash.isEmptyString(" ") // => false
' rodash.isEmptyString("Hello") // => false
function isEmptyString(value as Dynamic) as Boolean
return (type(value) = "String" OR type(value) = "roString") AND value.isEmpty()
end function
' Checks if the supplied values are the same.
' By default, when comparing arrays and associative arrays the function will compare the values on the elements. If the strict parameter is set to true, the function will compare the references of the elements.
' @since 0.0.21
' @category Lang
' @param {Dynamic} valueOne - First value.
' @param {Dynamic} valueTwo - Second value.
' @returns {Boolean} True if the values are the same and false if not or if any of the values are a type that could not be compared.
' @example
' rodash.isEqual(1, 1) // => true
' rodash.isEqual(1, 2) // => false
' rodash.isEqual([], []) // => true
' rodash.isEqual({}, {}) // => true
' rodash.isEqual({a: 1}, {a: 1}) // => true
' rodash.isEqual({a: 1}, {a: 2}) // => false
' rodash.isEqual("Hello", "Hello") // => true
' rodash.isEqual("Hello", "World") // => false
function isEqual(valueOne as Dynamic, valueTwo as Dynamic, strict = false as Boolean) as Boolean
' If the first argument is true we don't need to check the follwing conditionals
if internal_canBeCompared(valueOne, valueTwo) then
return (valueOne = valueTwo)
else if isNode(valueOne) then
if isNode(valueTwo) then
return valueOne.isSameNode(valueTwo)
end if
else if (type(valueOne) = "roAssociativeArray") AND (type(valueTwo) = "roAssociativeArray") then
if strict then
key = ("internal_key_" + bslib_toString(random(1000000, 2000000)))
valueOne.addReplace(key, "true")
isSame = false
if valueTwo.doesExist(key) then
isSame = true
end if
valueOne.delete(key)
return isSame
end if
if (clone(valueOne.keys()).join(",")) = (clone(valueTwo.keys()).join(",")) then
return (formatJson(valueOne) = formatJson(valueTwo))
end if
else if (type(valueOne) = "roArray") then
if strict then
key = ("internal_key_" + bslib_toString(random(1000000, 2000000)))
valueOne.push(key)
isSame = isEqual((valueTwo[valueTwo.count() - 1]), key)
valueOne.pop()
return isSame
end if
if (type(valueTwo) = "roArray") AND (valueOne.count() = valueTwo.count()) then
return (formatJson(valueOne) = formatJson(valueTwo))
end if
end if
return false
end function
' Checks if the supplied values are the same.
' @since 0.0.21
' @category Lang
' @param {Dynamic} valueOne - First value.
' @param {Dynamic} valueTwo - Second value.
' @returns {Boolean} True if the values are the same and false if not or if any of the values are a type that could not be compared.
function isEqualWith(valueOne as Dynamic, valueTwo as Dynamic, customizer = Invalid) as Boolean
' If the first argument is true we don't need to check the follwing conditionals
' TODO: revisit this agressively
if internal_canBeCompared(valueOne, valueTwo) then
return customizer(valueOne, valueTwo)
else if isNode(valueOne) then
if isNode(valueTwo) then
valueOne = valueOne.getFields()
valueOne.delete("change")
valueOne.delete("focusable")
valueOne.delete("focusedChild")
valueOne.delete("ready")
valueTwo = valueTwo.getFields()
valueTwo.delete("change")
valueTwo.delete("focusable")
valueTwo.delete("focusedChild")
valueTwo.delete("ready")
return isEqualWith(valueOne, valueTwo, customizer)
end if
else if (type(valueOne) = "roAssociativeArray") then
if (type(valueTwo) = "roAssociativeArray") AND (valueOne.keys().count() = valueTwo.keys().count()) then
keys = valueOne.keys()
for each key in keys
if customizer(valueOne[key], valueTwo[key]) then
return true
end if
end for
end if
else if (type(valueOne) = "roArray") then
if (type(valueTwo) = "roArray") AND (valueOne.count() = valueTwo.count()) then
for i = 0 to valueOne.count() - 1
if customizer(valueOne[i], valueTwo[i]) then
return true
end if
end for
end if
end if
return false
end function
' Assesses the passed object to determine if it is an Error Object.
' TODO: MORE SUPPORT - TRY/CATCH?
' @since 0.0.21
' @category Lang
' @param {Dynamic} value - the object to assess
' @returns {Boolean} True if the object represents and error.
function isError(value as Dynamic) as Boolean
if (type(value) = "roAssociativeArray") then
if ((type(value.status) = "String" OR type(value.status) = "roString") AND NOT value.status.isEmpty()) AND (value.status.Instr("error") > -1) then
return true
end if
errorCodes = internal_getConstants().BrightScriptErrorCodes
if hasKeys(value, [
"number"
"message"
"exception"
]) then
for each errorCode in errorCodes
if value.number = errorCode then
return true
end if
end for
end if
end if
return false
end function
' Checks if `value` is a finite primitive number.
' @since 0.0.21
' @category Lang
function isFinite(value as dynamic) as boolean
if NOT (type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger" OR type(value) = "Float" OR type(value) = "roFloat" OR type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble") then
return false
end if
constants = internal_getConstants()
if (value > constants.max_int) OR (value < constants.min_int) then
return false
end if
return true
end function
' Checks if the supplied value is a valid Float type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isFloat(1) // => false
' rodash.isFloat(1.0!) // => true
' rodash.isFloat(1.0#) // => false
function isFloat(value as Dynamic) as Boolean
return type(value) = "Float" OR type(value) = "roFloat"
end function
' Checks if the supplied value is a valid Function type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isFunction(value as Dynamic) as Boolean
valueType = type(value)
return (valueType = "roFunction") OR (valueType = "Function")
end function
' Checks if the supplied value is a roInputEvent type
' @since 0.0.26
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isInputEvent(value as Dynamic) as Boolean
return type(value) = "roInputEvent"
end function
' Checks if the supplied value is a valid Integer type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isInteger(value as Dynamic) as Boolean
return type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger"
end function
' Checks if the supplied value is Invalid
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isInvalid(Invalid) // => true
' rodash.isInvalid(undefined) // => true
' rodash.isInvalid("") // => false
function isInvalid(value as Dynamic) as Boolean
return type(value) = "<uninitialized>" OR value = Invalid
end function
' Checks if value is a valid array-like length
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isLength(value as Dynamic) as Boolean
if (type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger") AND isFinite(value) AND (value >= 0) then
return true
end if
return false
end function
' Alias to isArray function
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
' @example
' rodash.isMap([]) // => true
' rodash.isMap({}) // => false
function isMap(value as Dynamic) as Boolean
return (type(value) = "roArray")
end function
' Checks if the supplied value is a roMessagePort type
' @since 0.0.26
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isMessagePort(value as Dynamic) as Boolean
return type(value) = "roMessagePort"
end function
' Method determines whether the passed value is NaN and its type is a valid number
' @since 0.0.21
' @category Lang
' @param {Dynamic} value - The variable to be checked
' @returns {Boolean} Results of the check
function isNaN(value as Dynamic) as Boolean
return NOT (type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger" OR type(value) = "Float" OR type(value) = "roFloat" OR type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble")
end function
' Checks if the supplied value is a valid Node type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @param {String} subType An optional subType parameter to further refine the check
' @returns {Boolean} Results of the check
function isNode(value as Dynamic, subType = "" as String) as Boolean
if type(value) <> "roSGNode" then
return false
end if
if subType <> "" then
return value.isSubtype(subType)
end if
return true
end function
' Checks if the supplied value is a valid roSGNodeEvent type
' @since 0.0.26
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isNodeEvent(value as Dynamic) as Boolean
return type(value) = "roSGNodeEvent"
end function
' Checks if the supplied value is a valid roUrlEvent type
' @since 0.0.26
' @category Lang
' @param {Dynamic} value - The variable to be checked
' @param {String} subType - An optional subType parameter to further refine the check
' @returns Results of the check
function isNodeWithChildren(value as Dynamic, subType = "" as String) as Boolean
if type(value) <> "roSGNode" then
return false
end if
if subType <> "" then
return value.isSubtype(subType) AND value.getChildCount() > 0
end if
return value.getChildCount() > 0
end function
' Checks if the supplied value is a valid and populated AssociativeArray type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isNonEmptyAA(value as Dynamic)
return type(value) = "roAssociativeArray" AND value.keys().count() > 0
end function
' Checks if the supplied value is a valid Array type and not empty
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isNonEmptyArray(value as Dynamic) as Boolean
return type(value) = "roArray" AND NOT value.isEmpty()
end function
' Checks if the supplied value is a valid String type and is not empty
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isNonEmptyString(value as Dynamic) as Boolean
return (type(value) = "String" OR type(value) = "roString") AND NOT value.isEmpty()
end function
' Checks if the supplied value is not Invalid or uninitialized
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isNotInvalid(value as Dynamic) as Boolean
return type(value) <> "<uninitialized>" AND value <> Invalid
end function
' Alias to isInvalid function
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isNull(value as Dynamic) as Boolean
return NOT (type(value) <> "<uninitialized>" AND value <> Invalid)
end function
' Checks if the supplied value is a valid number type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isNumber(value as Dynamic) as Boolean
return type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger" OR type(value) = "Float" OR type(value) = "roFloat" OR type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble"
end function
' Checks if the supplied value is a valid String type
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isString(value as Dynamic)
return type(value) = "String" OR type(value) = "roString"
end function
' Checks if the supplied value is a valid roUrlEvent type
' @since 0.0.26
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isUrlEvent(value as Dynamic) as Boolean
return type(value) = "roUrlEvent"
end function
' Checks if the supplied value is a valid url transfer type
' @since 0.0.26
' @category Lang
' @param {Dynamic} value The variable to be checked
' @returns {Boolean} Results of the check
function isUrlTransfer(value as Dynamic) as Boolean
return type(value) = "roUrlTransfer"
end function
' Converts all elements in array into a string separated by separator.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to convert
' @param {String} separator - The element separator
' @returns {Array} Returns the joined string
function join(array = CreateObject("roArray", 0, true) as Object, separator = "" as String)
return clone(array).join(separator)
end function
' Converts a string to kebab case.
' @since 0.0.21
' @category String
function kebabCase(value = "" as string)
value = value.replace("-", " ").replace("_", " ")
value = value.trim()
valueArray = value.split(" ")
return lcase((clone(valueArray).join("-")))
end function
' Creates an object composed of keys generated from the results of running each element of collection thru iteratee. The corresponding value of each key is the last element responsible for generating the key. The iteratee is invoked with one argument: (value).
' @since 0.0.24
' @category Collection
' @param {Dynamic} collection - The collection to sample
' @param {String} key - The iteratee to transform keys.
' @returns {Dynamic} - Returns the composed aggregate object.
function keyBy(collection = invalid as dynamic, key = "" as string) as object
returnObject = CreateObject("roAssociativeArray")
if not (type(collection) = "roArray") then
return returnObject
end if
for each item in collection
if (type(item) = "roAssociativeArray") and item.doesExist(key) then
newKey = toString(item[key])
returnObject[newKey] = item
end if
end for
return returnObject
end function
' Gets the last element of array.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to query
' @returns {Dynamic} Returns the last element of array
function last(array = CreateObject("roArray", 0, true)) as Dynamic
return array[array.count() - 1]
end function
' This method is like rodash.indexOf except that it iterates over elements of array from right to left.
' @since 0.0.23
' @category Array
' @param {Array} array - The array to query
' @param {Dynamic} value - The value to search for
' @param {Integer} fromIndex - The index to search from
' @returns {Dynamic} Returns the index of the matched value, else -1
function lastIndexOf(array = CreateObject("roArray", 0, true) as Object, value = Invalid as Dynamic, fromIndex = Invalid as Dynamic) as Dynamic
if NOT (type(array) = "roArray") then
return -1
end if
if (type(fromIndex) = "<uninitialized>" OR fromIndex = Invalid) then
fromIndex = array.count() - 1
else if fromIndex < 0 then
fromIndex = array.count() + fromIndex
end if
' Ensure fromIndex is within valid bounds
fromIndex = ((maxBy([
0
min([
array.count() - 1
fromIndex
])
])))
for i = fromIndex to 0 step -1
if isEqual(array[i], value) then
return i
end if
end for
return -1
end function
' Converts a string to lower case.
' @since 0.0.21
' @category String
function lowerCase(value = "" as string)
value = value.replace("-", " ").replace("_", " ")
value = value.trim()
valueArray = value.split(" ")
return lcase((clone(valueArray).join(" ")))
end function
' Converts the first character of string to lower case.
' @since 0.0.21
' @category String
function lowerFirst(value = "" as string)
value = value.trim()
valueArray = value.split("")
valueArray[0] = lcase(valueArray[0])
return (clone(valueArray).join(""))
end function
' Checks if value is less than other.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value - The value to compare.
' @param {Dynamic} other - The other value to compare.
' @returns {Boolean} - Returns `true` if the value is less than other, else `false`.
function lt(value as dynamic, other as dynamic)
return value < other
end function
' Checks if value is less than or equal to other.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value - The value to compare.
' @param {Dynamic} other - The other value to compare.
' @returns {Boolean} - Returns `true` if the value is less than or equal to other, else `false`.
function lte(value as dynamic, other as dynamic)
return value <= other
end function
' Creates an array of values by running each element in collection thru iteratee. The iteratee is invoked with three arguments:(value, index|key, collection)
' @since 0.0.21
' @category Collection
' @param {Dynamic} collection - The collection to iterate over
' @param {Dynamic} iteratee - The function invoked per iteration
' @returns {Array} Returns the new mapped array
' @example
' rodash.map([4, 8], rodash.square) // => [16, 64]
function map(collection = CreateObject("roAssociativeArray") as Dynamic, iteratee = Invalid as Dynamic)
returnArray = CreateObject("roArray", 0, true)
collectionToProcess = CreateObject("roArray", 0, true)
if (type(collection) = "String" OR type(collection) = "roString") then
collectionToProcess.append(collection.split(""))
else if (type(collection) = "roAssociativeArray") then
for each key in collection.keys()
collectionToProcess.push(collection[key])
end for
else if (type(collection) = "roArray") then
collectionToProcess.append(collection)
end if
for each item in collectionToProcess
if (type(iteratee) = "String" OR type(iteratee) = "roString") then
if (type(item) = "roAssociativeArray") then
returnArray.push(item[iteratee])
end if
else if isFunction(iteratee) then
returnArray.push(iteratee(item))
else
returnArray.push(item)
end if
end for
return returnArray
end function
' Computes the maximum value of array. If array is empty or falsey, invalid is returned.
' @since 0.0.21
' @category Math
' @param {Array} array - The array to iterate over
' @returns {Dynamic} Returns the maximum value
' @example
' rodash.max([4, 2, 8, 6]) // => 8
function max(array = CreateObject("roArray", 0, true) as Object) as Dynamic
return maxBy(array)
end function
' Computes the maximum value of array. If array is empty or falsey, invalid is returned.
' @since 0.0.21
' @category Math
' @param {Array} array - The array to iterate over
' @returns {Dynamic} Returns the maximum value
function maxBy(array = CreateObject("roArray", 0, true) as Object, iteratee = Invalid) as Dynamic
if isEmpty(array) then
return Invalid
end if
maxValue = Invalid
if (type(iteratee) = "<uninitialized>" OR iteratee = Invalid) then
maxValue = internal_getConstants().min_int
for each value in array
if (value > maxValue) then
maxValue = value
end if
end for
else if isFunction(iteratee) AND (type(array[0]) = "roAssociativeArray") then
maxValue = array[0]
for each value in array
if (iteratee(value) > iteratee(maxValue)) then
maxValue = value
end if
end for
else if (type(iteratee) = "String" OR type(iteratee) = "roString") AND (type(array[0]) = "roAssociativeArray") then
maxValue = array[0]
for each value in array
if (value[iteratee] > maxValue[iteratee]) then
maxValue = value
end if
end for
end if
return maxValue
end function
' Computes the mean of the values in array.
' @since 0.0.21
' @category Math
' @param {Array} array - The array to iterate over
' @returns {Dynamic} Returns the mean value
' @example
' rodash.mean([4, 2, 8, 6]) // => 5
function mean(array)
return meanBy(array)
end function
' This method is like `rodash.mean` except that it accepts `iteratee` which is invoked for each element in array to generate the value to be averaged. The iteratee is invoked with one argument: (value).
' @since 0.0.21
' @category Math
' @param {Array} array - The array to iterate over
' @param {Function} iteratee - The iteratee invoked per element
' @returns {Dynamic} Returns the mean value
function meanBy(array, iteratee = Invalid)
if isEmpty(array) then
return Invalid
end if
return divide(sumBy(array, iteratee), array.count())
end function
' This method is like rodash.assign except that it recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. Source properties that resolve to undefined are skipped if a destination value exists. Array and plain object properties are merged recursively. Other objects and value types are overridden by assignment. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
' @since 0.0.33
' @category Collection
' @param {Dynamic} target - The target object to merge into
' @param {Dynamic} source - The source object to merge from
' @returns {Object} Returns the merged object
' @example
' rodash.merge({a:1}, {b:2}) // => {a:1, b:2}
' rodash.merge({a:1}, {a:2}) // => {a:2}
' rodash.merge({a:1}, {a:{b:2}}) // => {a:{b:2}}
' rodash.merge({a:{b:1}}, {a:{c:2}}) // => {a:{b:1, c:2}}
' rodash.merge({a:{b:1}}, [{a:{b:2}}, {a:{c:3}}]) // => {a:{b:2, c:3}}
function merge(target as Object, sources as Object) as Object
if (type(sources) = "roAssociativeArray") then
sources = [
sources
]
end if
' Iterate through each key in the source object
for each source in sources
for each key in source
if target.doesExist(key) then
' If the key exists in both target and source, check for nested objects
if type(target[key]) = "roAssociativeArray" AND type(source[key]) = "roAssociativeArray" then
' Recursive merge for nested objects
target[key] = merge(target[key], source[key])
else
' Overwrite the value if it exists and isn't a nested object
target[key] = source[key]
end if
else
' Add the key to the target if it doesn't exist
target[key] = source[key]
end if
end for
end for
return target
end function
' Computes the minimum value of array. If array is empty or falsey, invalid is returned.
' @since 0.0.21
' @category Math
' @param {Array} array - The array to iterate over
' @returns {Dynamic} Returns the minumum value
function min(array = CreateObject("roArray", 0, true) as Object) as Dynamic
return minBy(array)
end function
' Computes the minimum value of array. If array is empty or falsey, invalid is returned.
' @since 0.0.21
' @category Math
' @param {Array} array - The array to iterate over
' @returns {Dynamic} Returns the maximum value
function minBy(array = CreateObject("roArray", 0, true) as Object, iteratee = Invalid) as Dynamic
if isEmpty(array) then
return Invalid
end if
minValue = Invalid
if (type(iteratee) = "<uninitialized>" OR iteratee = Invalid) then
minValue = internal_getConstants().max_int
for each value in array
if (value < minValue) then
minValue = value
end if
end for
else if isFunction(iteratee) AND (type(array[0]) = "roAssociativeArray") then
minValue = array[0]
for each value in array
if (iteratee(value) < iteratee(minValue)) then
minValue = value
end if
end for
else if (type(iteratee) = "String" OR type(iteratee) = "roString") AND (type(array[0]) = "roAssociativeArray") then
minValue = array[0]
for each value in array
if (value[iteratee] < minValue[iteratee]) then
minValue = value
end if
end for
end if
return minValue
end function
' Multiplies two numbers.
' @since 0.0.21
' @category Math
' @param {Dynamic} multiplier - The first number in a multiplication.
' @param {Dynamic} multiplicand - The second number in a multiplication.
' @returns {Dynamic} - Returns the product of the two numbers.
function multiply(multiplier as dynamic, multiplicand as dynamic) as dynamic
if (NOT (type(multiplier) = "Integer" OR type(multiplier) = "roInt" OR type(multiplier) = "roInteger" OR type(multiplier) = "LongInteger" OR type(multiplier) = "Float" OR type(multiplier) = "roFloat" OR type(multiplier) = "Double" OR type(multiplier) = "roDouble" OR type(multiplier) = "roIntrinsicDouble")) OR (NOT (type(multiplicand) = "Integer" OR type(multiplicand) = "roInt" OR type(multiplicand) = "roInteger" OR type(multiplicand) = "LongInteger" OR type(multiplicand) = "Float" OR type(multiplicand) = "roFloat" OR type(multiplicand) = "Double" OR type(multiplicand) = "roDouble" OR type(multiplicand) = "roIntrinsicDouble"))
return 0
end if
return multiplier * multiplicand
end function
' Gets the number of milliseconds that have elapsed since the Unix epoch (1 January 1970 00:00:00 UTC).
' @since 0.0.21
' @category Date
' @returns {Integer} The number of milliseconds that have elapsed since the Unix epoch.
function now() as Integer
dateObj = internal_getDateObject()
return dateObj.asSeconds() + dateObj.getMilliseconds()
end function
' The opposite of rodash.pick; this method creates an object composed of the own and inherited enumerable property paths of object that are not omitted.
' @since 0.0.23
' @category Object
' @param {Object} object - The source object.
' @param {Array} paths - The property paths to omit.
' @returns {Dynamic} - Returns the new object.
function omit(object as Object, paths = CreateObject("roArray", 0, true) as Object) as Dynamic
result = CreateObject("roAssociativeArray")
for each key in object.keys()
if indexOf(paths, key) = -1 then
result[key] = object[key]
end if
end for
return result
end function
' This method is like `sortBy` except that it allows specifying the sort
' orders of the iteratees to sort by. If `orders` is unspecified, all values
' are sorted in ascending order. Otherwise, specify an order of "desc" for
' descending or "asc" for ascending sort order of corresponding values.
' You may also specify a compare function for an order.
' @since 0.0.21
' @category Array
' @param {Dynamic} collection - The collection to shuffle
' @param {Dynamic} [iteratee] - The iteratees to sort by
' @param {Dynamic} [orders] - The sort orders of `iteratees`.
' @returns {Array} Returns the new ordered array
function orderBy(collection, iteratees, orders) as Object
if (type(collection) = "<uninitialized>" OR collection = Invalid) OR NOT (type(collection) = "roArray") then
return []
end if
if NOT (type(iteratees) = "roArray") then
iteratees = bslib_ternary(iteratees = Invalid, [], [
iteratees
])
end if
if NOT (type(orders) = "roArray") then
orders = bslib_ternary(orders = Invalid, [], [
orders
])
end if
returnCollection = clone(collection)
n = returnCollection.Count()
for i = 0 to n - 2
for j = 0 to n - i - 2
if internal_orderByCompare(returnCollection[j], returnCollection[j + 1], iteratees, orders)
' Swap returnCollection[j] and returnCollection[j + 1]
temp = returnCollection[j]
returnCollection[j] = returnCollection[j + 1]
returnCollection[j + 1] = temp
end if
end for
end for
return returnCollection
end function
' Add padding to the supplied value after converting to a string. For example "1" to "01".
' @since 0.0.22
' @category String
' @param {String} value The value to add padding to.
' @param {Integer} padLength The minimum output string length.
' @param {String} paddingCharacter The string to use as padding.
' @returns {String} Resulting padded string.
function padString(value as Dynamic, padLength = 2 as Integer, paddingCharacter = "0" as Dynamic) as String
value = toString(value)
while value.len() < padLength
value = paddingCharacter + value
end while
return value
end function
' Alias to `rodsah.padString`
' @since 0.0.21
' @category String
function paddString(value as Dynamic, padLength = 2 as Integer, paddingCharacter = "0" as Dynamic) as String
return padString(value, padLength, paddingCharacter)
end function
' Creates an object composed of the picked object properties.
' @since 0.0.23
' @category Object
' @param {Object} object - The object to pick from.
' @param {Array} paths - The property paths to pick.
' @returns {Dynamic} - Returns the picked value.
function pick(object as Object, paths = CreateObject("roArray", 0, true) as Object) as Dynamic
picked = CreateObject("roAssociativeArray")
object = clone(object)
for each key in paths
if object.doesExist(key) then
picked[key] = object[key]
end if
end for
return picked
end function
' Generates a random number between the lower and upper bounds.
' @since 0.0.21
' @category Number
function random(lower = 0 as dynamic, upper = 1 as dynamic, floating = false as boolean) as dynamic
if floating then
return lower + rnd(0) * (upper - lower)
end if
return lower + int(rnd(0) * (upper - lower + 1))
end function
' Reduces collection to a value which is the accumulated result of running each element in collection thru iteratee, where each successive invocation is supplied the return value of the previous. If accumulator is not given, the first element of collection is used as the initial value. The iteratee is invoked with four arguments:(accumulator, value, index|key, collection).
' @since 0.0.21
' @category Collection
' @param {Dynamic} collection - The collection to iterate over
' @param {Dynamic} iteratee - The function invoked per iteration
' @param {Integer} accumulator - The initial value
' @returns {Array} Returns the accumulated value
function reduce(collection = Invalid as Dynamic, iteratee = Invalid as Dynamic, accumulator = Invalid as Dynamic)
result = accumulator
if (type(iteratee) = "<uninitialized>" OR iteratee = Invalid) then
return collection
else if isFunction(iteratee) then
if (type(collection) = "roArray") then
for each item in collection
result = iteratee(result, item)
end for
else if (type(collection) = "roAssociativeArray") then
for each key in collection.keys()
item = collection[key]
result = iteratee(result, item, key)
end for
end if
end if
return result
end function
' Removes the supplied node from it's parent. Can be set as an observer callback.
' @since 0.0.32
' @category Node
' @param {roSGNode|roSGNodeEvent} nodeOrEvent - The node or node event to be removed.
sub removeNode(nodeOrEvent as Dynamic)
if (type(nodeOrEvent) = "roSGNodeEvent") then
node = nodeOrEvent.getRoSGNode()
node.unobserveFieldScoped(nodeOrEvent.getField())
else
node = nodeOrEvent
end if
if isNode(node) then
parent = node.getParent()
if isNode(parent) then
parent.removeChild(node)
end if
node = Invalid 'bs:disable-line LINT1005 1005
end if
end sub
' Removes all children of a node.
' @since 0.0.32
' @category Node
' @param {Object} node - The node to remove the children of
sub removeNodeChildren(node as Object)
if isNode(node) then
node.removeChildrenIndex(node.getChildCount(), 0)
end if
end sub
' Computes number rounded up to precision.
' @since 0.0.21
' @category Math
' @param {Float} num - The number to round.
' @param {Dynamic} precision - The precision to round to.
' @returns {Dynamic} - Returns the rounded number.
function round(num as Float, precision = 0 as Integer) as Float
if num >= 0 then
return floor(num + 0.5 * 10 ^ (-precision), precision)
else
return ceil(num - 0.5 * 10 ^ (-precision), precision)
end if
end function
' Gets a random element from collection.
' @since 0.0.23
' @category Collection
' @param {Dynamic} collection - The collection to sample
' @returns {Dynamic} - Returns the random element
function sample(collection = invalid as dynamic)
if not (type(collection) = "roArray") then
return invalid
end if
return collection[random(0, collection.count() - 1)]
end function
' Gets n random elements at unique keys from collection up to the size of collection.
' @since 0.0.23
' @category Collection
' @param {Dynamic} collection - The collection to sample
' @param {Integer} n - The number of elements to sample
' @returns {Dynamic} - Returns the random elements.
function sampleSize(collection as Object, n as Integer) as Object
if n <= 0 then
return CreateObject("roArray", 0, true)
end if
result = CreateObject("roArray", n, true)
if (type(collection) = "roArray" AND NOT collection.isEmpty()) then
' Create a copy of the original array to avoid modifying it
copyCollection = clone(collection)
count = copyCollection.count()
' Limit n to the collection size
if n > count then
n = count
end if
' Perform Fisher-Yates shuffle for the first n elements
for i = 0 to n - 1
' Generate random index between i and count - 1
j = random(i, count - 1)
' Swap the current element with the element at index j
temp = copyCollection[i]
copyCollection[i] = copyCollection[j]
copyCollection[j] = temp
' Add the swapped element to the result
result.push(copyCollection[i])
end for
end if
return result
end function
' Used to set a nested String value in the supplied object
' @since 0.0.21
' @category Object
' @param {Object} aa - Object to drill down into.
' @param {String} keyPath - A dot notation based string to the expected value.
' @param {Dynamic} value - The value to be set.
' @returns {Boolean} True if set successfully.
function set(aa as Object, keyPath as String, value as Dynamic) as Boolean
if NOT (type(aa) = "roAssociativeArray") then
return false
end if
level = aa
keys = internal_sanitizeKeyPath(keyPath).tokenize(".")
while keys.count() > 1
key = keys.shift()
if NOT (type(level[key]) = "roAssociativeArray") then
level[key] = CreateObject("roAssociativeArray")
end if
level = level[key]
end while
finalKey = keys.shift()
level[finalKey] = value
return true
end function
' Creates an array of shuffled values, using a version of the Fisher-Yates shuffle.
' @since 0.0.21
' @category Collection
' @param {Dynamic} collection - The collection to shuffle
' @returns {Array} Returns the new shuffled array
function shuffle(collection = CreateObject("roArray", 0, true) as Object)
return sampleSize(collection, collection.count())
end function
' Gets the size of collection by returning its length for array-like values or the number of own enumerable string keyed properties for objects.
' @since 0.0.21
' @category Collection
' @param {Dynamic} collection - The collection to inspect
' @returns {Integer} Returns the collection size.
function size(collection = Invalid as Dynamic)
if (type(collection) = "<uninitialized>" OR collection = Invalid) OR (NOT (type(collection) = "roArray") AND NOT (type(collection) = "roAssociativeArray") AND NOT (type(collection) = "String" OR type(collection) = "roString")) then
return []
end if
if (type(collection) = "roAssociativeArray") then
collection = toArray(collection)
else if (type(collection) = "String" OR type(collection) = "roString") then
return collection.len()
end if
return collection.count()
end function
' Creates a slice of array from start up to, but not including, end.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to slice
' @param {Integer} startPos - The start position
' @param {Integer} endPos - The end position
' @returns {Dynamic} Returns the slice of array
function slice(array = CreateObject("roArray", 0, true) as Object, startPos = 0 as Integer, endPos = -1 as Integer) as Object
if NOT (type(array) = "roArray") then
return Invalid
end if
if endPos = -1 then
endPos = array.count()
end if
return clone(array).slice(startPos, endPos)
end function
' Creates an array of elements, sorted in ascending order by the results of running each element in a collection thru each iteratee. This method performs a stable sort, that is, it preserves the original sort order of equal elements. The iteratees are invoked with one argument: (value).
' @since 0.0.21
' @category Collection
' @param {Dynamic} collection - The collection to sort
' @param {Dynamic} iteratee - The iteratees to sort by
' @returns {Array} Returns the new sorted array
function sortBy(collection = Invalid as Dynamic, iteratee = Invalid as Dynamic)
if (type(collection) = "<uninitialized>" OR collection = Invalid) OR NOT (type(collection) = "roArray") then
return collection
end if
returnCollection = clone(collection)
if (type(iteratee) = "roArray") then
for each iteration in iteratee
if (type(iteration) = "String" OR type(iteration) = "roString") then
returnCollection.sortBy(iteration)
end if
end for
else if isFunction(iteratee) then
key = ""
for each aa in collection
for each key in aa.keys()
if isEqual(aa[key], iteratee(aa)) then
exit for
end if
end for
if NOT key = "" then
exit for
end if
end for
if NOT key = "" then
returnCollection.sortBy(key)
end if
end if
return returnCollection
end function
' Uses a binary search to determine the lowest index at which value should be inserted into array in order to maintain its sort order.
' @since 0.0.21
' @category Array
' @param {Array} array - The sorted array to inspect
' @returns {Object} Returns the index at which value should be inserted into array
function sortedIndex(array = CreateObject("roArray", 0, true) as Object, value = 0 as Integer)
for i = 0 to array.count() - 1
item = array[i]
nextItem = array[i + 1]
if (type(nextItem) <> "<uninitialized>" AND nextItem <> Invalid) then
if (item >= value AND value <= nextItem) then
return i
end if
end if
end for
return i
end function
' Computes the square of the value.
' @since 0.0.30
' @category Math
' @param {Integer} value - The value to multiple by itself
' @returns {Integer} Returns the square of the value
function square(value as Integer) as Dynamic
if NOT (type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger" OR type(value) = "Float" OR type(value) = "roFloat" OR type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble") then
return Invalid
end if
return value * value
end function
' Check for the existence of a given sub string
' @since 0.0.21
' @category String
' @param {String} value The string to search
' @param {String} subString The sub string to search for
' @returns {Boolean} Results of the search
function stringIncludes(value as String, subString as String) as Boolean
return value.Instr(subString) > -1
end function
' Finds the sub string index position
' @since 0.0.21
' @category String
' @param {String} value The string to search
' @param {String} subString The sub string to search for
' @returns {Integer} Results of the search
function stringIndexOf(value as String, subString as String) as Integer
return value.Instr(subString)
end function
' Subtract two numbers.
' @since 0.0.21
' @category Math
' @param {Integer} minuend - The first number in a subtraction
' @param {Integer} subtrahend - The second number in a subtraction
' @returns {Integer} Returns the difference.
function subtract(minuend as Dynamic, subtrahend as Dynamic) as Dynamic
if (NOT (type(minuend) = "Integer" OR type(minuend) = "roInt" OR type(minuend) = "roInteger" OR type(minuend) = "LongInteger" OR type(minuend) = "Float" OR type(minuend) = "roFloat" OR type(minuend) = "Double" OR type(minuend) = "roDouble" OR type(minuend) = "roIntrinsicDouble")) OR (NOT (type(subtrahend) = "Integer" OR type(subtrahend) = "roInt" OR type(subtrahend) = "roInteger" OR type(subtrahend) = "LongInteger" OR type(subtrahend) = "Float" OR type(subtrahend) = "roFloat" OR type(subtrahend) = "Double" OR type(subtrahend) = "roDouble" OR type(subtrahend) = "roIntrinsicDouble"))
return 0
end if
return minuend - subtrahend
end function
' Computes the sum of the values in an array.
' @since 0.0.21
' @category Math
' @param {Array} array - The array to sum
' @returns {Integer} Returns the sum of the values in the array
function sum(array as Object)
if NOT (type(array) = "roArray") then
return 0
end if
sumValue = 0
for each item in array
sumValue += item
end for
return sumValue
end function
' This method is like `sum` except that it accepts `iteratee` which is invoked for each element in array to generate the value to be summed.
' The iteratee is invoked with one argument: (value).
' @since 0.0.21
' @category Math
' @param {Array} array - The array to iterate over
' @param {Function} iteratee - The iteratee invoked per element
' @returns {Integer} Returns the sum
function sumBy(array = CreateObject("roArray", 0, true) as Object, iteratee = Invalid) as Dynamic
if isEmpty(array) then
return Invalid
end if
sumValue = Invalid
if (type(iteratee) = "<uninitialized>" OR iteratee = Invalid) then
sumValue = 0
for each value in array
sumValue += value
end for
else if isFunction(iteratee) AND (type(array[0]) = "roAssociativeArray") then
sumValue = 0
for each value in array
sumValue += iteratee(value)
end for
else if (type(iteratee) = "String" OR type(iteratee) = "roString") AND (type(array[0]) = "roAssociativeArray") then
sumValue = 0
for each value in array
sumValue += value[iteratee]
end for
end if
return sumValue
end function
' Creates a slice of array with n elements taken from the beginning
' @since 0.0.21
' @category Array
' @param {Array} array - The sorted array to query
' @param {Integer} n - The number of elements to take
' @returns {Object} Returns the slice of array
function take(array = CreateObject("roArray", 0, true) as Object, n = Invalid as Dynamic) as Object
if (type(n) = "<uninitialized>" OR n = Invalid) then
n = 1
end if
if NOT (type(array) = "roArray" AND NOT array.isEmpty()) OR n = 0 then
return CreateObject("roArray", 0, true)
end if
return slice(array, 0, n)
end function
' Creates a slice of array with n elements taken from the end
' @since 0.0.21
' @category Array
' @param {Array} array - The sorted array to query
' @param {Integer} n - The number of elements to take
' @returns {Object} Returns the slice of array
function takeRight(array = CreateObject("roArray", 0, true) as Object, n = Invalid as Dynamic) as Object
if (type(n) = "<uninitialized>" OR n = Invalid) then
n = 1
end if
if NOT (type(array) = "roArray" AND NOT array.isEmpty()) OR n = 0 then
return CreateObject("roArray", 0, true)
end if
length = array.count()
startPos = length - n
if startPos < 0 then
startPos = 0
end if
return slice(array, startPos, length)
end function
' Invokes the iteratee n times, returning an array of the results of each invocation. The iteratee is invoked with one argument; (index).
' @since 0.0.24
' @category Utils
' @param {Integer} n - The number of times to invoke iteratee.
' @param {Function} iteratee - The function invoked per iteration.
' @returns {Array} Returns the array of results.
' @example
' rodash.times(3, rodash.toString) ' => ["0", "1", "2"]
' rodash.times(4, rodash.isNumber) ' => [true, true, true, true]
' rodash.times(4, rodash.isString) ' => [false, false, false, false]
function times(n = 0 as Integer, iteratee = Invalid as Dynamic) as Object
returnArray = CreateObject("roArray", 0, true)
if NOT (type(n) = "Integer" OR type(n) = "roInt" OR type(n) = "roInteger" OR type(n) = "LongInteger") then
return returnArray
end if
for i = 0 to n - 1
returnArray.push(iteratee(i))
end for
return returnArray
end function
' Attempts to convert the supplied value to a array.
' @since 0.0.21
' @category Lang
' @todo Add more support for other types.
' @param {Dynamic} value The value to convert.
' @returns {Object} Results of the conversion.
function toArray(input as Dynamic) as Object
arr = CreateObject("roArray", 0, true)
inputType = type(input)
if (inputType = "roAssociativeArray") then
' Get values from associative array
for each key in input.keys()
arr.push(input[key])
end for
else if (inputType = "String" OR inputType = "roString") then
arr = input.split("")
else
' For anything else (numbers, invalid), return an empty array
arr = CreateObject("roArray", 0, true)
end if
return arr
end function
' Converts a date object to an ISO string
' @since 0.0.21
' @category Date
' @returns {String} Returns the date object as an ISO string
function toISOString(dateObj = Invalid as Dynamic) as String
if ((type(dateObj) = "roDateTime")) then
return ""
end if
return dateObj.toISOString()
end function
' Attempts to convert the supplied value into a valid number
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The variable to be converted
' @returns {Dynamic} Results of the conversion
' @example
' rodash.toNumber("1") // => 1
' rodash.toNumber("1.0") // => 1.0
' rodash.toNumber(1) // => 1
' rodash.toNumber(1.0#) // => 1.0
' rodash.toNumber(true) // => 1
' rodash.toNumber(false) // => 0
function toNumber(value as Dynamic) as Dynamic
if (type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger" OR type(value) = "Float" OR type(value) = "roFloat" OR type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble") then
return value
else if (type(value) = "Boolean" OR type(value) = "roBoolean") then
if value then
return 1
end if
return 0
end if
if (type(value) = "String" OR type(value) = "roString") then
' TODO: Temporary fix until we figure a better way to avoid val converting 8037667 to 8.03767e+06
if (value.Instr(".") > -1) then
return val(value)
else
return val(value, 10)
end if
end if
return 0
end function
' Creates an array of own enumerable string keyed-value pairs for object which can be consumed by rodash.fromPairs. If object is a map or set, its entries are returned.
' @since 0.0.24
' @category Array
' @param {Object} obj - The object to query.
' @returns {Array} Returns the key-value pairs.
' @example
' rodash.toPairs({ 'a': 1, 'b': 2 }) // => [['a', 1], ['b', 2]]
' rodash.toPairs({ 'a': 1, 'b': 2, 'c': 3 }) // => [['a', 1], ['b', 2], ['c', 3]]
function toPairs(obj = CreateObject("roAssociativeArray") as Object) as Object
returnArray = CreateObject("roArray", 0, true)
if NOT (type(obj) = "roAssociativeArray") then
return returnArray
end if
for each key in obj.keys()
returnArray.push([
key
obj[key]
])
end for
return returnArray
end function
' Attempts to convert the supplied value to a string.
' @since 0.0.21
' @category Lang
' @param {Dynamic} value The value to convert.
' @returns {String} Results of the conversion.
' @example
' rodash.toString(1) // => "1"
' rodash.toString(1.0#) // => "1.0"
' rodash.toString(true) // => "true"
' rodash.toString(false) // => "false"
function toString(value as Dynamic) as String
if (type(value) = "String" OR type(value) = "roString") then
return value
end if
if (type(value) = "Integer" OR type(value) = "roInt" OR type(value) = "roInteger" OR type(value) = "LongInteger" OR type(value) = "Float" OR type(value) = "roFloat" OR type(value) = "Double" OR type(value) = "roDouble" OR type(value) = "roIntrinsicDouble") then
return (value.toStr())
end if
if isNode(value) then
return internal_nodeToString(value)
end if
if (type(value) = "Boolean" OR type(value) = "roBoolean") then
return internal_booleanToString(value)
end if
if (type(value) = "roAssociativeArray") then
return internal_aaToString(value)
end if
if (type(value) = "roArray") then
return internal_arrayToString(value)
end if
return ""
end function
' Creates an array of unique values, in order, from all given arrays using SameValueZero for equality comparisons.
' @since 0.0.21
' @category Array
' @param {Array} arrays - The arrays to inspect
' @returns {Object} Returns the new array of combined values
' @example
' rodash.union([[2], [1, 2]]) // => [2, 1]
' rodash.union([[2], [1, 2], [2, 3]]) // => [2, 1, 3]
function union(arrays = CreateObject("roArray", 0, true) as Object) as Object
return uniq(flattenDeep(arrays))
end function
' Creates a duplicate-free version of an array, using SameValueZero for equality comparisons, in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the array.
' @since 0.0.21
' @category Array
' @param {Array} array - The array to inspect
' @returns {Object} Returns the new duplicate free array
function uniq(array = CreateObject("roArray", 0, true) as Object) as Object
returnArray = CreateObject("roArray", 0, true)
table = CreateObject("roAssociativeArray")
for each item in array
key = item.toStr()
if NOT table.doesExist(key)
returnArray.push(item)
table[key] = true
end if
end for
return returnArray
end function
' Creates a duplicate-free version of an array, in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the array.
' By default, when comparing arrays and associative arrays the function will compare the values on the elements. If the strict parameter is set to true, the function will compare the references of the AA and Array elements.
' @since 0.0.29
' @category Array
' @param {Array[]} array - The arrays to inspect
' @param {Boolean} strict - If true, the function will compare the references of the AA and Array elements
' @returns {Array} Returns the new array of filtered values.
' @example
' rodash.xor([[2, 1], [2, 3]]) // => [1, 3]
' rodash.xor([[2, 1], [2, 3], [2, 3]]) // => [1]
function xor(arrays as Object, strict = false as Object) as Object
' Create an array to store the result of the XOR operation (elements with count 1)
resultArray = []
removeArray = []
for each array in arrays
for each item in array
' If the item is not in the result array, add it
if findIndex(resultArray, item, 0, strict) = -1
resultArray.push(item)
else
' If the item is already in the result array, remove it
removeArray.push(item)
end if
end for
end for
while removeArray.count() > 0
' Remove the first occurrence of the item in removeArray from resultArray
resultArray.delete(findIndex(resultArray, removeArray[0]))
' Remove the first item from removeArray
removeArray.delete(0)
end while
return resultArray
end function
' Creates an array of grouped elements, the first of which contains the first elements of the given arrays, the second of which contains the second elements of the given arrays, and so on.
' @since 0.0.21
' @category Array
' @param {Array} arrays - The property identifiers
' @returns {Object} Returns the new array of grouped elements
function zip(arrays = CreateObject("roArray", 0, true) as Object) as Object
arrayCount = arrays.count()
returnArray = CreateObject("roArray", arrayCount, true)
for i = 0 to arrayCount - 1
array = arrays[i]
for ii = 0 to array.count() - 1
if (type(returnArray[ii]) = "<uninitialized>" OR returnArray[ii] = Invalid) then
returnArray[ii] = CreateObject("roArray", 0, true)
end if
returnArray[ii].push(array[ii])
end for
end for
return returnArray
end function
' This method is like rodash.fromPairs except that it accepts two arrays, one of property identifiers and one of corresponding values.
' @since 0.0.21
' @category Array
' @param {Array} array - The property identifiers
' @param {Array} values - The property values
' @returns {Object} Returns the new object
function zipObject(props = CreateObject("roArray", 0, true) as Object, values = CreateObject("roArray", 0, true) as Object) as Object
returnObject = CreateObject("roAssociativeArray")
for i = 0 to props.count() - 1
returnObject[props[i]] = values[i]
end for
return returnObject
end function
' This method is like rodash.zipObject except that it supports property paths.
' @ignore
' @category Array
' @param {Array} array - The property identifiers
' @param {Array} values - The property values
' @returns {Object} Returns the new object
function zipObjectDeep(props = CreateObject("roArray", 0, true) as Object, values = CreateObject("roArray", 0, true) as Object) as Object
' COME BACK
end function
Source