compared with
Current by Artur Bodera
on Feb 20, 2012 14:30.

Key
This line was removed.
This word was removed. This word was added.
This line was added.

Changes (195)

View Page History
h1. Zend Cli & Console RFC
<h1>Zend Console RFC</h1>

This RFC contains a proposal for implementing goals set previously in [RFC - CLI|http://framework.zend.com/wiki/display/ZFDEV2/RFC+-+CLI].
<p>This RFC contains a proposal for implementing goals set previously in <a href="http://framework.zend.com/wiki/display/ZFDEV2/RFC+-+CLI">RFC - CLI</a>. </p>

<p>It is partially implemented and under development in this Git Repository: [https://github.com/Thinkscape/zf2-console-sandbox] <a href="https://github.com/Thinkscape/zf2-console-sandbox">https://github.com/Thinkscape/zf2-console-sandbox</a></p>

Components and features {color:red}marked in red{color} are unfinished (broken).
<p>Components and features <span style="color: red;">marked in red</span> are unfinished (broken).</p>

Components and features {color:gray}marked in gray{color} are not implemented yet.
<p>Components and features <span style="color: gray;">marked in gray</span> are not implemented yet.</p>


h2. Zend\Console
<h2>Zend\Console</h2>

h5. Zend\Console
<h5>Zend\Console</h5>

A <p>A static class used for detecting and retrieving Console Adapters. </p>

<p>It will be generally used as a factory for auto-detected console adapter:</p>

{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
// auto-detect console adapter
$console = Zend\Console\Console::getInstance();
$console->writeLine("Hello world!");
{code}
]]></ac:plain-text-body></ac:macro>

<p>We can tell the factory to instantiate a specific adapter (keep in mind that it might be incompatible with current terminal)</p>

{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
use Zend\Console\Console, Zend\Console\Color;

$console = Console::getInstance("WindowsAnsicon");
$console->writeLine("Hello world!", Color::GREEN);
{code}
]]></ac:plain-text-body></ac:macro>

<p>Charset is auto-detected as well, but we can force one:</p>

{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
use Zend\Console\Console;

$console = Console::getInstance(null, "Ascii");
$console->writeBox(1,1,10,10); // draw a box
{code}
]]></ac:plain-text-body></ac:macro>



h5. Zend\Console\Adapter
<h5>Zend\Console\Adapter</h5>

<p>Adapters provide API for interacting with various console environments. Adapter can be picked (sensed) automatically by {{Zend\Console}} <code>Zend\Console</code> static class.</p>

Basic Adapter responsibilities are:
* input/output API
** get/write line
** get/write char
** {{writeBox()}} - basic line drawing
** {{writeTextBox()}} - basic managed text drawing
* retrieving terminal size (width, height)
* cursor positioning
* handling styled (colored) text
* clearing terminal screen/line.
<p>Basic Adapter responsibilities are:</p>
<ul>
<li>input/output API
<ul>
<li>get/write line</li>
<li>get/write char</li>
<li><code>writeBox()</code> - basic line drawing</li>
<li><code>writeTextBox()</code> - basic managed text drawing</li>
</ul>
</li>
<li>retrieving terminal size (width, height)</li>
<li>cursor positioning</li>
<li>handling styled (colored) text</li>
<li>clearing terminal screen/line.</li>
</ul>


Currently there are following adapters implemented:
* {{Adapter\Posix}} - for posix-compliant systems, such as Unix, Linux, BSD, etc.
* {{Adapter\Windows}} - for stock MS Windows (versions XP up)
* {{Adapter\WindowsAnsicon}} - for MS Windows with Ansicon extension
* {color:red}{{Adapter\Virtual}}{color} - a failback providing absolute cursor positioning for limited console environments

