TypedArgs
A tiny operator‑typed CLI language for structured data.
TypedArgs is not an option parser.
It is a mini‑language for expressing structured data on the command line — scalars, arrays, hashes, and arrays of hashes — using a small set of explicit, shell‑safe operators.
It runs anywhere MRuby runs: embedded systems, containers, CI runners, Windows, macOS, Linux, BusyBox, Alpine, and fully sandboxed MRuby VMs. No dependencies. No shell tricks. No heuristics. No guessing.
TypedArgs behaves the same everywhere.
Why TypedArgs Exists
Most CLI parsers try to guess what the user meant. TypedArgs refuses.
Shells are inconsistent. Quoting rules differ. JSON on the command line is painful.
Suffix‑typed flags collide with shells. YAML is too heavy.
Users deserve a grammar that is:
- Explicit — the operator defines the shape
- Portable — works in every shell without quoting
- Deterministic — same input, same output, always
- Minimal — four operators, one mental model
- Structured — arrays and hashes are first‑class citizens
TypedArgs is the answer: a tiny algebra of flags.
The Operator Model
TypedArgs is built on four operators.
They define the shape of the value — nothing else is needed.
| Operator | Meaning |
|---|---|
= |
scalar assignment |
+= |
append scalar to array |
:fields:= |
assign hash tuple |
+:fields:= |
append hash tuple to array |
This is the entire language.
No suffixes.
No brackets.
No type inference.
No shell‑sensitive characters.
Just operators.
Installation
TypedArgs is pure Ruby and MRuby‑core‑friendly.
Drop the Ruby files into your MRuby build or load them into your VM.
Basic Usage
args = TypedArgs.opts("--mode=fast", "--debug=true")
args["mode"] # => "fast"
args["debug"] # => true
If no arguments are passed, TypedArgs.opts defaults to ARGV.
You must supply that array yourself in MRuby; see tools/typedargs_test/test.c for an example.
Grammar Overview
TypedArgs defines a small, explicit grammar for keys and values.
Everything is driven by operators.
Scalars
--mode=fast
--count=5
--debug=true
--foo=nil
Values may be:
- strings
- integers
- floats
- booleans (
true/false) nil
Dotted Keys
--db.user=root
--cache.redis.host=localhost
Keys may contain:
- letters
- digits
- underscore
- dash
- dot
Keys may not start with a digit or dash.
Dotted keys are treated as flat strings, not nested hashes.
Arrays (+=)
--item+=a
--item+=b
Result:
{ "item" => ["a", "b"] }
+= always appends.
If the key didn’t exist, an array is created.
Hash Tuples (:fields:=)
--range:min,max:=5,10
Result:
{ "range" => { "min" => 5, "max" => 10 } }
Arity is enforced:
If you declare two fields, you must supply two values.
Arrays of Hashes (+:fields:=)
--servers+:name,port:=alpha,80
--servers+:name,port:=beta,443
Result:
{
"servers" => [
{ "name" => "alpha", "port" => 80 },
{ "name" => "beta", "port" => 443 }
]
}
+: always appends a hash to an array.
Short‑Flag Aliases
TypedArgs.alias("-v", "--verbose")
TypedArgs.opts("-v")
# => { "verbose" => true }
Aliases expand before parsing.
They can target dotted keys and any operator form.
Error Reporting
TypedArgs provides compiler‑style diagnostics with caret indicators.
Example:
--range:min,max:=5
^
Syntax error: Arity mismatch: expected 2, got 1
Every error includes:
- the original argument
- a caret pointing to the exact byte
- a clear error class
TypedArgs is self‑teaching.
Operator Semantics
TypedArgs applies flags in order.
Later flags overwrite earlier ones unless using accumulation operators.
Scalar Assignment (=)
| Syntax | Meaning |
|---|---|
--key=value |
assign scalar |
Overwrites previous value.
Scalar Accumulation (+=)
| Syntax | Meaning |
|---|---|
--key+=value |
append scalar to array |
Creates array if missing.
Overwrites previous non‑array values.
Hash Tuple Assignment (:fields:=)
| Syntax | Meaning |
|---|---|
--key:field1,field2:=v1,v2 |
assign hash |
Overwrites previous value.
Array of Hashes (+:fields:=)
| Syntax | Meaning |
|---|---|
--key+:field1,field2:=v1,v2 |
append hash to array |
Creates array if missing.
Sequential Override Rules
| Sequence | Result |
|---|---|
--foo=1 → --foo+=2 |
[2] |
--foo+=1 → --foo+=2 |
[1,2] |
--foo:min,max:=1,2 → --foo:min,max:=3,4 |
{ "min"=>3,"max"=>4 } |
--foo+:min,max:=1,2 → --foo+:min,max:=3,4 |
[{"min"=>1,"max"=>2},{"min"=>3,"max"=>4}] |
--foo=1 → --foo+=2 → --foo:name:=alpha → --foo=bar |
"bar" |
TypedArgs is explicit:
the operator determines the shape.
Conformance Suite
TypedArgs ships with a full conformance suite covering:
- scalars
- arrays
- hashes
- arrays of hashes
- dotted keys
- alias expansion
- invalid characters
- invalid suffix placement
- invalid field lists
- tuple arity
- invalid numbers
- unterminated strings
- invalid short flags
- invalid dotted paths
- empty keys
- alias expansion to invalid keys
The suite is the specification.
If an implementation passes the suite, it is TypedArgs.
Design Philosophy
TypedArgs is intentionally:
- Explicit — no guessing
- Portable — no shell dependencies
- Minimal — four operators, one grammar
- Deterministic — predictable and stable
- Structured — arrays and hashes are first‑class
TypedArgs does not depend on:
- shell brace expansion
- shell quoting rules
- environment‑specific behavior
- Bash‑only features
The shell’s only job is to pass raw strings.
TypedArgs does everything else.
License
Apache‑2