opts
The contract an options table is held to. A call that reads a fixed set of keys acts on those keys and no others, so a key it does not know names a change the caller asked for and never got — a cube asked for `size = 3` that comes back one unit wide, reporting success. `Opts.chec…
opts
The contract an options table is held to. A call that reads a fixed set of
keys acts on those keys and no others, so a key it does not know names a
change the caller asked for and never got — a cube asked for size = 3 that
comes back one unit wide, reporting success. Opts.check makes that a refusal
carrying what to write instead: the key, the accepted set, and the nearest
accepted spelling.
The same three parts answer for a name of any kind — tools.use names the
near-miss toolbox, MaterialAuthor names the near-miss shader property — so
the distance search lives here too, and every caller ranks candidates the same
way.
Pure Luau, no engine dependencies.
Exports
Opts.check(where: string, value: any, accepted: { string }, inTable?: string)— raise unless every key ofvalueis named byaccepted.nilaccepts.Opts.forward(where: string, own: { string }, fn, ...) -> ...— callfn(...), and when it refuses an option, append the vocabularywhereitself takes.Opts.unknown(value, accepted) -> { string }— the keysvaluecarries thataccepteddoes not name, sorted.Opts.nearest(key: string, candidates: { string }) -> string?— the candidatekeyis most plausibly a misspelling of, or nil.Opts.editDistance(a: string, b: string, limit: number) -> number— single-character edits between two names, capped atlimit + 1.
Usage
local Opts = require("@builtin::modules.opts")
-- The keys this call reads, named once.
local CUBE_OPTS = { "animate", "scale" }
function M.cube(name, x, y, z, opts)
Opts.check("primitives.cube", opts, CUBE_OPTS)
-- primitives.cube: unknown option 'scail'. Accepted: animate, scale. Did you mean 'scale'?
-- The spawn target is handed to `entity.spawn`, so it is that call's
-- contract a key is checked against — `own` says what this one takes.
local e = Opts.forward("primitives.cube", { "opts.scale", "opts.animate" }, entity.spawn, name)
-- entity.spawn: unknown option 'size'. Valid options: name, hidden, …
-- (primitives.cube itself takes: opts.scale, opts.animate)
end
A call taking more than one table names which one the key was written in:
Opts.check("primitives.ground", color, { "r", "g", "b", "a" }, "color")
-- primitives.ground: unknown option 'red' in color. Accepted: r, g, b, a. Did you mean 'r'?
Notes
- Refusals raise at level 0: the message is the whole error, so a caller reads the contract rather than the line inside the library that checked it.
- A key of any type is reported by how it is written, so the positional form of
a named shape (
{ 200, 50, 50 }for{ r = , g = , b = }) names its indices rather than passing as a table with nothing the call reads. nearestis case-insensitive, and a candidate containing the key scores by how much longer it is, soroughnesprefersroughnessoverclearcoat_roughness. How far a plain misspelling may stray scales with the key's own length — a four-letter key admits two edits, a longer one three — so a short key is not answered with an unrelated short name.- Equal scores go to the shorter candidate, then the alphabetically earlier one, so the answer never depends on the order candidates were listed in.
forwardmatches the phrase both this module and the engine's own option checks use for the condition (unknown option '<key>'). Every other error passes through as raised.
Scoped to this part · feeds back into the world's score.