h5. Zend\Console\Charset
<p>Currently there are following adapters implemented:</p>
<ul>
<li><code>Adapter\Posix</code> - for posix-compliant systems, such as Unix, Linux, BSD, etc.</li>
<li><code>Adapter\Windows</code> - for stock MS Windows (versions XP up)</li>
<li><code>Adapter\WindowsAnsicon</code> - for MS Windows with Ansicon extension</li>
<li><span style="color: red;"><code>Adapter\Virtual</code></span> - a failback providing absolute cursor positioning for limited console environments</li>
</ul>

Charset components contain character definitions and escape codes required to draw special console characters.
Charset is selected (sensed) automatically by Console Adapter to match console capabilities.

Currently there are following charsets implemented:
* {{Charset\Ascii}} - basic ascii, failback charset
* {{Charset\AsciiExtended}} - Ascii 127+ charset, used primarily by {{Adapter\Windows}}
* {{Charset\DECSG}} - DEC Special Graphics set (defined by VT100), used primarily by {{Adapter\Posix}} in non-utf8 mode
* {{Charset\Utf8}} - charset for utf8 enabled terminals
* {{Charset\Utf8Heavy}} - charset for utf8 enabled terminals, using heavier line art.
<h5>Zend\Console\Charset</h5>

<p>Charset components contain character definitions and escape codes required to draw special console characters. <br />
Charset is selected (sensed) automatically by Console Adapter to match console capabilities.</p>

h2. Zend\Cli Components
<p>Currently there are following charsets implemented:</p>
<ul>
<li><code>Charset\Ascii</code> - basic ascii, failback charset</li>
<li><code>Charset\AsciiExtended</code> - Ascii 127+ charset, used primarily by <code>Adapter\Windows</code></li>
<li><code>Charset\DECSG</code> - DEC Special Graphics set (defined by VT100), used primarily by <code>Adapter\Posix</code> in non-utf8 mode</li>
<li><code>Charset\Utf8</code> - charset for utf8 enabled terminals</li>
<li><code>Charset\Utf8Heavy</code> - charset for utf8 enabled terminals, using heavier line art.</li>
</ul>

Cli stands for *Command Line Interface* and the following components are used to introduce app-level interactivity and logic.

h5. Zend\Cli\Request
<h5>Zend\Console\Request</h5>

Basic CLI Request class, a container for command-line parameters and environment info that is used for Cli MVC routing.
<p>Basic Console Request class, a container for command-line parameters and environment info that is used for Console MVC routing.</p>

<p>Responsibilities:</p>
<ul>
* retrieve <li>retrieve and store command line params (in raw form, usually from {{$argv}}) <code>$argv</code>)</li>
* retrieve and store php-provided environment info (usually from {{$_ENV}})
<li>retrieve and store php-provided environment info (usually from <code>$_ENV</code>)</li>
</ul>

Basic usage:
{code}
<p>Basic usage:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
$request = new Zend\Cli\Request(); Zend\Console\Request();
echo $request->params->get(2); // echo second command line argument
echo $request->env->get("PWD"); // echo current working directory name
{code}
]]></ac:plain-text-body></ac:macro>

h5. Zend\Cli\Prompt
<h5>Zend\Console\Prompt</h5>

<p>These classes provide interactive, cross-system user prompts. They depend on {{Console\Adapter}} <code>Console\Adapter</code> and handle most common interactive input found in terminal applications.</p>

Currently the following classes are implemented:
<p>Currently the following classes are implemented:</p>
<ul>
* {{Prompt\Char}} <li><code>Prompt\Char</code> - prompt for a single char (key), optionally filter against a key mask of allowed chars.</li>
* {{Prompt\Confirm}} - ask the user to confirm an operation
* {{Prompt\Line}} - ask for a line of input
<li><code>Prompt\Confirm</code> - ask the user to confirm an operation</li>
<li><code>Prompt\Line</code> - ask for a line of input</li>
* {{Prompt\Number}} <li><code>Prompt\Number</code> - prompt for a number, optionally validated against min, max and floating-point restrictions.</li>
* {{Prompt\Select}} <li><code>Prompt\Select</code> - ask the user to select one option from the provided list.</li>
* {color:gray}{{Prompt\File}}{color} - prompt for a path to existing/readable file.
* {color:gray}{{Prompt\Dir}}{color} - prompt for an existing (writable/readable) dir path.
<li><span style="color: gray;"><code>Prompt\File</code></span> - prompt for a path to existing/readable file.</li>
<li><span style="color: gray;"><code>Prompt\Dir</code></span> - prompt for an existing (writable/readable) dir path.</li>
</ul>

