Files
2026-09-05 13:19:55 -05:00

174 lines
5.1 KiB
Markdown

# CliGen::Command.argument Macro
## TOC
- [Overview](#Overview)
## Overview
This macro as explained briefly in the [Macros Doc](../Macros.md), handles setting up and configuring instance variables & configuring instance variables & annotations as well as checking for misconfigurations in your provided macro arguments before you experience.
Overall this is used for annotating instance variables for the CliGen framework can know how to create your [CliGen::Flag(T)][flag-doc] objects.
```crystal
class MyCmd < CliGen::Command
argument(myvar : String = "test",
short: "-m",
long: "--myvar",
description: "This is my test flag",
options: %w[ test test2 test3 ]
)
def main
puts "@myvar was #{@myvar}"
end
end
```
## Caveots
### Dedicated short & long flasg
A unfortunate limitation is that the `-h|--help` & `-v|--verbose` flags are all allocated to two internal flags used by all [CommandNode(T)][commandnode-doc] objects
### Duplicate Short Flags
While this is limited to Flags defined in your Command
## Arguments
### short:
**Type:** StringLiteral
**Required:** false
This represents the short form of the flag bring provided. it is optional as
not all flags have to have a short form flag.
### long:
**Type:** StringLiteral
**Required:** true*
This represents the long-form of the flag. It is required in order to generate
the [Flag(T)][flag-doc].
### description:
Type: StringLiteral
Required: true
This is the description of your flag and is required for `Flag(T)` creation
### delimiter:
**Type:** StringLiteral
**Required:** false
For [Flag][flag-doc](Array(T)) flags this is the delimiter that will seperate any inline args (ex: "," will split "a,b,c") provided at the commandline. If nil/not provided, the framework will default to ',' as this is the usual choice.
### env_var:
**Type:** StringLiteral
**Required:** false
This is the ENV VAR that can be used to specify your flag value when not
provided by the user.
### validation:
**Type:** ProcLiteral
**Required:** false
This is a proc that can be used to provide an ad-hoc way of verifying the
value provided by a user.
```crystal
validation: ->(i : Int32) : Bool do
(1..23).includes?(i)
end
```
*Example: Int Validator*
This is used as a fallback to where the options: key doesn't cleanly
provide enough of a check for the provided values.
Note:
The input value MUST be the same as the value type as the instance
variable. Otherwise CliGen will not compile. IF requested I can
add a raw_validation: key as well to do the same but for just the
String variable provided by the user.
### on_match:
**Type:** ProcLiteral
**Required:** false
Much like validation, this is used as a hook for doing arbitrary actions
with the parsed value from the user (very useful for global flags).
```crystal
on_match: ->(arg : String) do
begin
::Log.setup(level: ::Log::Severity.parse(arg))
rescue e : ArgumentError
STDERR.puts "ERROR : Failed to set to #{arg} log level: (#{e.class}: #{e.message})"
end
end
```
*Example: Log level setter*
NOTE: This specific example will be reworked once Enum support is added to the framework to do checking directly.
In this way you can use on_match: to hook a global flag and have it call some
arbitrary method elsewhere in the codebase to help setup the environment
before the main command is run.
### options:
**Type:** ArrayLiteral(T)|Call
**Required:** false
CURRENTLY this is being as a way of providing a static set of values that we
are to use when doing a provided argument.
```crystal
options: %w[ a b c ]
```
*Example: Options for string var*
Howver, this currently also supports delegating the retrieval of values (in array format) to be learned at runtime by providing a call to a global methods/class method/util method/etc
```crystal
module MyModule
def self.my_method : Array(String)
if File.exists?("/etc/valid_things.txt")
File.read("/etc/valid_things.txt").split(",")
else
%w[ a b c ]
end
end
CliGen.add_global_flag(String,
short: "-t",
long: "--test",
description: "This does things. I promise",
options: ::MyModule.my_method,
on_match: ->(t : String) do
puts "Matched #{t}"
end
)
end
```
*Example: Deletgating to runtime*
Doing things this way gives you some runtime flexibility, but makes you
responsible for ensuring that it doesn't crash or provide incorrect data
at runtime. As (unfortunately) the framework doesn't account for developer
error at runtime like it can at compile-time with a static array of
values.
### format:
**Type:** RegexLiteral
**Required:** false
This metadata is used to provide (mostly for strings when you don't have a
statically known list of values that can be provided at runtime, but you
want to filter out invalid options.
```crystal
format: /^([a-z0-9]+)(,?[a-z0-9]+)+$/
```
EX: filtering for csv formatted info
[command-doc]: ../../Command.md
[flag-doc]: ../../Flag.md
[commandnode-doc]: ../../CommandNode.md