API Reference
Disclaimer: These are not the official docs and the new functions are not available for use. It would be nice if someone helped me add them though.
Types
Array
type Array<Value> = {[number]: Value}
A table with values of type Value and numeric keys 1..n with no gaps
Args
type Args<Value> = {[number]: Value}
A table with values of type Value and numeric keys, possibly with gaps.
Map
Map<Key, Value> = {[Key]: Value}
A table with keys of type Key and values of type Value
Set
type Set<Key> = {[Key]: boolean}
A table with keys of a fixed type Key and a boolean value representing membership of the set (default is false)
Table
type Table = {[any]: any}
A table of any type
Class
type Class<Object> = {
new: () -> Object
}
A class has a constructor returning an instance of Object type
Handlers
Some functions such as filter will require handlers. There will be a Key
and Value
type to denote whether the key or value argument is passed first, but they are both any
type unless otherwise specified.
AnyFunction
type AnyFunction = (...any) -> any
Represents a function which takes any arguments and returns any value
Tables
These utilities operate on Tables of any kind.
all
type AllHandler = (Value, Key) -> boolean
all(input: types.Table, handler: AllHandler?): boolean
Iterates through all elements of the input Table.
Calls the handler for each entry and returns false
if the handler returns falsy for any element which it is called with. Otherwise, all elements were truthy so return true
.
If the handler is not provided, use the truthiness of the values in the table.
Examples
-- These are the only falsy values in Lua
Dash.all({nil, false}) --> false
Dash.all({true, 0, "0"}) --> true
-- Do all words start with 'ro'?
Dash.all(
{"roblox", "roact", "rodux"},
function(word) return Dash.startsWith(word, "ro")
end)
--[[
Output: true
]]
collect
type CollectHandler = (Key, Value) -> (any, any)?
collect(input: Types.Table, handler: CollectHandler): Types.Map<any, any>
Collect returns a new Table derived from input by iterating through its pairs and calling
the handler on each (key, value)
tuple.
The handler should return a new (newKey, value)
tuple to be inserted into the returned Table,
or nil
if no value should be added.
Example
-- Invert keys and values of a table
Dash.collect({a = "1", b = "2", c = 3}, function(key, value)
return value, key
end)
--[[
Output: {
[3] = "c"
["1"] = "a",
["2"] = "b",
}
]]
collectArray
type CollectHandler<Key, Value, NewValue> = (key: Key, value: Value) -> NewValue?
collectArray<Key, Value, NewValue>(input: { [Key]: Value }, handler: CollectHandler<Key, Value, NewValue>): { NewValue }
Collect returns a new array derived from input by iterating through its pairs and calling
the handler on each (key, value)
tuple.
The handler should return a new value to be pushed onto the end of the result array, or nil
if no value should be added.
Example
-- Double all elements, ignoring results that are multiples of three
Dash.collectArray({1, 2, 3, 4, 5, 6}, function(key, value)
local newValue = value * 2
return if newValue % 3 == 0 then nil else newValue
end)
--[[
Output: {
[1] = 2,
[2] = 4,
[3] = 8,
[4] = 10
}
]]
collectSet
type CollectHandler<Key, Value, NewValue> = (key: Key, value: Value) -> NewValue?
collectSet<Key, Value, NewValue>(
input: { [Key]: Value },
handler: CollectHandler<Key, Value, NewValue>?
): Types.Set<Value | NewValue>
Build a set from the entries of the input Table, calling handler on each entry and using the returned value as an element to add to the set.
If handler is not provided, values of input
are used as elements.
Examples
-- Convert array to Set
Dash.collectSet({"toast", "bagel", "donut"})
--[[
Output: {
["bagel"] = true,
["donut"] = true,
["toast"] = true
}
]]
-- Create set of first letters of each word
Dash.collectSet({"toast", "bagel", "donut", "bread"}, function(key, value)
return value:sub(1, 1)
end)
--[[
Output: {
["b"] = true,
["d"] = true,
["t"] = true
}
]]
copy
copy(input: Types.Table): Types.Table
Returns a shallow copy of the input Table.
Example
Dash.copy({a = 1, b = 3})
--[[
Output: {
["a"] = 1,
["b"] = 3
}
]]
count
type CountHandler<Key, Value> = (Value, Key) -> boolean
count<Key, Value>(input: { [Key]: Value }, handler: CountHandler<Key, Value>?): number
If no handler is provided, return the number of elements in the input Table.
If the handler is provided, increase the count for each element for which the handler returns true on the (value, key)
pair.
Examples
Dash.count({1, 2, 3, 4, 5}) --> 5
-- Count the number of ids that start with 1
Dash.count(
{[12] = true, [24] = true, [153] = true, [199] = true},
function(value, id) return tostring(id):sub(1, 1) == "1"
end)
--[[
Output: 3
]]
-- Count the number of numbers divisible by 5
Dash.count(
{1, 1, 2, 3, 5, 8, 13, 21, 34, 55},
function(num) return num % 5 == 0
end)
--[[
Output: 2
]]
filter
type FilterHandler<Key, Value> = (Value, Key) -> boolean
filter<Key, Value>(input: { [Key]: Value }, handler: FilterHandler<Key, Value>): { Value }
Filter the input Table by calling the handler on each (value, key)
tuple.
For an array input, the order of elements is preserved in the output.
The handler should return truthy to preserve the value in the resulting Table.
Example
-- Take only the elements whose values begin with "r"
Dash.filter(
{place = "roblox", packages = "rotriever", ide = "studio"},
function(word) return Dash.startsWith(word, "r")
end)
--[[
Output: {
[1] = "roblox",
[2] = "rotriever"
}
]]
find
type FindHandler<Key, Value> = (Value, Key) -> boolean
find<Key, Value>(input: { [Key]: Value }, handler: FindHandler<Key, Value>): Value?
Returns an element in the input Table that the handler returns true
for, when passed the
(value, key)
entry.
Returns nil if no entries satisfy the condition.
For an array, this first matching element is returned. For a Map, an arbitrary matching element is returned if it exists.
Examples
-- Check if there's the "ExtraSettings" key and get the value of that key if so
Dash.find(
{Id = 145, IsReady = false, ExtraSettings = {AutoReady = true}},
function(value, key) return key == "ExtraSettings" end
)
--[[
Output: {
["AutoReady"] = true
}
]]
Dash.find({Id = 145, IsReady = false},
function(value, key) return key == "ExtraSettings" end
)
--[[
Output: nil
]]
forEach
type ForEachHandler<Key, Value> = (Value, Key) -> ()
forEach<Key, Value>(input: { [Key]: Value }, handler: ForEachHandler<Key, Value>)
Iterates through the elements of the input Table.
If the table is an array, it iterates in order 1..n.
If the table is a Map, the keys are visited in an arbitrary order.
Calls the handler for each entry.
Example
-- Print all values of table
Dash.forEach({"Item 1", "Item 2", "Item 3"}, function(value) print(value) end)
--[[
Output: Item 1
Item 2
Item 3
]]
frequencies
type FrequenciesHandler<Key, Value, NewKey> = (Value, Key) -> NewKey
frequencies<Key, Value, NewKey>(
input: { [Key]: Value },
handler: FrequenciesHandler<Key, Value, NewKey>?
): { [NewKey | Value]: number }
If no handler is provided, returns a Map with keys as unique values of the input Table and values as the count of each value.
If a handler is provided, returns a Map with keys as unique elements given by the handler and values as the count of each mapped key.
Examples
Dash.frequencies({"Red", "Black", "Orange", "Red"})
--[[
Output:{
["Black"] = 1,
["Orange"] = 1,
["Red"] = 2
}
]]
-- Count colors by simple definition of neutral and non-neutral
function toNeutral(color)
return if Dash.includes({"Black", "Gray", "White"}, color)
then "Neutral"
else "Non-neutral"
end
Dash.frequencies(
{"Black", "Orange", "Blue", "Gray", "White"},
function(color) return toNeutral(color)
end)
--[[
Output: {
["Neutral"] = 3,
["Non-neutral"] = 2
}
]]
groupBy
type GroupByHandler<Key, Value, GroupKey> = (Value, Key) -> GroupKey
groupBy<Key, Value, GroupKey>(
input: { [Key]: Value },
getKey: GroupByHandler<Key, Value, GroupKey> | GroupKey
): { [GroupKey]: { Value } }
Groups values in the input Table by their getKey value.
Each value of the result Table is an array of values from the input Table which were assigned the corresponding key.
If getKey is a function, it is called with each (value, key)
entry and uses the return
value as the corresponding key to insert at in the result Table. Otherwise, the getKey value
is used directly as the key itself.
Example
local output = groupBy({
bike = {
name = "bike",
color = "blue"
},
car = {
name = "car",
color = "red"
},
van = {
name = "van",
color = "white"
},
ghost = {
name = "ghost"
}
}, "color")
--[[
Output: {
blue = {
{
color = "blue",
name = "bike"
}
},
red = {
{
color = "red",
name = "car"
}
},
white = {
{
color = "white",
name = "van"
}
}
}
]]
includes
includes(source: Types.Table, value: any): boolean
Returns true if the item exists as a value in the source Table.
Example
-- Does the table include 100?
Dash.includes({1, 10, 100, 1000}, 100)
--[[
Output: true
]]
See
For a stronger version of Dash.includes
, use Dash.some.
keyBy
type KeyByHandler<Key, Value, NewKey> = (Value, Key) -> NewKey
keyBy<Key, Value, NewKey>(input: { [Key]: Value }, getKey: KeyByHandler<Key, Value, NewKey> | NewKey): { [NewKey]: Value }
Assigns values in the input Table by their getKey value.
If getKey is a function, it is called with each (value, key)
entry and uses the return
value as the corresponding key to assign to in the result Table. Otherwise, the getKey value
is used directly as the key itself.
Example
local output = keyBy({
bike = {
name = "bike",
color = "blue"
},
car = {
name = "car",
color = "red"
},
van = {
name = "van",
color = "white"
},
ghost = {
name = "ghost"
}
}, "color")
[[
Output: {
blue = {
color = "blue",
name = "bike"
},
red = {
color = "red",
name = "car"
},
white = {
color = "white",
name = "van"
}
}]]
keys
keys<Key, Value>(input: { [Key]: Value }): { Key }
Returns an array of the keys in the input Table.
If the input is an array, ordering is preserved.
If the input is a Map, elements are keys in an arbitrary order.
Example:
Dash.keys({
Color = "Purple",
Type = "Fruit",
Shape = "Round"
})
--[[
Output: {
[1] = "Color",
[2] = "Type",
[3] = "Shape"
}
]]
map
type MapHandler<Key, Value, NewValue> = (Value, Key) -> NewValue
map<Key, Value, NewValue>(input: { [Key]: Value }, handler: MapHandler<Key, Value, NewValue>): { [Key]: NewValue }
Iterates through the elements of the input Table.
For an array input, the elements are visited in order 1..n.
For a Map input, the elements are visited in an arbitrary order.
Calls the handler for each entry and constructs a new Table using the same keys but replacing the values with new ones returned from the handler.
Values returned by handler must be defined.
Example
-- Map characters to their ASCII
Dash.map({"a", "b", "c"}, function(char) return string.byte(char) end)
--[[
Output: {
[1] = 97,
[2] = 98,
[3] = 99
}
]]
See
- Dash.collectArray if you want to return nil values.
mapOne
type MapHandler<Key, Value, NewValue> = (Value, Key) -> NewValue?
mapOne<Key, Value, NewValue>(input: { [Key]: Value }, handler: MapHandler<Key, Value, NewValue>?): NewValue?
Iterates through the elements of the input Table in no particular order.
Calls the handler for each entry and returns the first non-nil value returned by the handler.
If all returned from the handler values are nil
, nil
is returned.
If handler is nil
, the first value visited is returned.
Example
-- Get any message that's not hidden and return its id.
Dash.mapOne({
{Id = 1, IsHidden = true},
{Id = 3, IsHidden = false},
{Id = 2, IsHidden = false},
}, function(message)
return if message.IsHidden then nil else message.Id
end)
--[[
Output: 3
]]
max
type MaxComparator = (any, any) -> boolean
type MaxHandler = (Value, Key) -> any
max(input: Types.Table, handler: MaxHandler?, comparator: MaxComparator): any
Returns the maximum value in the input Table. By default, this returns the greatest value in the table as defined by the >
operator.
If a handler is provided, elements will first be transformed by handler(value, key)
before being used for comparison.
Elements will be compared using the comparator if it is provided. The comparator should take two elements and return true
if the first one is greater than the second one, and false
otherwise.
If the provided input has no elements, return nil
.
Examples
Dash.max({1, 2, 3}) --> 3
Dash.max({"1", "2", "10"}) --> "2"
Dash.max({1, 2, 3}, function(num) return -num end) --> 1
Dash.max(
{"blue", "red", "orange"},
nil,
function(word1, word2) return word1:len() > word2:len() end
) --> "orange"
memoize
type ResolverFunction = (...any) -> string
memoize(func: Types.AnyFunction, resolver: ResolverFunction?): Types.AnyFunction
Creates a function that memoizes the result of func
. The memoized function will cache results based on the arguments provided. If a resolver function is provided, it will be used to generate the cache key from the arguments.
Examples
local function add(a, b)
return a + b
end
local memoizedAdd = memoize(add)
print(memoizedAdd(1, 2)) -- Calculates and caches: 3
print(memoizedAdd(1, 2)) -- Returns from cache: 3
-- With custom resolver
local memoizedWithResolver = memoize(add, function(a, b)
return string.format("%d_%d", a, b)
end)
Usage
- Use memoization for expensive computations that are called frequently with the same arguments
- The resolver function can be used to customize how arguments are used to generate cache keys
- Be mindful of memory usage as cached results are stored indefinitely
min
type MinComparator = (any, any) -> boolean
type MinHandler = (Value, Key) -> any
min(input: Types.Table, handler: MinHandler?, comparator: MinComparator): any
Returns the minimum value in the input Table. By default, this returns the least value in the table as defined by the <
operator.
If a handler is provided, elements will first be transformed by handler(value, key)
before being used for comparison.
Elements will be compared using the comparator if it is provided. The comparator should take two elements and return true
if the first one is less than the second one, and false
otherwise.
If the provided input has no elements, return nil
.
Examples
Dash.min({1, 2, 3}) --> 1
Dash.min({"2", "20", "10"}) --> "10"
Dash.min({3, 2, 1}, function(num) return -num end) --> 3
Dash.min(
{"blue", "red", "orange"},
nil,
function(word1, word2) return word1:len() < word2:len() end
) --> "red"
omit
omit<Key, Value>(input: { [Key]: Value }, keys: { Key }): { [Key]: Value }
Return a new Table made from entries in the input Table whose key is not in the keys array.
If the input is an array, ordering is preserved.
If the input is a Map, elements are returned in an arbitrary order.
Example
-- Remove the ShouldShow key/value pair from the table
Dash.omit({
ShouldShow = true,
Text = "Hello World!",
Title = "Greetings!",
}, {"ShouldShow"})
--[[
Output: {
["Text"] = "Hello World!",
["Title"] = "Greetings!"
}
]]
pick
type PickHandler<Key, Value> = (Value, Key) -> boolean
pick<Key, Value>(input: { [Key]: Value }, handler: PickHandler<Key, Value>): { [Key]: Value }
Pick entries in the input Table which should remain in the output by calling the handler on
each (child, index)
tuple.
The handler should return truthy to preserve the value in the resulting Table.
Examples
Dash.pick(
{10, 20, 30, 40, 50, 60},
function(value, _) return value % 20 == 0 end
)
--[[
Output: {
[2] = 20,
[4] = 40,
[6] = 60
}
]]
reduce
type ReduceHandler<Key, Value, Accumulator> = (Accumulator, Value, Key) -> Accumulator
reduce<Key, Value, Accumulator>(
input: { [Key]: Value },
handler: ReduceHandler<Key, Value, Accumulator>,
initial: Accumulator
): Accumulator
Iterate through the elements of the input Table, preserving order if it is an array.
Call the handler for each element, passing the return of the previous call as the first argument.
The initial value is passed into the first call, and the final value returned by the function.
Examples
-- Count occurences of each element in array and output a table of counts
-- See Dash.frequencies
Dash.reduce(
{"Red", "Black", "Red", "Red", "Black"},
function(acc, color)
if acc[color] == nil then
acc[color] = 1
else
acc[color] += 1
end
return acc
end, {}
)
--[[
Output: {
["Black"] = 2,
["Red"] = 3
}
]]
-- Sum up elements, doubling even indices and halving odd indices
-- Expected: 0.5 + 4 + 1.5 + 8 + 2.5 = 16.5
Dash.reduce(
{1, 2, 3, 4, 5},
function(acc, num, index)
return acc + if index % 2 == 0 then num * 2 else num / 2
end, 0
)
--[[
Output: 16.5
]]
shallowEqual
shallowEqual(left: any, right: any): boolean
Returns true
if the left and right values are equal (by the equality operator) or the
inputs are tables, and all their keys are equal.
Examples
Dash.shallowEqual({
A = 1,
B = 2
}, {
A = 1,
B = 2,
})
--[[
Output: true
]]
Dash.shallowEqual({
A = 1,
B = 2,
C = 3
}, {
A = 1,
B = 2,
D = 3
})
--[[
Output: false
]]
some
type SomeHandler<Key, Value> = (Value, Key) -> boolean
some<Key, Value>(input: { [Key]: Value }, handler: SomeHandler<Key, Value>): boolean
Iterates through the elements of the input Table in no particular order.
Calls the handler for each entry and returns true
if the handler returns truthy for any
element which it is called with.
Example
-- Does there exist a red fruit?
Dash.some(
{
{Type = "Cherry", Color = "Red"},
{Type = "Strawberry", Color = "Red"},
{Type = "Blueberry", Color = "Blue"}
},
function(fruit) return fruit.Color == "Red" end
)
--[[
Output: true
]]
values
values<Key, Value>(input: { [Key]: Value }): { Value }
Returns an array of the values in the input Table.
If the input is an array, ordering is preserved.
If the input is a Map, values are returned in an arbitrary order.
Example
Dash.values({
Type = "Cherry",
Color = "Red",
Price = "Expensive",
EnjoymentLevel = "High"
})
--[[
Output: {
[1] = "Red",
[2] = "Cherry",
[3] = "High",
[4] = "Expensive"
}
]]
Arrays
These utilities operate on arrays, tables with ordered keys 1..n.
append
append<T>(target: { T }, ...: { T }): { T }
Adds new elements to the target array from subsequent array arguments in left-to-right order.
Arguments which are nil
or None are skipped.
Example
Dash.append({1, 2}, {3, 4}, {5})
--[[
Output: {
[1] = 1,
[2] = 2,
[3] = 3,
[4] = 4,
[5] = 5
}
]]
findIndex
type FindHandler<Value> = (Value, number) -> boolean
findIndex<Value>(input: { Value }, handler: FindHandler<Value>): number?
Returns the index of the first element in the input array that the handler returns true
for,
when passed the (value, key)
entry.
Returns nil if no entries satisfy the condition.
Examples
-- Find index of "Clementine" fruit if it exists in the array
Dash.findIndex(
{"Apple", "Banana", "Clementine"},
function(fruit) return fruit == "Clementine" end
)
--[[
Output: 3
]]
Dash.findIndex(
{"Apple", "Banana"},
function(fruit) return fruit == "Clementine" end
)
--[[
Output: nil
]]
flat
flat(input: { any }): { any }
Flattens the input array by a single level. Outputs a new array of elements merged from the input array arguments in left-to-right order.
Example
-- Flatten a partition of numbers in the range 1-5
Dash.flat({
{1, 2, 3},
{4, 5}
})
--[[
Output: {
[1] = 1,
[2] = 2,
[3] = 3,
[4] = 4,
[5] = 5
}
]]
last
type FindHandler<Value> = (Value, number) -> boolean
last<Value>(input: { Value }, handler: FindHandler<Value>?): Value?
Returns the last element in the input array that the handler returns true
for, when
passed the (value, key)
entry.
Returns nil if no entries satisfy the condition.
If handler is not defined, the function simply returns the last element of the array.
Examples
Dash.last({3, 2, 1})
--[[
Output: 1
]]
-- Get last odd number
Dash.last({4, 3, 2}, function(num) return num % 2 == 1 end)
--[[
Output: 3
]]
mapFirst
type MapHandler<Value, NewValue> = (Value, number) -> NewValue?
mapFirst<Value, NewValue>(input: { Value }, handler: MapHandler<Value, NewValue>): NewValue?
Iterates through the elements of the input array in order 1..n.
Calls the handler for each entry and returns the first non-nil value returned by the handler.
If all returned from the handler values are nil
, nil
is returned.
Example
-- Get first color that's 6 letters and return its first letter
Dash.mapFirst(
{"Red", "Yellow", "Orange", "Blue"},
function(color)
return if color:len() == 6 then color:sub(1, 1) else nil
end
)
--[[
Output: Y
]]
mapLast
type MapHandler<Value, NewValue> = (Value, number) -> NewValue?
mapLast<Value, NewValue>(input: { Value }, handler: MapHandler<Value, NewValue>): NewValue?
Iterates through the elements of the input array in reverse in order n..1.
Calls the handler for each entry and returns the first non-nil value returned by the handler.
If all returned from the handler values are nil
, nil
is returned.
Example
-- Get last color that's 6 letters and return its first letter
Dash.mapLast(
{"Red", "Yellow", "Orange", "Blue"},
function(color)
return if color:len() == 6 then color:sub(1, 1) else nil
end
)
--[[
Output: O
]]
product
product(input: { number }): number
Multiplies together all the numbers in the input array.
If the input has no elements, return 1
.
Example
Dash.product({3, 3, 2}) --> 18
reverse
reverse<T>(input: { T }): { T }
Reverse the order of the elements in the input array.
Example
Dash.reverse({3, 2, 1})
--[[
Output: {
[1] = 1,
[2] = 2,
[3] = 3
}
]]
slice
slice<T>(input: { T }, left: number?, right: number?): { T }
Return a portion of the input array starting with the element at the left index and ending with the element at the right index (i.e. an inclusive range)
If left is not defined, it defaults to 1. If right is not defined, it defaults to the length of the array (i.e. the last element)
If left is -n
, the slice starts with the element n
places from the last one.
If right is -n
, the slice ends with the element n
places from the last one.
An empty array is returned if the slice has no or negative length.
Examples
Dash.slice({1, 2, 3, 4, 5}, 2, 4)
--[[
Output: {
[1] = 2,
[2] = 3,
[3] = 4
}
]]
Dash.slice({1, 2, 3, 4, 5}, 3)
--[[
Output: {
[1] = 3,
[2] = 4,
[3] = 5
}
]]
Dash.slice({1, 2, 3, 4, 5}, nil, -1)
--[[
Output: {
[1] = 1,
[2] = 2,
[3] = 3,
[4] = 4
}
]]
sum
sum(input: { number }): number
Adds together all the numbers in the input array.
If the input array has no elements, return 0
.
Example
Dash.sum({3, 2, 1}) --> 6
Maps
These utilities operate on Maps, tables with arbitrary keys.
assign
assign<Key, Value>(target: Types.Map<Key, Value>, ...: Types.Map<Key, Value>): Types.Map<Key, Value>
Adds new values to target from subsequent Table arguments in left-to-right order.
Examples
local characters = {
Frodo = {
name = "Frodo Baggins",
team = "blue"
},
Boromir = {
score = 5
}
}
local otherCharacters = {
Frodo = {
team = "red",
score = 10
},
Bilbo = {
team = "yellow",
},
Boromir = {
score = {1, 2, 3}
}
}
local result = assign(characters, otherCharacters)
print(result) --[[
--> {
Frodo = {
team = "red",
score = 10
},
Bilbo = {
team = "yellow"
},
Boromir = {
score = {1, 2, 3}
}
}
]]
See
- Dash.join for an immutable alternative
freeze
freeze(objectName: string, object: Types.Table, throwIfMissing: boolean?): Types.Table
Returns a new read-only view of object which prevents any values from being changed.
Parameters
Name | Description |
---|---|
name |
The name of the object for improved error message readability. |
throwIfMissing |
If true then access to a missing key will also throw. |
Notes
Unfortunately you cannot iterate using pairs
or ipairs
on frozen objects because Luau doesn't support defining these custom iterators in metatables.
Example
local drink = freeze("Ice Cream", {
flavor = "mint",
topping = "sprinkles"
}, true)
print(drink.flavor) --> "mint"
drink.flavor = "vanilla"
--!> ReadonlyKey: Attempt to write to readonly key "flavor" (a string) of frozen object "Ice Cream"
print(drink.syrup) --> nil
--!> MissingKey: Attempt to read missing key "syrup" (a string) of frozen object "Ice Cream"
get
get<T>(object: { [any]: any }, path: { any }, defaultValue: T?): T?
Gets the value at path of object. If the resolved value is nil, the defaultValue is returned in its place.
The path should be an array of keys (e.g. { "a", "b", "c" }
, { "test", "test.test", 0 }
).
Examples
local object = {
a = {
b = {
c = 3
}
}
}
Dash.get(object, { "a", "b", "c" }) --> 3
Dash.get(object, { "x", "y", "z" }, "default") --> "default"
-- Array indexing
local object = {
items = {
{ name = "first" },
{ name = "second" }
}
}
Dash.get(object, { "items", 1, "name" }) --> "first"
-- Keys with dots
local object = {
test = {
["test.test"] = {
[0] = "value"
}
}
}
Dash.get(object, { "test", "test.test", 0 }) --> "value"
See - Dash.getOrSet - for getting a value with a default generator function
getOrSet
type GetValueHandler<Key, Value> = ({ [Key]: Value }, Key) -> Value
getOrSet<Key, Value>(input: { [Key]: Value }, key: Key, getValue: GetValueHandler<Key, Value>): Value
Returns a value of the input Table at the key provided. If the key is missing, the value is acquired from the getValue handler, added to the input Table and returned.
Examples
Dash.getOrSet(
{Item = "Gummy Bear", Color = "Lime"},
"Color",
function() return "Yellow" end
)
--[[
Output: Lime
]]
Dash.getOrSet(
{Item = "Gummy Bear"},
"Color",
function() return "Yellow" end
)
--[[
Output: Yellow
]]
join
join<Key, Value>(...: Types.Map<Key, Value>): Types.Map<Key, Value>
Output a new Map from merging all the keys in the Map arguments in left-to-right order.
Example
Dash.join(
{Text = "Hello World!", Color = "Sky Blue"},
{Title = "Greetings!", Color = "Indigo"}
)
--[[
Output: {
["Color"] = "Indigo",
["Text"] = "Hello World!",
["Title"] = "Greetings!"
}
]]
See
- Dash.assign for a mutable alternative
joinDeep
joinDeep(source: Types.Map<any, any>, delta: Types.Map<any, any>): Types.Map<any, any>
Creates a shallow clone of the source Map, and copies the values from the delta Map by key, like the join utility.
However, if any of the values are tables themselves, the joinDeep function is called recursively to produce a new table at the specified key.
The purpose of this function is to merge nested immutable data using as few table creation operations as possible, making it appropriate for updating state in a reducer.
Usage
- The None symbol can be used to remove an existing value.
Example
local source = {
name = "car",
lights = {
front = 2,
back = 2,
indicators = {
color = "orange"
},
brake = {
color = "red"
}
},
tyres = 4
}
local delta = {
name = "bike",
lights = {
front = 3,
indicators = {
rate = 20
}
},
tyres = None
}
local output = joinDeep(source, delta)
[[
Output: {
lights = {
back = 2,
brake = {
color = "red"
},
front = 3,
indicators = {
color = "orange",
rate = 20
}
},
name = "bike"
}
]]
Strings
These utilities are helpful for working with strings.
endsWith
endsWith(input: string, suffix: string): boolean
Checks if input ends with the string suffix.
Examples
endsWith("Fun Roblox Games", "Games") --> true
endsWith("Bad Roblox Memes", "Games") --> false
isLowercase
isLowercase(input: string): boolean
Returns true
if the first character of input is a lower-case character.
Throws if the input is not a string or it is the empty string.
Our current version of Lua unfortunately does not support upper or lower-case detection outside the english alphabet. This function has been implemented to return the expected result once this has been corrected.
Examples
Dash.isLowercase("abcdef") --> true
Dash.isLowercase("Title") --> false
isUppercase
isUppercase(input: string): boolean
Returns true
if the first character of input is an upper-case character.
Throws if the input is not a string or it is the empty string.
Our current version of Lua unfortunately does not support upper or lower-case detection outside the english alphabet. This function has been implemented to return the expected result once this has been corrected.
Examples
Dash.isUppercase("ABCDEF") --> true
Dash.isUppercase("rObLoX") --> false
leftPad
leftPad(input: string, length: number, prefix: string?): string
Makes a string of length
from input
by repeating characters from prefix
at the start of the string.
Params
prefix
- default =""
Examples
leftPad("toast", 6) --> " toast"
leftPad("2", 2, "0") --> "02"
leftPad("toast", 10, ":)") --> ":):):toast"
rightPad
rightPad(input: string, length: number, suffix: string?): string
Makes a string of length
from input
by repeating characters from suffix
at the end of the string.
By default, suffix is " "
.
Examples
rightPad("toast", 6) --> "toast "
rightPad("2", 2, "!") --> "2!"
rightPad("toast", 10, ":)") --> "toast:):):"
splitOn
splitOn(input: string, pattern: string): { string }
Splits input into parts based on a pattern delimiter and returns a Table of the parts, followed by a Table of the matched delimiters.
Example
local parts, delimeters = Dash.splitOn(
"The quick brown fox jumps over the lazy dog",
" "
)
print(parts)
--[[
Output: {
[1] = "The",
[2] = "quick",
[3] = "brown",
[4] = "fox",
[5] = "jumps",
[6] = "over",
[7] = "the",
[8] = "lazy",
[9] = "dog"
}
]]
print(delimeters)
--[[
{
[1] = " ",
[2] = " ",
[3] = " ",
[4] = " ",
[5] = " ",
[6] = " ",
[7] = " ",
[8] = " "
}
]]
startsWith
startsWith(input: string, prefix: string): boolean
Checks if input starts with the string start.
Examples
startsWith("Fun Roblox Games", "Fun") --> true
startsWith("Chess", "Fun") --> false
trim
trim(input: string): string
Remove any whitespace at the start and end of the input string.
Example
Dash.trim("\n\t\rhello world ") --> "hello world"
Functions
These utilities are helpful for working with functions.
compose
compose(...: { Types.AnyFunction }): Types.AnyFunction
Returns a function that calls the argument functions in left-right order on an input, passing the return of the previous function as argument(s) to the next.
Example
local function fry(item)
return "fried " .. item
end
local function cheesify(item)
return "cheesy " .. item
end
local prepare = compose(fry, cheesify)
prepare("nachos") --> "cheesy fried nachos"
forEachArgs
forEachArgs(handler: Types.AnyFunction, ...: Args<Value>): ()
Iterates through the tail arguments in order, including nil values up to the argument list length.
Calls the handler for each entry.
identity
identity(...)
The identity function, which simply returns its input parameters.
Can be used to make it clear that a handler returns its inputs.
isCallable
isCallable<T>(value: T): boolean
Returns true
if the value can be called i.e. you can write value(...)
.
noop
noop()
A function which does nothing.
Can be used to make it clear that a handler has no function.
chain
chain("test":gmatch("t"), "test":gmatch("e"))
Returns a stateful iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterator, until all the iterators are exhausted.
Classes
These utilities are helpful for working with classes.
Error
Error.new(name: string, message: string, tags: Table?)
Create an error object with a specified name and message.
In native Lua, errors can only be string values. At Roblox, we can take advantage of throwing error objects to provide structured information about problems that occur.
The tags table stores rich information about an error which can be provided when it is thrown, and later passed to a logging endpoint.
Throwing an error instance captures its stack trace, avoiding the need to explicitly use xpcall.
Fields
Name | Description |
---|---|
name: string |
The name of the error |
message: string |
A message which will be formatted with Dash.format if the error is thrown |
tags: Table |
A table to store custom rich information about the error |
stack: string? |
The value of debug.traceback() when the error is thrown |
Methods
Name | Description |
---|---|
:joinTags(tags: Table?) |
Return a new error instance containing the tags provided joined to any existing tags of the current error instance. |
:throw(tags: Table?) |
Throw an error. The stack of the error is captured and stored. If tags are provided, a new error is created and thrown with the joined tags of this instance. |
Static Methods
Name | Description |
---|---|
.new(name: string, message: string, tags: Table?) |
Returns a new Error instance |
.is(other: any) |
Returns true if other is an Error instance |
Usage
In general, errors should not be used during normal control flow.
Symbol
Create a symbol with a specified name. Upper snake-case is recommended as the symbol is a constant, unless you are linking the symbol conceptually to a different string.
Symbols are useful when you want a value that isn't equal to any other type, for example if you want to store a unique property on an object that won't be accidentally accessed with a simple string lookup.
Static Methods
Name | Description |
---|---|
.new(name: string) |
Returns a new unique Symbol instance with called name |
.is(other: any) |
Returns true if other is a Symbol instance |
Example
local CHEESE = Symbol.new("CHEESE")
local FAKE_CHEESE = Symbol.new("CHEESE")
print(CHEESE == CHEESE) --> true
print(CHEESE == FAKE_CHEESE) --> false
print(tostring(CHEESE)) --> "Symbol.new(CHEESE)"
class
Create a class called name with the specified constructor. The constructor should return a
plain table which will be turned into an instance of Class from a call to Class.new(...)
.
Instance Methods
Name | Description |
---|---|
:toString(): string |
Returns a string representation of the class |
:equals(other: any):boolean |
Returns true if the instance is equal to other |
:_init() |
A private function which is called once the instance has been initialized |
Static Methods
Name | Description |
---|---|
.new(...): Table |
Returns a new instance of the class |
.isInstance(value: any): boolean |
Returns true if value is an instance of the class |
Examples
-- Create a simple Vehicle class
local Vehicle = class("Vehicle", function(wheelCount: number) return
{
speed = 0,
wheelCount = wheelCount
}
end)
function Vehicle:drive(speed)
self.speed = speed
end
-- Create a car instance
local car = Vehicle.new(4)
car.wheelCount --> 4
car.speed --> 0
-- Drive the car
car:drive(10)
car.speed --> 10
Usage
- When using Dash classes, private fields should be prefixed with
_
to avoid accidental access. - A private field should only be accessed by a method of the class itself, though Dash does not restrict this in code.
- Public fields are recommended when there is no complex access logic e.g.
position.x
Symbols
Symbol definitions.
None
A symbol representing nothing, that can be used in place of nil as a key or value of a table, where nil is illegal.
Utility functions can check for the None symbol and treat it like a nil value.
Usage
Use cases include:
- Creating an ordered list with undefined values in it
- Creating a map with a key pointing to a nil value
Debugging
These utilities assist with debugging Lua code.
assertEqual
assertEqual(left: any, right: any, formattedErrorMessage: string?): ()
Performs a simple equality check and throws an error if left is not equal to right.
The formatted error message can be customized, which by default provides a serialization of both inputs using Dash.pretty.
The left
and right
values are available to be referenced in the formatted message.
cycles
cycles(value: any, initialCycles: Cycles?): Cycles
Get information about the number of times references to the same table values appear in a data structure.
Operates on cyclic structures, and returns a Cycles object for a given value by walking it recursively.
Cycles
Name | Type | Description |
---|---|---|
omit |
{ any } |
An array of keys which should not be visited |
visited |
Set<Table> |
A set of tables which were visited recursively |
refs |
Map<Table, number> |
A map from table to unique index in visit order |
nextRef |
number |
The number to use for the next unique table visited |
format
format(formatString: string, ...): string
Returns the format string with placeholders {...}
substituted with readable representations
of the subsequent arguments.
This function is a simpler & more powerful version of string.format
, inspired by format!
in Rust.
{}
formats and prints the next argument using:format()
if available, or a suitable default representation depending on its type.{blah}
formats and prints the key "blah" of the 1st argument{2}
formats and prints the 2nd argument.{#2}
prints the length of the 2nd argument. Display parameters can be combined after a:
in the curly braces. Any format parameters used instring.format
can be used here, along with these extras:{:?}
formats any value usingpretty
.{:#?}
formats any value using multilinepretty
.
Examples
local props = {"teeth", "claws", "whiskers", "tail"}
format("{} is in {:#?}", "whiskers", props)
--> [[whiskers is in {"teeth", "claws", "whiskers", "tail"}]]
format("The time is {:02}:{:02}", 2, 4) -> "The time is 02:04"
format("The color blue is #{:06X}", 255) -> "The color blue is #0000FF"
Usage
- Escape
{
with{{
and}
similarly with}}
. - See https://developer.roblox.com/articles/Format-String for complete list of formating options and further use cases.
formatValue
formatValue(value: any, displayString: string): string
Format a specific value using the specified displayString.
Examples
formatValue(255, "06X") --> "0000FF"
formatValue(255.5) --> "255.5"
See
- Dash.format - see format for a full description of valid display strings.
pretty
pretty(object: any, options: PrettyOptions?): string
Return a pretty string serialization of object.
This implementation deals with cycles in tables and can neatly display metatables.
Optionally use an indented multiline string, limit the depth of tables, omit or pick keys.
PrettyOptions
Name | Type | Description |
---|---|---|
depth |
number? |
The maximum depth of ancestors of a table to display |
omit |
{ any }? |
An array of keys which should not be visited |
multiline |
boolean? |
Whether to use multiple lines (default = false) |
noQuotes |
boolean? |
Whether to drop the quotation marks around strings. By default, this is true for table keys |
indent |
string? |
The indent string to use (default = "\t") |
visited |
Set<Table>? |
A set of tables which have already been visited and should be referred to by reference |
cycles |
Cycles? |
A cycles object returned from cycles to aid reference display |
See