Basic prompts usage:
{code}
use Zend\Cli\Prompt, Zend\Console\Color;

<p>Basic prompts usage:</p>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
use Zend\Console\Prompt, Zend\Console\Color;

/**
* Simple line prompt
);
$nixon = $prompt->show();
{code}
]]></ac:plain-text-body></ac:macro>

<p>More examples for all prompt classes can be found in [demo/prompts.php|https://github.com/Thinkscape/zf2-console-sandbox/blob/master/demo/prompts.php] <a href="https://github.com/Thinkscape/zf2-console-sandbox/blob/master/demo/prompts.php">demo/prompts.php</a></p>


h5. Zend\Cli\Decorator or Zend\Cli\Renderer
<h5>Zend\Console\Decorator or Zend\Console\Renderer</h5>

<p>This class will be used to format Cli Console output. Previous CLI RFC and prototypes introduced the concept of Decorators, that take any string (usually an output from a command) and decorate it (i.e. add line wrapping, add color, align, etc.). Because {{Zend\Cli}} <code>Zend\Console</code> components are being adapted to work with {{Zend\Mvc}}, <code>Zend\Mvc</code>, a new problem arised.</p>

{info}
<ac:macro ac:name="info"><ac:rich-text-body>
<p>This class does not exist yet, as it requires some more conceptual work.</p></ac:rich-text-body></ac:macro>
{info}

If Cli <p>If Console applications are being driven by Controllers and their Actions, there is a detachment between the interactive actions being performed and console output. It becomes very similar to HTTP request handling, where zf2-based application produces a piece of HTML content, that is later rendered by user's browser. In CLI, we do not have the luxury of a common "viewer" &quot;viewer&quot; or "browser" &quot;browser&quot; that would handle rendering of complex console output.</p>

<p>To emulate that behavior, I'd like to propose a simple markup language that will be used to pretty-print console output. </p>

Here is an example use-case:
<p>Here is an example use-case:</p>

{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
class InstallerController extends Action
{
}
}
{code}
]]></ac:plain-text-body></ac:macro>

<p>In above example InstallerController serves CLI requests and contains two actions. Each action returns a string with the response peppered with simple, self-explanatory CLI markup. The {{Zend\Cli\Renderer}} <code>Zend\Console\Renderer</code> component translated that markup and invokes appropriate {{Zend\Console\Adapters}} <code>Zend\Console\Adapters</code> to pretty-print the result in user's terminal window. If any of the requested features are missing in current environment, they will be ignored by the adapter (but the application and rendering will still work correctly).</p>


h2. Zend\Mvc Components
<h2>Zend\Mvc Components</h2>

h5. {color:red}Zend\Mvc\CliApplication{color}
<h5><span style="color: red;">Zend\Mvc\ConsoleApplication</span></h5>

<p>Extension of {{Zend\Mvc\Application}}, <code>Zend\Mvc\Application</code>, providing a dispatch loop to handle incoming command-line request and route them to appropriate Mvc action controllers.</p>

<p>Responsibilities:</p>
* Create a {{Cli\Request}} from passed command-line arguments.
* Prepare Cli-specific routes
* Pass the request to the router
<ul>
<li>Create a <code>Console\Request</code> from passed command-line arguments.</li>
<li>Prepare Console-specific routes</li>
<li>Pass the request to the router</li>
* If <li>If a route matches, invoke a controller and action to handle the request.
** If the Action returns a response, process it with 0 or more {{Cli\Decorators}} and output to terminal
<ul>
<li>If the Action returns a response, process it with 0 or more <code>Console\Decorators</code> and output to terminal</li>
** If <li>If the Action returns one or more prompts, display them to the user, collect values, merge with original request and dispatch it again.</li>
** If there are no prompts, end application execution.
<li>If there are no prompts, end application execution.</li>
</ul>
</li>
</ul>


h5. {color:red}Zend\Mvc\Route\Cli\Simple{color}

A basic, universal route for parsing CLI requests.
<h5><span style="color: red;">Zend\Mvc\Route\Console\Simple</span></h5>

Responsibilities:
* Take a route description and parse it
* Handle 0 or more constraints (regular expressions for validating param values)
* Handle 0 or more filters (for cleaning user-provided values)
* Handle 0 or more validators (for validating CLI user input)
* Handle 0 or more aliases (that can translate parameter names)
* Handle 0 or more default values
<p>A basic, universal route for parsing CLI requests.</p>

h2. CLI MVC application
<p>Responsibilities:</p>
<ul>
<li>Take a route description and parse it</li>
<li>Handle 0 or more constraints (regular expressions for validating param values)</li>
<li>Handle 0 or more filters (for cleaning user-provided values)</li>
<li>Handle 0 or more validators (for validating CLI user input)</li>
<li>Handle 0 or more aliases (that can translate parameter names)</li>
<li>Handle 0 or more default values</li>
</ul>

h5. General CLI application workflow

# {{app.php}} script is the entry point
# Module Manager, configuration and {{Zend\Mvc\CliApplication}} are instantiated and configured.
# {{CliApplication}} creates new instance of {{Zend\Cli\Request}}
# {{Zend\Cli\Request}} reads command-line arguments
# {{$application->run()}}
# Cli routes are read from config.
# {{Router}} runs the {{$cliRequest}} against all declared Cli routes until first route matches
## if a route matches, but param validation fails, an exception is thrown, caught by {{CliApplication}} and transformed to usage information
## if no route matches, a default "usage" route could be invoked
## if no route matches, a closest matching route will be used as a "did you mean..." suggestion
# {{RouteMatch}} is returned containing all matched mandatory and optional parameters, along with their values
# An Action controller is invoked with the request and an Action is called
## If the Action returns a string, it will be output to the terminal screen
## If the Action returns a ViewModel it will be analyzed
### ViewModel may contain 1 or more {{Cli\Prompts}} they will be displayed to the user
### All responses to prompts will be collected and merged with the original {{$cliRequest}} as params
### The {{$cliRequest}} is fed back into {{Router}}
### The {{Router}} matches the same (or another) route and Action Controller is invoked
### ... the process repeats itself until there are no more prompts (i.e. the application displays some output and finishes)
<h2>CLI MVC application</h2>

<h5>General CLI application workflow</h5>

h5. Example Cli route definition
{code} <ol>
$route = Zend\Mvc\Router\Cli\Simple::factory(array(
<li><code>app.php</code> script is the entry point</li>
<li>Module Manager, configuration and <code>Zend\Mvc\ConsoleApplication</code> are instantiated and configured.</li>
<li><code>ConsoleApplication</code> creates new instance of <code>Zend\Console\Request</code></li>
<li><code>Zend\Console\Request</code> reads command-line arguments</li>
<li><code>$application-&gt;run()</code></li>
<li>Console routes are read from config.</li>
<li><code>Router</code> runs the <code>$consoleRequest</code> against all declared Console routes until first route matches
<ol>
<li>if a route matches, but param validation fails, an exception is thrown, caught by <code>ConsoleApplication</code> and transformed to usage information</li>
<li>if no route matches, a default &quot;usage&quot; route could be invoked</li>
<li>if no route matches, a closest matching route will be used as a &quot;did you mean...&quot; suggestion</li>
</ol>
</li>
<li><code>RouteMatch</code> is returned containing all matched mandatory and optional parameters, along with their values</li>
<li>An Action controller is invoked with the request and an Action is called
<ol>
<li>If the Action returns a string, it will be output to the terminal screen</li>
<li>If the Action returns a ViewModel it will be analyzed
<ol>
<li>ViewModel may contain 1 or more <code>Console\Prompts</code> they will be displayed to the user</li>
<li>All responses to prompts will be collected and merged with the original <code>$consoleRequest</code> as params</li>
<li>The <code>$consoleRequest</code> is fed back into <code>Router</code></li>
<li>The <code>Router</code> matches the same (or another) route and Action Controller is invoked</li>
<li>... the process repeats itself until there are no more prompts (i.e. the application displays some output and finishes)</li>
</ol>
</li>
</ol>
</li>
</ol>



<h5>Example Console route definition</h5>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
$route = Zend\Mvc\Router\Console\Simple::factory(array(

// route definition
'route' => 'install ( module | package | application | app ) NAME [--verbose] [--quick] [--user=s]',
)
));
{code}
]]></ac:plain-text-body></ac:macro>

h5. Basic definitions
{color:green}*positional literal parameter*{color} - a single word that has be typed by the user for the route to match, i.e. literal "install"
<h5>Basic definitions</h5>
<p> <span style="color: green;"><strong>positional literal parameter</strong></span> - a single word that has be typed by the user for the route to match, i.e. literal &quot;install&quot;</p>

{color:green}*positional value parameter*{color} - a positional param that can take any value.
<p> <span style="color: green;"><strong>positional value parameter</strong></span> - a positional param that can take any value.</p>

{color:green}*named flag*{color} - a single, boolean (present or not present) named parameter, prefixed with double colons, i.e. "--verbose"
<p> <span style="color: green;"><strong>named flag</strong></span> - a single, boolean (present or not present) named parameter, prefixed with double colons, i.e. &quot;--verbose&quot;</p>

{color:green}*named short flag*{color} - a short version of a flag, prefixed with a single colon, i.e. "-v"
<p> <span style="color: green;"><strong>named short flag</strong></span> - a short version of a flag, prefixed with a single colon, i.e. &quot;-v&quot;</p>

{color:green}*named value parameter*{color} - a double-colon prefixed, named parameter that expects a value, i.e. "--name Foo"
<p> <span style="color: green;"><strong>named value parameter</strong></span> - a double-colon prefixed, named parameter that expects a value, i.e. &quot;--name Foo&quot;</p>



h5. Recognized route definition tokens
* {color:blue}{{param}}{color} - a mandatory literal positional parameter
* {color:blue}{{\[param\]}}{color} - an optional literal positional parameter
* {color:blue}{{( foo | bar | baz )}}{color} - a mandatory positional parameter, one of the provided options
* {color:blue}{{SOMEPARAM}}{color} - a mandatory positional value parameter (any string)
* {color:blue}{{\[SOMEPARAM\]}}{color} - an optional positional value parameter
* {color:blue}{{--param}}{color} - a mandatory flag
* {color:blue}{{\[--param\]}}{color} - an optional flag
* {color:blue}{{--param=s}}{color} - a mandatory value parameter (of type *s*tring or *n*umber)
* {color:blue}{{\[--param=s\]}}{color} - an optional value parameter (of type *s*tring or *n*umber)
* {color:blue}{{-v}}{color} - a mandatory short flag
* {color:blue}{{\[-v\]}}{color} - an optional short flag
<h5>Recognized route definition tokens</h5>
<ul>
<li><span style="color: blue;"><code>param</code></span> - a mandatory literal positional parameter</li>
<li><span style="color: blue;"><code>[param]</code></span> - an optional literal positional parameter</li>
<li><span style="color: blue;"><code>( foo | bar | baz )</code></span> - a mandatory positional parameter, one of the provided options</li>
<li><span style="color: blue;"><code>SOMEPARAM</code></span> - a mandatory positional value parameter (any string)</li>
<li><span style="color: blue;"><code>[SOMEPARAM]</code></span> - an optional positional value parameter</li>
<li><span style="color: blue;"><code>--param</code></span> - a mandatory flag</li>
<li><span style="color: blue;"><code>[--param]</code></span> - an optional flag</li>
<li><span style="color: blue;"><code>--param=s</code></span> - a mandatory value parameter (of type *s*tring or *n*umber)</li>
<li><span style="color: blue;"><code>[--param=s]</code></span> - an optional value parameter (of type *s*tring or *n*umber)</li>
<li><span style="color: blue;"><code>-v</code></span> - a mandatory short flag</li>
<li><span style="color: blue;"><code>[-v]</code></span> - an optional short flag</li>
* {color:blue}{{-p=s}}{color} <li><span style="color: blue;"><code>-p=s</code></span> - a mandatory short value parameter (of type *s*tring or *n*umber)</li>
* {color:blue}{{\[-p=s\]}}{color} - an optional short value parameter (of type *s*tring or *n*umber)
<li><span style="color: blue;"><code>[-p=s]</code></span> - an optional short value parameter (of type *s*tring or *n*umber)</li>
</ul>


h5. Example routes
{code}
<h5>Example routes</h5>
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
clean cache all
]]></ac:plain-text-body></ac:macro>
{code} <ul>
* three mandatory literal params - "clean", "cache" and "all"
<li>three mandatory literal params - &quot;clean&quot;, &quot;cache&quot; and &quot;all&quot;</li>
* request <li>request must contain all three params or the route will not match</li>
* params must exist in the exact order as described
* RouteMatch will contain the following: {{[ "clean" => true, "cache" => true, "all" => true ]}}
<li>params must exist in the exact order as described</li>
<li>RouteMatch will contain the following: <code>[ &quot;clean&quot; =&gt; true, &quot;cache&quot; =&gt; true, &quot;all&quot; =&gt; true ]</code></li>
</ul>

{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
clean directory CACHEDIR
]]></ac:plain-text-body></ac:macro>
{code} <ul>
* two mandatory literal params - "clean" and "cachedir"
* one mandatory value param {{CACHEDIR}}
* request must contain 2 params "clean" and "cachedir"
* those 2 params must be followed by a cache dir value
* if cache dir is not provided, route will not match
* RouteMatch will contain the following: {{[ "clean" => true, "directory" => true, "cachedir" => "...user supplied.." ]}}
<li>two mandatory literal params - &quot;clean&quot; and &quot;cachedir&quot;</li>
<li>one mandatory value param <code>CACHEDIR</code></li>
<li>request must contain 2 params &quot;clean&quot; and &quot;cachedir&quot;</li>
<li>those 2 params must be followed by a cache dir value</li>
<li>if cache dir is not provided, route will not match</li>
<li>RouteMatch will contain the following: <code>[ &quot;clean&quot; =&gt; true, &quot;directory&quot; =&gt; true, &quot;cachedir&quot; =&gt; &quot;...user supplied..&quot; ]</code></li>
</ul>

{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
clean cache [ all | modules | system | misc ]
]]></ac:plain-text-body></ac:macro>
{code} <ul>
* two mandatory literal params - "clean" and "cache"
* third optional literal param, one of: all modules system misc
* route will match with just two params
<li>two mandatory literal params - &quot;clean&quot; and &quot;cache&quot;</li>
<li>third optional literal param, one of: all modules system misc</li>
<li>route will match with just two params</li>
* route <li>route will match with three params only, if the third param is one of the supplied options</li>
* Assuming the third parameter is "system", RouteMatch will contain the following: {{[ "clean" => true, "cache" => true, "system" => true ]}}
<li>Assuming the third parameter is &quot;system&quot;, RouteMatch will contain the following: <code>[ &quot;clean&quot; =&gt; true, &quot;cache&quot; =&gt; true, &quot;system&quot; =&gt; true ]</code></li>
</ul>

{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
install ( module | application | misc )
]]></ac:plain-text-body></ac:macro>
{code} <ul>
* two mandatory literal params
* first mandatory literal param must equal to "install"
* second literal param must be one of: module application misc
<li>two mandatory literal params</li>
<li>first mandatory literal param must equal to &quot;install&quot;</li>
<li>second literal param must be one of: module application misc</li>
* route <li>route will not match if there is less than 2 params or if the second one does not match any of the options</li>
* Assuming the second parameter is "misc", RouteMatch will contain the following: {{[ "install" => true, "misc" => true ]}}
<li>Assuming the second parameter is &quot;misc&quot;, RouteMatch will contain the following: <code>[ &quot;install&quot; =&gt; true, &quot;misc&quot; =&gt; true ]</code></li>
</ul>


{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
start PROCESS [LOCATION]
]]></ac:plain-text-body></ac:macro>
{code} <ul>
* one mandatory literal param "start"
* one mandatory value (string) param PROCESS
* one optional value (string) param LOCATION
* route will not match if there is less than 2 params
* route will match if LOCATION is not provided
* Assuming "location" has been provided, RouteMatch will contain the following: {{[ "start" => true, "process" => "...user supplied..", "location" => ".. user supplied.." ]}}
<li>one mandatory literal param &quot;start&quot;</li>
<li>one mandatory value (string) param PROCESS</li>
<li>one optional value (string) param LOCATION</li>
<li>route will not match if there is less than 2 params</li>
<li>route will match if LOCATION is not provided</li>
<li>Assuming &quot;location&quot; has been provided, RouteMatch will contain the following: <code>[ &quot;start&quot; =&gt; true, &quot;process&quot; =&gt; &quot;...user supplied..&quot;, &quot;location&quot; =&gt; &quot;.. user supplied..&quot; ]</code></li>
</ul>


{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
process files [DIR] [--quick] [--verbose]
]]></ac:plain-text-body></ac:macro>
{code} <ul>
* two mandatory literal params - "process" and "files"
* one optional value param DIR
* two optional named params (flags) - "--quick" and "--verbose"
<li>two mandatory literal params - &quot;process&quot; and &quot;files&quot;</li>
<li>one optional value param DIR</li>
<li>two optional named params (flags) - &quot;-<span style="text-decoration: line-through;">quick&quot; and &quot;</span>-verbose&quot;</li>
* route <li>route will not match if there is less than 2 positional parameters</li>
* route <li>route will match if any of the optional parameters is not set set</li>
* route will match regardless of named parameters order
* Assuming "--quick" and dir has been provided, RouteMatch will contain the following: {{[ "process" => true, "files" => true, "dir" => "...user supplied..", "quick" => true ]}}
<li>route will match regardless of named parameters order</li>
<li>Assuming &quot;--quick&quot; and dir has been provided, RouteMatch will contain the following: <code>[ &quot;process&quot; =&gt; true, &quot;files&quot; =&gt; true, &quot;dir&quot; =&gt; &quot;...user supplied..&quot;, &quot;quick&quot; =&gt; true ]</code></li>
</ul>


{code}
<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
validate --value=s --validator=s [--verbose]
]]></ac:plain-text-body></ac:macro>
{code} <ul>
* one mandatory literal param "validate"
* two mandatory named params "value" and "validator"
* one optional "verbose" flag
* route will not match if "value" or "validator" parameter is missing
* route will match regardless of parameter order
* route will match regardless of presence of "verbose" flag
* RouteMatch will contain the following: {{[ "validate" => true, "value" => "..user supplied...", "validator" => "...user supplied.." ]}}
<li>one mandatory literal param &quot;validate&quot;</li>
<li>two mandatory named params &quot;value&quot; and &quot;validator&quot;</li>
<li>one optional &quot;verbose&quot; flag</li>
<li>route will not match if &quot;value&quot; or &quot;validator&quot; parameter is missing</li>
<li>route will match regardless of parameter order</li>
<li>route will match regardless of presence of &quot;verbose&quot; flag</li>
<li>RouteMatch will contain the following: <code>[ &quot;validate&quot; =&gt; true, &quot;value&quot; =&gt; &quot;..user supplied...&quot;, &quot;validator&quot; =&gt; &quot;...user supplied..&quot; ]</code></li>
</ul>