Added new macro features. resolve_value + default: key. Added raises to prevent CliGen features from being used outside of a already parsed state, and worked on specs. Will be working on specs later on as well to finish covering regex & redo timeparse & relative_operations

This commit is contained in:
2026-09-07 16:40:02 -05:00
parent 3fa77f5707
commit 8fab6912fc
89 changed files with 3615 additions and 515 deletions
+92 -21
View File
@@ -42,10 +42,19 @@ this project's own test programs.
Compile-time flow, in order:
1. `Command.inherited` installs a `macro finished` hook on each subclass, which calls
`define_command_initializer` (and `def_init` when `@[CommandInfo(def_init: true)]`).
2. `CliGen::App`'s `macro finished` (in `app/generate.cr`) walks `CliGen::Command.subclasses`
and emits `App.generate`, which constructs the runtime `Flag(T)` / `CommandNode(T)` object tree.
3. At runtime `App.process` lazily calls `generate`, then walks `ARGV`.
`validate_command_tree`, `define_command_initializer`, `generate_gather_handler`,
`generate_register_command`, `generate_gather_handler` (and `define_singleton_init`
when `@[CommandInfo(singleton_init: true)]`).
2. Each subclass therefore gets its own `self.register_command(array, parent:)` that
builds *its* `CommandNode(T)` + `Flag(T)` objects and recurses into its children.
3. `CliGen::App`'s `macro finished` (in `app/generate.cr`) selects the **root** commands —
those whose `@[CommandInfo]` has no `parent:` — and calls `register_command` on each.
4. At runtime `App.process` lazily calls `generate`, then walks `ARGV`.
Nesting is expressed by **annotation, not inheritance**: a subcommand subclasses
`CliGen::Command` directly and names its parent via `@[CommandInfo(parent: Other)]`.
Subclassing a `Command` instead would give it subclasses, which turns `T` into the
virtual type `T+` and makes `T.has_constant?`/`T.methods` fail with a compiler BUG.
### Entry point: `src/cligen.cr`
@@ -137,12 +146,23 @@ derived as `long.gsub(/--/,"").gsub(/-/,"_").upcase`. Both macros reject an expl
Run at the top of every `process`, so misconfiguration fails on first invocation:
- `Flag#check!` — rejects `-h` / `--help` (`ReservedFlagError`).
- **Compile time** — `check_flag_vars` validates every declaration (both `argument` and
`add_global_flag` route through it); `validate_command_tree` rejects a missing
`@[CommandInfo]`, a self-parent, and `parent:` cycles.
- **Load time** — `add_global_flag` constructs the flag, then checks `GLOBAL_FLAGS` for a
`long_key`/`short` collision and `abort`s with `__FILE__:__LINE__` of the call site.
Runs during module init, so it is outside `handle_command_raises`.
- `Flag#check!` — validates `short` against `FLAG_SHORT` and `long_key` against
`FLAG_LONG`. Only invoked on `@flags`, never on `GLOBAL_FLAGS`, which is why the
built-in `--help`/`--verbose` don't trip their own checks.
- `CommandNode#check!` — duplicate shorts/longs across `@flags + GLOBAL_FLAGS`
(`DuplicateFlagError`), duplicate child command names (`DuplicateCommandError`), and
(when `T != Nil`) requires either subcommands or a `#main` (`MissingDispatchError`).
- `App#check!``super`, then env-var collisions across `all_flags + GLOBAL_FLAGS`.
`all_flags` recurses the whole tree; empty env vars are excluded.
- `App#check!``super`, then env-var collisions across `all_flags.uniq + GLOBAL_FLAGS`.
`all_flags` recurses the whole tree. **The `.uniq` is load-bearing**: a parent's flag
object can appear in several nodes, and `uniq` collapses it via `Reference` identity
(`Flag` overrides neither `==` nor `hash`). Adding a custom `==` to `Flag` would
silently make this collapse *distinct* flags and stop catching real collisions.
### Errors: `src/cligen/exceptions.cr`
@@ -219,8 +239,8 @@ Called inside a `CliGen::Command` subclass:
| Macro | File | Purpose |
|---|---|---|
| `argument(var : T, description, ...)` | `command/argument.cr` | Declares a flag-backed ivar. Options: `long`, `short`, `validation`, `on_match`, `def_setter`, `def_getter`, `options`, `delimiter`, `format`, `allow_no_verification`, `env_var` |
| `selection(var : T, description, options, ...)` | `command/selection.cr` | Like `argument` but constrained to a fixed option list |
| `subcommand(func, description, examples) { ... }` | `command/subcommand.cr` | Defines a `@[SubCommand]` method from a block |
| `resolve_value(var, default: nil)` | `command/resolve_value.cr` | Reads a flag value from this command **or any ancestor**. Walks the `parent:` chain at compile time to find the declaring class, then walks `handler.parent?` at runtime to find its node. Returns the exact `T`, not a union. If the declaring ivar has no default, `default:` is **required** — the emitted `%default : T = ...` makes Crystal type-check it at the call site, and a `rescue MissingRequiredFlagError` uses it as the fallback |
| `help_template(filepath)` | `command/help_template.cr` | Per-command ECR override |
Module-level:
@@ -230,7 +250,12 @@ Module-level:
| `CliGen.add_global_flag(T, long:, description:, ...)` | `global_flag/add_global_flag.cr` | Appends to `GLOBAL_FLAGS`; visible on every command |
| `CliGen.override_help_template(filepath)` | `cligen.cr` | Project-wide ECR override |
`global_flag.cr` dogfoods `add_global_flag` for the built-in `-v/--verbose`.
`global_flag.cr` dogfoods `add_global_flag` for the built-in `-v/--verbose` and
`-h/--help`, both passing `internal: true` to bypass the reserved-name check.
`CliGen::MAX_COMMAND_DEPTH` (default 32, user-overridable by defining it before the
requires) bounds every parent-chain walk — macros have no `while`, so the walks are
`{% for i in (1..MAX_COMMAND_DEPTH) %}` with a sentinel. It doubles as the cycle guard.
### Extension points
@@ -244,15 +269,14 @@ in `flag.cr`.
## Annotations
`src/cligen/annotations.cr` declares seven; only five are wired:
`src/cligen/annotations.cr` declares six; only four are wired:
| Annotation | Applied to | Status |
|---|---|---|
| `@[CommandInfo(description:, def_init:)]` | Command subclass | **Required.** `description` must be a `StringLiteral`; `def_init: true` generates a no-arg initializer + `self.get` singleton accessor |
| `@[Argument(short:, long:, description:, validation:, on_match:, options:, delimiter:, format:, env_var:)]` | ivar | Emitted by `argument` **and** `selection`; read by `App.generate` and `define_command_initializer` |
| `@[CommandInfo(description:, parent:, singleton_init:)]` | Command subclass | **Required.** `description` must be a `StringLiteral`. `parent:` names the command this is a subcommand of (see nesting above). `singleton_init: true` generates a no-arg initializer + `self.get` accessor — note the check is `== true`, so any other value silently does nothing |
| `@[Argument(short:, long:, description:, validation:, on_match:, options:, delimiter:, format:, env_var:)]` | ivar | Emitted by `argument`; read by `App.generate` and `define_command_initializer` |
| `@[SubCommand(description:, examples:)]` | method | Emitted by `subcommand`; read by `CommandNode#subcommands` and the dispatch `case` |
| `@[PreRunCommand]` | method | Run unconditionally before subcommand dispatch |
| `@[Selection]` | ivar | *Read* by `generate`/`define_command_initializer`, but never emitted — `selection` emits `@[Argument]`. Effectively dead. |
| `@[ProxyCommand]` | — | Declared only; unused |
| `@[Trigger]` | — | Declared only; unused |
@@ -264,9 +288,30 @@ These have each caused real bugs in this codebase — check for them before touc
`==` silently returns false and `<` raises `undefined macro method 'Path#<'`. Call
`.resolve` first: `validation.return_type.resolve == Bool`, `type.resolve <= Array`.
Generic type *parameters* (`T` inside `Flag(T)`) are already `TypeNode` and are safe as-is.
This is the single most frequent bug in this codebase — it has appeared five separate
times, and it usually fails *silently* (a `Path == TypeNode` comparison is just always
false) or with an unrelated-looking error like `undefined macro method 'Path#annotation'`.
Resolve once at the point of extraction, not at each use.
- **`{% cond %}` failing inside a macro reports the wrong line.** When a macro expression
raises, the error points at the line that *consumes* the variable, not the assignment
that blew up — "undefined macro variable `x`" almost always means the line assigning `x`
errored. Look one line up.
- **Macros cannot be called from macro scope.** `{% if some_macro(x) %}` gives
`undefined macro method`. Macros emit code; they don't return values to the evaluator.
To share logic, either precompute into a constant both can read, or accept duplication.
- **`@type.instance_vars` only works in method scope.** In class-body scope (including a
`macro finished` directly in a class body) it raises "instance vars are not yet
initialized". Declaring an ivar requires class-body scope, so a macro can never read one
class's ivars *and* declare ivars in another. Constants are readable in both scopes and
are the way around it (`@type.constant("X") << ...` mutates one).
- **Macro `for` has no `break`**, and reassigning the loop variable does nothing. Bound the
loop and guard the body with a sentinel (`{% unless done || found %}`).
- **Emitted locals leak into the caller's scope.** `flg = ...` in a macro body clobbers a
user's `flg`. Use `%flg`, which is unique per expansion (and avoids type unions when the
same macro is called with different `T` in one scope).
- **`{% verbatim do %}`** is required whenever a macro body must emit macro code that runs
in the *subclass's* `macro finished` context (see `command.cr`, `def_init.cr`,
`define_command_initializer.cr`).
in the *subclass's* `macro finished` context (see `command.cr`,
`define_singleton_init.cr`, `define_command_initializer.cr`).
- Signed/unsigned dispatch is done by string inspection, since there's no `UInt` supertype
to test against: `{% int_case = T.stringify =~ /^UInt/ ? "uint?".id : "int?".id %}`.
- `macro finished` ordering is why `App.generate` can see every `Command` subclass.
@@ -278,6 +323,17 @@ These have each caused real bugs in this codebase — check for them before touc
`String`-array `process` overload, then generates most `it` blocks with `{% for int in
Int.subclasses %}` etc. so every numeric width is covered. `MyGoodData` / `MyBadData`
exercise `Coercable` / `Parsable`, including the "didn't mark anything processed" failure.
- `spec/cligen/command_spec.cr``resolve_value` at depth 1/2/3, both construction paths
(`define_singleton_init`'s no-arg `new` and `new(handler:)`), and the required-flag raise.
- `spec/cligen/timeparse_spec.cr` / `relative_operation_spec.cr` — the time subsystem.
- `spec/cligen/regex_spec.cr` — the flag and date matchers.
**Two spec hazards, both already hit:** env vars set in one example leak into others, so
anything touching `ENV` needs a `before_each { ENV.delete(...) }` — run `crystal spec
--order=<n>` for a few seeds before trusting a green suite. And time assertions must not
compare two independently-sampled clocks; `RelativeOperation#apply` takes an explicit
`Time`, so assert against a fixed `Time.utc` and reserve bracket assertions for
`Timeparse.parse`'s single `Time.local` call. Check `TZ=UTC crystal spec` too.
`utils/flag_matrix.cr` + `utils/flag_matrix.sh` cover what specs can't: env vars must be
set before process startup, so each of the 16 cases needs its own process. Run this after
@@ -285,9 +341,14 @@ touching value resolution, `check!`, or help rendering.
## Current state (branch `object_rework`)
Green: `crystal build --no-codegen` clean, `crystal spec` 164 examples / 0 failures,
`./utils/flag_matrix.sh` 16/16. Targeting v0.2.0 (`shard.yml` and `CliGen::VERSION` both
still say `0.1.0`).
Green: `crystal build --no-codegen` clean, `crystal spec` 276 examples / 0 failures,
`./utils/flag_matrix.sh` 16/16. `shard.yml` and `CliGen::VERSION` are both bumped to
`0.2.0`; no git tag exists yet.
**Verifying a change needs a consuming app, not just the lib build.** `crystal build
src/cligen.cr --no-codegen` does not instantiate `App.process`, `check_for_env_duplicates`,
or `satisfied?`, so type errors there stay invisible. Write a throwaway `require "cligen"`
program with a `Command` subclass and build *that*.
Known gaps, all deliberate:
@@ -295,9 +356,19 @@ Known gaps, all deliberate:
DESIGN.md marks it as planned.
- **`Array(Time)`** — unsupported; the three array element chains have no `Time` case.
- **Colon-based relative time formats** (`[-+]%H:%M:%S`) — documented in DESIGN.md as planned.
- `@[Selection]`, `@[ProxyCommand]`, `@[Trigger]` are dead (see above).
- The `Fiber.yield` log-flush workaround in `app.cr` is fragile; synchronous dispatch
would be deterministic.
- `@[ProxyCommand]` and `@[Trigger]` are declared but unused (see above).
- The `Fiber.yield` in `app.cr`'s `handle_command_raises` is **load-bearing, not
superstition** — Crystal's default `Log` backend dispatches async at INFO even with no
`Log.setup` call, so without the yield `abort`'s synchronous stderr write beats the log
lines that explain it. A sync dispatcher would be deterministic but is the *consumer's*
global setting, so the library can't impose it.
- `resolve_value` can no longer raise `MissingRequiredFlagError` — the declaring ivar
either has a default or the call site must supply one, so both paths are covered. The
gate applies only to the parent-chain branch; a local ivar was already resolved during
`initialize`, and the not-found branch raises at compile time regardless.
- `resolve_value`'s own cycle detection is unreachable: `validate_command_tree` runs in
`macro finished` and catches cycles before any method body instantiates. The `commands`
array it accumulates is still live — it feeds the "valid options are..." error listing.
## Repo conventions
+5 -5
View File
@@ -9,7 +9,7 @@ This document outlines the overall design of the CliGen shard & it's underlying
## How it works/High-Level overview
Using crystal macros, you define the shape (arguments/flags, selections, work functions/subcommands, etc) and later on in `src/cligen/app/generate.cr` will use macros to (at compile time) generate `CommandNode(T)` objects & `Flag(T)` objects to contain your command/subcommand/arg parsing code from the data you provided in your `CliGen::Command` subclass.
Using crystal macros, you define the shape (arguments/flags, work functions/subcommands, etc) and later on in `src/cligen/app/generate.cr` will use macros to (at compile time) generate `CommandNode(T)` objects & `Flag(T)` objects to contain your command/subcommand/arg parsing code from the data you provided in your `CliGen::Command` subclass.
## Architecture
@@ -72,8 +72,8 @@ The examples like above provide a "DSL-esk" way of defining:
- Instance Variables,
- Short/Long flags
- Description of the flags (used in the help output as well)
- A verification proc/lambda for doing ad-hoc checks of the value provided by the user (essentially allowing you to implement your own option: key like in selection)
- Selections (currently compile-time and will open it up to runtime collecting of options later on based on defined annotations in the class)
- A verification proc/lambda for doing ad-hoc checks of the value provided by the user (for cases where the `options:` key isn't expressive enough)
- A static list of valid options via the `options:` key (currently compile-time; will open up to runtime collection of options later on)
- define subcommands of this current command
@@ -405,7 +405,7 @@ This object serves as a wrapper around ARGV objects/strings/items and is used to
### Markdown Documentation Generation
Since all command metadata is present in annotations at compile time (`@[CliGen::CommandInfo]`, `@[CliGen::SubCommand]`, `@[CliGen::Argument]`, `@[CliGen::Selection]`), the framework can walk the same structures that `generate.cr` already walks and render them into a Markdown document instead of a `CommandNode` tree.
Since all command metadata is present in annotations at compile time (`@[CliGen::CommandInfo]`, `@[CliGen::SubCommand]`, `@[CliGen::Argument]`), the framework can walk the same structures that `generate.cr` already walks and render them into a Markdown document instead of a `CommandNode` tree.
The generation would be driven by a `macro finished` block (similar to `generate.cr`) that emits a `self.generate_docs` class method on `App`. This method walks every `Command` subclass and its annotations to produce a structured document.
@@ -466,7 +466,7 @@ complete -F _myapp myapp
Implementation notes:
* Script body generated at compile time via a `macro finished` walk of `Command.subclasses`
* `@[CliGen::Selection]` options (`%w[json yaml ecr]`) can be included as valid completions for their flag
* `@[CliGen::Argument]` options (`%w[json yaml ecr]`) can be included as valid completions for their flag
* Install path: `myapp --generate-completion bash > ~/.bash_completion.d/myapp` or printed with instructions
* Same annotation data used by the doc generator, so both stay in sync with the command definition
+1 -1
View File
@@ -4,7 +4,7 @@ A Crystal shard that generates CLI parsers from class definitions using annotati
## How It Works
Subclass `CliGen::Command`, annotate your instance variables with `@[CliGen::Argument]` or `@[CliGen::Selection]`, and register the command with an `CliGen::App`. At compile time, macros inspect the annotations and generate typed `Flag(T)` objects; at runtime, `CliGen::App.process` walks the `CommandNode` tree to route arguments, populate your command instance, and dispatch to the right method.
Subclass `CliGen::Command`, annotate your instance variables with `@[CliGen::Argument]`, and register the command with an `CliGen::App`. At compile time, macros inspect the annotations and generate typed `Flag(T)` objects; at runtime, `CliGen::App.process` walks the `CommandNode` tree to route arguments, populate your command instance, and dispatch to the right method.
## Installation
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="CliGen/SubCommand.html">SubCommand</a>
+288 -13
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="CliGen/SubCommand.html">SubCommand</a>
@@ -396,12 +401,22 @@
<br/>
cligen/command/def_init.cr
cligen/command/define_command_initializer.cr
<br/>
cligen/command/define_command_initializer.cr
cligen/command/define_singleton_init.cr
<br/>
cligen/command/generate_gather_handler.cr
<br/>
cligen/command/generate_register_command.cr
<br/>
@@ -411,7 +426,7 @@
<br/>
cligen/command/selection.cr
cligen/command/resolve_value.cr
<br/>
@@ -421,6 +436,11 @@
<br/>
cligen/command/validate_command_tree.cr
<br/>
cligen/command_node.cr
<br/>
@@ -500,8 +520,33 @@
</dt>
<dt class="entry-const" id="MAX_COMMAND_DEPTH">
<strong>MAX_COMMAND_DEPTH</strong> = <code><span class="n">32</span></code>
</dt>
<dd class="entry-const-doc">
<h1><a id="cli-genmax-command-depth" class="anchor" href="#cli-genmax-command-depth"> <svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>CliGen::MAX_COMMAND_DEPTH</h1>
<p>This exists to prevent the user from defining a command tree
that extends past the compile-time configured max via the
CliGen::MAX_COMMAND_DEPTH constant.</p>
<p>The reason this is a thing is because crystal macros don't allow for
unbounded while's/until's in macros, meaning it always has to be
deterministic. SO to deal with this and still allow for subcommand
defining you need either go with the default (32 command depth) or
define your own larger max (understand this will affect compile-time
due to this directly affecting loops in the Command macros).</p>
<p>So to still support this I had to make bounded for-loops usng</p>
<pre><code class="language-crystal"><span class="o">{%</span> <span class="k">for</span> i <span class="k">in</span> (<span class="n">1</span>..<span class="t">CliGen</span><span class="t">::</span><span class="t">MAX_COMMAND_DEPTH</span>) <span class="o">%}</span>
...<span class="k">do</span> checks...
<span class="o">{%</span> <span class="k">end</span> }</code></pre>
</dd>
<dt class="entry-const" id="VERSION">
<strong>VERSION</strong> = <code><span class="s">&quot;0.1.0&quot;</span></code>
<strong>VERSION</strong> = <code><span class="s">&quot;0.2.0&quot;</span></code>
</dt>
@@ -525,7 +570,9 @@
<ul class="list-summary">
<li class="entry-summary">
<a href="#add_global_flag%28type%2C%2A%2Clong%2Cdescription%2Cenv_var%3Dnil%2Cshort%3Dnil%2Cvalidation%3Dnil%2Cdefault%3Dnil%2Con_match%3Dnil%29-macro" class="signature"><strong>add_global_flag</strong>(type, *, long, description, env_var = <span class="n">nil</span>, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, default = <span class="n">nil</span>, on_match = <span class="n">nil</span>)</a>
<a href="#add_global_flag%28type%2C%2A%2Clong%2Cdescription%2Cenv_var%3D%22%22%2Cshort%3Dnil%2Cvalidation%3Dnil%2Cdefault%3Dnil%2Con_match%3Dnil%2Coptions%3Dnil%2Cformat%3Dnil%2Cinternal%3Dfalse%29-macro" class="signature"><strong>add_global_flag</strong>(type, *, long, description, env_var = <span class="s">&quot;&quot;</span>, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, default = <span class="n">nil</span>, on_match = <span class="n">nil</span>, options = <span class="n">nil</span>, format = <span class="n">nil</span>, internal = <span class="n">false</span>)</a>
<div class="summary"><p>This macro provides a user-friendly way to define a global flag for your project.</p></div>
</li>
@@ -558,14 +605,242 @@
Macro Detail
</h2>
<div class="entry-detail" id="add_global_flag(type,*,long,description,env_var=nil,short=nil,validation=nil,default=nil,on_match=nil)-macro">
<div class="entry-detail" id="add_global_flag(type,*,long,description,env_var=&quot;&quot;,short=nil,validation=nil,default=nil,on_match=nil,options=nil,format=nil,internal=false)-macro">
<div class="signature">
macro <strong>add_global_flag</strong>(type, *, long, description, env_var = <span class="n">nil</span>, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, default = <span class="n">nil</span>, on_match = <span class="n">nil</span>)
macro <strong>add_global_flag</strong>(type, *, long, description, env_var = <span class="s">&quot;&quot;</span>, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, default = <span class="n">nil</span>, on_match = <span class="n">nil</span>, options = <span class="n">nil</span>, format = <span class="n">nil</span>, internal = <span class="n">false</span>)
<a class="method-permalink" href="#add_global_flag%28type%2C%2A%2Clong%2Cdescription%2Cenv_var%3Dnil%2Cshort%3Dnil%2Cvalidation%3Dnil%2Cdefault%3Dnil%2Con_match%3Dnil%29-macro">#</a>
<a class="method-permalink" href="#add_global_flag%28type%2C%2A%2Clong%2Cdescription%2Cenv_var%3D%22%22%2Cshort%3Dnil%2Cvalidation%3Dnil%2Cdefault%3Dnil%2Con_match%3Dnil%2Coptions%3Dnil%2Cformat%3Dnil%2Cinternal%3Dfalse%29-macro">#</a>
</div>
<div class="doc">
<p>This macro provides a user-friendly way to define a global flag for your
project.</p>
<h2><a id="what-does-this-do" class="anchor" href="#what-does-this-do">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>What does this do?</h2>
<p>This macro is used to help define &amp; check a global flag to be used in the
all levels of commands.</p>
<p>When provided it will parse your values &amp; serialize them into a Flag(T)
object &amp; insert it in the CliGen::GLOBAL_FLAGS array after checking if
a flag using it's <code>--long</code> is already in use. In the case that that long
is already used it will raise at runtime and you'll need to choose another
long.</p>
<h2><a id="arguments" class="anchor" href="#arguments">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>Arguments</h2>
<h3><a id="type-type-node" class="anchor" href="#type-type-node">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>type: TypeNode</h3>
<p><strong>Required:</strong> true</p>
<p>This is the type of the flag (Bool, Int32, String, etc).</p>
<h3><a id="long-string-literal" class="anchor" href="#long-string-literal">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>long: StringLiteral</h3>
<p><strong>Required:</strong> true</p>
<p>This is the long form of the flag that will be matched at the command-line</p>
<h3><a id="description-string-literal" class="anchor" href="#description-string-literal">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>description: StringLiteral</h3>
<p><strong>Required:</strong> true</p>
<p>This is the full length description of the flag that will be presented in the
help text provided to the user.</p>
<h3><a id="env-var-string-literal" class="anchor" href="#env-var-string-literal">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>env_var: StringLiteral</h3>
<p><strong>Required:</strong> false</p>
<p>This is an ENV VAR that can be used to set this value without providing an
argument via the CLI. By default it will (unless explicitly disbled by
passing <code>env_var: nil</code> as an argument to disable the env_var entirely)
will parse your long flag and set the ENV VAR to the un &quot;--&quot; portion of it</p>
<p><strong>Warning:</strong> Incompatible ENV VAR formatting</p>
<p>When providing ENV VARs manually you cannot provide any whitespace or &quot;-&quot;
characters internally to it. As thse are both incompatible with ENV VARs.</p>
<p>If you provide an ENV VAR with these the framework will raise at
compile-time and tell you to change them.</p>
<p><strong>Note:</strong> Auto Generates ENV VAR from flag long</p>
<p>If you did not provide a ENV VAR manually (or disable it via setting it to
nil), the macro will use the long flag to create a ENV VAR that can be
matched. In this case if the flag has any internal &quot;-&quot; chars they will
be replaced with &quot;_&quot; so &quot;--long--flag--name&quot;/&quot;--long-flag-name&quot; -&gt;
&quot;LONG_FLAG_NAME&quot;.</p>
<p>When you provide a long: with a trailing ARGUMENT (ex: &quot;--item ITEM&quot;,
&quot;--item=ITEM&quot;) the flag will first be split on the whitespace or &quot;=&quot;
prior to being used for the ENV_VAR.</p>
<h3><a id="short-string-literal" class="anchor" href="#short-string-literal">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>short: StringLiteral</h3>
<p><strong>Required:</strong> false</p>
<p>This is the short form of a flag (&quot;--filename&quot; -&gt; &quot;-f&quot;) that can be matched
during parsing.</p>
<p><strong>Note:</strong> Alphabetic characters only</p>
<p>Unlike some other frameworks that might support numeric flags, due to the
issues around supporting them &amp; being able to discern if these are arguments
(-1/signed int's) or short flags (&quot;--one&quot; -&gt; &quot;-1&quot;), I've determined that I
will not be supporting numeric flags as this causes a number of
complications/complexities around ARGV parsing.</p>
<h3><a id="default-t" class="anchor" href="#default-t">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>default: T</h3>
<p><strong>Required:</strong> ?false?</p>
<p>This is the default value of the flag (String -&gt; &quot;abc&quot;, Int32 -&gt; 0, etc)
that will be returned if no direct (via parsing CLI args) or indirect
(by parsing ENV VAR values) arguments are provided.</p>
<p>While not technically required, it's advised to always set a default
when creating flags as if you don't and nothing is parsed/provided
when Flag(T)#value! is called it will raise a
CliGen::MissingRequiredFlagError exception at the call site.</p>
<h3><a id="options-array-literaltcall" class="anchor" href="#options-array-literaltcall">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>options: ArrayLiteral(T)|Call</h3>
<p><strong>Required:</strong> false</p>
<p>This argument sets a static list of accepted arguments to a specific subset
of values.</p>
<p>EX: Output format</p>
<pre><code class="language-crystal"><span class="t">CliGen</span>.add_global_flag(<span class="t">String</span>,
default: <span class="s">&quot;ecr&quot;</span>,
short: <span class="s">&quot;-f&quot;</span>,
long: <span class="s">&quot;--format&quot;</span>,
description: <span class="s">&quot;Provide the preferred output format&quot;</span>,
options: <span class="s">%w[ json yaml ecr ]</span>
)</code></pre>
<p><strong>Note:</strong> Support for runtime resolution</p>
<p>While the primary value of this is static arrays of values, you can also
delegate the discovery of values to a global method or helper method in
your codebase.</p>
<p>HOWEVER, when doing so ALWAYS ensure that you are providing a full path
to your method, as the the macro has no way of determining relative paths
in your modules. While, provided you are doing this in the same context as
the method you are running, this shouldn't be an issue, however best
practices dictate you provide a full path just to be careful.</p>
<p>EX: Delegated resolution</p>
<pre><code class="language-crystal"><span class="k">module</span> <span class="t">ABC</span>
<span class="k">def</span> <span class="m">self</span>.items
<span class="s">%w[ a b c d e f g taco ]</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="t">CliGen</span>.add_global_flag(<span class="t">String</span>,
default: <span class="s">&quot;a&quot;</span>,
short: <span class="s">&quot;-i&quot;</span>,
long: <span class="s">&quot;--item&quot;</span>,
description: <span class="s">&quot;Provide an item to print&quot;</span>,
options: <span class="t">::</span><span class="t">ABC</span>.items
)</code></pre>
<h3><a id="format-regex-literal" class="anchor" href="#format-regex-literal">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>format: RegexLiteral</h3>
<p><strong>Required:</strong> false</p>
<p>This exists to handle (for String &amp; Custom Data Types) filtering &amp; checking
that an argument being provided by a user is being given in a specific
format.</p>
<p>This is something you use when you're only wanting to validate formatting,
if you plan to do more specific/extensive validation you should use the
validation: field.</p>
<p>EX: Hostname matching</p>
<pre><code class="language-crystal"><span class="t">CliGen</span>.add_global_flag(<span class="t">Array</span>(<span class="t">String</span>),
default: <span class="o">[]</span> <span class="k">of</span> <span class="t">String</span>,
short: <span class="s">&quot;-H&quot;</span>,
long: <span class="s">&quot;--hostname&quot;</span>,
description: <span class="s">&quot;Provide a hostname to do remote work on&quot;</span>,
format: <span class="s">/^[a-zA-Z]{3}[0-9]+node[0-9]$/</span>
)</code></pre>
<h3><a id="validation-proc-literalt-bool" class="anchor" href="#validation-proc-literalt-bool">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>validation: ProcLiteral(T, Bool)</h3>
<p><strong>Required:</strong> false</p>
<p>Here you can provide a ad-hoc proc for doing validations of a provided
argument that can't easily be done by providing a static <code>options:</code> value.</p>
<p><strong>Note:</strong> Explicit input &amp; return type requirement</p>
<p>The explicit input <code>: T</code> &amp; return <code>: Bool</code> turn types are required as the
macros I setup are trying to enforce that both the input &amp; return types
are explicity to avoid truthy &amp; falsey semantics.</p>
<p>EX: checking int range</p>
<pre><code class="language-crystal"><span class="t">CliGen</span>.add_global_flag(<span class="t">Int32</span>,
short: <span class="s">&quot;-p&quot;</span>,
long: <span class="s">&quot;--port&quot;</span>,
description: <span class="s">&quot;Provide a single port to test against&quot;</span>,
validation: <span class="o">-&gt;</span>(port : <span class="t">Int32</span>) : <span class="t">Bool</span> <span class="k">do</span>
(<span class="t">UInt16</span><span class="t">::</span><span class="t">MIN</span>..<span class="t">UInt16</span><span class="t">::</span><span class="t">MAX</span>).includes?(port)
<span class="k">end</span>
)</code></pre>
<p>EX: file existance check</p>
<pre><code class="language-crystal"><span class="t">CliGen</span>.add_global_flag(<span class="t">String</span>,
short: <span class="s">&quot;-i&quot;</span>,
long: <span class="s">&quot;--filename&quot;</span>,
description: <span class="s">&quot;Provide a file that will serve as the input for this program&quot;</span>,
validation: <span class="o">-&gt;</span>(file : <span class="t">String</span>) : <span class="t">Bool</span> <span class="k">do</span>
<span class="k">if</span> <span class="t">File</span>.exists?(file)
<span class="n">true</span>
<span class="k">else</span>
<span class="t">STDERR</span>.puts <span class="s">&quot;ERROR : --filename : Provided file (</span><span class="i">#{</span>file<span class="i">}</span><span class="s">) does not exist&quot;</span>
<span class="n">false</span>
<span class="k">end</span>
<span class="k">end</span>
)</code></pre>
<h3><a id="on-match-proc-literalt-nil" class="anchor" href="#on-match-proc-literalt-nil">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>on_match: ProcLiteral(T, Nil)</h3>
<p><strong>Required:</strong> false</p>
<p>This option is where you provide the proc for handling ad-hoc</p>
<p>EX: Configuring the stdlib log level</p>
<pre><code class="language-crystal"><span class="t">CliGen</span>.add_global_flag(<span class="t">String</span>,
long: <span class="s">&quot;--log-level LEVEL&quot;</span>,
short: <span class="s">&quot;-l&quot;</span>,
description: <span class="s">&quot;Set the current log level of the stdlib Log library&quot;</span>,
options: <span class="s">%w[ trace debug notice info warn error fatal ]</span>,
on_match: <span class="o">-&gt;</span>(level : <span class="t">String</span>) <span class="k">do</span>
<span class="t">::</span><span class="t">Log</span>.setup(level: <span class="t">::</span><span class="t">Log</span><span class="t">::</span><span class="t">Severity</span>.parse(level))
<span class="k">end</span>
)</code></pre>
<p>EX: Collecting arguments in a global array</p>
<pre><code class="language-crystal"><span class="k">module</span> <span class="t">MyModule</span>
<span class="t">MY_ARRAY</span> <span class="o">=</span> <span class="o">[]</span> <span class="k">of</span> <span class="t">String</span>
<span class="t">CliGen</span>.add_global_flag(<span class="t">String</span>,
long: <span class="s">&quot;--filename FILE&quot;</span>,
short: <span class="s">&quot;-i&quot;</span>,
description: <span class="s">&quot;Provide a single file to check against (repeatable)&quot;</span>,
validation: <span class="o">-&gt;</span>(file : <span class="t">String</span>) : <span class="t">Bool</span> <span class="k">do</span>
<span class="k">if</span> <span class="t">File</span>.exists?(file)
<span class="n">true</span>
<span class="k">else</span>
<span class="t">STDERR</span>.puts <span class="s">&quot;ERROR : --filename : </span><span class="i">#{</span>file<span class="i">}</span><span class="s"> does not exist&quot;</span>
<span class="n">false</span>
<span class="k">end</span>
<span class="k">end</span>,
on_match: <span class="o">-&gt;</span>(file : <span class="t">String</span>) <span class="k">do</span>
<span class="t">::</span><span class="t">MyModule</span><span class="t">::</span><span class="t">MY_ARRAY</span> <span class="o">&lt;&lt;</span> file
<span class="k">end</span>
)
<span class="k">end</span></code></pre>
<p>For more detailed documentation please visit the wiki in the repo. All topics are covered there in much greater detail than inline documentation here</p>
</div>
<br/>
<div>
+43 -9
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
@@ -419,6 +424,11 @@ for global-flag matching, then hands off to the matched child CommandNode.</p>
</h2>
<ul class="list-summary">
<li class="entry-summary">
<a href="#get-class-method" class="signature"><strong>.get</strong></a>
</li>
<li class="entry-summary">
<a href="#handle_command_raises%28%26%29%3ANil-class-method" class="signature"><strong>.handle_command_raises</strong>(&) : Nil</a>
@@ -500,8 +510,8 @@ for global-flag matching, then hands off to the matched child CommandNode.</p>
<h3>Constructor methods inherited from class <code><a href="../CliGen/CommandNode.html">CliGen::CommandNode(Nil)</a></code></h3>
<a href="../CliGen/CommandNode.html#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="tooltip">
<span>new(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), description : String | Nil = <span class="n">nil</span>)</span>
<a href="../CliGen/CommandNode.html#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cparent%3ABaseCommandNode%7CNil%3Dnil%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="tooltip">
<span>new(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), parent : BaseCommandNode | Nil = <span class="n">nil</span>, description : String | Nil = <span class="n">nil</span>)</span>
new</a>
@@ -519,6 +529,11 @@ for global-flag matching, then hands off to the matched child CommandNode.</p>
<h3>Instance methods inherited from class <code><a href="../CliGen/BaseCommandNode.html">CliGen::BaseCommandNode</a></code></h3>
<a href="../CliGen/BaseCommandNode.html#all_commands%3AArray%28BaseCommandNode%29-instance-method" class="tooltip">
<span>all_commands : Array(BaseCommandNode)</span>
all_commands</a>,
<a href="../CliGen/BaseCommandNode.html#all_flags%3AArray%28BaseFlag%29-instance-method" class="tooltip">
<span>all_flags : Array(BaseFlag)</span>
all_flags</a>,
@@ -584,6 +599,11 @@ for global-flag matching, then hands off to the matched child CommandNode.</p>
name</a>,
<a href="../CliGen/BaseCommandNode.html#parent%3F%3ABaseCommandNode%7CNil-instance-method" class="tooltip">
<span>parent? : BaseCommandNode | Nil</span>
parent?</a>,
<a href="../CliGen/BaseCommandNode.html#process%28args%3AArray%28String%29%29%3ANil-instance-method" class="tooltip">
<span>process(args : Array(String)) : Nil<br/>process(args : Array(CliGen::Arg)) : Nil</span>
process</a>,
@@ -611,8 +631,8 @@ for global-flag matching, then hands off to the matched child CommandNode.</p>
<h3>Constructor methods inherited from class <code><a href="../CliGen/BaseCommandNode.html">CliGen::BaseCommandNode</a></code></h3>
<a href="../CliGen/BaseCommandNode.html#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cmeta%3ACommandMeta%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="tooltip">
<span>new(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), meta : CommandMeta, description : String | Nil = <span class="n">nil</span>)</span>
<a href="../CliGen/BaseCommandNode.html#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cmeta%3ACommandMeta%2Cparent%3ABaseCommandNode%7CNil%3Dnil%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="tooltip">
<span>new(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), meta : CommandMeta, parent : BaseCommandNode | Nil = <span class="n">nil</span>, description : String | Nil = <span class="n">nil</span>)</span>
new</a>
@@ -689,6 +709,20 @@ for global-flag matching, then hands off to the matched child CommandNode.</p>
Class Method Detail
</h2>
<div class="entry-detail" id="get-class-method">
<div class="signature">
def self.<strong>get</strong>
<a class="method-permalink" href="#get-class-method">#</a>
</div>
<br/>
<div>
</div>
</div>
<div class="entry-detail" id="handle_command_raises(&amp;):Nil-class-method">
<div class="signature">
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+11 -6
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
@@ -346,7 +351,7 @@
</h2>
<p>This is used for annotating instance variables for the CliGen framework can know how to create your <code><a href="../CliGen/Flag.html">CliGen::Flag</a>(T)</code> objects</p>
<p>WHILE this is usually being handled by the <code><a href="../CliGen/Command.html#argument%28variable%2Cdescription%2Clong%3Dnil%2Cshort%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%2Cdef_setter%3Dfalse%2Cdef_getter%3Dfalse%2Coptions%3Dnil%2Cdelimiter%3D%22%2C%22%2Cformat%3Dnil%2Callow_no_verification%3Dfalse%2Cenv_var%3Dnil%29-macro">CliGen::Command.argument</a></code> macro
<p>WHILE this is usually being handled by the <code><a href="../CliGen/Command.html#argument%28variable%2Cdescription%2Clong%3Dnil%2Cshort%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%2Cdef_setter%3Dfalse%2Cdef_getter%3Dfalse%2Coptions%3Dnil%2Cdelimiter%3D%22%2C%22%2Cformat%3Dnil%2Callow_no_verification%3Dfalse%2Cenv_var%3D%22%22%29-macro">CliGen::Command.argument</a></code> macro
inside of the class body.</p>
<p>EX:</p>
<pre><code class="language-crystal"><span class="k">class</span> <span class="t">MyCmd</span> <span class="o">&lt;</span> <span class="t">CliGen</span><span class="t">::</span><span class="t">Command</span>
+52 -9
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
@@ -429,7 +434,7 @@ Everything that doesn't depend on T lives here.</p>
<ul class="list-summary">
<li class="entry-summary">
<a href="#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cmeta%3ACommandMeta%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="signature"><strong>.new</strong>(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), meta : CommandMeta, description : String | Nil = <span class="n">nil</span>)</a>
<a href="#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cmeta%3ACommandMeta%2Cparent%3ABaseCommandNode%7CNil%3Dnil%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="signature"><strong>.new</strong>(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), meta : CommandMeta, parent : BaseCommandNode | Nil = <span class="n">nil</span>, description : String | Nil = <span class="n">nil</span>)</a>
</li>
@@ -451,6 +456,11 @@ Everything that doesn't depend on T lives here.</p>
</h2>
<ul class="list-summary">
<li class="entry-summary">
<a href="#all_commands%3AArray%28BaseCommandNode%29-instance-method" class="signature"><strong>#all_commands</strong> : Array(BaseCommandNode)</a>
</li>
<li class="entry-summary">
<a href="#all_flags%3AArray%28BaseFlag%29-instance-method" class="signature"><strong>#all_flags</strong> : Array(BaseFlag)</a>
@@ -521,6 +531,11 @@ Everything that doesn't depend on T lives here.</p>
</li>
<li class="entry-summary">
<a href="#parent%3F%3ABaseCommandNode%7CNil-instance-method" class="signature"><strong>#parent?</strong> : BaseCommandNode | Nil</a>
</li>
<li class="entry-summary">
<a href="#process%28args%3AArray%28String%29%29%3ANil-instance-method" class="signature"><strong>#process</strong>(args : Array(String)) : Nil</a>
@@ -592,12 +607,12 @@ Everything that doesn't depend on T lives here.</p>
Constructor Detail
</h2>
<div class="entry-detail" id="new(name:String,flags:Array(BaseFlag),commands:Array(BaseCommandNode),pre_run_commands:Array(RunCommand),post_run_commands:Array(RunCommand),meta:CommandMeta,description:String|Nil=nil)-class-method">
<div class="entry-detail" id="new(name:String,flags:Array(BaseFlag),commands:Array(BaseCommandNode),pre_run_commands:Array(RunCommand),post_run_commands:Array(RunCommand),meta:CommandMeta,parent:BaseCommandNode|Nil=nil,description:String|Nil=nil)-class-method">
<div class="signature">
def self.<strong>new</strong>(name : String, flags : Array(<a href="../CliGen/BaseFlag.html">BaseFlag</a>), commands : Array(<a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a>), pre_run_commands : Array(<a href="../CliGen/RunCommand.html">RunCommand</a>), post_run_commands : Array(<a href="../CliGen/RunCommand.html">RunCommand</a>), meta : <a href="../CliGen/CommandMeta.html">CommandMeta</a>, description : String | Nil = <span class="n">nil</span>)
def self.<strong>new</strong>(name : String, flags : Array(<a href="../CliGen/BaseFlag.html">BaseFlag</a>), commands : Array(<a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a>), pre_run_commands : Array(<a href="../CliGen/RunCommand.html">RunCommand</a>), post_run_commands : Array(<a href="../CliGen/RunCommand.html">RunCommand</a>), meta : <a href="../CliGen/CommandMeta.html">CommandMeta</a>, parent : <a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a> | Nil = <span class="n">nil</span>, description : String | Nil = <span class="n">nil</span>)
<a class="method-permalink" href="#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cmeta%3ACommandMeta%2Cdescription%3AString%7CNil%3Dnil%29-class-method">#</a>
<a class="method-permalink" href="#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cmeta%3ACommandMeta%2Cparent%3ABaseCommandNode%7CNil%3Dnil%2Cdescription%3AString%7CNil%3Dnil%29-class-method">#</a>
</div>
<br/>
@@ -622,6 +637,20 @@ Everything that doesn't depend on T lives here.</p>
Instance Method Detail
</h2>
<div class="entry-detail" id="all_commands:Array(BaseCommandNode)-instance-method">
<div class="signature">
def <strong>all_commands</strong> : Array(<a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a>)
<a class="method-permalink" href="#all_commands%3AArray%28BaseCommandNode%29-instance-method">#</a>
</div>
<br/>
<div>
</div>
</div>
<div class="entry-detail" id="all_flags:Array(BaseFlag)-instance-method">
<div class="signature">
@@ -818,6 +847,20 @@ Everything that doesn't depend on T lives here.</p>
</div>
</div>
<div class="entry-detail" id="parent?:BaseCommandNode|Nil-instance-method">
<div class="signature">
def <strong>parent?</strong> : <a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a> | Nil
<a class="method-permalink" href="#parent%3F%3ABaseCommandNode%7CNil-instance-method">#</a>
</div>
<br/>
<div>
</div>
</div>
<div class="entry-detail" id="process(args:Array(String)):Nil-instance-method">
<div class="signature">
+18 -13
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
@@ -417,7 +422,7 @@
<ul class="list-summary">
<li class="entry-summary">
<a href="#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%2Cdescription%3AString%2Cdelimiter%3AString%2Cmeta%3AFlagMeta%29-class-method" class="signature"><strong>.new</strong>(var : String, short : String | Nil, long : String, env_var : String, description : String, delimiter : String, meta : FlagMeta)</a>
<a href="#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%7CNil%2Cdescription%3AString%2Cdelimiter%3AString%2Cmeta%3AFlagMeta%29-class-method" class="signature"><strong>.new</strong>(var : String, short : String | Nil, long : String, env_var : String | Nil, description : String, delimiter : String, meta : FlagMeta)</a>
</li>
@@ -455,7 +460,7 @@
</li>
<li class="entry-summary">
<a href="#env_var%3AString-instance-method" class="signature"><strong>#env_var</strong> : String</a>
<a href="#env_var%3AString%7CNil-instance-method" class="signature"><strong>#env_var</strong> : String | Nil</a>
</li>
@@ -548,12 +553,12 @@
Constructor Detail
</h2>
<div class="entry-detail" id="new(var:String,short:String|Nil,long:String,env_var:String,description:String,delimiter:String,meta:FlagMeta)-class-method">
<div class="entry-detail" id="new(var:String,short:String|Nil,long:String,env_var:String|Nil,description:String,delimiter:String,meta:FlagMeta)-class-method">
<div class="signature">
def self.<strong>new</strong>(var : String, short : String | Nil, long : String, env_var : String, description : String, delimiter : String, meta : <a href="../CliGen/FlagMeta.html">FlagMeta</a>)
def self.<strong>new</strong>(var : String, short : String | Nil, long : String, env_var : String | Nil, description : String, delimiter : String, meta : <a href="../CliGen/FlagMeta.html">FlagMeta</a>)
<a class="method-permalink" href="#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%2Cdescription%3AString%2Cdelimiter%3AString%2Cmeta%3AFlagMeta%29-class-method">#</a>
<a class="method-permalink" href="#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%7CNil%2Cdescription%3AString%2Cdelimiter%3AString%2Cmeta%3AFlagMeta%29-class-method">#</a>
</div>
<br/>
@@ -620,12 +625,12 @@
</div>
</div>
<div class="entry-detail" id="env_var:String-instance-method">
<div class="entry-detail" id="env_var:String|Nil-instance-method">
<div class="signature">
def <strong>env_var</strong> : String
def <strong>env_var</strong> : String | Nil
<a class="method-permalink" href="#env_var%3AString-instance-method">#</a>
<a class="method-permalink" href="#env_var%3AString%7CNil-instance-method">#</a>
</div>
<br/>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+209 -35
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
@@ -373,12 +378,22 @@
<br/>
cligen/command/def_init.cr
cligen/command/define_command_initializer.cr
<br/>
cligen/command/define_command_initializer.cr
cligen/command/define_singleton_init.cr
<br/>
cligen/command/generate_gather_handler.cr
<br/>
cligen/command/generate_register_command.cr
<br/>
@@ -388,7 +403,7 @@
<br/>
cligen/command/selection.cr
cligen/command/resolve_value.cr
<br/>
@@ -398,6 +413,11 @@
<br/>
cligen/command/validate_command_tree.cr
<br/>
@@ -418,12 +438,7 @@
<ul class="list-summary">
<li class="entry-summary">
<a href="#argument%28variable%2Cdescription%2Clong%3Dnil%2Cshort%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%2Cdef_setter%3Dfalse%2Cdef_getter%3Dfalse%2Coptions%3Dnil%2Cdelimiter%3D%22%2C%22%2Cformat%3Dnil%2Callow_no_verification%3Dfalse%2Cenv_var%3Dnil%29-macro" class="signature"><strong>argument</strong>(variable, description, long = <span class="n">nil</span>, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, on_match = <span class="n">nil</span>, def_setter = <span class="n">false</span>, def_getter = <span class="n">false</span>, options = <span class="n">nil</span>, delimiter = <span class="s">&quot;,&quot;</span>, format = <span class="n">nil</span>, allow_no_verification = <span class="n">false</span>, env_var = <span class="n">nil</span>)</a>
</li>
<li class="entry-summary">
<a href="#def_init-macro" class="signature"><strong>def_init</strong></a>
<a href="#argument%28variable%2Cdescription%2Clong%3Dnil%2Cshort%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%2Cdef_setter%3Dfalse%2Cdef_getter%3Dfalse%2Coptions%3Dnil%2Cdelimiter%3D%22%2C%22%2Cformat%3Dnil%2Callow_no_verification%3Dfalse%2Cenv_var%3D%22%22%29-macro" class="signature"><strong>argument</strong>(variable, description, long = <span class="n">nil</span>, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, on_match = <span class="n">nil</span>, def_setter = <span class="n">false</span>, def_getter = <span class="n">false</span>, options = <span class="n">nil</span>, delimiter = <span class="s">&quot;,&quot;</span>, format = <span class="n">nil</span>, allow_no_verification = <span class="n">false</span>, env_var = <span class="s">&quot;&quot;</span>)</a>
</li>
@@ -432,13 +447,32 @@
</li>
<li class="entry-summary">
<a href="#define_singleton_init-macro" class="signature"><strong>define_singleton_init</strong></a>
<div class="summary"><p>This macro simply provides a easy singleton initializer for your command to allow for you do (if this class isn't the target of a command) to still be able to gather a Command object without having to have it as the target.</p></div>
</li>
<li class="entry-summary">
<a href="#generate_gather_handler-macro" class="signature"><strong>generate_gather_handler</strong></a>
</li>
<li class="entry-summary">
<a href="#generate_register_command-macro" class="signature"><strong>generate_register_command</strong></a>
</li>
<li class="entry-summary">
<a href="#help_template%28filepath%29-macro" class="signature"><strong>help_template</strong>(filepath)</a>
</li>
<li class="entry-summary">
<a href="#selection%28variable%2Cdescription%2Coptions%2Cshort%3Dnil%2Clong%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%29-macro" class="signature"><strong>selection</strong>(variable, description, options, short = <span class="n">nil</span>, long = <span class="n">nil</span>, validation = <span class="n">nil</span>, on_match = <span class="n">nil</span>)</a>
<a href="#resolve_value%28variable%2C%2A%2Cdefault%3Dnil%29-macro" class="signature"><strong>resolve_value</strong>(variable, *, default = <span class="n">nil</span>)</a>
<div class="summary"><p>This macro is just meant to provide the user an ability to resolve instance var/varibles from parent commands.</p></div>
</li>
@@ -447,10 +481,34 @@
</li>
<li class="entry-summary">
<a href="#validate_command_tree-macro" class="signature"><strong>validate_command_tree</strong></a>
<div class="summary"><p>This macro serves as a compile-time checker of the command-tree to validate that there is no recursive references of the command-list that would possibly cause a recursive stack-overflow during App.generate when App begins registering all user defined commands.</p></div>
</li>
</ul>
<h2>
<a id="instance-method-summary" class="anchor" href="#instance-method-summary">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>
Instance Method Summary
</h2>
<ul class="list-summary">
<li class="entry-summary">
<a href="#handler%3F%3ABool-instance-method" class="signature"><strong>#handler?</strong> : Bool</a>
</li>
</ul>
<div class="methods-inherited">
@@ -497,26 +555,12 @@
Macro Detail
</h2>
<div class="entry-detail" id="argument(variable,description,long=nil,short=nil,validation=nil,on_match=nil,def_setter=false,def_getter=false,options=nil,delimiter=&quot;,&quot;,format=nil,allow_no_verification=false,env_var=nil)-macro">
<div class="entry-detail" id="argument(variable,description,long=nil,short=nil,validation=nil,on_match=nil,def_setter=false,def_getter=false,options=nil,delimiter=&quot;,&quot;,format=nil,allow_no_verification=false,env_var=&quot;&quot;)-macro">
<div class="signature">
macro <strong>argument</strong>(variable, description, long = <span class="n">nil</span>, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, on_match = <span class="n">nil</span>, def_setter = <span class="n">false</span>, def_getter = <span class="n">false</span>, options = <span class="n">nil</span>, delimiter = <span class="s">&quot;,&quot;</span>, format = <span class="n">nil</span>, allow_no_verification = <span class="n">false</span>, env_var = <span class="n">nil</span>)
macro <strong>argument</strong>(variable, description, long = <span class="n">nil</span>, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, on_match = <span class="n">nil</span>, def_setter = <span class="n">false</span>, def_getter = <span class="n">false</span>, options = <span class="n">nil</span>, delimiter = <span class="s">&quot;,&quot;</span>, format = <span class="n">nil</span>, allow_no_verification = <span class="n">false</span>, env_var = <span class="s">&quot;&quot;</span>)
<a class="method-permalink" href="#argument%28variable%2Cdescription%2Clong%3Dnil%2Cshort%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%2Cdef_setter%3Dfalse%2Cdef_getter%3Dfalse%2Coptions%3Dnil%2Cdelimiter%3D%22%2C%22%2Cformat%3Dnil%2Callow_no_verification%3Dfalse%2Cenv_var%3Dnil%29-macro">#</a>
</div>
<br/>
<div>
</div>
</div>
<div class="entry-detail" id="def_init-macro">
<div class="signature">
macro <strong>def_init</strong>
<a class="method-permalink" href="#def_init-macro">#</a>
<a class="method-permalink" href="#argument%28variable%2Cdescription%2Clong%3Dnil%2Cshort%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%2Cdef_setter%3Dfalse%2Cdef_getter%3Dfalse%2Coptions%3Dnil%2Cdelimiter%3D%22%2C%22%2Cformat%3Dnil%2Callow_no_verification%3Dfalse%2Cenv_var%3D%22%22%29-macro">#</a>
</div>
<br/>
@@ -539,6 +583,60 @@
</div>
</div>
<div class="entry-detail" id="define_singleton_init-macro">
<div class="signature">
macro <strong>define_singleton_init</strong>
<a class="method-permalink" href="#define_singleton_init-macro">#</a>
</div>
<div class="doc">
<p>This macro simply provides a easy singleton initializer for your command
to allow for you do (if this class isn't the target of a command) to still
be able to gather a Command object without having to have it as the target.</p>
<p>This will setup the default (no args) initializer to gather the handler from
CliGen::App and then resolve all of the ivar (CliGen managed) to the parsed
values from the associated Flag(T) object that (if the process itself is
being started by CliGen the provided flags will store the value to be
set here)</p>
</div>
<br/>
<div>
</div>
</div>
<div class="entry-detail" id="generate_gather_handler-macro">
<div class="signature">
macro <strong>generate_gather_handler</strong>
<a class="method-permalink" href="#generate_gather_handler-macro">#</a>
</div>
<br/>
<div>
</div>
</div>
<div class="entry-detail" id="generate_register_command-macro">
<div class="signature">
macro <strong>generate_register_command</strong>
<a class="method-permalink" href="#generate_register_command-macro">#</a>
</div>
<br/>
<div>
</div>
</div>
<div class="entry-detail" id="help_template(filepath)-macro">
<div class="signature">
@@ -553,14 +651,29 @@
</div>
</div>
<div class="entry-detail" id="selection(variable,description,options,short=nil,long=nil,validation=nil,on_match=nil)-macro">
<div class="entry-detail" id="resolve_value(variable,*,default=nil)-macro">
<div class="signature">
macro <strong>selection</strong>(variable, description, options, short = <span class="n">nil</span>, long = <span class="n">nil</span>, validation = <span class="n">nil</span>, on_match = <span class="n">nil</span>)
macro <strong>resolve_value</strong>(variable, *, default = <span class="n">nil</span>)
<a class="method-permalink" href="#selection%28variable%2Cdescription%2Coptions%2Cshort%3Dnil%2Clong%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%29-macro">#</a>
<a class="method-permalink" href="#resolve_value%28variable%2C%2A%2Cdefault%3Dnil%29-macro">#</a>
</div>
<div class="doc">
<p>This macro is just meant to provide the user an ability to resolve instance
var/varibles from parent commands. Simply to allow subcommands to be able
to retrieve values from their parents</p>
<p>As an aside, this (as written) can only be used for variables that have
a default defined (ex: @var : Int32 = 3)</p>
<p>For variables that (in your parent class) isn't set with a default value,
you will need to provide the (default: <val>) kwarg to set your own
runtime default if the value itself cannot be ensured by the compiler.</p>
<p>This is a requirement as this macro MUST always return a value without
rasing, and the only way to do that is force the user to provide a
default of their choosing.</p>
</div>
<br/>
<div>
@@ -581,7 +694,68 @@
</div>
</div>
<div class="entry-detail" id="validate_command_tree-macro">
<div class="signature">
macro <strong>validate_command_tree</strong>
<a class="method-permalink" href="#validate_command_tree-macro">#</a>
</div>
<div class="doc">
<p>This macro serves as a compile-time checker of the command-tree to
validate that there is no recursive references of the command-list
that would possibly cause a recursive stack-overflow during App.generate
when App begins registering all user defined commands.</p>
<p>However, while this does exist, due to the way that the App.generate method
handles gathering root commands it makes this edge-case impossible to hit
aside from manually running the
Command#register_command([] of CliGen::Command) method.</p>
<p>However, with this in place this issue cannot be hit at runtime as this will
prevent compilation if a recursive/circular command tree exists.</p>
<p>Additionally, this exists to prevent the user from defining a command tree
that extends past the compile-time configured max via the
CliGen::MAX_COMMAND_DEPTH constant.</p>
<p>The reason this is a thing is because crystal macros don't allow for
unbounded while's/until's in macros, meaning it always has to be
deterministic. SO to deal with this and still allow for subcommand
defining you need either go with the default (32 command depth) or
define your own larger max (understand this will affect compile-time
due to this directly affecting loops in the Command macros).</p>
</div>
<br/>
<div>
</div>
</div>
<h2>
<a id="instance-method-detail" class="anchor" href="#instance-method-detail">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>
Instance Method Detail
</h2>
<div class="entry-detail" id="handler?:Bool-instance-method">
<div class="signature">
def <strong>handler?</strong> : Bool
<a class="method-permalink" href="#handler%3F%3ABool-instance-method">#</a>
</div>
<br/>
<div>
</div>
</div>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+26 -11
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
@@ -398,7 +403,7 @@
<ul class="list-summary">
<li class="entry-summary">
<a href="#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="signature"><strong>.new</strong>(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), description : String | Nil = <span class="n">nil</span>)</a>
<a href="#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cparent%3ABaseCommandNode%7CNil%3Dnil%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="signature"><strong>.new</strong>(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), parent : BaseCommandNode | Nil = <span class="n">nil</span>, description : String | Nil = <span class="n">nil</span>)</a>
</li>
@@ -456,6 +461,11 @@
<h3>Instance methods inherited from class <code><a href="../CliGen/BaseCommandNode.html">CliGen::BaseCommandNode</a></code></h3>
<a href="../CliGen/BaseCommandNode.html#all_commands%3AArray%28BaseCommandNode%29-instance-method" class="tooltip">
<span>all_commands : Array(BaseCommandNode)</span>
all_commands</a>,
<a href="../CliGen/BaseCommandNode.html#all_flags%3AArray%28BaseFlag%29-instance-method" class="tooltip">
<span>all_flags : Array(BaseFlag)</span>
all_flags</a>,
@@ -521,6 +531,11 @@
name</a>,
<a href="../CliGen/BaseCommandNode.html#parent%3F%3ABaseCommandNode%7CNil-instance-method" class="tooltip">
<span>parent? : BaseCommandNode | Nil</span>
parent?</a>,
<a href="../CliGen/BaseCommandNode.html#process%28args%3AArray%28String%29%29%3ANil-instance-method" class="tooltip">
<span>process(args : Array(String)) : Nil<br/>process(args : Array(CliGen::Arg)) : Nil</span>
process</a>,
@@ -548,8 +563,8 @@
<h3>Constructor methods inherited from class <code><a href="../CliGen/BaseCommandNode.html">CliGen::BaseCommandNode</a></code></h3>
<a href="../CliGen/BaseCommandNode.html#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cmeta%3ACommandMeta%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="tooltip">
<span>new(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), meta : CommandMeta, description : String | Nil = <span class="n">nil</span>)</span>
<a href="../CliGen/BaseCommandNode.html#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cmeta%3ACommandMeta%2Cparent%3ABaseCommandNode%7CNil%3Dnil%2Cdescription%3AString%7CNil%3Dnil%29-class-method" class="tooltip">
<span>new(name : String, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand), meta : CommandMeta, parent : BaseCommandNode | Nil = <span class="n">nil</span>, description : String | Nil = <span class="n">nil</span>)</span>
new</a>
@@ -600,12 +615,12 @@
Constructor Detail
</h2>
<div class="entry-detail" id="new(name:String,flags:Array(BaseFlag),commands:Array(BaseCommandNode),pre_run_commands:Array(RunCommand),post_run_commands:Array(RunCommand),description:String|Nil=nil)-class-method">
<div class="entry-detail" id="new(name:String,flags:Array(BaseFlag),commands:Array(BaseCommandNode),pre_run_commands:Array(RunCommand),post_run_commands:Array(RunCommand),parent:BaseCommandNode|Nil=nil,description:String|Nil=nil)-class-method">
<div class="signature">
def self.<strong>new</strong>(name : String, flags : Array(<a href="../CliGen/BaseFlag.html">BaseFlag</a>), commands : Array(<a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a>), pre_run_commands : Array(<a href="../CliGen/RunCommand.html">RunCommand</a>), post_run_commands : Array(<a href="../CliGen/RunCommand.html">RunCommand</a>), description : String | Nil = <span class="n">nil</span>)
def self.<strong>new</strong>(name : String, flags : Array(<a href="../CliGen/BaseFlag.html">BaseFlag</a>), commands : Array(<a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a>), pre_run_commands : Array(<a href="../CliGen/RunCommand.html">RunCommand</a>), post_run_commands : Array(<a href="../CliGen/RunCommand.html">RunCommand</a>), parent : <a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a> | Nil = <span class="n">nil</span>, description : String | Nil = <span class="n">nil</span>)
<a class="method-permalink" href="#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cdescription%3AString%7CNil%3Dnil%29-class-method">#</a>
<a class="method-permalink" href="#new%28name%3AString%2Cflags%3AArray%28BaseFlag%29%2Ccommands%3AArray%28BaseCommandNode%29%2Cpre_run_commands%3AArray%28RunCommand%29%2Cpost_run_commands%3AArray%28RunCommand%29%2Cparent%3ABaseCommandNode%7CNil%3Dnil%2Cdescription%3AString%7CNil%3Dnil%29-class-method">#</a>
</div>
<br/>
+444
View File
@@ -0,0 +1,444 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Crystal Docs 1.20.3">
<meta name="crystal_docs.project_version" content="object_rework-dev">
<meta name="crystal_docs.project_name" content="CliGenerator">
<link href="../css/style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../js/doc.js"></script>
<meta name="repository-name" content="CliGenerator">
<title>CliGen::Common - CliGenerator object_rework-dev</title>
<script type="text/javascript">
CrystalDocs.base_path = "../";
</script>
</head>
<body>
<svg class="hidden">
<symbol id="octicon-link" viewBox="0 0 16 16">
<path fill="currentColor" fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path>
</symbol>
</svg>
<input type="checkbox" id="sidebar-btn">
<label for="sidebar-btn" id="sidebar-btn-label">
<svg class="open" xmlns="http://www.w3.org/2000/svg" height="2em" width="2em" viewBox="0 0 512 512"><title>Open Sidebar</title><path fill="currentColor" d="M80 96v64h352V96H80zm0 112v64h352v-64H80zm0 112v64h352v-64H80z"></path></svg>
<svg class="close" xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" viewBox="0 0 512 512"><title>Close Sidebar</title><path fill="currentColor" d="m118.6 73.4-45.2 45.2L210.7 256 73.4 393.4l45.2 45.2L256 301.3l137.4 137.3 45.2-45.2L301.3 256l137.3-137.4-45.2-45.2L256 210.7Z"></path></svg>
</label>
<div class="sidebar">
<div class="sidebar-header">
<div class="search-box">
<input type="search" class="search-input" placeholder="Search..." spellcheck="false" aria-label="Search">
</div>
<div class="project-summary">
<h1 class="project-name">
<a href="../index.html">
CliGenerator
</a>
</h1>
<span class="project-version">
object_rework-dev
</span>
</div>
</div>
<div class="search-results hidden">
<ul class="search-list"></ul>
</div>
<div class="types-list">
<ul>
<li class="parent open current" data-id="CliGenerator/CliGen" data-name="cligen">
<a href="../CliGen.html">CliGen</a>
<ul>
<li class=" " data-id="CliGenerator/CliGen/App" data-name="cligen::app">
<a href="../CliGen/App.html">App</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Arg" data-name="cligen::arg">
<a href="../CliGen/Arg.html">Arg</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ArgReprocessedError" data-name="cligen::argreprocessederror">
<a href="../CliGen/ArgReprocessedError.html">ArgReprocessedError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Argument" data-name="cligen::argument">
<a href="../CliGen/Argument.html">Argument</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/BaseCommandNode" data-name="cligen::basecommandnode">
<a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/BaseFlag" data-name="cligen::baseflag">
<a href="../CliGen/BaseFlag.html">BaseFlag</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Coercable" data-name="cligen::coercable">
<a href="../CliGen/Coercable.html">Coercable</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Command" data-name="cligen::command">
<a href="../CliGen/Command.html">Command</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/CommandInfo" data-name="cligen::commandinfo">
<a href="../CliGen/CommandInfo.html">CommandInfo</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/CommandMeta" data-name="cligen::commandmeta">
<a href="../CliGen/CommandMeta.html">CommandMeta</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/CommandNode" data-name="cligen::commandnode(t)">
<a href="../CliGen/CommandNode.html">CommandNode</a>
</li>
<li class=" current" data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/DuplicateCommandError" data-name="cligen::duplicatecommanderror">
<a href="../CliGen/DuplicateCommandError.html">DuplicateCommandError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/DuplicateFlagError" data-name="cligen::duplicateflagerror">
<a href="../CliGen/DuplicateFlagError.html">DuplicateFlagError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Error" data-name="cligen::error">
<a href="../CliGen/Error.html">Error</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Flag" data-name="cligen::flag(t)">
<a href="../CliGen/Flag.html">Flag</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagArgumentError" data-name="cligen::flagargumenterror">
<a href="../CliGen/FlagArgumentError.html">FlagArgumentError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagBundleError" data-name="cligen::flagbundleerror">
<a href="../CliGen/FlagBundleError.html">FlagBundleError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagMeta" data-name="cligen::flagmeta">
<a href="../CliGen/FlagMeta.html">FlagMeta</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagMissingArgumentError" data-name="cligen::flagmissingargumenterror">
<a href="../CliGen/FlagMissingArgumentError.html">FlagMissingArgumentError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagNotFoundError" data-name="cligen::flagnotfounderror">
<a href="../CliGen/FlagNotFoundError.html">FlagNotFoundError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Format" data-name="cligen::format">
<a href="../CliGen/Format.html">Format</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/HelpRequestedError" data-name="cligen::helprequestederror">
<a href="../CliGen/HelpRequestedError.html">HelpRequestedError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalError" data-name="cligen::internalerror">
<a href="../CliGen/InternalError.html">InternalError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidOptionError" data-name="cligen::invalidoptionerror">
<a href="../CliGen/InvalidOptionError.html">InvalidOptionError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/MatchType" data-name="cligen::matchtype">
<a href="../CliGen/MatchType.html">MatchType</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/MissingDispatchError" data-name="cligen::missingdispatcherror">
<a href="../CliGen/MissingDispatchError.html">MissingDispatchError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/MissingRequiredFlagError" data-name="cligen::missingrequiredflagerror">
<a href="../CliGen/MissingRequiredFlagError.html">MissingRequiredFlagError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Parsable" data-name="cligen::parsable">
<a href="../CliGen/Parsable.html">Parsable</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ParseableInvariantError" data-name="cligen::parseableinvarianterror">
<a href="../CliGen/ParseableInvariantError.html">ParseableInvariantError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/PreRunCommand" data-name="cligen::preruncommand">
<a href="../CliGen/PreRunCommand.html">PreRunCommand</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ProxyCommand" data-name="cligen::proxycommand">
<a href="../CliGen/ProxyCommand.html">ProxyCommand</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Regex" data-name="cligen::regex">
<a href="../CliGen/Regex.html">Regex</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/RegexInvariantError" data-name="cligen::regexinvarianterror">
<a href="../CliGen/RegexInvariantError.html">RegexInvariantError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ReservedFlagError" data-name="cligen::reservedflagerror">
<a href="../CliGen/ReservedFlagError.html">ReservedFlagError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/RunCommand" data-name="cligen::runcommand">
<a href="../CliGen/RunCommand.html">RunCommand</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/RuntimeError" data-name="cligen::runtimeerror">
<a href="../CliGen/RuntimeError.html">RuntimeError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommandInfo" data-name="cligen::subcommandinfo">
<a href="../CliGen/SubCommandInfo.html">SubCommandInfo</a>
</li>
<li class="parent " data-id="CliGenerator/CliGen/Timeparse" data-name="cligen::timeparse">
<a href="../CliGen/Timeparse.html">Timeparse</a>
<ul>
<li class=" " data-id="CliGenerator/CliGen/Timeparse/OperationUnit" data-name="cligen::timeparse::operationunit">
<a href="../CliGen/Timeparse/OperationUnit.html">OperationUnit</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Timeparse/RelativeOperation" data-name="cligen::timeparse::relativeoperation">
<a href="../CliGen/Timeparse/RelativeOperation.html">RelativeOperation</a>
</li>
</ul>
</li>
<li class=" " data-id="CliGenerator/CliGen/TimeParseError" data-name="cligen::timeparseerror">
<a href="../CliGen/TimeParseError.html">TimeParseError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Trigger" data-name="cligen::trigger">
<a href="../CliGen/Trigger.html">Trigger</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/UnknownCommandNodeError" data-name="cligen::unknowncommandnodeerror">
<a href="../CliGen/UnknownCommandNodeError.html">UnknownCommandNodeError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/UnknownFlagError" data-name="cligen::unknownflagerror">
<a href="../CliGen/UnknownFlagError.html">UnknownFlagError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ValidationError" data-name="cligen::validationerror">
<a href="../CliGen/ValidationError.html">ValidationError</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="main-content">
<h1 class="type-name">
<span class="kind">
module
</span> CliGen::<wbr>Common
</h1>
<h2>
<a id="defined-in" class="anchor" href="#defined-in">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>
Defined in:
</h2>
cligen/common/check_flag_vars.cr
<br/>
<h2>
<a id="macro-summary" class="anchor" href="#macro-summary">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>
Macro Summary
</h2>
<ul class="list-summary">
<li class="entry-summary">
<a href="#check_flag_vars%28%2A%2Ctype%2Clong%2Cdescription%2Craise_base%2Cshort%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%2Coptions%3Dnil%2Cformat%3Dnil%2Cenv_var%3Dnil%2Cdelimiter%3D%22%2C%22%2Callow_no_verification%3Dfalse%2Cinternal%3Dfalse%29-macro" class="signature"><strong>check_flag_vars</strong>(*, type, long, description, raise_base, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, on_match = <span class="n">nil</span>, options = <span class="n">nil</span>, format = <span class="n">nil</span>, env_var = <span class="n">nil</span>, delimiter = <span class="s">&quot;,&quot;</span>, allow_no_verification = <span class="n">false</span>, internal = <span class="n">false</span>)</a>
</li>
</ul>
<div class="methods-inherited">
</div>
<h2>
<a id="macro-detail" class="anchor" href="#macro-detail">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>
Macro Detail
</h2>
<div class="entry-detail" id="check_flag_vars(*,type,long,description,raise_base,short=nil,validation=nil,on_match=nil,options=nil,format=nil,env_var=nil,delimiter=&quot;,&quot;,allow_no_verification=false,internal=false)-macro">
<div class="signature">
macro <strong>check_flag_vars</strong>(*, type, long, description, raise_base, short = <span class="n">nil</span>, validation = <span class="n">nil</span>, on_match = <span class="n">nil</span>, options = <span class="n">nil</span>, format = <span class="n">nil</span>, env_var = <span class="n">nil</span>, delimiter = <span class="s">&quot;,&quot;</span>, allow_no_verification = <span class="n">false</span>, internal = <span class="n">false</span>)
<a class="method-permalink" href="#check_flag_vars%28%2A%2Ctype%2Clong%2Cdescription%2Craise_base%2Cshort%3Dnil%2Cvalidation%3Dnil%2Con_match%3Dnil%2Coptions%3Dnil%2Cformat%3Dnil%2Cenv_var%3Dnil%2Cdelimiter%3D%22%2C%22%2Callow_no_verification%3Dfalse%2Cinternal%3Dfalse%29-macro">#</a>
</div>
<br/>
<div>
</div>
</div>
</div>
</body>
</html>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" current" data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+18 -13
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
@@ -384,7 +389,7 @@
<ul class="list-summary">
<li class="entry-summary">
<a href="#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%2Cdescription%3AString%2Cdelimiter%3AString%3D%22%2C%22%2Cdefault%3AT%7CNil%3Dnil%2Coptions%3AArray%28T%29%7CNil%3Dnil%2Cvalidate%3AT-%3EBool%7CNil%3Dnil%2Con_match%3AProc%28T%2CNil%29%7CNil%3Dnil%2Cformat%3A%3A%3ARegex%7CNil%3Dnil%29-class-method" class="signature"><strong>.new</strong>(var : String, short : String | Nil, long : String, env_var : String, description : String, delimiter : String = <span class="s">&quot;,&quot;</span>, default : T | Nil = <span class="n">nil</span>, options : Array(T) | Nil = <span class="n">nil</span>, validate : T -> Bool | Nil = <span class="n">nil</span>, on_match : Proc(T, Nil) | Nil = <span class="n">nil</span>, format : ::Regex | Nil = <span class="n">nil</span>)</a>
<a href="#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%7CNil%2Cdescription%3AString%2Cdelimiter%3AString%3D%22%2C%22%2Cdefault%3AT%7CNil%3Dnil%2Coptions%3AArray%28T%29%7CNil%3Dnil%2Cvalidate%3AT-%3EBool%7CNil%3Dnil%2Con_match%3AProc%28T%2CNil%29%7CNil%3Dnil%2Cformat%3A%3A%3ARegex%7CNil%3Dnil%29-class-method" class="signature"><strong>.new</strong>(var : String, short : String | Nil, long : String, env_var : String | Nil, description : String, delimiter : String = <span class="s">&quot;,&quot;</span>, default : T | Nil = <span class="n">nil</span>, options : Array(T) | Nil = <span class="n">nil</span>, validate : T -> Bool | Nil = <span class="n">nil</span>, on_match : Proc(T, Nil) | Nil = <span class="n">nil</span>, format : ::Regex | Nil = <span class="n">nil</span>)</a>
</li>
@@ -467,8 +472,8 @@
description</a>,
<a href="../CliGen/BaseFlag.html#env_var%3AString-instance-method" class="tooltip">
<span>env_var : String</span>
<a href="../CliGen/BaseFlag.html#env_var%3AString%7CNil-instance-method" class="tooltip">
<span>env_var : String | Nil</span>
env_var</a>,
@@ -524,8 +529,8 @@
<h3>Constructor methods inherited from class <code><a href="../CliGen/BaseFlag.html">CliGen::BaseFlag</a></code></h3>
<a href="../CliGen/BaseFlag.html#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%2Cdescription%3AString%2Cdelimiter%3AString%2Cmeta%3AFlagMeta%29-class-method" class="tooltip">
<span>new(var : String, short : String | Nil, long : String, env_var : String, description : String, delimiter : String, meta : FlagMeta)</span>
<a href="../CliGen/BaseFlag.html#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%7CNil%2Cdescription%3AString%2Cdelimiter%3AString%2Cmeta%3AFlagMeta%29-class-method" class="tooltip">
<span>new(var : String, short : String | Nil, long : String, env_var : String | Nil, description : String, delimiter : String, meta : FlagMeta)</span>
new</a>
@@ -576,12 +581,12 @@
Constructor Detail
</h2>
<div class="entry-detail" id="new(var:String,short:String|Nil,long:String,env_var:String,description:String,delimiter:String=&quot;,&quot;,default:T|Nil=nil,options:Array(T)|Nil=nil,validate:T-&gt;Bool|Nil=nil,on_match:Proc(T,Nil)|Nil=nil,format:::Regex|Nil=nil)-class-method">
<div class="entry-detail" id="new(var:String,short:String|Nil,long:String,env_var:String|Nil,description:String,delimiter:String=&quot;,&quot;,default:T|Nil=nil,options:Array(T)|Nil=nil,validate:T-&gt;Bool|Nil=nil,on_match:Proc(T,Nil)|Nil=nil,format:::Regex|Nil=nil)-class-method">
<div class="signature">
def self.<strong>new</strong>(var : String, short : String | Nil, long : String, env_var : String, description : String, delimiter : String = <span class="s">&quot;,&quot;</span>, default : T | Nil = <span class="n">nil</span>, options : Array(T) | Nil = <span class="n">nil</span>, validate : T -> Bool | Nil = <span class="n">nil</span>, on_match : Proc(T, Nil) | Nil = <span class="n">nil</span>, format : ::Regex | Nil = <span class="n">nil</span>)
def self.<strong>new</strong>(var : String, short : String | Nil, long : String, env_var : String | Nil, description : String, delimiter : String = <span class="s">&quot;,&quot;</span>, default : T | Nil = <span class="n">nil</span>, options : Array(T) | Nil = <span class="n">nil</span>, validate : T -> Bool | Nil = <span class="n">nil</span>, on_match : Proc(T, Nil) | Nil = <span class="n">nil</span>, format : ::Regex | Nil = <span class="n">nil</span>)
<a class="method-permalink" href="#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%2Cdescription%3AString%2Cdelimiter%3AString%3D%22%2C%22%2Cdefault%3AT%7CNil%3Dnil%2Coptions%3AArray%28T%29%7CNil%3Dnil%2Cvalidate%3AT-%3EBool%7CNil%3Dnil%2Con_match%3AProc%28T%2CNil%29%7CNil%3Dnil%2Cformat%3A%3A%3ARegex%7CNil%3Dnil%29-class-method">#</a>
<a class="method-permalink" href="#new%28var%3AString%2Cshort%3AString%7CNil%2Clong%3AString%2Cenv_var%3AString%7CNil%2Cdescription%3AString%2Cdelimiter%3AString%3D%22%2C%22%2Cdefault%3AT%7CNil%3Dnil%2Coptions%3AArray%28T%29%7CNil%3Dnil%2Cvalidate%3AT-%3EBool%7CNil%3Dnil%2Con_match%3AProc%28T%2CNil%29%7CNil%3Dnil%2Cformat%3A%3A%3ARegex%7CNil%3Dnil%29-class-method">#</a>
</div>
<br/>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+403
View File
@@ -0,0 +1,403 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Crystal Docs 1.20.3">
<meta name="crystal_docs.project_version" content="object_rework-dev">
<meta name="crystal_docs.project_name" content="CliGenerator">
<link href="../css/style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="../js/doc.js"></script>
<meta name="repository-name" content="CliGenerator">
<title>CliGen::InternalVar - CliGenerator object_rework-dev</title>
<script type="text/javascript">
CrystalDocs.base_path = "../";
</script>
</head>
<body>
<svg class="hidden">
<symbol id="octicon-link" viewBox="0 0 16 16">
<path fill="currentColor" fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path>
</symbol>
</svg>
<input type="checkbox" id="sidebar-btn">
<label for="sidebar-btn" id="sidebar-btn-label">
<svg class="open" xmlns="http://www.w3.org/2000/svg" height="2em" width="2em" viewBox="0 0 512 512"><title>Open Sidebar</title><path fill="currentColor" d="M80 96v64h352V96H80zm0 112v64h352v-64H80zm0 112v64h352v-64H80z"></path></svg>
<svg class="close" xmlns="http://www.w3.org/2000/svg" width="2em" height="2em" viewBox="0 0 512 512"><title>Close Sidebar</title><path fill="currentColor" d="m118.6 73.4-45.2 45.2L210.7 256 73.4 393.4l45.2 45.2L256 301.3l137.4 137.3 45.2-45.2L301.3 256l137.3-137.4-45.2-45.2L256 210.7Z"></path></svg>
</label>
<div class="sidebar">
<div class="sidebar-header">
<div class="search-box">
<input type="search" class="search-input" placeholder="Search..." spellcheck="false" aria-label="Search">
</div>
<div class="project-summary">
<h1 class="project-name">
<a href="../index.html">
CliGenerator
</a>
</h1>
<span class="project-version">
object_rework-dev
</span>
</div>
</div>
<div class="search-results hidden">
<ul class="search-list"></ul>
</div>
<div class="types-list">
<ul>
<li class="parent open current" data-id="CliGenerator/CliGen" data-name="cligen">
<a href="../CliGen.html">CliGen</a>
<ul>
<li class=" " data-id="CliGenerator/CliGen/App" data-name="cligen::app">
<a href="../CliGen/App.html">App</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Arg" data-name="cligen::arg">
<a href="../CliGen/Arg.html">Arg</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ArgReprocessedError" data-name="cligen::argreprocessederror">
<a href="../CliGen/ArgReprocessedError.html">ArgReprocessedError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Argument" data-name="cligen::argument">
<a href="../CliGen/Argument.html">Argument</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/BaseCommandNode" data-name="cligen::basecommandnode">
<a href="../CliGen/BaseCommandNode.html">BaseCommandNode</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/BaseFlag" data-name="cligen::baseflag">
<a href="../CliGen/BaseFlag.html">BaseFlag</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Coercable" data-name="cligen::coercable">
<a href="../CliGen/Coercable.html">Coercable</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Command" data-name="cligen::command">
<a href="../CliGen/Command.html">Command</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/CommandInfo" data-name="cligen::commandinfo">
<a href="../CliGen/CommandInfo.html">CommandInfo</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/CommandMeta" data-name="cligen::commandmeta">
<a href="../CliGen/CommandMeta.html">CommandMeta</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/CommandNode" data-name="cligen::commandnode(t)">
<a href="../CliGen/CommandNode.html">CommandNode</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/DuplicateCommandError" data-name="cligen::duplicatecommanderror">
<a href="../CliGen/DuplicateCommandError.html">DuplicateCommandError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/DuplicateFlagError" data-name="cligen::duplicateflagerror">
<a href="../CliGen/DuplicateFlagError.html">DuplicateFlagError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Error" data-name="cligen::error">
<a href="../CliGen/Error.html">Error</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Flag" data-name="cligen::flag(t)">
<a href="../CliGen/Flag.html">Flag</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagArgumentError" data-name="cligen::flagargumenterror">
<a href="../CliGen/FlagArgumentError.html">FlagArgumentError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagBundleError" data-name="cligen::flagbundleerror">
<a href="../CliGen/FlagBundleError.html">FlagBundleError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagMeta" data-name="cligen::flagmeta">
<a href="../CliGen/FlagMeta.html">FlagMeta</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagMissingArgumentError" data-name="cligen::flagmissingargumenterror">
<a href="../CliGen/FlagMissingArgumentError.html">FlagMissingArgumentError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/FlagNotFoundError" data-name="cligen::flagnotfounderror">
<a href="../CliGen/FlagNotFoundError.html">FlagNotFoundError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Format" data-name="cligen::format">
<a href="../CliGen/Format.html">Format</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/HelpRequestedError" data-name="cligen::helprequestederror">
<a href="../CliGen/HelpRequestedError.html">HelpRequestedError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalError" data-name="cligen::internalerror">
<a href="../CliGen/InternalError.html">InternalError</a>
</li>
<li class=" current" data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidOptionError" data-name="cligen::invalidoptionerror">
<a href="../CliGen/InvalidOptionError.html">InvalidOptionError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/MatchType" data-name="cligen::matchtype">
<a href="../CliGen/MatchType.html">MatchType</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/MissingDispatchError" data-name="cligen::missingdispatcherror">
<a href="../CliGen/MissingDispatchError.html">MissingDispatchError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/MissingRequiredFlagError" data-name="cligen::missingrequiredflagerror">
<a href="../CliGen/MissingRequiredFlagError.html">MissingRequiredFlagError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Parsable" data-name="cligen::parsable">
<a href="../CliGen/Parsable.html">Parsable</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ParseableInvariantError" data-name="cligen::parseableinvarianterror">
<a href="../CliGen/ParseableInvariantError.html">ParseableInvariantError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/PreRunCommand" data-name="cligen::preruncommand">
<a href="../CliGen/PreRunCommand.html">PreRunCommand</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ProxyCommand" data-name="cligen::proxycommand">
<a href="../CliGen/ProxyCommand.html">ProxyCommand</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Regex" data-name="cligen::regex">
<a href="../CliGen/Regex.html">Regex</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/RegexInvariantError" data-name="cligen::regexinvarianterror">
<a href="../CliGen/RegexInvariantError.html">RegexInvariantError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ReservedFlagError" data-name="cligen::reservedflagerror">
<a href="../CliGen/ReservedFlagError.html">ReservedFlagError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/RunCommand" data-name="cligen::runcommand">
<a href="../CliGen/RunCommand.html">RunCommand</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/RuntimeError" data-name="cligen::runtimeerror">
<a href="../CliGen/RuntimeError.html">RuntimeError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommandInfo" data-name="cligen::subcommandinfo">
<a href="../CliGen/SubCommandInfo.html">SubCommandInfo</a>
</li>
<li class="parent " data-id="CliGenerator/CliGen/Timeparse" data-name="cligen::timeparse">
<a href="../CliGen/Timeparse.html">Timeparse</a>
<ul>
<li class=" " data-id="CliGenerator/CliGen/Timeparse/OperationUnit" data-name="cligen::timeparse::operationunit">
<a href="../CliGen/Timeparse/OperationUnit.html">OperationUnit</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Timeparse/RelativeOperation" data-name="cligen::timeparse::relativeoperation">
<a href="../CliGen/Timeparse/RelativeOperation.html">RelativeOperation</a>
</li>
</ul>
</li>
<li class=" " data-id="CliGenerator/CliGen/TimeParseError" data-name="cligen::timeparseerror">
<a href="../CliGen/TimeParseError.html">TimeParseError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/Trigger" data-name="cligen::trigger">
<a href="../CliGen/Trigger.html">Trigger</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/UnknownCommandNodeError" data-name="cligen::unknowncommandnodeerror">
<a href="../CliGen/UnknownCommandNodeError.html">UnknownCommandNodeError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/UnknownFlagError" data-name="cligen::unknownflagerror">
<a href="../CliGen/UnknownFlagError.html">UnknownFlagError</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ValidationError" data-name="cligen::validationerror">
<a href="../CliGen/ValidationError.html">ValidationError</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="main-content">
<h1 class="type-name">
<span class="kind">
annotation
</span> CliGen::<wbr>InternalVar
</h1>
<h2>
<a id="defined-in" class="anchor" href="#defined-in">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
</svg>
</a>
Defined in:
</h2>
cligen/annotations.cr
<br/>
<div class="methods-inherited">
</div>
</div>
</body>
</html>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" current" data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+22 -7
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
@@ -390,8 +395,13 @@
</dt>
<dt class="entry-const" id="FLAG_LONG">
<strong>FLAG_LONG</strong> = <code><span class="s">/^--[a-zA-Z0-9][a-zA-Z0-9-_]+$/</span></code>
</dt>
<dt class="entry-const" id="FLAG_MULTIPLE_SHORT">
<strong>FLAG_MULTIPLE_SHORT</strong> = <code><span class="s">/^-[a-zA-Z0-9]+$/</span></code>
<strong>FLAG_MULTIPLE_SHORT</strong> = <code><span class="s">/^-[a-zA-Z][a-zA-Z]+$/</span></code>
</dt>
@@ -400,8 +410,13 @@
</dt>
<dt class="entry-const" id="FLAG_SHORT">
<strong>FLAG_SHORT</strong> = <code><span class="s">/^-[a-zA-Z]$/</span></code>
</dt>
<dt class="entry-const" id="FLAG_WITH_ARG">
<strong>FLAG_WITH_ARG</strong> = <code><span class="s">/^(?&lt;flag&gt;(-[a-zA-Z]|--[a-zA-Z-_]+))=&quot;?(?&lt;arg&gt;\S+?)&quot;?$/</span></code>
<strong>FLAG_WITH_ARG</strong> = <code><span class="s">/^(?&lt;flag&gt;(-[a-zA-Z]|--[a-zA-Z0-9][a-zA-Z0-9-_]+))=&quot;?(?&lt;arg&gt;.+?)&quot;?$/</span></code>
</dt>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" current" data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+10 -5
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="../CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="../CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="../CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="../CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="../CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="../CliGen/SubCommand.html">SubCommand</a>
+11 -6
View File
@@ -117,6 +117,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Common" data-name="cligen::common">
<a href="CliGen/Common.html">Common</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/ConfigurationError" data-name="cligen::configurationerror">
<a href="CliGen/ConfigurationError.html">ConfigurationError</a>
@@ -182,6 +187,11 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/InternalVar" data-name="cligen::internalvar">
<a href="CliGen/InternalVar.html">InternalVar</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/InvalidFlagValueError" data-name="cligen::invalidflagvalueerror">
<a href="CliGen/InvalidFlagValueError.html">InvalidFlagValueError</a>
@@ -252,11 +262,6 @@
</li>
<li class=" " data-id="CliGenerator/CliGen/Selection" data-name="cligen::selection">
<a href="CliGen/Selection.html">Selection</a>
</li>
<li class=" " data-id="CliGenerator/CliGen/SubCommand" data-name="cligen::subcommand">
<a href="CliGen/SubCommand.html">SubCommand</a>
@@ -334,7 +339,7 @@
<use href="#octicon-link"/>
</svg>
</a>How It Works</h2>
<p>Subclass <code><a href="CliGen/Command.html">CliGen::Command</a></code>, annotate your instance variables with <code>@[<a href="CliGen/Argument.html">CliGen::Argument</a>]</code> or <code>@[<a href="CliGen/Selection.html">CliGen::Selection</a>]</code>, and register the command with an <code><a href="CliGen/App.html">CliGen::App</a></code>. At compile time, macros inspect the annotations and generate typed <code>Flag(T)</code> objects; at runtime, <code>CliGen::App.process</code> walks the <code>CommandNode</code> tree to route arguments, populate your command instance, and dispatch to the right method.</p>
<p>Subclass <code><a href="CliGen/Command.html">CliGen::Command</a></code>, annotate your instance variables with <code>@[<a href="CliGen/Argument.html">CliGen::Argument</a>]</code>, and register the command with an <code><a href="CliGen/App.html">CliGen::App</a></code>. At compile time, macros inspect the annotations and generate typed <code>Flag(T)</code> objects; at runtime, <code>CliGen::App.process</code> walks the <code>CommandNode</code> tree to route arguments, populate your command instance, and dispatch to the right method.</p>
<h2><a id="installation" class="anchor" href="#installation">
<svg class="octicon-link" aria-hidden="true">
<use href="#octicon-link"/>
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,5 +1,5 @@
name: cligen
version: 0.1.0
version: 0.2.0
authors:
- Tristan Ancelet <tristanancelet@yahoo.com>
+107
View File
@@ -0,0 +1,107 @@
require "../spec_helper"
@[CliGen::CommandInfo(description: "Abc", singleton_init: true)]
class MyCmd < CliGen::Command
argument(abcdef : String = "123",
description: "This is a thing"
)
argument(ghijkl : Int32 = 666,
description: "The number of the devil"
)
argument(badvar : String,
description: "This will fail on init"
)
def main
puts "abc"
end
def get_badvar
resolve_value badvar, default: "was unset"
end
end
@[CliGen::CommandInfo(description: "Def", parent: ::MyCmd, singleton_init: true)]
class MySubCmd < CliGen::Command
argument(dfdfdf : String = "abc",
description: "ALKJSDFLSKDFJ"
)
def main
resolve_value abcdef
end
end
@[CliGen::CommandInfo(description: "Def", parent: ::MySubCmd, singleton_init: true)]
class MySubSubCmd < CliGen::Command
def main
resolve_value ghijkl
end
def main2
resolve_value badvar, default: "unset"
end
end
def get_handler_for(cls : String)
if handler = CliGen::App.get.all_commands.find(&.meta.cls.== cls)
handler
else
raise "ERROR"
end
end
describe CliGen::Command do
before_each do
ENV.delete("MYCMD_BADVAR")
end
describe "#resolve_value" do
it "does work 1 level deep" do
MySubCmd.new.main.should eq("123")
end
it "works 2 levels deep" do
MySubSubCmd.new.main.should eq(666)
end
it "If a argument is without a default value it will fall back to the default" do
MySubSubCmd.new.main2.should eq("unset")
end
it "will return the provided value if the Flag(T) has an ENVVAR to match" do
ENV["MYCMD_BADVAR"]="ABC"
MySubSubCmd.new.main2.should eq("ABC")
end
it "works on instance variables" do
a = "the cake was a lie"
ENV["MYCMD_BADVAR"] = a
handler = get_handler_for("MyCmd")
MyCmd.new(handler: handler).get_badvar.should eq(a)
end
end
describe "#initialize" do
it "will raise CliGen::MissingRequiredFlagError on handler initialize if no flag value is set for badvar" do
handler = get_handler_for("MyCmd")
expect_raises(CliGen::MissingRequiredFlagError) do
MyCmd.new(handler: handler)
end
end
it "will not raise if badvar is set via ENV VAR" do
ENV["MYCMD_BADVAR"]="the cake was a lie"
handler = get_handler_for("MyCmd")
MyCmd.new(handler: handler).get_badvar.should eq("the cake was a lie")
end
end
describe ".get" do
it "will raise CliGen::AppNotProcessedError if a user attempts to use .get before CliGen::App has processed commandline arguments" do
expect_raises(CliGen::AppNotProcessedError) do
MySubCmd.get
end
end
end
end
+9 -9
View File
@@ -104,21 +104,21 @@ describe CliGen::Flag do
before_each { ENV.delete("TEST") }
describe "#check!" do
it "will throw CliGen::ReservedFlagError if -h is used as short" do
expect_raises(CliGen::ReservedFlagError) do
make_flag(type: Bool, short: "-h", long: "--not-help").check!
it "will throw CliGen::ConfigurationError if a short is provided as a long" do
expect_raises(CliGen::ConfigurationError) do
make_flag(type: Bool, short: nil, long: "-n").check!
end
end
it "will throw CliGen::ReservedFlagError if --help is used in long" do
expect_raises(CliGen::ReservedFlagError) do
make_flag(type: Bool, short: "-b", long: "--help TOPIC").check!
it "will throw CliGen::ConfigurationError if a long is provided as a short" do
expect_raises(CliGen::ConfigurationError) do
make_flag(type: Bool, short: "--b", long: "--help TOPIC").check!
end
end
it "will throw CliGen::ReservedFlagError if --help is used as long_key" do
expect_raises(CliGen::ReservedFlagError) do
make_flag(type: Bool, short: "-b", long: "--help").check!
it "will throw CliGen::ConfigurationError if long flag does not have enough characters" do
expect_raises(CliGen::ConfigurationError) do
make_flag(type: Bool, short: "-b", long: "--h").check!
end
end
end
+344
View File
@@ -0,0 +1,344 @@
require "../spec_helper"
macro get_match(a, b, &work)
match = CliGen::Regex::{{a}}.match({{b}}).not_nil!
{{work.body}}
end
macro does_match(a, b)
CliGen::Regex::{{a}}.matches?({{b}}).should be_true
end
macro doesnt_match(a, b)
CliGen::Regex::{{a}}.matches?({{b}}).should be_false
end
describe CliGen::Regex do
describe "FLAG_REGEX" do
it "will match LONG (--long) format" do
does_match(FLAG_REGEX, "--long")
end
it "will match a SHORT (-s) format" do
does_match(FLAG_REGEX, "-s")
end
it "will not match a LONG with an arg (--long=abc)" do
doesnt_match(FLAG_REGEX, "--long=abc")
end
it "will not match a SHORT with an arg (-s=abc)" do
doesnt_match(FLAG_REGEX, "-s=abc")
end
end
describe "FLAG_WITH_ARG" do
it "will match a LONG with arg without quotes (--long=arg)" do
get_match(FLAG_WITH_ARG, "--long=arg") do
match["flag"].should eq("--long")
match["arg"].should eq("arg")
end
end
it "will match a LONG with arg with quotes (--long=\"arg\")" do
get_match(FLAG_WITH_ARG, "--long=\"arg\"") do
match["flag"].should eq("--long")
match["arg"].should eq("arg")
end
end
it "will match a LONG with arg with quotes and spaces in the arg (--long=\"arg abcd ef\")" do
get_match(FLAG_WITH_ARG, "--long=\"arg abcd ef\"") do
match["flag"].should eq("--long")
match["arg"].should eq("arg abcd ef")
end
end
it "will match a LONG with arg without quotes and with spaces in the arg (--long=arg abcd ef)" do
get_match(FLAG_WITH_ARG, "--long=arg abcd ef") do
match["flag"].should eq("--long")
match["arg"].should eq("arg abcd ef")
end
end
end
describe "FLAG_MULTIPLE_SHORT" do
it "does match a valid multi-short flag (-abcdef)" do
does_match(FLAG_MULTIPLE_SHORT, "-abcdef")
end
it "does not match a singleshort flag (-a)" do
doesnt_match(FLAG_MULTIPLE_SHORT, "-a")
end
{% for int in (0..9) %}
it "does not match a multi-short flag with a digit in it (-abc{{int}}) as -{{int}} is not a valid short" do
doesnt_match(FLAG_MULTIPLE_SHORT, "-abc{{int}}")
end
{% end %}
it "does not match a long flag (--long)" do
doesnt_match(FLAG_MULTIPLE_SHORT, "--long")
end
end
describe "FLAG_LONG" do
it "matches a valid long flag (--long)" do
does_match(FLAG_LONG, "--long")
end
it "does not match a short flag (-s)" do
doesnt_match(FLAG_LONG, "-s")
end
it "doesn't match a long flag with an arg" do
doesnt_match(FLAG_LONG, "--long=abc")
end
end
describe "FLAG_SHORT" do
it "matches a valid short flag (-s)" do
does_match(FLAG_SHORT, "-s")
end
{% for int in (0..9) %}
it "does not match a digit flag (-{{int}})" do
doesnt_match(FLAG_SHORT, "-{{int}}")
end
{% end %}
end
describe "TIMEZONE" do
{% for sign in %w[ - + ] %}
{% for i in [ 2, 4, 7 ] %}
{% for j in [ 0, 7, 59 ] %}
{% format = "%s%02d%02d".id %}
it "will match a valid offset ({{format}})" % [ {{sign}}, {{i}}, {{j}} ] do
does_match(TIMEZONE, {{format.stringify}} % [ {{sign}}, {{i}}, {{j}} ])
end
{% end %}
{% end %}
{% end %}
it "won't accept any offsets above \"+2359\"" do
doesnt_match(TIMEZONE, "-2400")
end
it "won't accept any invalid minute values (+2361)" do
doesnt_match(TIMEZONE, "-2361")
end
it "able to parse fields out of the offset (-2330)" do
get_match(TIMEZONE, "-2330") do
match["offset_sign"].should eq("-")
match["offset_hour"].should eq("23")
match["offset_minute"].should eq("30")
match["timezone"].should eq("-2330")
end
end
end
describe "TIME" do
it "should be able to match a valid time (22:23:24) and parse the fields" do
does_match(TIME, "22:23:24")
get_match(TIME, "22:23:24") do
match["hour"].should eq("22")
match["minute"].should eq("23")
match["second"].should eq("24")
match["time"].should eq("22:23:24")
end
end
end
describe "DATE" do
it "should be able to match a valid date (2026-08-10) and parse the fields" do
does_match(DATE, "2026-08-10")
get_match(DATE, "2026-08-10") do
match["date"].should eq("2026-08-10")
match["year"].should eq("2026")
match["month"].should eq("08")
match["day"].should eq("10")
end
end
end
describe "EPOCH" do
it "should match a valid epoch time, based on the pattern, and parse it's fields (@1788748305)" do
does_match(EPOCH, "@1788748305")
get_match(EPOCH, "@1788748305") do
match["epoch"].should eq("1788748305")
end
end
end
describe "RELATIVE" do
it "should match a valid operation" do
{% for sign in %w[ - + ].map(&.id) %}
{% for token in %w[ day days week weeks hour hours month months second seconds year years ].map(&.id) %}
does_match(RELATIVE, "{{sign}}1 {{token}}")
{% end %}
{% end %}
end
it "should not match invalid units (taco, tuesday, misfit, really?)" do
tokens = %w[ taco tuesday misfit really? ]
tokens.each do |token|
doesnt_match(RELATIVE, "+1 #{token}")
end
end
end
describe "RELATIVE_OPERATION" do
it "should match a valid operation and we can parse the fields" do
{% for sign in %w[ - + ].map(&.id) %}
{% for int in %w[ 1 3 10 ].map(&.id) %}
{% for token in %w[ day days week weeks hour hours month months second seconds year years ].map(&.id) %}
get_match(RELATIVE_OPERATION, "{{sign}}{{int}} {{token}}") do
match["sign"].should eq("{{sign}}")
match["quantity"].should eq("{{int}}")
match["unit"].should eq("{{token}}")
end
{% end %}
{% end %}
{% end %}
end
end
describe "INPUT_DATE_FULL" do
it "will match a bounded full date with an offset (2024-08-13 22:23:24 -0700)" do
get_match(INPUT_DATE_FULL, "2024-08-13 22:23:24 -0700") do
match["date"].should eq("2024-08-13")
match["year"].should eq("2024")
match["month"].should eq("08")
match["day"].should eq("13")
match["time"].should eq("22:23:24")
match["hour"].should eq("22")
match["minute"].should eq("23")
match["second"].should eq("24")
match["timezone"].should eq("-0700")
match["offset_sign"].should eq("-")
match["offset_hour"].should eq("07")
match["offset_minute"].should eq("00")
end
end
it "will match a bounded full date without an offset (2024-08-13 22:23:24)" do
get_match(INPUT_DATE_FULL, "2024-08-13 22:23:24") do
match["date"].should eq("2024-08-13")
match["year"].should eq("2024")
match["month"].should eq("08")
match["day"].should eq("13")
match["time"].should eq("22:23:24")
match["hour"].should eq("22")
match["minute"].should eq("23")
match["second"].should eq("24")
match["timezone"]?.should eq(nil)
end
end
end
describe "INPUT_DATE_SIMPLE" do
it "will match a bounded simple date without an offset (2024-08-13)" do
get_match(INPUT_DATE_SIMPLE, "2024-08-13") do
match["date"].should eq("2024-08-13")
match["year"].should eq("2024")
match["month"].should eq("08")
match["day"].should eq("13")
match["timezone"]?.should eq(nil)
end
end
it "will match a bounded simple date with an offset (2024-08-13 -0700)" do
get_match(INPUT_DATE_SIMPLE, "2024-08-13 -0700") do
match["date"].should eq("2024-08-13")
match["year"].should eq("2024")
match["month"].should eq("08")
match["day"].should eq("13")
match["timezone"].should eq("-0700")
match["offset_sign"].should eq("-")
match["offset_hour"].should eq("07")
match["offset_minute"].should eq("00")
end
end
end
describe "INPUT_DATE_EPOCH" do
it "will match a bounded epoch time without an offset (@1788748305)" do
get_match(INPUT_DATE_EPOCH, "@1788748305") do
match["epoch"].should eq("1788748305")
match["timezone"]?.should eq(nil)
end
end
it "will match a bounded simple date with an offset (@1788748305 -0700)" do
get_match(INPUT_DATE_EPOCH, "@1788748305 -0700") do
match["epoch"].should eq("1788748305")
match["timezone"].should eq("-0700")
match["offset_sign"].should eq("-")
match["offset_hour"].should eq("07")
match["offset_minute"].should eq("00")
end
end
end
describe "INPUT_RELATIVE_OPERATIONS" do
it "matches a single relative operation without timzone (+1 day)" do
get_match(INPUT_RELATIVE_OPERATIONS, "+1 day") do
match["operations"].should eq("+1 day")
match["timezone"]?.should be_nil
end
end
it "matches a single relative operation with timzone (+1 day -0700)" do
get_match(INPUT_RELATIVE_OPERATIONS, "+1 day -0700") do
match["operations"].should eq("+1 day")
match["timezone"].should eq("-0700")
match["offset_sign"].should eq("-")
match["offset_hour"].should eq("07")
match["offset_minute"].should eq("00")
end
end
it "matches multiple relative operations without timzone (+1 day -2 years)" do
get_match(INPUT_RELATIVE_OPERATIONS, "+1 day -2 years") do
match["operations"].should eq("+1 day -2 years")
match["timezone"]?.should be_nil
end
end
it "matches multiple relative operations without timzone (+1 day -2 years -0700)" do
get_match(INPUT_RELATIVE_OPERATIONS, "+1 day -2 years -0700") do
match["operations"].should eq("+1 day -2 years")
match["timezone"].should eq("-0700")
match["offset_sign"].should eq("-")
match["offset_hour"].should eq("07")
match["offset_minute"].should eq("00")
end
end
end
describe "FLOAT" do
it "will match a traditional float (1.1)" do
does_match(FLOAT, "1.1")
end
it "will match an int (1)" do
does_match(FLOAT, "1")
end
it "will match a negative float (-1.1)" do
does_match(FLOAT, "-1.1")
end
it "will match a negative int (-1)" do
does_match(FLOAT, "-1")
end
end
describe "INT" do
end
describe "UINT" do
end
end
+102
View File
@@ -0,0 +1,102 @@
require "../spec_helper"
def get_ops(raw : String)
CliGen::Timeparse::RelativeOperation.get_operations(raw)
end
describe CliGen::Timeparse::RelativeOperation do
describe ".get_operations" do
it "will correctly parse a single relative operation & provide an array of 1" do
op = "+1 seconds"
ops = get_ops(op)
ops.size.should eq(1)
my_op = ops.first
my_op.sign.should eq(1)
my_op.quantity.should eq(1)
my_op.unit.should eq(CliGen::Timeparse::OperationUnit::SECOND)
end
it "will correctly parse multiple relative operations & provide an array of 2" do
op = "+1 seconds -1 minute"
ops = get_ops(op)
ops.size.should eq(2)
op1 = ops.shift
op1.sign.should eq(1)
op1.quantity.should eq(1)
op1.unit.should eq(CliGen::Timeparse::OperationUnit::SECOND)
op2 = ops.shift
op2.sign.should eq(-1)
op2.quantity.should eq(1)
op2.unit.should eq(CliGen::Timeparse::OperationUnit::MINUTE)
end
it "will parse every unit in both singular and plural form" do
{
"year" => CliGen::Timeparse::OperationUnit::YEAR,
"month" => CliGen::Timeparse::OperationUnit::MONTH,
"week" => CliGen::Timeparse::OperationUnit::WEEK,
"day" => CliGen::Timeparse::OperationUnit::DAY,
"hour" => CliGen::Timeparse::OperationUnit::HOUR,
"minute" => CliGen::Timeparse::OperationUnit::MINUTE,
"second" => CliGen::Timeparse::OperationUnit::SECOND,
}.each do |word, unit|
[word, "#{word}s"].each do |form|
ops = get_ops("+1 #{form}")
ops.size.should eq(1)
ops.first.unit.should eq(unit)
end
end
end
it "will correctly parse a negative sign and a multi-digit quantity" do
op = get_ops("-42 days").first
op.sign.should eq(-1)
op.quantity.should eq(42)
op.unit.should eq(CliGen::Timeparse::OperationUnit::DAY)
end
end
describe "#apply" do
it "will apply a single operation correctly" do
time = Time.local
atime = time + 2.minute
get_ops("+2 minutes").each{|op| time = op.apply(time)}
time.should eq(atime)
end
it "will apply multiple operations correctly" do
time = Time.local
atime = time + 2.minute - 3.minute + 2.year
get_ops("+2 minutes -3 minutes +2 years").each{|op| time = op.apply(time)}
time.should eq(atime)
end
it "will apply each Time::Span unit correctly" do
time = Time.utc(2026, 4, 24, 10, 20, 30)
get_ops("+3 weeks").first.apply(time).should eq(time + 3.weeks)
get_ops("+3 days").first.apply(time).should eq(time + 3.days)
get_ops("+3 hours").first.apply(time).should eq(time + 3.hours)
get_ops("+3 minutes").first.apply(time).should eq(time + 3.minutes)
get_ops("+3 seconds").first.apply(time).should eq(time + 3.seconds)
end
it "will apply MONTH and YEAR as calendar spans, not fixed durations" do
# Jan 31 + 1 month clamps to Feb 28 - a fixed 30.days span would give Mar 02
jan31 = Time.utc(2026, 1, 31, 12, 0, 0)
get_ops("+1 month").first.apply(jan31).should eq(Time.utc(2026, 2, 28, 12, 0, 0))
get_ops("+1 year").first.apply(jan31).should eq(Time.utc(2027, 1, 31, 12, 0, 0))
# leap year: Feb 29 2028 exists, so +2 years from 2026-02-28 stays on the 28th
feb28 = Time.utc(2026, 2, 28, 12, 0, 0)
get_ops("+2 years").first.apply(feb28).should eq(Time.utc(2028, 2, 28, 12, 0, 0))
end
it "will apply a negative operation correctly" do
time = Time.utc(2026, 3, 15, 8, 0, 0)
get_ops("-1 month").first.apply(time).should eq(Time.utc(2026, 2, 15, 8, 0, 0))
get_ops("-10 days").first.apply(time).should eq(time - 10.days)
end
end
end
+139
View File
@@ -0,0 +1,139 @@
require "../spec_helper"
module CliGen::Timeparse
def self.test_get_location(raw : String)
get_location(raw)
end
end
describe CliGen::Timeparse do
describe ".parse" do
it "accepts time in %Y-%m-%d format" do
time = "2026-04-24"
a = ::Time.parse_local(time, "%Y-%m-%d")
CliGen::Timeparse.parse(time).should eq(a)
end
it "accepts time in %Y-%m-%d %z format and will respect the provided offset" do
time = "2026-04-24 -0900"
a = ::Time.parse!(time, "%Y-%m-%d %z")
CliGen::Timeparse.parse(time).should eq(a)
end
it "strips surrounding whitespace before parsing" do
a = ::Time.parse_local("2026-04-24", "%Y-%m-%d")
CliGen::Timeparse.parse(" 2026-04-24 ").should eq(a)
end
it "accepts time in %Y-%m-%d %H:%M:%S format and defaults to the local timezone" do
time = "2026-04-24 10:20:30"
a = ::Time.parse(time, "%Y-%m-%d %H:%M:%S", location: ::Time::Location.local)
CliGen::Timeparse.parse(time).should eq(a)
end
it "accepts time in %Y-%m-%d %H:%M:%S %z format and will respect the provided offset" do
time = "2026-04-24 10:20:30 -0900"
a = ::Time.parse!(time, "%Y-%m-%d %H:%M:%S %z")
CliGen::Timeparse.parse(time).should eq(a)
end
it "accepts epoch time in the @%s format and will default to UTC" do
time = "@1788742653"
a = ::Time.unix(time.lchop.to_i)
CliGen::Timeparse.parse(time).should eq(a)
end
it "accepts epoch time in the @%s %z format and will set the timezone to match the offset provided" do
time = "@1788742653 -0700"
a = ::Time.unix(time.lchop.split(" ").first.to_i).in(Time::Location.fixed(-1 * (7 * 3600)))
CliGen::Timeparse.parse(time).should eq(a)
end
it "accepts a single relative operation and will return the time" do
time = CliGen::Timeparse.parse("+10 minutes")
b_time = Time.local + 9.minute
a_time = Time.local + 11.minute
(b_time..a_time).includes?(time).should be_true
end
it "accepts a single relative operation + offset and will return the time" do
time = CliGen::Timeparse.parse("+10 minutes -0900")
b_time = Time.local + 9.minute
a_time = Time.local + 11.minute
(b_time..a_time).includes?(time).should be_true
time.location.should eq(Time::Location.fixed("-0900", -1 * (9 * 3600)))
end
it "accepts multiple relative operations and will return the time" do
time = CliGen::Timeparse.parse("+20 minutes +2 minute")
b_time = Time.local + 21.minute
a_time = Time.local + 23.minute
(b_time..a_time).includes?(time).should be_true
end
it "accepts a multiple relative operation + offset and will return the time" do
time = CliGen::Timeparse.parse("+10 minutes +2 minutes -0900")
b_time = Time.local + 11.minute
a_time = Time.local + 13.minute
(b_time..a_time).includes?(time).should be_true
time.location.should eq(Time::Location.fixed("-0900", -1 * (9 * 3600)))
end
end
describe ".parse error handling" do
it "raises CliGen::TimeParseError when the input matches no known format" do
expect_raises(CliGen::TimeParseError) do
CliGen::Timeparse.parse("not-a-date")
end
end
it "includes the offending input in the unknown-format message" do
ex = expect_raises(CliGen::TimeParseError) do
CliGen::Timeparse.parse("nonsense")
end
ex.message.to_s.should contain("nonsense")
end
it "raises CliGen::TimeParseError for a shape-valid but out-of-range month/day" do
expect_raises(CliGen::TimeParseError) do
CliGen::Timeparse.parse("2026-13-45")
end
end
it "raises CliGen::TimeParseError for an out-of-range hour" do
expect_raises(CliGen::TimeParseError) do
CliGen::Timeparse.parse("2026-01-15 25:00:00")
end
end
it "raises CliGen::TimeParseError for a day that does not exist in that month" do
expect_raises(CliGen::TimeParseError) do
CliGen::Timeparse.parse("2026-02-30")
end
end
# Guards the catch-all rescue: this path raises OverflowError, not ArgumentError.
# Narrowing the rescue back to specific stdlib types would let it escape
# App#handle_command_raises and reach the user as a stack trace.
it "raises CliGen::TimeParseError for an epoch large enough to overflow" do
expect_raises(CliGen::TimeParseError) do
CliGen::Timeparse.parse("@99999999999999999999")
end
end
it "raises CliGen::TimeParseError rather than an offset error for an out-of-range timezone" do
expect_raises(CliGen::TimeParseError) do
CliGen::Timeparse.parse("2026-01-15 -9999")
end
end
end
describe ".get_location" do
it "correctly generates an offest" do
a = "-0900"
b = Time::Location.fixed(a, (-1) * ((9 * 3600) + (0 * 60)))
CliGen::Timeparse.test_get_location(a).should eq(b)
end
end
end
+32 -1
View File
@@ -14,7 +14,38 @@ require "./cligen/command_node"
require "./cligen/app"
module CliGen
VERSION = "0.1.0"
VERSION = "0.2.0"
macro finished
{% unless CliGen.has_constant?("MAX_COMMAND_DEPTH") %}
{% puts "DEBUG : CliGen : User did not override MAX_COMMAND_DEPTH. Setting to default of 32" if env("DEBUG") %}
# # CliGen::MAX_COMMAND_DEPTH
#
# This exists to prevent the user from defining a command tree
# that extends past the compile-time configured max via the
# CliGen::MAX_COMMAND_DEPTH constant.
#
# The reason this is a thing is because crystal macros don't allow for
# unbounded while's/until's in macros, meaning it always has to be
# deterministic. SO to deal with this and still allow for subcommand
# defining you need either go with the default (32 command depth) or
# define your own larger max (understand this will affect compile-time
# due to this directly affecting loops in the Command macros).
#
# So to still support this I had to make bounded for-loops usng
#
#
# \{% for i in (1..CliGen::MAX_COMMAND_DEPTH) %}
# ...do checks...
# \{% end }
#
#
MAX_COMMAND_DEPTH = 32
{% else %}
{% puts "DEBUG : CliGen : User override the MAX_COMMAND_DEPTH. Not overriding with default" if env("DEBUG") %}
{% raise "ERROR : CliGen::MAX_COMMAND_DEPTH must be an integer" unless CliGen::MAX_COMMAND_DEPTH.is_a? NumberLiteral %}
{% end %}
end
APPNAME = File.basename(PROGRAM_NAME)
+2 -3
View File
@@ -2,6 +2,8 @@
# Copyright 2026 Tristan Ancelet
module CliGen
annotation InternalVar
end
# (Not Implemented Yet)
# In the future you would use this to annotate a "proxy command" that will allow you to defer execution
# of a "subcommand" to an external method not located in the class itself.
@@ -206,9 +208,6 @@ module CliGen
annotation Trigger
end
annotation Selection
end
annotation PreRunCommand
end
+18 -5
View File
@@ -11,6 +11,11 @@ module CliGen
# for global-flag matching, then hands off to the matched child CommandNode.
class App < CliGen::CommandNode(Nil)
@@instance : self?
@@processed : Bool = false
def self.processed?
@@processed
end
def initialize(@name, flags : Array(BaseFlag), commands : Array(BaseCommandNode), pre_run_commands : Array(RunCommand), post_run_commands : Array(RunCommand))
super(name: @name, flags: flags, commands: commands, pre_run_commands: pre_run_commands, post_run_commands: post_run_commands)
@@ -19,13 +24,13 @@ module CliGen
def check!
super
check_for_env_duplicates(all_flags + CliGen::GLOBAL_FLAGS)
check_for_env_duplicates(all_flags.uniq + CliGen::GLOBAL_FLAGS)
end
def check_for_env_duplicates(flags : Array(BaseFlag))
flgs = flags.reject(&.env_var.empty?)
flgs = flags.reject(&.env_var.nil?)
env_vars = flgs.group_by(&.env_var)
env_vars = flgs.group_by(&.env_var.not_nil!)
failures = [] of Tuple(String, Array(BaseFlag))
@@ -68,11 +73,19 @@ module CliGen
end
end
def self.get
generate if @@instance.nil?
@@instance.not_nil!
end
# Convenience entry point; defaults to ARGV
def self.process(args : Array(String) = ARGV.to_a) : Nil
generate if @@instance.nil?
raise CliGen::AppAlreadyProcessedError.new("ERROR : CliGen::App.process : App has already processed CLI arguments. It is not allowed to be run again") if processed?
handle_command_raises do
@@instance.not_nil!.process(args)
if app = get
@@processed = true
app.process(args)
end
end
end
end
+11 -41
View File
@@ -5,55 +5,25 @@ module CliGen
macro finished
class App
private def self.generate
app_flags = [] of BaseFlag
app_commands = [] of BaseCommandNode
{% verbatim do %}
{% for cmd in CliGen::Command.subclasses %}
{% cmd_info = cmd.annotation(CliGen::CommandInfo) %}
{% raise "ERROR : CliGen::App.generate : No CliGen::CommandInfo annotation made for #{cmd.name}" unless cmd_info %}
{% raise "ERROR : CliGen::App.generate : Description must be provided for #{cmd.name}" unless cmd_info[:description].is_a? StringLiteral %}
{% cmd_name = cmd.name.split("::").last.downcase %}
{% cmd_flags = cmd.instance_vars.select{|v| v.annotation(CliGen::Argument) || v.annotation(CliGen::Selection) } %}
cmd_flags = [] of BaseFlag
cmd_sub_commands = [] of BaseCommandNode
cmd_pre_run_cmds = [] of Proc(Nil)
cmd_post_run_cmds = [] of Proc(Nil)
{% for var in cmd_flags %}
{% anno = var.annotation(CliGen::Argument) || var.annotation(CliGen::Selection) %}
cmd_flags << Flag({{var.type}}).new(
var: {{ var.name.stringify }},
short: {% if anno[:short] %} {{anno[:short]}} {% else %} nil {% end %},
long: {{ anno[:long] }},
env_var: {% if anno[:env_var] %} {{anno[:env_var]}} {% else %} {{"#{cmd.name.split("::").last.upcase.id}_#{var.name.upcase}"}} {% end %},
description: {{ anno[:description] }},
default: {% unless var.default_value.nil? %} {{var.default_value}} {% else %} nil {% end %},
validate: {% if anno[:validation] %} {{anno[:validation]}} {% else %} nil {% end %},
on_match: {% if anno[:on_match] %} {{anno[:on_match]}} {% else %} nil {% end %},
options: {% if anno[:options] %} {{anno[:options]}} {% else %} nil {% end %},
delimiter: {% if anno[:delimiter] %} {{anno[:delimiter]}} {% else %} "," {% end %},
format: {% if anno[:format] %} {{anno[:format]}} {% else %} nil {% end %}
)
{% debug if env("DEBUG") %}
{% unless CliGen::Command.subclasses.reject(&.annotation(CliGen::CommandInfo)[:parent]).empty? %}
{% for cmd in CliGen::Command.subclasses.reject(&.annotation(CliGen::CommandInfo)[:parent]) %}
{% cmd_info = cmd.annotation(CliGen::CommandInfo) %}
{% raise "ERROR : CliGen::App.generate : No CliGen::CommandInfo annotation made for #{cmd.name}" unless cmd_info %}
{% raise "ERROR : CliGen::App.generate : Description must be provided for #{cmd.name}" unless cmd_info[:description].is_a? StringLiteral %}
{{cmd}}.register_command(app_commands)
{% end %}
{% else %}
{% raise "ERROR : CliGen::App.generate : No root commands were found for App.generate to index. Ensure that you have at least one CliGen::Command subclass with no parent in the CliGen::CommandInfo annotation" %}
{% end %}
{% end %}
app_commands << CommandNode({{cmd}}).new(
name: {{cmd_name}},
flags: cmd_flags,
commands: cmd_sub_commands,
pre_run_commands: cmd_pre_run_cmds,
post_run_commands: cmd_post_run_cmds,
description: {{cmd_info[:description]}}
)
{% debug if env("DEBUG") %}
{% end %}
{% end %}
new(
name: File.basename(::PROGRAM_NAME),
flags: app_flags,
flags: [] of BaseFlag,
commands: app_commands,
pre_run_commands: [] of Proc(Nil),
post_run_commands: [] of Proc(Nil)
+37 -6
View File
@@ -6,23 +6,54 @@ require "time"
require "./annotations"
require "./command/argument"
require "./command/selection"
require "./command/help_template"
require "./command/subcommand"
require "./command/def_init"
require "./command/define_singleton_init"
require "./command/define_command_initializer"
require "./command/generate_register_command"
require "./command/generate_gather_handler"
require "./command/resolve_value"
require "./command/validate_command_tree"
module CliGen
class Command
@[CliGen::InternalVar]
@handler : CliGen::BaseCommandNode?
def handler? : Bool
! @handler.nil?
end
macro inherited
{% verbatim do %}
macro finished
{% anno = @type.annotation(CliGen::CommandInfo) %}
{% raise "" unless anno %}
{% if anno[:def_init] %}
def_init
{% if anno = @type.annotation(CliGen::CommandInfo) %}
{% if anno[:singleton_init] == true %}
define_singleton_init
{% end %}
{% else %}
{% raise "ERROR : #{@type.name} < CliGen::Command : When creating a Command subclass you MUST have an (CliGen::CommandInfo) annotation. No if's and's or but's. OKAY?" %}
{% end %}
# This validates that the Command doesn't have a circular dependency
# chain which would cause a rcursive loop in the register_command
# method at runtime
validate_command_tree
# This defines the initializer that the CommandNode(T) uses to set the
# values of this command object
define_command_initializer
# Generate the command registration method to allow App to have this
# command registered in the App.commands or another commands @commands
# as a subcommand
generate_register_command
# This generates the gather_handler method that allows a command (if
# initialized via sources other than CliGen::CommandNode(T)) to get
# it's related CliGen::CommandNode(T) handler to gather flag values
# with the resolve_value macro or in the singleton init method
generate_gather_handler
end
{% end %}
end
+3 -3
View File
@@ -3,7 +3,7 @@
module CliGen
class Command
macro argument(variable, description, long = nil, short = nil, validation = nil, on_match = nil, def_setter = false, def_getter = false, options = nil, delimiter = ",", format = nil, allow_no_verification = false, env_var = nil)
macro argument(variable, description, long = nil, short = nil, validation = nil, on_match = nil, def_setter = false, def_getter = false, options = nil, delimiter = ",", format = nil, allow_no_verification = false, env_var = "")
{% raise "ERROR : CliGen::Command.argument : def_setter must be a Bool" unless def_setter.is_a? BoolLiteral %}
{% raise "ERROR : CliGen::Command.argument : def_getter must be a Bool" unless def_getter.is_a? BoolLiteral %}
{% raise "ERROR : CliGen::Command.argument : First argument (#{variable}) must be a TypeDeclaration (ex: '<var> : <type> [= val]')" unless variable.is_a? TypeDeclaration %}
@@ -27,9 +27,9 @@ module CliGen
)
{% if type.resolve < Array && ! options.nil? %}
@[CliGen::Argument(short: {{short}}, long: {{long}}, description: {{description}}, validation: {{validation}}, on_match: {{on_match}}, options: [{{options}}], delimiter: {{delimiter}}, format: {{format}}, env_var: {{env_var}})]
@[CliGen::Argument(short: {{short}}, long: {{long}}, description: {{description}}, validation: {{validation}}, on_match: {{on_match}}, options: [{{options}}], delimiter: {{delimiter}}, format: {{format}}, env_var: {{env_var}}, allow_no_verification: {{allow_no_verification}})]
{% else %}
@[CliGen::Argument(short: {{short}}, long: {{long}}, description: {{description}}, validation: {{validation}}, on_match: {{on_match}}, options: {{options}}, delimiter: {{delimiter}}, format: {{format}}, env_var: {{env_var}})]
@[CliGen::Argument(short: {{short}}, long: {{long}}, description: {{description}}, validation: {{validation}}, on_match: {{on_match}}, options: {{options}}, delimiter: {{delimiter}}, format: {{format}}, env_var: {{env_var}}, allow_no_verification: {{allow_no_verification}})]
{% end %}
@{{variable}}
-25
View File
@@ -1,25 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright 2026 Tristan Ancelet
module CliGen
class Command
macro def_init
def initialize
{% verbatim do %}
{% for var in @type.instance_vars %}
{% raise "ERROR : Can't define a default initializer if #{var.name} doesn't have a default" if var.default_value.nil? && !var.type.nilable? %}
@{{var.name}} = {{var.default_value}}
{% end %}
{% end %}
end
def after_initialize
@@instance = self
end
def self.get
@@instance ||= new
end
end
end
end
@@ -5,11 +5,13 @@ module CliGen
class Command
macro define_command_initializer
def initialize(*, handler : CliGen::BaseCommandNode)
@handler = handler
{% verbatim do %}
Log.debug { "#{self.class.name}#initialize : Initializing class" }
{% for var in @type.instance_vars %}
Log.debug { "{{@type.name}}#initialize : Checking {{var.name}}" }
{% anno = (var.annotation(CliGen::Argument) || var.annotation(CliGen::Selection)) %}
{% anno = var.annotation(CliGen::Argument) %}
{% if anno %}
{% raise "ERROR : #{@type.name}#initialize : Argument '#{var.name}' cannot be a nilable type (#{var.type}) — flags always resolve to a concrete value" if var.type.union? %}
Log.debug { "{{@type.name}}#initialize : {{var.name}} is a CliGen managed ivar. Will attempt to gather from associated CliGen::Flag" }
@@ -21,6 +23,7 @@ module CliGen
else
raise CliGen::FlagNotFoundError.new("{{@type.name}}\#{{@def.name}} : No flag found for \"{{var.name}}\"")
end
{% elsif var.annotation(CliGen::InternalVar) %}
{% else %}
Log.debug { "{{@type.name}}#initialize : {{var.name}} is not a CliGen managed ivar. Will initialize to default defined in class" }
{% raise "ERROR : #{@type.name}#{@def.name} : Instance Variable(#{var.name}) is not handled by CliGen and does not have a default value" if var.default_value.nil? %}
@@ -0,0 +1,48 @@
# SPDX-License-Identifier: MIT
# Copyright 2026 Tristan Ancelet
module CliGen
class Command
# This macro simply provides a easy singleton initializer for your command
# to allow for you do (if this class isn't the target of a command) to still
# be able to gather a Command object without having to have it as the target.
#
# This will setup the default (no args) initializer to gather the handler from
# CliGen::App and then resolve all of the ivar (CliGen managed) to the parsed
# values from the associated Flag(T) object that (if the process itself is
# being started by CliGen the provided flags will store the value to be
# set here)
macro define_singleton_init
def initialize
{% verbatim do %}
gather_handler unless @handler
if handler = @handler
{% for var in @type.instance_vars %}
{% raise "ERROR : Can't define a default initializer if #{var.name} doesn't have a default" if var.default_value.nil? && !var.type.nilable? %}
{% if anno = var.annotation(CliGen::Argument) %}
{% raise "ERROR : #{@type}#initialize : Can't define a default initializer for a cligen managed ivar if #{var.name} doesn't have a default" if var.default_value.nil? %}
# If the variable is cligen managed we can define the value from the handler and resolve the setting from
@{{var.name}} = handler.flags.find{|flg| flg.var == {{var.name.stringify}} && flg.long == {{anno[:long]}}}.not_nil!.as(CliGen::Flag({{var.type}})).value!
{% elsif var.annotation(CliGen::InternalVar) %}
{% else %}
{% raise "ERROR : #{@type}#initialize : Can't define a default initializer if #{var.name} doesn't have a default" if var.default_value.nil? && !var.type.nilable? %}
@{{var.name}} = {{var.default_value}}
{% end %}
{% end %}
else
raise "ERROR : Was unable to retrieve a handler from CliGen::App"
end
{% end %}
end
def after_initialize
@@instance = self
end
def self.get
raise CliGen::AppNotProcessedError.new("ERROR : {{@type.name}}#get : #{__FILE__}:#{__LINE__} : {{@type.name}}#get was called before CliGen::App has processed commandline arguments") unless CliGen::App.processed?
@@instance ||= new
end
end
end
end
@@ -0,0 +1,13 @@
module CliGen
class Command
macro generate_gather_handler
def gather_handler
unless @handler
unless @handler = CliGen::App.get.all_commands.find(&.meta.cls.== {{ @type.name.stringify }})
raise CliGen::ConfigurationError.new("ERROR : #{self.class}#gather_handler : Was unable to find handler for this instance")
end
end
end
end
end
end
@@ -0,0 +1,86 @@
require "../flag"
module CliGen
class Command
macro generate_register_command
{% verbatim do %}
def self.register_command(command_array : Array(CliGen::BaseCommandNode), parent : CliGen::BaseCommandNode? = nil)
cmd_flags = [] of CliGen::BaseFlag
cmd_subcommands = [] of CliGen::BaseCommandNode
cmd_pre_run_cmds = [] of Proc(Nil)
cmd_post_run_cmds = [] of Proc(Nil)
{% for var in @type.instance_vars.select(&.annotation(CliGen::Argument)) %}
{% anno = var.annotation(CliGen::Argument) %}
CliGen::Common.check_flag_vars(
raise_base: {{"CliGen::Command(#{@type.name}).generate_register_command"}},
type: {{var.type}},
long: {{anno[:long]}},
env_var: {{anno[:env_var]}},
short: {{anno[:short]}},
validation: {{anno[:validation]}},
on_match: {{anno[:on_match]}},
options: {{anno[:options]}},
description: {{anno[:description]}},
allow_no_verification: {{anno[:allow_no_verification]}},
format: {{anno[:format]}},
delimiter: {{anno[:delimiter]}}
)
cmd_flags << CliGen::Flag({{var.type}}).new(
var: {{ var.name.stringify }},
short: {% if anno[:short] %} {{anno[:short]}} {% else %} nil {% end %},
long: {{ anno[:long] }},
{% if anno[:env_var] == "" %}
{% if @type.name.stringify =~ /::/ %}
env_var: "{{@type.name.upcase.split("::").last.id}}_{{var.name.upcase}}",
{% else %}
env_var: "{{@type.name.upcase.id}}_{{var.name.upcase}}",
{% end %}
{% else %}
env_var: {{anno[:env_var]}},
{% end %}
description: {{ anno[:description] }},
default: {% unless var.default_value.nil? %} {{var.default_value}} {% else %} nil {% end %},
validate: {% if anno[:validation] %} {{anno[:validation]}} {% else %} nil {% end %},
on_match: {% if anno[:on_match] %} {{anno[:on_match]}} {% else %} nil {% end %},
options: {% if anno[:options] %} {{anno[:options]}} {% else %} nil {% end %},
delimiter: {% if anno[:delimiter] %} {{anno[:delimiter]}} {% else %} "," {% end %},
format: {% if anno[:format] %} {{anno[:format]}} {% else %} nil {% end %}
)
{% end %}
{% begin %}
{% cmd_anno = @type.annotation(CliGen::CommandInfo) %}
command = CliGen::CommandNode({{@type}}).new(
{% if @type.name.stringify =~ /::/ %}
name: {{@type.name.stringify.split("::").last.downcase}},
{% else %}
name: {{@type.name.stringify.downcase}},
{% end %}
flags: cmd_flags,
commands: cmd_subcommands,
pre_run_commands: cmd_pre_run_cmds,
post_run_commands: cmd_post_run_cmds,
parent: parent,
description: {{cmd_anno[:description]}}
)
command_array << command
{% end %}
{% for cmd in CliGen::Command.subclasses %}
{% cmd_anno = cmd.annotation(CliGen::CommandInfo) %}
{% unless cmd.annotation(CliGen::CommandInfo) %}
{% raise "ERROR : CliGen::Command(#{@type}).generate_register_command : #{cmd} must have an CliGen::CommandInfo annotation" %}
{% end %}
{% unless cmd_anno[:parent].nil? %}
{% if cmd_anno[:parent].resolve == @type %}
{{cmd}}.register_command(cmd_subcommands, parent: command)
{% end %}
{% end %}
{% end %}
end
{% end %}
end
end
end
+132
View File
@@ -0,0 +1,132 @@
module CliGen
class Command
# This macro is just meant to provide the user an ability to resolve instance
# var/varibles from parent commands. Simply to allow subcommands to be able
# to retrieve values from their parents
#
# As an aside, this (as written) can only be used for variables that have
# a default defined (ex: @var : Int32 = 3)
#
# For variables that (in your parent class) isn't set with a default value,
# you will need to provide the (default: <val>) kwarg to set your own
# runtime default if the value itself cannot be ensured by the compiler.
#
# This is a requirement as this macro MUST always return a value without
# rasing, and the only way to do that is force the user to provide a
# default of their choosing.
macro resolve_value(variable, *, default = nil)
{% variable = variable.id %}
{% commands = [] of TypeNode %}
{% commands << @type %}
{% puts "DEBUG : #{@type.name}##{@def.name} : resolve_value : Entered with #{variable}" if env("DEBUG") %}
{% anno = @type.annotation(CliGen::CommandInfo) %}
{% parent = nil %}
{% current = nil %}
{% var = nil %}
# if this provided variable exists in the current clases space
{% if v = @type.instance_vars.find(&.name.stringify.== variable.stringify) %}
{% puts "DEBUG : #{@type.name}##{@def.name} : resolve_value : Looks like variable is a local one" if env("DEBUG") %}
@{{v.name}}
# in this case we have a command tree (annotation driven) and we're going
# to try and iterate through them to see if we can find the variable name
# that the user is trying to meet
{% elsif p = anno[:parent] %}
{% puts "DEBUG : #{@type.name}##{@def.name} : resolve_value : Looks we couldn't find it in the class itself. Checking parents" if env("DEBUG") %}
{% puts "DEBUG : #{@type.name}##{@def.name} : resolve_value : Parent is defined as #{p}" if env("DEBUG") %}
{% var = nil %}
{% current = p.resolve %}
{% puts "DEBUG : #{@type.name}##{@def.name} : resolve_value : Beginning iteration into parent chain to find an object with that variable" if env("DEBUG") %}
{% for i in (1..CliGen::MAX_COMMAND_DEPTH) %}
{% iteration = "#{i}/#{CliGen::MAX_COMMAND_DEPTH}".id %}
{% unless current.nil? %}
{% anno = current.annotation(CliGen::CommandInfo) %}
{% puts "TRACE : #{@type.name}##{@def.name} : resolve_value : Iteration (#{iteration}) : var = #{var}" if env("TRACE") %}
{% puts "TRACE : #{@type.name}##{@def.name} : resolve_value : Iteration (#{iteration}) : current = #{current}" if env("TRACE") %}
{% puts "TRACE : #{@type.name}##{@def.name} : resolve_value : Iteration (#{iteration}) : anno = #{anno}" if env("TRACE") %}
{% if commands.includes?(current) %}
{% puts "ERROR : #{@type}##{@def} : resolve_value : #{current.name} has already been processed. Meaning we have detected a circular reference. " %}
{% puts "Processed commands: " %}
{% for cmd, i in commands %}
{% puts "#{i}) #{cmd.name}" %}
{% end %}
{% raise "Circular Referfence detected. Please fix your annotations." %}
{% else %}
{% commands << current %}
{% end %}
{% if v = current.instance_vars.select(&.annotation(CliGen::Argument)).find(&.name.stringify.== variable.stringify) %}
{% puts "DEBUG : #{@type.name}##{@def.name} : resolve_value : Iteration (#{iteration}) : found variable from current parent : v = #{v}" if env("DEBUG") %}
{% var = v %}
{% parent = current %}
{% current = nil %}
{% elsif p = anno[:parent] %}
{% current = p.resolve %}
{% else %}
{% current = nil %}
{% end %}
{% end %}
{% end %}
{% unless current.nil? %}
{% puts "ERROR : #{@type}##{@def.name} : resolve_value : It looks like your Commands tree either has a circular reference or extends past the max number of commands allowed. " %}
{% puts "CliGen::MAX_COMMAND_DEPTH: #{CliGen::MAX_COMMAND_DEPTH}" %}
{% puts "Last Recorded Command: #{current.name}" %}
{% puts "Processed Command List:" %}
{% for cmd, i in commands %}
{% puts "#{i}: #{cmd}" %}
{% end %}
{% raise "Please fix this or up the MAX_COMMAND_DEPTH." %}
{% end %}
{% if var.nil? %}
{% puts "ERROR : #{@type}##{@def.name} : resolve_value : Was not able to find a variable in the command tree that matched #{variable}." %}
{% puts "Valid Options are: " %}
{% for cmd in commands %}
{% puts "Command(#{cmd.name}): " %}
{% for ivar in cmd.instance_vars.select(&.annotation(CliGen::Argument)) %}
{% anno = ivar.annotation(CliGen::Argument) %}
{% puts "- #{ivar.name} : #{ivar.type} = #{ivar.default_value.nil? ? "!not set!" : ivar.default_value} (description: \"#{anno[:description]}\")" %}
{% end %}
{% puts "" %}
{% end %}
{% end %}
{% if var.default_value.nil? %}
{% if default.nil? %}
{% raise "ERROR : #{@type}##{@def.name} : resolve_value : #{var.name} is recorded to not have any default values. So in order to use this macro you must provide a default via the (default:) key in this macro" %}
{% else %}
%default : {{var.type}} = {{default}}
{% end %}
{% end %}
gather_handler unless @handler
%handler : CliGen::BaseCommandNode? = @handler
unless %handler
raise "ERROR : No handler defined for this command"
end
%parent : CliGen::BaseCommandNode? = %handler.parent?
until %parent.nil? || %parent.not_nil!.meta.cls == {{parent.name.stringify}}
%parent = %parent.parent?
end
if %parent.nil?
raise "ERROR : {{@type}}\#{{@def.name}} : resolve_value : Was unable to find the parent for {{variable}}"
else
if %flg = %parent.flags.find(&.var.== {{variable.stringify}})
{% unless default.nil? %}
begin
{% end %}
%flg.as(CliGen::Flag({{var.type}})).value!
{% unless default.nil? %}
rescue e : CliGen::MissingRequiredFlagError
%default
end
{% end %}
else
raise "ERROR : {{@type}}\#{{@def.name}} : resolve_value : Was unable to find the flag for {{variable}}"
end
end
{% else %}
{% raise "ERROR : #{@type}##{@def.name} : resolve_value : Wasn't able to find a source for #{variable}" %}
{% end %}
end
end
end
-24
View File
@@ -1,24 +0,0 @@
# SPDX-License-Identifier: MIT
# Copyright 2026 Tristan Ancelet
module CliGen
class Command
macro selection(variable, description, options, short = nil, long = nil, validation = nil, on_match = nil)
{% raise "ERROR : CliGen::Command.selection : First selection must be a TypeDeclaration (ex: '<var> : <type> [= val]')" unless variable.is_a? TypeDeclaration %}
{% if short %}
{% raise "ERROR : CliGen::Command.selection : Provided short must be a string" unless short.is_a? StringLiteral %}
{% end %}
{% long = "--#{variable.var}" if long.nil? %}
{% raise "ERROR : CliGen::Command.selection : Provided long must be a flag format" unless long =~ /^--[a-zA-Z0-9-_]+/ %}
{% raise "ERROR : CliGen::Command.selection : Provided long must be a string" unless long.is_a? StringLiteral %}
{% raise "ERROR : CliGen::Command.selection : You must provide a short or long" unless long || short %}
{% raise "ERROR : CliGen::Command.selection : You must provide a description" unless description %}
{% raise "ERROR : CliGen::Command.selection : Provided description must be a String" unless description.is_a? StringLiteral %}
{% options = options.resolve if options.is_a? Path %}
{% raise "ERROR : CliGen::Command.selection : Provided options must be an ArrayLiteral" unless options.is_a? ArrayLiteral %}
@[CliGen::Argument(short: {{short}}, long: {{long}}, description: {{description}}, validation: {{validation}}, on_match: {{on_match}}, options: {{options}}, delimiter: "-")]
@{{variable}}
end
end
end
@@ -0,0 +1,68 @@
module CliGen
class Command
# This macro serves as a compile-time checker of the command-tree to
# validate that there is no recursive references of the command-list
# that would possibly cause a recursive stack-overflow during App.generate
# when App begins registering all user defined commands.
#
# However, while this does exist, due to the way that the App.generate method
# handles gathering root commands it makes this edge-case impossible to hit
# aside from manually running the
# Command#register_command([] of CliGen::Command) method.
#
# However, with this in place this issue cannot be hit at runtime as this will
# prevent compilation if a recursive/circular command tree exists.
#
# Additionally, this exists to prevent the user from defining a command tree
# that extends past the compile-time configured max via the
# CliGen::MAX_COMMAND_DEPTH constant.
#
# The reason this is a thing is because crystal macros don't allow for
# unbounded while's/until's in macros, meaning it always has to be
# deterministic. SO to deal with this and still allow for subcommand
# defining you need either go with the default (32 command depth) or
# define your own larger max (understand this will affect compile-time
# due to this directly affecting loops in the Command macros).
macro validate_command_tree
# Checking if the current type's parent is itself
{% if p = @type.annotation(CliGen::CommandInfo)[:parent] %}
{% if p.resolve == @type %}
{% raise "ERROR : #{@type.name} < CliGen::Command : Circular parent defined between #{@type.name} and itself" %}
{% end %}
{% end %}
{% commands = [] of TypeNode %}
# Checking if any other commands in the tree are circular with this one
{% issue_topic = nil %}
{% current = @type %}
{% for i in (1..CliGen::MAX_COMMAND_DEPTH) %}
{% unless current.nil? %}
{% commands << current %}
{% if parent = current.annotation(CliGen::CommandInfo)[:parent] %}
{% parent = parent.resolve %}
{% if parent == @type %}
{% issue_topic = current %}
{% else %}
{% current = parent %}
{% end %}
{% else %}
{% current = nil %}
{% end %}
{% end %}
{% end %}
{% if issue_topic %}
{% raise "ERROR : #{@type.name} < CliGen::Command : Circular parent defined between #{@type.name} and #{issue_topic.name}" %}
{% end %}
{% unless current.nil? %}
{% puts "ERROR : #{@type.name} < CliGen::Command : Discovered command-tree is either circular or larger than CliGen::MAX_COMMAND_DEPTH (which is set to #{CliGen::MAX_COMMAND_DEPTH}). Please address" %}
{% puts "Processed Commands: " %}
{% for cmd, i in commands %}
{% puts "#{i}) #{cmd.name}" %}
{% end %}
{% raise "Please address this and retry" %}
{% end %}
end
end
end
+12 -6
View File
@@ -18,12 +18,22 @@ module CliGen
commands : Array(BaseCommandNode),
pre_run_commands : Array(RunCommand),
post_run_commands : Array(RunCommand),
parent : BaseCommandNode? = nil,
description : String? = nil
)
meta = CommandMeta.new(
cls: {{T.name.stringify}}
)
super(name, flags, commands, pre_run_commands, post_run_commands, meta, description)
super(
name: name,
flags: flags,
commands: commands,
pre_run_commands: pre_run_commands,
post_run_commands: post_run_commands,
meta: meta,
parent: parent,
description: description
)
end
def subcommands : Array(SubCommandInfo)
@@ -137,10 +147,6 @@ module CliGen
raise CliGen::InternalError.new("CommandNode(#{@name})#process : subcommand '#{matched_subcommand}' was already matched — duplicate subcommand token") if matched_subcommand
matched_subcommand = arg.value
when MatchType::Help
Log.trace { "CommandNode(#{@name})#process : Arg(#{arg.value}) is a help option. Raising to have App print out help output" }
raise CliGen::HelpRequestedError.new(help)
when MatchType::FlagWithArg
Log.debug { "CommandNode(#{@name})#process : Arg(#{arg.value}) was found to be a flag with an arg <flag>=<arg>" }
if regex_match = CliGen::Regex::FLAG_WITH_ARG.match(arg.value)
@@ -163,7 +169,7 @@ module CliGen
Log.debug { "CommandNode(#{@name})#process : Arg(#{arg.value}) was found to be an combined short flag" }
val = arg.value.lchop('-')
flg : BaseFlag? = flag?("#{val[0]}")
flg : BaseFlag? = flag?("-#{val[0]}")
unless flg
raise CliGen::UnknownFlagError.new("#{CliGen::APPNAME}: unknown flag '-#{val[0]}'")
end
+6 -3
View File
@@ -16,6 +16,7 @@ module CliGen
getter commands : Array(BaseCommandNode)
getter description : String?
getter meta : CommandMeta
getter? parent : BaseCommandNode?
@pre_run_commands : Array(RunCommand)
@post_run_commands : Array(RunCommand)
@@ -28,6 +29,7 @@ module CliGen
@pre_run_commands : Array(RunCommand),
@post_run_commands : Array(RunCommand),
@meta : CommandMeta,
@parent : BaseCommandNode? = nil,
@description : String? = nil
)
end
@@ -36,6 +38,10 @@ module CliGen
@flags + @commands.flat_map(&.all_flags)
end
def all_commands : Array(BaseCommandNode)
@commands + @commands.flat_map(&.all_commands)
end
def check_for_duplicate_subcommands!
failures = [] of Tuple(String, Array(BaseCommandNode))
@@ -121,9 +127,6 @@ module CliGen
end
case arg
when "-h", "--help"
Log.debug { "CommandNode(#{@name})#find_match(#{arg}) : was found to be a help flag" }
CliGen::MatchType::Help
when CliGen::Regex::FLAG_REGEX
Log.debug { "CommandNode(#{@name})#find_match(#{arg}) : arg found to match the format of a flag" }
if flg = flag?(arg)
+18 -5
View File
@@ -2,20 +2,33 @@
# Copyright 2026 Tristan Ancelet
module CliGen::Common
macro check_flag_vars(*, type, long, description, raise_base, short = nil, validation = nil, on_match = nil, options = nil, format = nil, env_var = nil, delimiter = ",", allow_no_verification = false)
macro check_flag_vars(*, type, long, description, raise_base, short = nil, validation = nil, on_match = nil, options = nil, format = nil, env_var = nil, delimiter = ",", allow_no_verification = false, internal = false)
{% raise_base = raise_base.id %}
{% raise "ERROR : #{raise_base} : Provided type (#{type}) must resolve to a type" unless type.resolve.is_a? TypeNode %}
{% if env_var %}
{% unless env_var.nil? || env_var == "" %}
{% raise "ERROR : #{raise_base} : Provided env_var must be a string" unless env_var.is_a? StringLiteral %}
{% raise "ERROR : #{raise_base} : Provided env_var cannot contain a \"-\". Please fix and re-run" if env_var.includes?("-") %}
{% end %}
{% raise "ERROR : #{raise_base} : Provided delimiter must be a string" unless delimiter.is_a? StringLiteral %}
{% if short %}
{% unless short.nil? %}
{% raise "ERROR : #{raise_base} : Provided short must be a string" unless short.is_a? StringLiteral %}
{% raise "ERROR : #{raise_base} : Provided short(#{short}) must be in a valid short format (-[a-zA-Z])" unless short =~ /^-[A-Za-z]$/ %}
{% raise "ERROR : #{raise_base} : Provided short(#{short}) must be in a valid short format #{::CliGen::Regex::FLAG_SHORT}" unless short =~ ::CliGen::Regex::FLAG_SHORT %}
{% unless internal %}
{% if %w[ -h -v ].includes?(short) %}
{% raise "ERROR : #{raise_base} : Short(#{short}) is a reserved for internal usage. Please choose another short" %}
{% end %}
{% end %}
{% end %}
{% raise "ERROR : #{raise_base} : Provided long must be a string" unless long.is_a? StringLiteral %}
{% raise "ERROR : #{raise_base} : Provided long must match --[a-zA-Z0-9-_]+" unless long =~ /^--[a-zA-Z0-9-_]+/ %}
{% if long =~ /\s+|=+/ %}
{% long = long.split(/\s+|=+/).first %}
{% end %}
{% raise "ERROR : #{raise_base} : Provided long (#{long}) must match #{::CliGen::Regex::FLAG_LONG.source}" unless long =~ ::CliGen::Regex::FLAG_LONG %}
{% unless internal %}
{% if %w[ --help --verbose ].includes?(long) %}
{% raise "ERROR : #{raise_base} : Long(#{long}) is a reserved for internal usage. Please choose another long" %}
{% end %}
{% end %}
{% raise "ERROR : #{raise_base} : You must provide a description" unless description %}
{% raise "ERROR : #{raise_base} : Provided description must be a String" unless description.is_a? StringLiteral || description.is_a? StringInterpolation %}
{% unless on_match.nil? %}
+12 -4
View File
@@ -6,7 +6,7 @@ module CliGen
class Error < Exception; end
# -------------------------------------------------------------------------
# Internal errors - framework invariant violations, should never reach users
# Internal errors : framework invariant violations, should never reach users
# -------------------------------------------------------------------------
class InternalError < Error; end
@@ -21,11 +21,19 @@ module CliGen
class UnknownCommandNodeError < InternalError; end
# -------------------------------------------------------------------------
# Configuration errors - shard consumer wired something up incorrectly
# Configuration errors : shard consumer wired something up incorrectly
# -------------------------------------------------------------------------
class ConfigurationError < Error; end
# Used when a user attempts to initialize a singleton class before
# CliGen::App has processed any commandline arguments.
class AppNotProcessedError < ConfigurationError; end
# Used when a user double-calls App#process. As we do not want to double process
# thigns
class AppAlreadyProcessedError < ConfigurationError; end
# -h or --help was used as a flag short/long (reserved for internal help)
class ReservedFlagError < ConfigurationError; end
@@ -48,7 +56,7 @@ module CliGen
class ParseableInvariantError < ConfigurationError; end
# -------------------------------------------------------------------------
# Runtime errors - bad user input at the CLI level
# Runtime errors : bad user input at the CLI level
# -------------------------------------------------------------------------
class RuntimeError < Error; end
@@ -75,7 +83,7 @@ module CliGen
class FlagBundleError < RuntimeError; end
# -------------------------------------------------------------------------
# Help signal - not an error; exit 0 after printing
# Help signal : not an error; exit 0 after printing
# -------------------------------------------------------------------------
# Raised when -h/--help is matched; carries the rendered help string
+37 -9
View File
@@ -19,7 +19,7 @@ module CliGen
var : String,
short : String?,
long : String,
env_var : String,
env_var : String?,
description : String,
delimiter : String = ",",
@default : T? = nil,
@@ -200,8 +200,11 @@ module CliGen
# Priority: provided arg → env var → default → abort
if v.nil?
if raw = ENV[@env_var]?
v = coerce(raw)
# Since ENVVAR is optional it can be nil
if var = @env_var
if raw = ENV[var]?
v = coerce(raw)
end
end
end
@@ -228,7 +231,7 @@ module CliGen
def satisfied? : Bool
Log.trace { "Flag(long: #{@long}, type: #{@meta.type})#satisfied? : called" }
return true if !@value.nil?
return true if @env_var && ENV[@env_var]?
return true if !@env_var.nil? && ENV[@env_var.not_nil!]?
return true if !@default.nil?
false
end
@@ -254,12 +257,37 @@ module CliGen
def check! : Nil
Log.trace { "Flag(long: #{@long}, type: #{@meta.type})#check! : called" }
unless @short.nil?
raise CliGen::ConfigurationError.new("Flag({{T}}, long: #{@long})#check! : #{@short} flag short must start with '--'") unless @short.not_nil!.starts_with?("-")
if short = @short
unless short =~ CliGen::Regex::FLAG_SHORT
raise CliGen::ConfigurationError.new(
"Flag({{T}}, long: #{@long})#check! : #{short} must match be a single \"-\" followed by a single character [a-zA-Z]. " \
"Valid pattern (#{CliGen::Regex::FLAG_SHORT.source})"
)
end
end
unless long_key =~ CliGen::Regex::FLAG_LONG
raise CliGen::ConfigurationError.new(
"Flag({{T}}, long: #{@long})#check! : flag long (#{long_key}) must begin with \"--\" followed by a series of alphanumeric " \
"characters and/or \"-\". Valid pattern (#{CliGen::Regex::FLAG_LONG.source})"
)
end
# If #check! is ever called on CliGen::GLOBAL_FLAGS this will die as the
# internal flags are also included in there. However, since this isn't
# called on them this check is safe and is only scoped for the class/command
# authored ones
if %w[ --verbose --help ].includes?(@long_key)
raise CliGen::ReservedFlagError.new(
"Flag({{T}}, long: #{@long})#check! : Long(#{@long_key}) is a reserved long flag. You will need to use another"
)
end
if short = @short
if %w[ -v -h ].includes?(short)
raise CliGen::ReservedFlagError.new(
"Flag({{T}}, long: #{@long})#check! : Long(#{@short}) is a reserved short flag. You will need to use another"
)
end
end
raise CliGen::ConfigurationError.new("Flag({{T}}, long: #{@long})#check! : #{@long} flag long must start with '--'") unless @long.starts_with?("--")
raise CliGen::ReservedFlagError.new("Flag({{T}}, long: #{@long})#check! : -h is reserved for internal help") if @short == "-h"
raise CliGen::ReservedFlagError.new("Flag({{T}}, long: #{@long})#check! : --help is reserved for internal help") if @long_key == "--help"
end
private def coerce(raw : String) : T
+3 -3
View File
@@ -11,7 +11,7 @@ module CliGen
getter short : String?
getter long : String
getter long_key : String
getter env_var : String
getter env_var : String?
getter description : String
getter delimiter : String
getter meta : FlagMeta
@@ -22,7 +22,7 @@ module CliGen
@var : String,
@short : String?,
@long : String,
@env_var : String,
@env_var : String?,
@description : String,
@delimiter : String,
@meta : FlagMeta
@@ -38,7 +38,7 @@ module CliGen
}
# if the user provides just a "--long" I want the @long_key to match it
if @long =~ /\s|=/
@long_key = @long.split(/\s|=/).first
@long_key = @long.split(/\s|=/).first.strip
else
@long_key = @long
end
+16 -3
View File
@@ -12,17 +12,30 @@ module CliGen
long: "--verbose",
env_var: "VERBOSE",
default: false,
description: "Enable verbose output from program & help output"
description: "Enable verbose output from program & help output",
internal: true
)
add_global_flag(Bool,
short: "-h",
long: "--help",
env_var: "",
env_var: nil,
default: false,
description: "Print out this help output",
internal: true,
on_match: ->(v : Bool) do
raise CliGen::
raise CliGen::HelpRequestedError.new("")
end
)
{% unless env("CLIGEN_VERSION") == "no" %}
add_global_flag(Bool,
long: "--cligen-version",
env_var: nil,
description: "Print out the version of cligen",
on_match: ->(v : Bool) do
puts CliGen::VERSION
exit 0
end
)
{% end %}
end
+284 -4
View File
@@ -4,9 +4,250 @@
require "../common/check_flag_vars"
module CliGen
macro add_global_flag(type, *, long, description, env_var = nil, short = nil, validation = nil, default = nil, on_match = nil, options = nil)
# This macro provides a user-friendly way to define a global flag for your
# project.
#
# ## What does this do?
# This macro is used to help define & check a global flag to be used in the
# all levels of commands.
#
# When provided it will parse your values & serialize them into a Flag(T)
# object & insert it in the CliGen::GLOBAL_FLAGS array after checking if
# a flag using it's `--long` is already in use. In the case that that long
# is already used it will raise at runtime and you'll need to choose another
# long.
#
# ## Arguments
# ### type: TypeNode
# **Required:** true
#
# This is the type of the flag (Bool, Int32, String, etc).
#
#
# ### long: StringLiteral
# **Required:** true
#
# This is the long form of the flag that will be matched at the command-line
#
#
# ### description: StringLiteral
# **Required:** true
#
# This is the full length description of the flag that will be presented in the
# help text provided to the user.
#
#
# ### env_var: StringLiteral
# **Required:** false
#
# This is an ENV VAR that can be used to set this value without providing an
# argument via the CLI. By default it will (unless explicitly disbled by
# passing `env_var: nil` as an argument to disable the env_var entirely)
# will parse your long flag and set the ENV VAR to the un "--" portion of it
#
# **Warning:** Incompatible ENV VAR formatting
#
# When providing ENV VARs manually you cannot provide any whitespace or "-"
# characters internally to it. As thse are both incompatible with ENV VARs.
#
# If you provide an ENV VAR with these the framework will raise at
# compile-time and tell you to change them.
#
# **Note:** Auto Generates ENV VAR from flag long
#
# If you did not provide a ENV VAR manually (or disable it via setting it to
# nil), the macro will use the long flag to create a ENV VAR that can be
# matched. In this case if the flag has any internal "-" chars they will
# be replaced with "_" so "--long--flag--name"/"--long-flag-name" ->
# "LONG_FLAG_NAME".
#
# When you provide a long: with a trailing ARGUMENT (ex: "--item ITEM",
# "--item=ITEM") the flag will first be split on the whitespace or "="
# prior to being used for the ENV_VAR.
#
#
# ### short: StringLiteral
# **Required:** false
#
# This is the short form of a flag ("--filename" -> "-f") that can be matched
# during parsing.
#
# **Note:** Alphabetic characters only
#
# Unlike some other frameworks that might support numeric flags, due to the
# issues around supporting them & being able to discern if these are arguments
# (-1/signed int's) or short flags ("--one" -> "-1"), I've determined that I
# will not be supporting numeric flags as this causes a number of
# complications/complexities around ARGV parsing.
#
#
# ### default: T
# **Required:** ?false?
#
# This is the default value of the flag (String -> "abc", Int32 -> 0, etc)
# that will be returned if no direct (via parsing CLI args) or indirect
# (by parsing ENV VAR values) arguments are provided.
#
# While not technically required, it's advised to always set a default
# when creating flags as if you don't and nothing is parsed/provided
# when Flag(T)#value! is called it will raise a
# CliGen::MissingRequiredFlagError exception at the call site.
#
#
# ### options: ArrayLiteral(T)|Call
# **Required:** false
#
# This argument sets a static list of accepted arguments to a specific subset
# of values.
#
# EX: Output format
#
# CliGen.add_global_flag(String,
# default: "ecr",
# short: "-f",
# long: "--format",
# description: "Provide the preferred output format",
# options: %w[ json yaml ecr ]
# )
#
#
# **Note:** Support for runtime resolution
#
# While the primary value of this is static arrays of values, you can also
# delegate the discovery of values to a global method or helper method in
# your codebase.
#
# HOWEVER, when doing so ALWAYS ensure that you are providing a full path
# to your method, as the the macro has no way of determining relative paths
# in your modules. While, provided you are doing this in the same context as
# the method you are running, this shouldn't be an issue, however best
# practices dictate you provide a full path just to be careful.
#
# EX: Delegated resolution
#
# module ABC
# def self.items
# %w[ a b c d e f g taco ]
# end
# end
#
# CliGen.add_global_flag(String,
# default: "a",
# short: "-i",
# long: "--item",
# description: "Provide an item to print",
# options: ::ABC.items
# )
#
#
# ### format: RegexLiteral
# **Required:** false
#
# This exists to handle (for String & Custom Data Types) filtering & checking
# that an argument being provided by a user is being given in a specific
# format.
#
# This is something you use when you're only wanting to validate formatting,
# if you plan to do more specific/extensive validation you should use the
# validation: field.
#
# EX: Hostname matching
#
# CliGen.add_global_flag(Array(String),
# default: [] of String,
# short: "-H",
# long: "--hostname",
# description: "Provide a hostname to do remote work on",
# format: /^[a-zA-Z]{3}[0-9]+node[0-9]$/
# )
#
#
# ### validation: ProcLiteral(T, Bool)
# **Required:** false
#
# Here you can provide a ad-hoc proc for doing validations of a provided
# argument that can't easily be done by providing a static `options:` value.
#
# **Note:** Explicit input & return type requirement
#
# The explicit input `: T` & return `: Bool` turn types are required as the
# macros I setup are trying to enforce that both the input & return types
# are explicity to avoid truthy & falsey semantics.
#
# EX: checking int range
#
# CliGen.add_global_flag(Int32,
# short: "-p",
# long: "--port",
# description: "Provide a single port to test against",
# validation: ->(port : Int32) : Bool do
# (UInt16::MIN..UInt16::MAX).includes?(port)
# end
# )
#
#
# EX: file existance check
#
# CliGen.add_global_flag(String,
# short: "-i",
# long: "--filename",
# description: "Provide a file that will serve as the input for this program",
# validation: ->(file : String) : Bool do
# if File.exists?(file)
# true
# else
# STDERR.puts "ERROR : --filename : Provided file (#{file}) does not exist"
# false
# end
# end
# )
#
#
# ### on_match: ProcLiteral(T, Nil)
# **Required:** false
#
# This option is where you provide the proc for handling ad-hoc
#
# EX: Configuring the stdlib log level
#
# CliGen.add_global_flag(String,
# long: "--log-level LEVEL",
# short: "-l",
# description: "Set the current log level of the stdlib Log library",
# options: %w[ trace debug notice info warn error fatal ],
# on_match: ->(level : String) do
# ::Log.setup(level: ::Log::Severity.parse(level))
# end
# )
#
# EX: Collecting arguments in a global array
#
#
# module MyModule
# MY_ARRAY = [] of String
# CliGen.add_global_flag(String,
# long: "--filename FILE",
# short: "-i",
# description: "Provide a single file to check against (repeatable)",
# validation: ->(file : String) : Bool do
# if File.exists?(file)
# true
# else
# STDERR.puts "ERROR : --filename : #{file} does not exist"
# false
# end
# end,
# on_match: ->(file : String) do
# ::MyModule::MY_ARRAY << file
# end
# )
# end
#
#
# For more detailed documentation please visit the wiki in the repo. All topics are covered there in much greater detail than inline documentation here
macro add_global_flag(type, *, long, description, env_var = "", short = nil, validation = nil, default = nil, on_match = nil, options = nil, format = nil, internal = false)
{% raise "ERROR : CliGen.add_global_flag : Provided long must be a string" unless long.is_a? StringLiteral %}
{% env_var = long.gsub(/^--/,"").gsub(/-+/,"_").upcase if env_var.nil? %}
{% env_var = long.split(/=|\s+/).first.gsub(/^--/,"").gsub(/-+/,"_").upcase if env_var == "" %}
CliGen::Common.check_flag_vars(
raise_base: {{"CliGen.add_global_flag(#{long.id})"}},
@@ -17,10 +258,12 @@ module CliGen
validation: {{validation}},
on_match: {{on_match}},
options: {{options}},
description: {{description}}
format: {{format}},
description: {{description}},
internal: {{internal}}
)
::CliGen::GLOBAL_FLAGS << ::CliGen::Flag({{type}}).new(
%flg = ::CliGen::Flag({{type}}).new(
var: "",
short: {{short}},
long: {{long}},
@@ -31,5 +274,42 @@ module CliGen
on_match: {% unless on_match.nil? %} {{on_match}} {% else %} nil {% end %},
validate: {% unless validation.nil? %} {{validation}} {% else %} nil {% end %}
)
# If the user is defining a global flag check to make sure that long
# isn't already defined
if %oflg = ::CliGen::GLOBAL_FLAGS.find(&.long_key.== %flg.long_key)
abort <<-EOF
ERROR : CliGen.add_global_flag : Flag({{type}}, long: "{{long.id}}") : at #{__FILE__}:#{__LINE__}
Provided long flag (#{%flg.long_key}) is in conflict with another flag in CliGen::GLOBAL_FLAGS.
You will need to choose another long.
Conflicted Flag:
Flag(#{%oflg.meta.type}, long: "#{%oflg.long}", description: "#{%oflg.description}")
\n
EOF
end
{% unless short.nil? %}
# If the user is defining a global flag check to make sure that short
# isn't already defined
if %oflg = ::CliGen::GLOBAL_FLAGS.find(&.short.== %flg.short)
abort <<-EOF
ERROR : CliGen.add_global_flag : Flag({{type}}, long: "{{long.id}}") : at #{__FILE__}:#{__LINE__}
Provided short flag (#{%flg.short}) is in conflict with another flag in CliGen::GLOBAL_FLAGS.
You will need to choose another short.
Conflicted Flag:
Flag(#{%oflg.meta.type}, long: "#{%oflg.long}", description: "#{%oflg.description}")
\n
EOF
end
{% end %}
# if they didn't fail completely add it to the global flags
::CliGen::GLOBAL_FLAGS << %flg
end
end
+4 -2
View File
@@ -3,8 +3,10 @@
module CliGen::Regex
FLAG_REGEX=/^(-[a-zA-Z]|--[a-zA-Z-_0-9]+)$/
FLAG_WITH_ARG=/^(?<flag>(-[a-zA-Z]|--[a-zA-Z-_]+))="?(?<arg>\S+?)"?$/
FLAG_MULTIPLE_SHORT=/^-[a-zA-Z][a-zA-Z0-9]+$/
FLAG_WITH_ARG=/^(?<flag>(-[a-zA-Z]|--[a-zA-Z0-9][a-zA-Z0-9-_]+))="?(?<arg>.+?)"?$/
FLAG_MULTIPLE_SHORT=/^-[a-zA-Z][a-zA-Z]+$/
FLAG_LONG = /^--[a-zA-Z0-9][a-zA-Z0-9-_]+$/
FLAG_SHORT = /^-[a-zA-Z]$/
# ---------------------------------------------------------------------------
# Date/time components.
+7
View File
@@ -2,6 +2,9 @@ Command: <%= @name %>
<%- unless @description.nil? -%>
Description: <%= @description %>
<%- end -%>
<%- if p = parent? -%>
Parent Command: <%= p.name %>
<%- end -%>
<%- unless @flags.empty? -%>
<%- len = @flags.map{|f| f.short.nil? ? f.long.size : "#{f.short},#{f.long}".size}.max + 5 -%>
@@ -17,7 +20,9 @@ Flags:
<%= "%-#{len}s %s" % [flags.join(","), flag.description.strip] %><%= flag.meta.options.nil? ? "" : " (valid: #{flag.meta.options.not_nil!.join(", ")})" %><%= flag.meta.default.empty? ? "" : " (default: #{flag.meta.default.not_nil!})" %>
<%- if verbose? -%>
<%= "%-#{len}s %s" % ["", "Type: #{flag.meta.type}"] %>
<%- unless flag.env_var.nil? -%>
<%= "%-#{len}s %s" % ["", "ENV VAR: #{flag.env_var}"] %>
<%- end -%>
<%- unless flag.meta.format.nil? -%>
<%= "%-#{len}s %s" % ["", "Valid Format: #{flag.meta.format}"] %>
<%- end -%>
@@ -42,7 +47,9 @@ Global Flags
<%= "%-#{len}s %s" % [flags.join(","), flag.description.strip] %><%= flag.meta.options.nil? ? "" : " (valid: #{flag.meta.options.not_nil!.join(", ")})" %><%= flag.meta.default.empty? ? "" : " (default: #{flag.meta.default.not_nil!})" %>
<%- if verbose? -%>
<%= "%-#{len}s %s" % ["", "Type: #{flag.meta.type}"] %>
<%- unless flag.env_var.nil? -%>
<%= "%-#{len}s %s" % ["", "ENV VAR: #{flag.env_var}"] %>
<%- end -%>
<%- unless flag.meta.format.nil? -%>
<%= "%-#{len}s %s" % ["", "Valid Format: #{flag.meta.format}"] %>
<%- end -%>
+4
View File
@@ -90,5 +90,9 @@ module CliGen::Timeparse
EOF
)
end
rescue e : CliGen::Error
raise e
rescue e : Exception
raise CliGen::TimeParseError.new("invalid date/time \"#{raw}\" : #{e.message}")
end
end