suite gestion des arguments

This commit is contained in:
Jephté Clain 2025-09-16 02:51:32 +04:00
parent ce86cfe354
commit 87aa8fd4ee
6 changed files with 717 additions and 242 deletions

View File

@ -1,194 +0,0 @@
<?php
namespace nulib\app\cli;
use nulib\A;
use nulib\cl;
use nulib\php\types\varray;
class Arg {
const TYPE_SHORT = 0, TYPE_LONG = 1, TYPE_COMMAND = 2;
const ARGS_NONE = 0, ARGS_MANDATORY = 1, ARGS_OPTIONAL = 2;
function __construct(array $def) {
[$options, $params] = cl::split_assoc($def);
$args = $params["args"] ?? null;
$args ??= $params["arg"] ?? null;
if ($args === true) $args = 1;
if (is_int($args)) $args = array_fill(0, $args, "value");
$this->_args = cl::withn($args);
$this->argsdesc = $params["argsdesc"] ?? null;
$extends = $params["extends"] ?? null;
if ($extends !== null) {
A::merge($extends["add"], $options);
$this->extends = $extends;
$this->processExtends();
#XXX à terme, processExtends() est appelé par ArgsParser après le
# chargement de tous les arguments, parce que [arg] peut-être une
# référence e.g ["extends" => ["arg" => "-o", "add" => ["--longo"]]]
} else {
$this->addOptions($options);
}
}
protected ?array $options = [];
function getOptions(): array {
return array_keys($this->options);
}
public bool $haveShortOptions = false;
public bool $haveLongOptions = false;
public bool $haveCommands = false;
public bool $haveArgs = false;
public ?int $minArgs = null;
public ?int $maxArgs = null;
public ?string $argsdesc = null;
function addOptions(?array $options): void {
if ($options === null) return;
foreach ($options as $option) {
if (substr($option, 0, 2) === "--") {
$type = self::TYPE_LONG;
if (preg_match('/^--([^:-]+)(::?)?$/', $option, $ms)) {
$name = $ms[1];
$args = $ms[2] ?? null;
$option = "--$name";
} else {
throw new ArgException("$option: invalid long option");
}
} elseif (substr($option, 0, 1) === "-") {
$type = self::TYPE_SHORT;
if (preg_match('/^-([^:-])(::?)?$/', $option, $ms)) {
$name = $ms[1];
$args = $ms[2] ?? null;
$option = "-$name";
} else {
throw new ArgException("$option: invalid short option");
}
} else {
$type = self::TYPE_COMMAND;
if (preg_match('/^([^:-]+)$/', $option, $ms)) {
$name = $ms[1];
$args = null;
$option = "$name";
} else {
throw new ArgException("$option: invalid command");
}
}
if ($args === ":") {
$argsType = self::ARGS_MANDATORY;
} elseif ($args === "::") {
$argsType = self::ARGS_OPTIONAL;
} else {
$argsType = self::ARGS_NONE;
}
$this->options[$option] = [
"name" => $name,
"option" => $option,
"type" => $type,
"args_type" => $argsType,
];
}
$this->updateType();
}
function removeOptions(?array $options): void {
if ($options === null) return;
foreach ($options as $option) {
if (substr($option, 0, 2) === "--") {
if (preg_match('/^--([^:-]+)(::?)?$/', $option, $ms)) {
$name = $ms[1];
$option = "--$name";
} else {
throw new ArgException("$option: invalid long option");
}
} elseif (substr($option, 0, 1) === "-") {
if (preg_match('/^-([^:-])(::?)?$/', $option, $ms)) {
$name = $ms[1];
$option = "-$name";
} else {
throw new ArgException("$option: invalid short option");
}
} else {
if (preg_match('/^([^:-]+)$/', $option, $ms)) {
$name = $ms[1];
$option = "$name";
} else {
throw new ArgException("$option: invalid command");
}
}
unset($this->options[$option]);
}
$this->updateType();
}
protected ?array $extends;
function processExtends(): void {
$extends = $this->extends;
$base = $extends["arg"] ?? null;
if ($base === null) return;
$base = new self($base);
$this->options = $base->options;
$this->removeOptions(varray::withn($extends["remove"] ?? null));
$this->addOptions(varray::withn($extends["add"] ?? null));
}
protected function updateType(): void {
$haveShortOptions = false;
$haveLongOptions = false;
$haveCommands = false;
foreach ($this->options as $option) {
switch ($option["type"]) {
case self::TYPE_SHORT:
$haveShortOptions = true;
break;
case self::TYPE_LONG:
$haveLongOptions = true;
break;
case self::TYPE_COMMAND:
$haveCommands = true;
break;
}
}
$this->haveShortOptions = $haveShortOptions;
$this->haveLongOptions = $haveLongOptions;
$this->haveCommands = $haveCommands;
}
protected ?array $_args = null;
protected function updateArgs(): void {
if ($this->_args === null) {
$haveArgs = false;
$optionalArgs = null;
foreach ($this->options as $option) {
switch ($option["args_type"]) {
case self::ARGS_NONE:
break;
case self::ARGS_MANDATORY:
$haveArgs = true;
$optionalArgs = false;
break;
case self::ARGS_OPTIONAL:
$haveArgs = true;
$optionalArgs ??= true;
break;
}
}
$optionalArgs ??= false;
if ($haveArgs) {
$args = ["value"];
if ($optionalArgs) $args = [$args];
}
}
#XXX calculer minArgs, maxArgs, argsdesc
$this->haveArgs = $haveArgs;
$this->_args = $args;
$this->argsdesc = $argsdesc;
}
}

