Extending OptParse
This page is the procedural part of the development guide: what to do when you add a new value parser or parser family.
Adding A New Value Parser
The shortest path is:
- add a new file under
src/parsers/valueparsers/ - define the concrete value parser struct
- define its call overload
(::YourValueParser)(input::String)::ParseResult{T} - define
default_metavar(::YourValueParser)if applicable - include it from
src/parsers/valueparsers/valueparsers.jl - add it to the wrapped
ValueParserunion - add exported constructor functions and docstrings in
valueparsers.jl - add compact display support in
src/display/parser_show.jlif needed - add unit tests
- add it to
docs/src/reference.mdif it is public
Expected shape
Use existing value parser files as templates, especially:
string.jlinteger.jlfloat.jl
Typical pieces:
struct MyVal{T}
metavar::String
...
end
default_metavar(::MyVal{T}) where {T} = "..."
function (p::MyVal{T})(input::String)::ParseResult{T} where {T}
...
endConstructor placement
Public constructor functions belong in src/parsers/valueparsers/valueparsers.jl, not in the leaf file.
That file is the public API layer for value parsers and should contain:
- the public constructor names
- positional
metavaroverloads when appropriate - docstrings
Positional metavar style
The current preferred API is:
str("FILE")
integer("PORT")
flt("RATIO")
choice("MODE", values)
path("FILE")The metavar = ... keyword still exists at the lower level, but docstrings and examples should prefer the positional form.
Value parser checklist
Before considering a value parser done, verify:
- parse returns
ParseResult{T} - errors are family-specific and rendered through
render_error - the constructor is in the wrapped
ValueParserunion - the public constructor is exported if intended to be public
showoutput is readable- docstrings exist
- reference docs include the constructor
- unit tests cover success, failure, and
@test_opt
Adding A New Parser Family
The shortest path is:
- decide whether it is a primitive, constructor, or modifier
- add the concrete family file under the appropriate
src/parsers/...subdirectory - define a family-specific state alias
- define error codes and a renderer
- define the concrete parser struct
- implement
parse - implement
complete - include it from the family include file
- add it to the wrapped
Parserunion insrc/parsers/parser.jl - add the public constructor function and docstring in
src/parsers/parser.jl - add
show_compact/show_prettysupport if needed - add tests
- add docs, reference entries, and examples if public
Start from a state alias
Always define a parser-family-specific state alias first.
Examples:
const GateState = ParseResult{Bool}
const OptionState{T} = ParseResult{T}
const CommandState{S} = Option{Option{S}}
const MultipleState{S} = Vector{S}This usually clarifies the rest of the implementation immediately.
Tight signatures
Use the family alias in method signatures:
function parse(p::ArgGate{Bool, GateState}, ctx::Context{GateState})::InnerParseResult{GateState}Do not leave parser family methods broadly typed unless there is a very strong reason.
Public constructor placement
Public constructor functions belong in src/parsers/parser.jl.
That file is the user-facing API layer for parser families:
- exported names
- docstrings
- curried convenience overloads where needed
Parser-family checklist
Before considering a parser family done, verify:
- the state alias is explicit
parseandcompletesignatures reflect the real invariant state type- family-specific errors render correctly
- the family was added to the wrapped
Parserunion - the public constructor exists and is exported if public
showoutput is useful- docs/examples/reference mention the new parser if public
- tests cover both behavior and inference
Display And Docstring Conventions
Public names should match displayed names
If the public constructor is command(...), the parser pretty-printer should show command(...), not an older or internal alias.
Likewise:
flag(...)should display asflag(...)gate(...)should display asgate(...)sequence(...)should display assequence(...)
One subtle exception exists right now:
flag(...)is implemented asdefault(gate(...), false)- the pretty-printer special-cases this shape so public
flag(...)still displays asflag(...)
Reference docs must mention exported bindings explicitly
Documenter will complain if:
- an exported name has a docstring
- but the reference page does not include it in an
@docsblock
So when adding a public constructor, always update:
docs/src/reference.md