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:
+288
-13
@@ -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">"0.1.0"</span></code>
|
||||
<strong>VERSION</strong> = <code><span class="s">"0.2.0"</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">""</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="",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">""</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 & check a global flag to be used in the
|
||||
all levels of commands.</p>
|
||||
<p>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 <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 "--" 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 "-"
|
||||
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 "-" chars they will
|
||||
be replaced with "_" so "--long--flag--name"/"--long-flag-name" ->
|
||||
"LONG_FLAG_NAME".</p>
|
||||
<p>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.</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 ("--filename" -> "-f") 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 & 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.</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 -> "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.</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">"ecr"</span>,
|
||||
short: <span class="s">"-f"</span>,
|
||||
long: <span class="s">"--format"</span>,
|
||||
description: <span class="s">"Provide the preferred output format"</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">"a"</span>,
|
||||
short: <span class="s">"-i"</span>,
|
||||
long: <span class="s">"--item"</span>,
|
||||
description: <span class="s">"Provide an item to print"</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 & Custom Data Types) filtering & 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">"-H"</span>,
|
||||
long: <span class="s">"--hostname"</span>,
|
||||
description: <span class="s">"Provide a hostname to do remote work on"</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 & return type requirement</p>
|
||||
<p>The explicit input <code>: T</code> & return <code>: Bool</code> 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.</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">"-p"</span>,
|
||||
long: <span class="s">"--port"</span>,
|
||||
description: <span class="s">"Provide a single port to test against"</span>,
|
||||
validation: <span class="o">-></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">"-i"</span>,
|
||||
long: <span class="s">"--filename"</span>,
|
||||
description: <span class="s">"Provide a file that will serve as the input for this program"</span>,
|
||||
validation: <span class="o">-></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">"ERROR : --filename : Provided file (</span><span class="i">#{</span>file<span class="i">}</span><span class="s">) does not exist"</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">"--log-level LEVEL"</span>,
|
||||
short: <span class="s">"-l"</span>,
|
||||
description: <span class="s">"Set the current log level of the stdlib Log library"</span>,
|
||||
options: <span class="s">%w[ trace debug notice info warn error fatal ]</span>,
|
||||
on_match: <span class="o">-></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">"--filename FILE"</span>,
|
||||
short: <span class="s">"-i"</span>,
|
||||
description: <span class="s">"Provide a single file to check against (repeatable)"</span>,
|
||||
validation: <span class="o">-></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">"ERROR : --filename : </span><span class="i">#{</span>file<span class="i">}</span><span class="s"> does not exist"</span>
|
||||
<span class="n">false</span>
|
||||
<span class="k">end</span>
|
||||
<span class="k">end</span>,
|
||||
on_match: <span class="o">-></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"><<</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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user