369
src/app/cli/ArgDef.php Normal file
View File

@ -0,0 +1,369 @@
<?php
namespace nulib\app\cli;
use nulib\A;
use nulib\cl;
use nulib\php\func;
use nulib\php\types\varray;
class ArgDef {
const TYPE_SHORT = 0, TYPE_LONG = 1, TYPE_COMMAND = 2;
const ARGS_NONE = 0, ARGS_MANDATORY = 1, ARGS_OPTIONAL = 2;
const ACTION_SET = 0, ACTION_INC = 1, ACTION_DEC = 2, ACTION_FUNC = 3;
function __construct(array $def) {
[$options, $params] = cl::split_assoc($def);
$args = $params["args"] ?? null;
$args ??= $params["arg"] ?? null;
if ($args === true) $args = 1;
if (is_int($args)) $args = array_fill(0, $args, "value");
$this->args = cl::withn($args);
$this->argsdesc = $params["argsdesc"] ?? null;
$extends = $params["extends"] ?? null;
if ($extends !== null) {
A::merge($extends["add"], $options);
$this->extends = $extends;
} else {
$this->addOptions($options);
}
$this->ensureArray = $params["ensure_array"] ?? null;
$action = $params["action"] ?? null;
$func = null;
if ($action !== null) {
switch ($action) {
case "--set":
$action = self::ACTION_SET;
break;
case "--inc":
$action = self::ACTION_INC;
break;
case "--dec":
$action = self::ACTION_DEC;
break;
default:
$func = func::with($action);
$action = self::ACTION_FUNC;
break;
}
}
$this->action = $action;
$this->func = $func;
$this->inverse = $params["inverse"] ?? false;
$this->value = $params["value"] ?? null;
$this->name = $params["name"] ?? null;
$this->property = $params["property"] ?? null;
$this->key = $params["key"] ?? null;
$this->help = $params["help"] ?? null;
}
protected ?array $options = [];
function getOptions(): array {
return array_keys($this->options);
}
public bool $isRemains = false;
public bool $haveShortOptions = false;
public bool $haveLongOptions = false;
public bool $haveCommands = false;
public bool $haveArgs = false;
public ?int $minArgs = null;
public ?int $maxArgs = null;
public ?string $argsdesc = null;
function addOptions(?array $options): void {
if ($options === null) return;
foreach ($options as $option) {
if (substr($option, 0, 2) === "--") {
$type = self::TYPE_LONG;
if (preg_match('/^--([^:-]+)(::?)?$/', $option, $ms)) {
$name = $ms[1];
$args = $ms[2] ?? null;
$option = "--$name";
} else {
throw new ArgException("$option: invalid long option");
}
} elseif (substr($option, 0, 1) === "-") {
$type = self::TYPE_SHORT;
if (preg_match('/^-([^:-])(::?)?$/', $option, $ms)) {
$name = $ms[1];
$args = $ms[2] ?? null;
$option = "-$name";
} else {
throw new ArgException("$option: invalid short option");
}
} else {
$type = self::TYPE_COMMAND;
if (preg_match('/^([^:-]+)$/', $option, $ms)) {
$name = $ms[1];
$args = null;
$option = "$name";
} else {
throw new ArgException("$option: invalid command");
}
}
if ($args === ":") {
$argsType = self::ARGS_MANDATORY;
} elseif ($args === "::") {
$argsType = self::ARGS_OPTIONAL;
} else {
$argsType = self::ARGS_NONE;
}
$this->options[$option] = [
"name" => $name,
"option" => $option,
"type" => $type,
"args_type" => $argsType,
];
}
$this->updateType();
}
function removeOptions(?array $options): void {
if ($options === null) return;
foreach ($options as $option) {
if (substr($option, 0, 2) === "--") {
if (preg_match('/^--([^:-]+)(::?)?$/', $option, $ms)) {
$name = $ms[1];
$option = "--$name";
} else {
throw new ArgException("$option: invalid long option");
}
} elseif (substr($option, 0, 1) === "-") {
if (preg_match('/^-([^:-])(::?)?$/', $option, $ms)) {
$name = $ms[1];
$option = "-$name";
} else {
throw new ArgException("$option: invalid short option");
}
} else {
if (preg_match('/^([^:-]+)$/', $option, $ms)) {
$name = $ms[1];
$option = "$name";
} else {
throw new ArgException("$option: invalid command");
}
}
unset($this->options[$option]);
}
$this->updateType();
}
function removeOption(string $option): void {
unset($this->options[$option]);
}
protected ?array $extends = null;
/** traiter le paramètre extends */
function processExtends(): void {
$extends = $this->extends;
if ($extends === null) return;
$base = $extends["arg"] ?? null;
if ($base === null) return;
$base = new self($base);
$this->options = $base->options;
$this->removeOptions(varray::withn($extends["remove"] ?? null));
$this->addOptions(varray::withn($extends["add"] ?? null));
}
/** mettre à jour le type d'option */
protected function updateType(): void {
$haveShortOptions = false;
$haveLongOptions = false;
$haveCommands = false;
$isRemains = true;
foreach ($this->options as $option) {
$isRemains = false;
switch ($option["type"]) {
case self::TYPE_SHORT:
$haveShortOptions = true;
break;
case self::TYPE_LONG:
$haveLongOptions = true;
break;
case self::TYPE_COMMAND:
$haveCommands = true;
break;
}
}
$this->isRemains = $isRemains;
$this->haveShortOptions = $haveShortOptions;
$this->haveLongOptions = $haveLongOptions;
$this->haveCommands = $haveCommands;
}
protected ?array $args = null;
/**
* traiter les informations concernant les arguments puis calculer les nombres
* minimum et maximum d'arguments que prend l'option
*/
function processArgs(): void {
$args = $this->args;
if ($args === null) {
$haveArgs = false;
$optionalArgs = null;
foreach ($this->options as $option) {
switch ($option["args_type"]) {
case self::ARGS_NONE:
break;
case self::ARGS_MANDATORY:
$haveArgs = true;
$optionalArgs = false;
break;
case self::ARGS_OPTIONAL:
$haveArgs = true;
$optionalArgs ??= true;
break;
}
}
$optionalArgs ??= false;
if ($haveArgs) {
$args = ["value"];
if ($optionalArgs) $args = [$args];
}
}
if ($this->isRemains) $desc = "remaining args";
else $desc = cl::first($this->options)["option"];
$args ??= [];
$argsdesc = [];
$nbArgs = 0;
$reqs = [];
$haveNull = false;
$optArgs = null;
foreach ($args as $arg) {
$nbArgs++;
if (is_string($arg)) {
$reqs[] = $arg;
$argsdesc[] = strtoupper($arg);
} elseif (is_array($arg)) {
$optArgs = $arg;
break;
} elseif ($arg === null) {
$haveNull = true;
break;
} else {
throw new ArgException("$desc: $arg: invalid option arg");
}
}
if ($nbArgs !== count($args)) {
throw new ArgException("$desc: invalid args format");
}
$opts = [];
$optArgsdesc = null;
$lastarg = "VALUE";
if ($optArgs !== null) {
$haveOpt = false;
$nbArgs = 0;
foreach ($optArgs as $arg) {
$nbArgs++;
if (is_string($arg)) {
$haveOpt = true;
$opts[] = $arg;
$lastarg = strtoupper($arg);
$optArgsdesc[] = $lastarg;
} elseif ($arg === null) {
$haveNull = true;
break;
} else {
throw new ArgException("$desc: $arg: invalid option arg");
}
}
if ($nbArgs !== count($args)) {
throw new ArgException("$desc: invalid args format");
}
if (!$haveOpt) $haveNull = true;
}
if ($haveNull) $optArgsdesc[] = "${lastarg}s...";
if ($optArgsdesc !== null) {
$argsdesc[] = "[".implode(" ", $optArgsdesc)."]";
}
$minArgs = count($reqs);
if ($haveNull) $maxArgs = PHP_INT_MAX;
else $maxArgs = $minArgs + count($opts);
$this->haveArgs = $haveArgs;
$this->minArgs = $minArgs;
$this->maxArgs = $maxArgs;
$this->argsdesc = implode(" ", $argsdesc);
}
protected ?bool $ensureArray = null;
protected ?int $action = null;
protected ?func $func = null;
protected bool $inverse = false;
protected $value = null;
protected ?string $name = null;
protected ?string $property = null;
protected ?string $key = null;
private static function get_longest(array $options, int $type): ?string {
$longest = null;
$maxlen = 0;
foreach ($options as $option) {
if ($option["type"] !== $type) continue;
$name = $option["name"];
$len = strlen($name);
if ($len > $maxlen) {
$longest = $name;
$maxlen = $len;
}
}
return $longest;
}
function processAction(): void {
$this->ensureArray ??= $this->isRemains || $this->maxArgs > 1;
$action = $this->action;
if ($action === null) {
if ($this->haveArgs) {
$action = self::ACTION_SET;
} elseif ($this->value !== null) {
$action = self::ACTION_SET;
} elseif ($this->inverse) {
$action = self::ACTION_DEC;
} else {
$action = self::ACTION_INC;
}
$this->action = $action;
}
$name = $this->name;
$property = $this->property;
$key = $this->key;
if ($action !== self::ACTION_FUNC && !$this->isRemains &&
$name === null && $property === null && $key === null
) {
# si on ne précise pas le nom de la propriété, la dériver à partir du
# nom de l'option la plus longue
$longest = self::get_longest($this->options, self::TYPE_LONG);
$longest ??= self::get_longest($this->options, self::TYPE_COMMAND);
$longest ??= self::get_longest($this->options, self::TYPE_SHORT);
if ($longest !== null) {
$longest = preg_replace('/[^A-Za-z0-9]+/', "_", $longest);
if (preg_match('/^[0-9]/', $longest)) {
# le nom de la propriété ne doit pas commencer par un chiffre
$longest = "p$longest";
}
$name = $longest;
}
} elseif ($name === null && $property !== null) {
$name = $property;
} elseif ($name === null && $key !== null) {
$name = $key;
}
$this->name = $name;
}
}

245
src/app/cli/ArgDefs.php Normal file
View File

@ -0,0 +1,245 @@
<?php
namespace nulib\app\cli;
use nulib\cl;
class ArgDefs {
function __construct(array $defs) {
[$defs, $params] = cl::split_assoc($defs);
$argDefs = [];
foreach ($defs as $def) {
$argDefs[] = new ArgDef($def);
}
foreach ($argDefs as $argDef) {
$argDef->processExtends();
}
$index = [];
foreach ($argDefs as $argDef) {
$options = $argDef->getOptions();
foreach ($options as $option) {
if (array_key_exists($option, $index)) {
$index[$option]->removeOption($option);
}
$index[$option] = $argDef;
}
}
foreach ($argDefs as $argDef) {
$argDef->processArgs();
$argDef->processAction();
}
$this->argDefs = $argDefs;
$this->index = $index;
}
protected array $argDefs;
protected array $index;
function getArgDef(string $option): ?ArgDef {
return $this->index[$option] ?? null;
}
/**
* consommer les arguments de $src en avançant l'index $srci et provisionner
* $dest à partir de $desti. si $desti est plus grand que 0, celà veut dire
* que $dest a déjà commencé à être provisionné, et qu'il faut continuer.
*
* $destmin est le nombre minimum d'arguments à consommer. $destmax est le
* nombre maximum d'arguments à consommer.
*
* $srci est la position de l'élément courant à consommer le cas échéant
* retourner le nombre d'arguments qui manquent (ou 0 si tous les arguments
* ont été consommés)
*
* pour les arguments optionnels, ils sont consommés tant qu'il y en a de
* disponible, ou jusqu'à la présence de '--'. Si $keepsep, l'argument '--'
* est gardé dans la liste des arguments optionnels.
*/
private static function consume_args($src, &$srci, &$dest, $desti, $destmin, $destmax, bool $keepsep): int {
$srcmax = count($src);
# arguments obligatoires
while ($desti < $destmin) {
if ($srci < $srcmax) {
$dest[] = $src[$srci];
} else {
# pas assez d'arguments
return $destmin - $desti;
}
$srci++;
$desti++;
}
# arguments facultatifs
while ($desti < $destmax && $srci < $srcmax) {
$opt = $src[$srci];
if ($opt === "--") {
# fin des options facultatives
if ($keepsep) $dest[] = $opt;
$srci++;
break;
}
$dest[] = $opt;
$srci++;
$desti++;
}
return 0;
}
private static function check_missing(?string $option, int $count) {
if ($count > 0) {
throw new ArgException("$option: nombre d'arguments insuffisant (manque $count)");
}
}
function normalize(array $args): array {
$i = 0;
$max = count($args);
$options = [];
$remains = [];
$parseOpts = true;
while ($i < $max) {
$arg = $args[$i++];
if (!$parseOpts) {
# le reste n'est que des arguments
$remains[] = $arg;
continue;
}
if ($arg === "--") {
# fin des options
$parseOpts = false;
continue;
}
if (substr($arg, 0, 2) === "--") {
#######################################################################
# option longue
$pos = strpos($arg, "=");
if ($pos !== false) {
# option avec valeur
$option = substr($arg, 0, $pos);
$value = substr($arg, $pos + 1);
} else {
# option sans valeur
$option = $arg;
$value = null;
}
/** @var ArgDef $argDef */
$argDef = $this->index[$option] ?? null;
if ($argDef === null) {
# chercher une correspondance
$len = strlen($option);
$candidates = [];
foreach (array_keys($this->index) as $candidate) {
if (substr($candidate, 0, $len) === $option) {
$candidates[] = $candidate;
}
}
switch (count($candidates)) {
case 0:
throw new ArgException("$option: option invalide");
case 1:
$option = $candidates[0];
break;
default:
$candidates = implode(", ", $candidates);
throw new ArgException("$option: option ambigue (les options possibles sont $candidates)");
}
$argDef = $this->index[$option];
}
if ($argDef->haveArgs) {
$minArgs = $argDef->minArgs;
$maxArgs = $argDef->maxArgs;
$values = [];
if ($value !== null) {
$values[] = $value;
$offset = 1;
} elseif ($minArgs == 0) {
# cas particulier: la première valeur doit être collée à l'option
# si $maxArgs == 1
$offset = $maxArgs == 1 ? 1 : 0;
} else {
$offset = 0;
}
$this->check_missing($option,
self::consume_args($args, $i, $values, $offset, $minArgs, $maxArgs, true));
if ($minArgs == 0 && $maxArgs == 1) {
# cas particulier: la première valeur doit être collée à l'option
if (count($values) > 0) {
$options[] = "$option=$values[0]";
$values = array_slice($values, 1);
} else {
$options[] = $option;
}
} else {
$options[] = $option;
}
$options = array_merge($options, $values);
} elseif ($value !== null) {
throw new ArgException("$option: cette option ne prend pas d'arguments");
} else {
$options[] = $option;
}
} elseif (substr($arg, 0, 1) === "-") {
#######################################################################
# option courte
$pos = 1;
$len = strlen($arg);
while ($pos < $len) {
$option = "-".substr($arg, $pos, 1);
/** @var ArgDef $argDef */
$argDef = $this->index[$option] ?? null;
if ($argDef === null) {
throw new ArgException("$option: option invalide");
}
if ($argDef->haveArgs) {
$minArgs = $argDef->minArgs;
$maxArgs = $argDef->maxArgs;
$values = [];
if ($len > $pos + 1) {
$values[] = substr($arg, $pos + 1);
$offset = 1;
$pos = $len;
} elseif ($minArgs == 0) {
# cas particulier: la première valeur doit être collée à l'option
# si $maxArgs == 1
$offset = $maxArgs == 1 ? 1 : 0;
} else {
$offset = 0;
}
$this->check_missing($option,
self::consume_args($args, $i, $values, $offset, $minArgs, $maxArgs, true));
if ($minArgs == 0 && $maxArgs == 1) {
# cas particulier: la première valeur doit être collée à l'option
if (count($values) > 0) {
$options[] = "$option$values[0]";
$values = array_slice($values, 1);
} else {
$options[] = $option;
}
} else {
$options[] = $option;
}
$options = array_merge($options, $values);
} else {
$options[] = $option;
}
$pos++;
}
} else {
#XXX implémenter les commandes
#######################################################################
# argument
$remains[] = $arg;
}
}
return array_merge($options, ["--"], $remains);
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace nulib\app\cli;
use nur\t\TestCase;
class ArgDefTest extends TestCase {
protected static function assertArg(
ArgDef $argDef,
array $options,
bool $haveShortOptions, bool $haveLongOptions, bool $haveCommands,
bool $haveArgs, ?int $minArgs, ?int $maxArgs, ?string $argsdesc
) {
$argDef->processExtends();
$argDef->processArgs();
$argDef->processAction();
self::assertSame($options, $argDef->getOptions());
self::assertSame($haveShortOptions, $argDef->haveShortOptions, "haveShortOptions");
self::assertSame($haveLongOptions, $argDef->haveLongOptions, "haveLongOptions");
self::assertSame($haveCommands, $argDef->haveCommands, "haveCommands");
self::assertSame($haveArgs, $argDef->haveArgs, "haveArgs");
self::assertSame($minArgs, $argDef->minArgs, "minArgs");
self::assertSame($maxArgs, $argDef->maxArgs, "maxArgs");
self::assertSame($argsdesc, $argDef->argsdesc, "argsdesc");
}
function testBase() {
$argDef = new ArgDef(["-o", "--longo"]);
self::assertArg($argDef,
["-o", "--longo"],
true, true, false,
false, 0, 0, "");
$argDef = new ArgDef(["-o:", "--longo"]);
self::assertArg($argDef,
["-o", "--longo"],
true, true, false,
true, 1, 1, "VALUE");
$argDef = new ArgDef(["-o::", "--longo"]);
self::assertArg($argDef,
["-o", "--longo"],
true, true, false,
true, 0, 1, "[VALUE]");
$argDef = new ArgDef(["-o:", "--longo:"]);
self::assertArg($argDef,
["-o", "--longo"],
true, true, false,
true, 1, 1, "VALUE");
$argDef = new ArgDef(["-o:", "--longo::"]);
self::assertArg($argDef,
["-o", "--longo"],
true, true, false,
true, 1, 1, "VALUE");
}
function testExtends() {
$argDef = [
"extends" => [
"arg" => ["-o:", "--longo"],
"add" => ["-a", "--longa"],
"remove" => ["-o", "--longo"],
],
];
$arg = new ArgDef($argDef);
self::assertArg($arg,
["-a", "--longa"],
true, true, false,
false, 0, 0, "");
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace nulib\app\cli;
use nur\t\TestCase;
class ArgDefsTest extends TestCase {
function testBase() {
$argDefs = new ArgDefs([
["-a"],
["--longb"],
["-c", "--longc"],
["-m:", "--mandatory"],
["-o::", "--optional"],
["-x", "--x1"],
["-x", "--x2"],
]);
self::assertSame(["--"]
, $argDefs->normalize([]));
self::assertSame(["--", "a", "b"]
, $argDefs->normalize(["a", "b"]));
self::assertSame(["-a", "--mandatory", "x", "--mandatory", "y", "--", "z", "x"]
, $argDefs->normalize(["-a", "--m", "x", "z", "--m=y", "x"]));
self::assertSame(["-m", "x", "-m", "y", "--"]
, $argDefs->normalize(["-mx", "-m", "y"]));
self::assertSame(["-ox", "-o", "--", "y"]
, $argDefs->normalize(["-ox", "-o", "y"]));
self::assertSame(["-a", "--", "-a", "-c"]
, $argDefs->normalize(["-a", "--", "-a", "-c"]));
}
}

View File

@ -1,48 +0,0 @@
<?php
namespace nulib\app\cli;
use nur\t\TestCase;
class ArgTest extends TestCase {
function testBase() {
$arg = new Arg(["-o", "--longo"]);
self::assertSame(["-o", "--longo"], $arg->getOptions());
self::assertFalse($arg->haveArgs);
self::assertFalse($arg->optionalArgs);
$arg = new Arg(["-o:", "--longo"]);
self::assertSame(["-o", "--longo"], $arg->getOptions());
self::assertTrue($arg->haveArgs);
self::assertFalse($arg->optionalArgs);
$arg = new Arg(["-o::", "--longo"]);
self::assertSame(["-o", "--longo"], $arg->getOptions());
self::assertTrue($arg->haveArgs);
self::assertTrue($arg->optionalArgs);
$arg = new Arg(["-o:", "--longo:"]);
self::assertSame(["-o", "--longo"], $arg->getOptions());
self::assertTrue($arg->haveArgs);
self::assertFalse($arg->optionalArgs);
$arg = new Arg(["-o:", "--longo::"]);
self::assertSame(["-o", "--longo"], $arg->getOptions());
self::assertTrue($arg->haveArgs);
self::assertFalse($arg->optionalArgs);
}
function testExtends() {
$basedef = ["-o:", "--longo"];
$def = [
"extends" => [
"arg" => $basedef,
"add" => ["-a", "--longa"],
"remove" => ["-o", "--longo"],
],
];
$arg = new Arg($def);
self::assertSame(["-a", "--longa"], $arg->getOptions());
self::assertFalse($arg->haveArgs);
self::assertFalse($arg->optionalArgs);
}
}