From 7351f90e28ec7098cf2ee92783b851ad8b5efcc0 Mon Sep 17 00:00:00 2001 From: darkelfe14728 Date: Sun, 3 Oct 2021 19:52:43 +0200 Subject: [PATCH] V2 --- composer.json | 3 +- src/CommandLine/Argument/AbstractArgument.php | 114 +++++++++++ .../Argument/AbstractArgumentList.php | 23 +++ src/CommandLine/Argument/ArgumentAbstract.php | 126 ------------ src/CommandLine/Argument/IArgument.php | 39 +--- .../Argument/IArgumentValueDescription.php | 12 +- .../Option/AbstractOptionArgument.php | 101 ++++++++++ src/CommandLine/Argument/Option/Flag.php | 51 ++--- .../Argument/Option/FlagWithReverse.php | 55 ----- .../Argument/Option/IArgumentOption.php | 46 ----- .../Option/IArgumentOptionSecondary.php | 19 -- .../Argument/Option/IOptionArgument.php | 23 +++ .../Argument/Option/OptionAbstract.php | 188 ------------------ .../Argument/Option/OptionArgumentList.php | 20 ++ src/CommandLine/Argument/Option/Value.php | 165 ++++++++++----- src/CommandLine/Argument/ParseResult.php | 80 -------- .../Argument/Parser/BooleanParser.php | 2 +- .../Argument/Parser/DecimalParser.php | 2 +- .../Argument/Parser/EnumParser.php | 2 +- .../Parser/{IValueParser.php => IParser.php} | 4 +- .../Argument/Parser/IntegerParser.php | 2 +- .../Argument/Parser/PathParser.php | 2 +- .../Argument/Parser/RegexParser.php | 2 +- .../Argument/Parser/StringParser.php | 2 +- .../Argument/Value/AbstractValueArgument.php | 117 +++++++++++ src/CommandLine/Argument/Value/FixedValue.php | 77 ------- .../Argument/Value/IArgumentValue.php | 31 --- .../Argument/Value/IValueArgument.php | 23 +++ src/CommandLine/Argument/Value/Value.php | 71 +++---- .../Argument/Value/ValueAbstract.php | 127 ------------ .../Argument/Value/ValueArgumentList.php | 20 ++ src/CommandLine/ArrayClass.php | 130 ++++++++++++ src/CommandLine/CommandLine.php | 147 ++++++-------- src/CommandLine/ReturnCode/IReturnCode.php | 21 ++ src/CommandLine/ReturnCode/ReturnCode.php | 64 ++++++ src/CommandLine/ReturnCode/ReturnCodeList.php | 35 ++++ 36 files changed, 939 insertions(+), 1007 deletions(-) create mode 100644 src/CommandLine/Argument/AbstractArgument.php create mode 100644 src/CommandLine/Argument/AbstractArgumentList.php delete mode 100644 src/CommandLine/Argument/ArgumentAbstract.php create mode 100644 src/CommandLine/Argument/Option/AbstractOptionArgument.php delete mode 100644 src/CommandLine/Argument/Option/FlagWithReverse.php delete mode 100644 src/CommandLine/Argument/Option/IArgumentOption.php delete mode 100644 src/CommandLine/Argument/Option/IArgumentOptionSecondary.php create mode 100644 src/CommandLine/Argument/Option/IOptionArgument.php delete mode 100644 src/CommandLine/Argument/Option/OptionAbstract.php create mode 100644 src/CommandLine/Argument/Option/OptionArgumentList.php delete mode 100644 src/CommandLine/Argument/ParseResult.php rename src/CommandLine/Argument/Parser/{IValueParser.php => IParser.php} (85%) create mode 100644 src/CommandLine/Argument/Value/AbstractValueArgument.php delete mode 100644 src/CommandLine/Argument/Value/FixedValue.php delete mode 100644 src/CommandLine/Argument/Value/IArgumentValue.php create mode 100644 src/CommandLine/Argument/Value/IValueArgument.php delete mode 100644 src/CommandLine/Argument/Value/ValueAbstract.php create mode 100644 src/CommandLine/Argument/Value/ValueArgumentList.php create mode 100644 src/CommandLine/ArrayClass.php create mode 100644 src/CommandLine/ReturnCode/IReturnCode.php create mode 100644 src/CommandLine/ReturnCode/ReturnCode.php create mode 100644 src/CommandLine/ReturnCode/ReturnCodeList.php diff --git a/composer.json b/composer.json index e3fb5be..482e062 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,8 @@ "minimum-stability": "dev", "require": { - "php": ">= 7.4" + "php": ">= 7.4", + "ext-reflection": "*" }, "autoload": { "psr-4": { diff --git a/src/CommandLine/Argument/AbstractArgument.php b/src/CommandLine/Argument/AbstractArgument.php new file mode 100644 index 0000000..cf0a883 --- /dev/null +++ b/src/CommandLine/Argument/AbstractArgument.php @@ -0,0 +1,114 @@ +setVarName($this->getName()); + $this->setDefault(); + + $this->setName($name); + $this->setDescription($description); + } + + /** + * @inheritDoc + */ + public function getVarName (): string { + return $this->varName; + } + /** + * Set the variable name in parse output + * + * @param string $varName The variable name + * + * @return $this + */ + public function setVarName (string $varName): self { + $this->varName = $varName; + return $this; + } + + /** + * @inheritDoc + */ + public function getDefault () { + return $this->_default; + } + /** + * Set the default value for the argument. Null if none + * + * @param mixed $default The default value + * + * @return $this + */ + public function setDefault ($default = null): self { + $this->_default = $default; + return $this; + } + + /** + * @inheritDoc + */ + public function getName (): string { + return $this->name; + } + /** + * Set the argument name in help + * + * @param string $name The argument name in help + * + * @return $this + */ + public function setName (string $name): self { + $this->name = $name; + return $this; + } + + /** + * @inheritDoc + */ + public function getDescription (): ?string { + return $this->description; + } + /** + * Set the argument description in help + * + * @param string|null $description The argument description + * + * @return $this + */ + public function setDescription (?string $description): self { + $this->description = $description; + return $this; + } +} \ No newline at end of file diff --git a/src/CommandLine/Argument/AbstractArgumentList.php b/src/CommandLine/Argument/AbstractArgumentList.php new file mode 100644 index 0000000..70eb280 --- /dev/null +++ b/src/CommandLine/Argument/AbstractArgumentList.php @@ -0,0 +1,23 @@ + + */ +abstract class AbstractArgumentList extends ArrayClass { + /** + * Get the key of an element. Null if auto-generated + * + * @param IArgument $element The element + * + * @return int The key or Null + */ + protected function getKeyForElement ($element): int { + return $element->getVarName(); + } +} \ No newline at end of file diff --git a/src/CommandLine/Argument/ArgumentAbstract.php b/src/CommandLine/Argument/ArgumentAbstract.php deleted file mode 100644 index 3c85b35..0000000 --- a/src/CommandLine/Argument/ArgumentAbstract.php +++ /dev/null @@ -1,126 +0,0 @@ -setName($name); - $this->setDescription($description); - } - - /** - * @inheritDoc - */ - public function getVarName (): string { - return $this->varName; - } - /** - * Définit le nom de la variable de retour de l'argument. - * - * @param string $varName Le nom - * - * @return $this - * - * @see $name - */ - public function setVarName (string $varName): self { - $this->varName = $varName; - return $this; - } - - /** - * @inheritDoc - */ - public function getName (): string { - return $this->name; - } - /** - * Définit le nom de l'argument. - * - * @param string $name Le nom - * @param boolean $replaceVarName Remplacer également le nom de la variable de retour ? - * - * @return $this - * - * @see $name - */ - public function setName (string $name, bool $replaceVarName = true): self { - $this->name = $name; - if ($replaceVarName) { - $this->setVarName($name); - } - return $this; - } - - /** - * @inheritDoc - */ - public function getDescription (): ?string { - return $this->description; - } - /** - * Définit la description de l'argument. - * - * @param string|null $description La description - * - * @return $this - * - * @see $description - */ - public function setDescription (?string $description): self { - $this->description = $description; - return $this; - } - - /** - * @inheritDoc - */ - public function getDefault () { - return $this->_default; - } - /** - * Définit le valeur par défaut - * - * @param mixed|null $default La valeur par défaut. - * - * @return $this - * - * @see $_default - */ - public function setDefault ($default = null): self { - $this->_default = $default; - return $this; - } -} \ No newline at end of file diff --git a/src/CommandLine/Argument/IArgument.php b/src/CommandLine/Argument/IArgument.php index f803302..513f6b5 100644 --- a/src/CommandLine/Argument/IArgument.php +++ b/src/CommandLine/Argument/IArgument.php @@ -1,50 +1,33 @@ $name (see {@see AbstractOptionArgument::convertNameToTagLong()} + * @param string|null $tagShort the short tag + */ + public function __construct (string $name, ?string $description, ?string $tagLong = null, ?string $tagShort = null) { + parent::__construct($name, $description); + + $this->setTagLong($tagLong ?? static::convertNameToTagLong($name)); + $this->setTagShort($tagShort); + } + + /** + * Convert a variable name to a long tag + * + * Performs the following tasks : + * 1. The underscores are replaced by a caret + * 2. The upper case letters are replaced by a caret followed with the lower case letter + * + * @param string $name The name to convert + * + * @return string The corresponding long tag + */ + public static function convertNameToTagLong (string $name): string { + return preg_replace_callback( + '/[A-Z_]/', + function ($matches) { + return '-' . ($matches[0] === '_' ? '' : '' . mb_strtolower($matches[0])); + }, + $name + ); + } + + /** + * @inheritDoc + */ + public function getTagShort (): ?string { + return $this->tagShort; + } + /** + * Set the short tag. Null if none + * + * @param string|null $tagShort The short tag + * + * @return $this + */ + public function setTagShort (string $tagShort = null): self { + $this->tagShort = $tagShort; + return $this; + } + /** + * Is a short tag defined ? + * + * @return boolean True if a short tag is defined, else False + */ + public function hasTagShort (): bool { + return $this->getTagShort() !== null; + } + + /** + * @inheritDoc + */ + public function getTagLong (): string { + return $this->tagLong; + } + /** + * Set the long tag + * + * @param string $tagLong The long tag + * + * @return $this + */ + public function setTagLong (string $tagLong): self { + $this->tagLong = $tagLong; + return $this; + } +} \ No newline at end of file diff --git a/src/CommandLine/Argument/Option/Flag.php b/src/CommandLine/Argument/Option/Flag.php index adeb4df..7dcdb60 100644 --- a/src/CommandLine/Argument/Option/Flag.php +++ b/src/CommandLine/Argument/Option/Flag.php @@ -1,58 +1,43 @@ $name (see {@see AbstractOptionArgument::convertNameToTagLong()} + * @param string|null $tagShort The short tag */ - public function __construct (string $name, bool $default, ?string $description, ?string $tagLong = null, ?string $tagShort = null) { + public function __construct (string $name, ?string $description, bool $default, ?string $tagLong = null, ?string $tagShort = null) { parent::__construct($name, $description, $tagLong, $tagShort); $this->setDefault($default); } /** - * @inheritDoc - */ - public function parse (array $args): ?ParseResult { - if ($this->_parseTag($args[0])) { - return new ParseResult(true, 1); - } - - return null; - } - - /** - * Définit la valeur par défaut + * Set default value for the argument * - * @param boolean $default La valeur par défaut. + * @param boolean $default The default value for the argument (boolean) * * @return $this + * + * @throws InvalidArgumentException If the default value provided is not valid (boolean) */ - public function setDefault ($default = null): self { + public function setDefault ($default = false): self { if (!is_bool($default)) { - throw new InvalidArgumentException('La valeur par défaut DOIT être un booléen'); + throw new InvalidArgumentException('The default value must be a boolean'); } parent::setDefault($default); diff --git a/src/CommandLine/Argument/Option/FlagWithReverse.php b/src/CommandLine/Argument/Option/FlagWithReverse.php deleted file mode 100644 index fc496a2..0000000 --- a/src/CommandLine/Argument/Option/FlagWithReverse.php +++ /dev/null @@ -1,55 +0,0 @@ -hasTagShort()) { - if (substr($this->getTagShort(), 0, 1) == 'n') { - $tagShort = substr($this->getTagShort(), 1); - } - else { - $tagShort = 'n' . $this->getTagShort(); - } - } - - if (substr($this->getTagLong(), 0, 3) == 'no-') { - $tagLong = substr($this->getTagLong(), 3); - } - else { - $tagLong = 'no-' . $this->getTagLong(); - } - - $name = $this->getName(); - if (substr($name, 0, 3) == 'no') { - $name = strtolower(substr($name, 2, 1)) . substr($name, 3); - } - else { - $name = 'no' . strtoupper(substr($name, 0, 1)) . substr($name, 1); - } - - $description = '[INVERSE] ' . $this->getDescription(); - - $reverse = new Flag($name, !$this->getDefault(), $description, $tagLong, $tagShort); - $reverse->setVarName($this->getVarName()); - - return array($reverse); - } -} \ No newline at end of file diff --git a/src/CommandLine/Argument/Option/IArgumentOption.php b/src/CommandLine/Argument/Option/IArgumentOption.php deleted file mode 100644 index 229aba4..0000000 --- a/src/CommandLine/Argument/Option/IArgumentOption.php +++ /dev/null @@ -1,46 +0,0 @@ -setTagLong($tagLong); - $this->setTagShort($tagShort); - } - - /** - * Est-ce la valeur correspond au tag court ou long ? - * - * Utilisé par les classes enfants pour savoir si le tag correspond. - * - * @param string $arg La valeur à examiner. - * - * @return boolean True si le tag correspond, sinon False. - */ - protected function _parseTag (string $arg): bool { - if ($this->hasTagShort()) { - if ($arg == '-' . $this->getTagShort()) { - return true; - } - } - - return $arg == '--' . $this->getTagLong(); - } - - /** - * Est-ce que la liste de valeur contient un argument de type "option" ? - * - * @param string[] $args La liste de valeurs à tester - * - * @return string|false La valeur qui une option au False si aucune correspondance - */ - public static function containsOption (array $args) { - foreach ($args as $arg) { - if (preg_match('@^--?[a-zA-Z0-9_-]+@', $arg)) { - return $arg; - } - } - - return false; - } - - public function getTagShort (): ?string { - return $this->tagShort; - } - /** - * Définit le tag court. - * - * @param string|null $tagShort Le tage court. - * - * @return $this - * - * @see $tagShort - */ - public function setTagShort (string $tagShort = null): self { - $this->tagShort = $tagShort; - return $this; - } - /** - * Est-ce que l'argument existe en forme courte ? - * - * @return boolean True si existe en forme courte, sinon False. - */ - public function hasTagShort (): bool { - return !is_null($this->tagShort); - } - - public function getTagLong (): string { - return $this->tagLong; - } - /** - * Définit le tag long. - * - * Si non fourni, est déduit du {@see $name nom de l'argument} : - * - Les "_" sont remplacés par "-" - * - Les lettres majuscules sont remplacées par "-" suivit de la lettre en minuscule - * - * @param string|null $tagLong Le tag long. - * - * @return $this - * - * @see $tagLong - */ - public function setTagLong (string $tagLong = null): self { - if (is_null($tagLong)) { - $this->tagLong = preg_replace_callback( - '/[A-Z_]/', - function ($matches) { - if ($matches[0] == '_') { - return '-'; - } - else { - return '-' . strtolower($matches[0]); - } - }, - $this->getName() - ); - } - else { - $this->tagLong = $tagLong; - } - - return $this; - } - - public function allowMultiple (): bool { - return $this->multiple; - } - /** - * Définit si l'argument est autorisé plusieurs fois ou non. - * - * @param boolean $multiple Argument autorisé plusieurs fois ? - * - * @return $this - * @see $_optional - */ - public function setMultiple (bool $multiple): self { - if (!is_bool($multiple)) { - throw new InvalidArgumentException('La multiplicité n\'est pas un booléen'); - } - - $this->multiple = $multiple; - return $this; - } - - public function isStoppingParse (): bool { - return $this->isStoppingParse; - } - /** - * Définit si l'argument met fin au parsage ou non. - * - * @param boolean $stoppingParse Met fin au parsage ? - * - * @return $this - * @see $_optional - */ - public function setStoppingParse (bool $stoppingParse): self { - if (!is_bool($stoppingParse)) { - throw new InvalidArgumentException('La stoppabilité n\'est pas un booléen'); - } - - $this->isStoppingParse = $stoppingParse; - return $this; - } -} \ No newline at end of file diff --git a/src/CommandLine/Argument/Option/OptionArgumentList.php b/src/CommandLine/Argument/Option/OptionArgumentList.php new file mode 100644 index 0000000..5937cf1 --- /dev/null +++ b/src/CommandLine/Argument/Option/OptionArgumentList.php @@ -0,0 +1,20 @@ +$name (see {@see AbstractOptionArgument::convertNameToTagLong()} + * @param string|null $tagShort The short tag */ - public function __construct (string $name, ?string $description, IValueParser $valueParser, ?string $tagLong = null, ?string $tagShort = null) { + public function __construct (string $name, ?string $description, IParser $valuesParser, ?string $tagLong = null, ?string $tagShort = null) { parent::__construct($name, $description, $tagLong, $tagShort); - $this->setValueParser($valueParser); + + $this->setValuesParser($valuesParser); + $this->setValueOccurMin(1); + $this->setValueOccurMax(1); } /** * @inheritDoc */ - public function parse (array $args): ?ParseResult { - try { - if (!$this->_parseTag($args[0])) { - return null; - } - - if (count($args) < 2 || is_null($args[1])) { - throw new IncorrectParse('La seconde valeur de l\'argument manquante'); - } + public function getValueDescription (): string { + return $this->valuesParser->getValueDescription(); + } - return new ParseResult($this->valueParser->parseValue($args[1]), 2); - } - catch (RuntimeException $e) { - throw new IncorrectParse('Échec du parsage de la valeur "' . $args[0] . '"', 0, $e); - } + /** + * The values parser + * + * @return IParser The values parser + */ + public function getValuesParser (): IParser { + return $this->valuesParser; + } + /** + * Set the values parser + * + * @param IParser $valuesParser The values parser + * + * @return $this + */ + public function setValuesParser (IParser $valuesParser): self { + $this->valuesParser = $valuesParser; + return $this; } /** - * @inheritDoc + * Is the value optional ? + * + * @return bool Is the value optional ? */ - public function getValueDescription (): string { - return $this->valueParser->getValueDescription(); + public function isValueOptional (): bool { + return $this->getValueOccurMin() === 0; + } + /** + * Set if the value is optional + * + * @param bool $optional Is the value optional ? + * + * @return $this + */ + public function setValueOptional (bool $optional): self { + $this->setValueOccurMin($optional ? 0 : 1); + return $this; } /** - * Le parseur de valeur. + * The minimum number of values * - * @return IValueParser Le parseur. + * @return int The minimum number of values + */ + public function getValueOccurMin (): int { + return $this->valueOccurMin; + } + /** + * Set the minimum number of values + * + * @param int $valueOccurMin The minimum number of values + * + * @return $this * - * @see $valueParser + * @throws InvalidArgumentException If the minimum number of values provided is not valid (strictly positive integer) + * @throws UnexpectedValueException If the minimum number of values provided is strictly greater than the maximum + */ + public function setValueOccurMin (int $valueOccurMin): self { + if (!is_numeric($valueOccurMin) || floor($valueOccurMin) != $valueOccurMin || ($valueOccurMin = (int)$valueOccurMin) < 0) { + throw new InvalidArgumentException('The minimum number of values must be a strictly positive integer'); + } + + $valueOccurMax = $this->getValueOccurMax(); + if ($valueOccurMax !== null && $valueOccurMin > $valueOccurMax) { + throw new UnexpectedValueException('The minimum number of values provided is strictly greater than the maximum'); + } + + $this->valueOccurMin = $valueOccurMin; + return $this; + } + + /** + * The maximum number of values. Null if unlimited * - * @noinspection PhpUnused + * @return int|null The maximum number of value */ - public function getValueParser (): IValueParser { - return $this->valueParser; + public function getValueOccurMax (): ?int { + return $this->valueOccurMax; } /** - * Définit le parseur de valeur + * Set the maximum number of values. Null if unlimited * - * @param IValueParser $valueParser Le parseur + * @param int|null $valueOccurMax The maximum number of values * * @return $this * - * @see $valueParser + * @throws InvalidArgumentException If the maximum number of values provided is not valid (strictly positive integer) + * @throws UnexpectedValueException If the maximum number of values provided is strictly lower than the minimum */ - public function setValueParser (IValueParser $valueParser): self { - $this->valueParser = $valueParser; + public function setValueOccurMax (?int $valueOccurMax): self { + if ($valueOccurMax !== null) { + if (!is_numeric($valueOccurMax) || floor($valueOccurMax) != $valueOccurMax || ($valueOccurMax = (int)$valueOccurMax) < 0) { + throw new InvalidArgumentException('The maximum number of values must be a strictly positive integer'); + } + + if ($valueOccurMax < $this->getValueOccurMin()) { + throw new UnexpectedValueException('The maximum number of values is strictly lower than the minimum'); + } + } + + $this->valueOccurMax = $valueOccurMax; return $this; } } \ No newline at end of file diff --git a/src/CommandLine/Argument/ParseResult.php b/src/CommandLine/Argument/ParseResult.php deleted file mode 100644 index 7e36087..0000000 --- a/src/CommandLine/Argument/ParseResult.php +++ /dev/null @@ -1,80 +0,0 @@ -setValue($value); - $this->setConsume($consume); - } - - /** - * Le nombre d'argument consumé. - * - * @return int Le nombre d'argument consumé. - * - * @see $consume - */ - public function getConsume (): int { - return $this->consume; - } - /** - * Définit le nombre d'argument consumé. - * - * @param $consume int Le nombre d'argument consumé. - * - * @return $this - * - * @see $consume - */ - public function setConsume (int $consume): self { - $this->consume = $consume; - return $this; - } - - /** - * La valeur. - * - * @return mixed La valeur. - * - * @see $value - */ - public function getValue() { - return $this->value; - } - /** - * Définit les valeurs définies. - * - * @param mixed $value La valeur. - * - * @return $this - * - * @see $value - */ - public function setValue ($value): self { - $this->value = $value; - return $this; - } -} \ No newline at end of file diff --git a/src/CommandLine/Argument/Parser/BooleanParser.php b/src/CommandLine/Argument/Parser/BooleanParser.php index 9baccaa..a1684ca 100644 --- a/src/CommandLine/Argument/Parser/BooleanParser.php +++ b/src/CommandLine/Argument/Parser/BooleanParser.php @@ -15,7 +15,7 @@ use RangeException; * * @package CommandLine\Argument\Parser */ -class BooleanParser implements IValueParser { +class BooleanParser implements IParser { /** * @inheritDoc */ diff --git a/src/CommandLine/Argument/Parser/DecimalParser.php b/src/CommandLine/Argument/Parser/DecimalParser.php index 679a63f..6f21872 100644 --- a/src/CommandLine/Argument/Parser/DecimalParser.php +++ b/src/CommandLine/Argument/Parser/DecimalParser.php @@ -14,7 +14,7 @@ use RangeException; * * @noinspection PhpUnused */ -class DecimalParser implements IValueParser { +class DecimalParser implements IParser { /** * @var double|null La valeur minimum autorisée. Null si pas de limite. */ diff --git a/src/CommandLine/Argument/Parser/EnumParser.php b/src/CommandLine/Argument/Parser/EnumParser.php index 58102be..afeb0e3 100644 --- a/src/CommandLine/Argument/Parser/EnumParser.php +++ b/src/CommandLine/Argument/Parser/EnumParser.php @@ -14,7 +14,7 @@ use RangeException; * * @noinspection PhpUnused */ -class EnumParser implements IValueParser { +class EnumParser implements IParser { /** * @var string[] Liste des valeurs autorisées */ diff --git a/src/CommandLine/Argument/Parser/IValueParser.php b/src/CommandLine/Argument/Parser/IParser.php similarity index 85% rename from src/CommandLine/Argument/Parser/IValueParser.php rename to src/CommandLine/Argument/Parser/IParser.php index e97191d..e3a7079 100644 --- a/src/CommandLine/Argument/Parser/IValueParser.php +++ b/src/CommandLine/Argument/Parser/IParser.php @@ -1,6 +1,6 @@ setOptional($optional); + $this->setDefault($default); + } + + /** + * Is the argument optional ? + * + * @return bool Is the argument optional ? + */ + public function isOptional (): bool { + return $this->getOccurMin() === 0; + } + /** + * Set if the argument is optional + * + * @param bool $optional Is the argument optional ? + * + * @return $this + */ + public function setOptional (bool $optional): self { + $this->setOccurMin($optional ? 0 : 1); + return $this; + } + + /** + * @inheritDoc + */ + public function getOccurMin (): int { + return $this->occurMin; + } + /** + * Set the minimum number of occurrence of values + * + * @param int $occurMin The minimum number of occurrence of values + * + * @return $this + * + * @throws InvalidArgumentException If the minimum number of occurrence of values provided is not valid (strictly positive integer) + * @throws UnexpectedValueException If the minimum number of occurrence of values provided is strictly greater than the maximum + */ + public function setOccurMin (int $occurMin): self { + if (!is_numeric($occurMin) || floor($occurMin) != $occurMin || ($occurMin = (int)$occurMin) < 0) { + throw new InvalidArgumentException('The minimum number of values must be a strictly positive integer'); + } + + $occurMax = $this->getOccurMax(); + if ($occurMax !== null && $occurMin > $occurMax) { + throw new UnexpectedValueException('The minimum number of values provided is strictly greater than the maximum'); + } + + $this->occurMin = $occurMin; + return $this; + } + + /** + * @inheritDoc + */ + public function getOccurMax (): ?int { + return $this->occurMax; + } + /** + * Set the maximum number of occurrence of values. Null if unlimited + * + * @param int|null $occurMax The maximum number of occurrence of values + * + * @return $this + * + * @throws InvalidArgumentException If the maximum number of occurrence of values provided is not valid (strictly positive integer) + * @throws UnexpectedValueException If the maximum number of occurrence of values provided is strictly lower than the minimum + */ + public function setOccurMax (?int $occurMax): self { + if ($occurMax !== null) { + if (!is_numeric($occurMax) || floor($occurMax) != $occurMax || ($occurMax = (int)$occurMax) < 0) { + throw new InvalidArgumentException('The maximum number of values must be a strictly positive integer'); + } + + if ($occurMax < $this->getOccurMin()) { + throw new UnexpectedValueException('The maximum number of values is strictly lower than the minimum'); + } + } + + $this->occurMax = $occurMax; + return $this; + } +} \ No newline at end of file diff --git a/src/CommandLine/Argument/Value/FixedValue.php b/src/CommandLine/Argument/Value/FixedValue.php deleted file mode 100644 index 63fcdf3..0000000 --- a/src/CommandLine/Argument/Value/FixedValue.php +++ /dev/null @@ -1,77 +0,0 @@ -setVarName($varName); - $this->setValue($value); - } - - /** - * @inheritDoc - */ - public function parse (array $args): ?ParseResult { - if ($args[0] == $this->getValue()) { - return new ParseResult($this->getValue(), 1); - } - - return null; - } - - /** - * @inheritDoc - */ - public function getValueDescription (): string { - return '"' . $this->getValue() . '"'; - } - - /** - * La valeur. - * - * @return string La valeur. - * - * @see $value - */ - public function getValue (): string { - return $this->value; - } - /** - * Définit la valeur - * - * @param string $value La valeur - * - * @return $this - * @see $value - */ - public function setValue (string $value): self { - $this->value = $value; - return $this; - } -} \ No newline at end of file diff --git a/src/CommandLine/Argument/Value/IArgumentValue.php b/src/CommandLine/Argument/Value/IArgumentValue.php deleted file mode 100644 index 33e9ce7..0000000 --- a/src/CommandLine/Argument/Value/IArgumentValue.php +++ /dev/null @@ -1,31 +0,0 @@ -setValueParser($valueParser); - } - - /** - * @inheritDoc + * By default, the {@see AbstractArgument::$varName variable name} is the same as the {@see AbstractArgument::$name argument in help} + * + * @param string $name The argument name in help + * @param string|null $description The argument name in documentation + * @param IParser $valuesParser The value parser + * @param boolean $optional Optional argument ? + * @param mixed $default The default value */ - public function parse (array $args): ?ParseResult { - try { - return new ParseResult($this->valueParser->parseValue($args[0]), 1); - } - catch (RangeException $e) { - throw new IncorrectParse('Échec du parsage de la valeur "' . $args[0] . '"', 0, $e); - } + public function __construct (string $name, ?string $description, IParser $valuesParser, bool $optional = false, $default = null) { + parent::__construct($name, $description, $optional, $default); + $this->setValuesParser($valuesParser); } /** * @inheritDoc */ public function getValueDescription (): string { - return $this->valueParser->getValueDescription(); + return $this->valuesParser->getValueDescription(); } /** - * Le parseur de valeur. + * The values parser * - * @return IValueParser Le parseur. - * - * @see $valueParser - * - * @noinspection PhpUnused + * @return IParser The values parser */ - public function getValueParser (): IValueParser { - return $this->valueParser; + public function getValuesParser (): IParser { + return $this->valuesParser; } /** - * Définit le parseur de valeur + * Set the values parser * - * @param IValueParser $valueParser Le parseur + * @param IParser $valuesParser The values parser * * @return $this - * - * @see $valueParser */ - public function setValueParser (IValueParser $valueParser): self { - $this->valueParser = $valueParser; + public function setValuesParser (IParser $valuesParser): self { + $this->valuesParser = $valuesParser; return $this; } } \ No newline at end of file diff --git a/src/CommandLine/Argument/Value/ValueAbstract.php b/src/CommandLine/Argument/Value/ValueAbstract.php deleted file mode 100644 index 756808c..0000000 --- a/src/CommandLine/Argument/Value/ValueAbstract.php +++ /dev/null @@ -1,127 +0,0 @@ -setOptional($optional); - } - - /** - * Est-ce que l'argument est facultatif ? - * - * @return bool Est-ce que l'argument est facultatif ? - * - * @noinspection PhpUnused - */ - public function isOptional (): bool { - return $this->getOccurMin() === 0; - } - /** - * Définit si l'argument est facultatif ou non. - * - * @param bool $optional Argument facultatif ? - * - * @return $this - */ - public function setOptional (bool $optional): self { - $this->setOccurMin($optional ? 0 : 1); - return $this; - } - - /** - * @inheritDoc - */ - public function getOccurMin (): int { - return $this->occurMin; - } - /** - * Définit le nombre minimum d'occurence. - * - * @param int $occurMin Le nombre minimum - * - * @return $this - * @see $occurMin - */ - public function setOccurMin (int $occurMin): self { - if (!is_numeric($occurMin)) { - throw new InvalidArgumentException('Le nombre minimum d\'ocurrence n\'est pas un entier'); - } - - if (floor($occurMin) != $occurMin) { - throw new InvalidArgumentException('Le nombre minimum d\'ocurrence n\'est pas un entier'); - } - - $int = (int)$occurMin; - if ($int < 0) { - throw new InvalidArgumentException('Le nombre minimum d\'ocurrence n\'est pas un entier positif'); - } - - $this->occurMin = $int; - return $this; - } - - /** - * @inheritDoc - */ - public function getOccurMax (): ?int { - return $this->occurMax; - } - /** - * Définit le nombre maximum d'occurence. - * - * @param int|null $occurMax Le nombre maximum. Null si illimité - * - * @return $this - * @see $occurMax - */ - public function setOccurMax (?int $occurMax): self { - if (!is_null($occurMax)) { - if (!is_numeric($occurMax)) { - throw new InvalidArgumentException('Le nombre maximum d\'ocurrence n\'est pas un entier'); - } - - if (floor($occurMax) != $occurMax) { - throw new InvalidArgumentException('Le nombre maximum d\'ocurrence n\'est pas un entier'); - } - - $occurMax = (int)$occurMax; - if ($occurMax <= 0) { - throw new InvalidArgumentException('Le nombre maximum d\'ocurrence n\'est pas un entier strictement positif'); - } - } - - $this->occurMax = $occurMax; - return $this; - } -} \ No newline at end of file diff --git a/src/CommandLine/Argument/Value/ValueArgumentList.php b/src/CommandLine/Argument/Value/ValueArgumentList.php new file mode 100644 index 0000000..b2481d7 --- /dev/null +++ b/src/CommandLine/Argument/Value/ValueArgumentList.php @@ -0,0 +1,20 @@ +setAll([]); + } + + /** + * Get all elements of the array + * + * @return T[] all elements of the array + */ + public function getAll (): array { + return $this->array; + } + /** + * Replace all elements of the array + * + * @param T[] $array The new list of elements + * + * @return $this + * + * @throws InvalidArgumentException If an element of the array is not valid + * + * @see ArrayClass::add() + */ + public function setAll (array $array): self { + self::checkArrayType($array); + + $this->array = []; + foreach ($array as $element) { + $this->add($element); + } + return $this; + } + + /** + * Add one or an array of elements + * + * @param T|T[] $elements The element(s) to add + * + * @return $this + * + * @throws InvalidArgumentException If an element of the array is not valid + */ + public function add ($elements): self { + if (!is_array($elements)) { + $elements = [$elements]; + } + $this->checkArrayType($elements); + + $realArray = []; + foreach ($elements as $element) { + $key = $this->getKeyForElement($element); + if ($key === null) { + $realArray[] = $element; + } + else { + $realArray[$key] = $element; + } + } + + $this->array = array_merge($this->array, $realArray); + return $this; + } + + /** + * Check if a element exists from his key + * + * @param int|string $elementKey The element key to check + * + * @return bool True if the element exists, else False + */ + public function exists ($elementKey): bool { + return isset($this->getAll()[$elementKey]); + } + + /** + * Check if all elements of the parameter array are valid + * + * @param T[] $array The array to check + * + * @throws InvalidArgumentException If an element of the array is not valid + * + * @see ArrayClass::$checker + */ + protected function checkArrayType (array $array): void { + foreach ($array as $arrayKey => $arrayElement) { + $this->checkArrayElementType($arrayKey, $arrayElement); + } + } + /** + * Check if the element of the array is valid + * + * @param int|string $key The key of the element + * @param T $element The element to check + * + * @throws InvalidArgumentException If the element is not valid + */ + protected function checkArrayElementType ($key, $element): void {} + + /** + * Get the key of an element. Null if auto-generated + * + * @param T $element The element + * + * @return int|string|null The key or Null + * @noinspection PhpReturnDocTypeMismatchInspection + */ + protected function getKeyForElement ($element) { + return null; + } +} \ No newline at end of file diff --git a/src/CommandLine/CommandLine.php b/src/CommandLine/CommandLine.php index a14cfda..98f857e 100644 --- a/src/CommandLine/CommandLine.php +++ b/src/CommandLine/CommandLine.php @@ -1,18 +1,15 @@ addValues(array($value)); } /** @@ -278,14 +257,14 @@ class CommandLine { * @return bool True si c'est bien un argument "value", sinon False */ public static function isValue ($argument): bool { - return $argument instanceof IArgumentValue; + return $argument instanceof IValueArgument; } /** * Vérifie que la liste d'arguments "value" est valide * - * Doit être un tableau et chaque élément doit implémenter {@see IArgumentValue} + * Doit être un tableau et chaque élément doit implémenter {@see IValueArgument} * - * @param IArgumentValue[] $values Les valeurs à vérifier + * @param IValueArgument[] $values Les valeurs à vérifier */ protected static function _checkValueList (array $values) { if (!is_array($values)) { @@ -293,7 +272,7 @@ class CommandLine { } foreach ($values as $key => $value) { if (!self::isValue($value)) { - throw new InvalidArgumentException('La valeur ' . $key . ' n\'est pas valide (n\'implémente pas IArgumentValue)'); + throw new InvalidArgumentException('La valeur ' . $key . ' n\'est pas valide (n\'implémente pas IValueArgument)'); } } } @@ -301,7 +280,7 @@ class CommandLine { /** * La liste des arguments "option" * - * @return IArgumentOption[] La liste des options + * @return IOptionArgument[] La liste des options * @see CommandLine::$argumentsOptions */ public function getOptions (): array { @@ -313,7 +292,7 @@ class CommandLine { * *Attention* : cette fonction _remplace_ la liste des options. * Pour seulement en ajouter, utiliser {@see CommandLine::addOptions()} * - * @param IArgumentOption[] $options La nouvelle liste d'options + * @param IOptionArgument[] $options La nouvelle liste d'options * * @return $this * @see CommandLine::$argumentsOptions @@ -329,13 +308,13 @@ class CommandLine { * * Pour ajouter une seule option, il est conseillé d'utiliser {@see CommandLine::addOption()} * - * @param IArgumentOption[]|IArgumentOption $options La liste d'options à ajouter + * @param IOptionArgument[]|IOptionArgument $options La liste d'options à ajouter * * @return $this * @see CommandLine::$argumentsOptions */ public function addOptions ($options): self { - if (!is_array($options) && $options instanceof IArgumentOption) { + if (!is_array($options) && $options instanceof IOptionArgument) { $options = array($options); } self::_checkOptionList($options); @@ -348,12 +327,12 @@ class CommandLine { * * Pour ajouter plusieurs options à la fois, il est conseillé d'utiliser {@see CommandLine::addOptions()} * - * @param IArgumentOption $option L'options à ajouter + * @param IOptionArgument $option L'options à ajouter * * @return $this * @see CommandLine::$argumentsOptions */ - public function addOption (IArgumentOption $option): self { + public function addOption (IOptionArgument $option): self { return $this->addOptions(array($option)); } /** @@ -380,14 +359,14 @@ class CommandLine { * @return bool True si c'est bien un argument "option", sinon False */ public static function isOption ($argument): bool { - return $argument instanceof IArgumentOption; + return $argument instanceof IOptionArgument; } /** * Vérifie que la liste d'arguments "option" est valide * - * Doit être un tableau et chaque élément doit implémenter {@see IArgumentOption} + * Doit être un tableau et chaque élément doit implémenter {@see IOptionArgument} * - * @param IArgumentOption[] $options Les options à vérifier + * @param IOptionArgument[] $options Les options à vérifier */ protected static function _checkOptionList (array $options) { if (!is_array($options)) { @@ -395,7 +374,7 @@ class CommandLine { } foreach ($options as $key => $option) { if (!self::isOption($option)) { - throw new InvalidArgumentException('L\'option ' . $key . ' n\'est pas valide (n\'implémente pas IArgumentOption)'); + throw new InvalidArgumentException('L\'option ' . $key . ' n\'est pas valide (n\'implémente pas IOptionArgument)'); } } } @@ -414,7 +393,7 @@ class CommandLine { * *Attention* : cette fonction _remplace_ la liste des arguments. * Pour seulement en ajouter, utiliser {@see CommandLine::addArguments()} * - * @param IArgumentValue[] $arguments La nouvelle liste d'arguments + * @param IValueArgument[] $arguments La nouvelle liste d'arguments * * @return $this */ @@ -434,7 +413,7 @@ class CommandLine { * @return $this */ public function addArguments ($arguments): self { - if (!is_array($arguments) && $arguments instanceof IArgumentValue) { + if (!is_array($arguments) && $arguments instanceof IValueArgument) { $arguments = array($arguments); } self::_checkValueList($arguments); @@ -460,11 +439,11 @@ class CommandLine { } if (self::isOption($argument)) { - /** @var IArgumentOption $argument */ + /** @var IOptionArgument $argument */ $this->addOption($argument); } elseif (self::isValue($argument)) { - /** @var IArgumentValue $argument */ + /** @var IValueArgument $argument */ $this->addValue($argument); } else { @@ -749,12 +728,12 @@ class CommandLine { /** * La syntax d'un argument "value" * - * @param IArgumentValue $value L'argument + * @param IValueArgument $value L'argument * * @return string La syntax de l'argument * @see generateHelp() */ - protected static function getSyntaxOfValue (IArgumentValue $value): string { + protected static function getSyntaxOfValue (IValueArgument $value): string { $syntax = ''; $min = $value->getOccurMin(); @@ -789,7 +768,7 @@ class CommandLine { /** * Génère l'aide d'une liste d'arguments "value" * - * @param IArgumentValue[] $values La liste des valeurs + * @param IValueArgument[] $values La liste des valeurs * * @return string[] L'aide de chaque valeur */ @@ -859,11 +838,11 @@ class CommandLine { $entry[] = preg_replace( '@\r?\n@', - '$0' . self::TAB . implode(self::TAB, $spaces), + '$0' . self::HELP_INDENT . implode(self::HELP_INDENT, $spaces), $value->getDescription() ); - $entries[] = self::TAB . implode(self::TAB, $entry); + $entries[] = self::HELP_INDENT . implode(self::HELP_INDENT, $entry); } return $entries; @@ -871,7 +850,7 @@ class CommandLine { /** * Génère l'aide d'une liste d'arguments "option" * - * @param IArgumentOption[] $options La liste des options + * @param IOptionArgument[] $options La liste des options * * @return string[] L'aide de chaque option */ @@ -944,11 +923,11 @@ class CommandLine { $entry[] = preg_replace( '@\r?\n@', - '$0' . self::TAB . implode(self::TAB, $spaces), + '$0' . self::HELP_INDENT . implode(self::HELP_INDENT, $spaces), $option->getDescription() ); - $entries[] = self::TAB . implode(self::TAB, $entry); + $entries[] = self::HELP_INDENT . implode(self::HELP_INDENT, $entry); } return $entries; @@ -983,11 +962,11 @@ class CommandLine { $entry[] = str_pad($code, $pads->codes, ' ', STR_PAD_RIGHT); $entry[] = preg_replace( '@\r?\n@', - '$0' . self::TAB . str_repeat(' ', $pads->codes) . self::TAB, + '$0' . self::HELP_INDENT . str_repeat(' ', $pads->codes) . self::HELP_INDENT, $description ); - $entries[] = self::TAB . implode(self::TAB, $entry); + $entries[] = self::HELP_INDENT . implode(self::HELP_INDENT, $entry); } return $entries; @@ -1065,7 +1044,7 @@ class CommandLine { return $out; } - if (($arg = OptionAbstract::containsOption($argv)) !== false) { + if (($arg = AbstractOptionArgument::containsOption($argv)) !== false) { throw new IncorrectParse('Option inconnue : ' . $arg); } @@ -1080,7 +1059,7 @@ class CommandLine { /** * @var int $ordre - * @var IArgumentValue $value + * @var IValueArgument $value */ foreach ($values as $ordre => $value) { $min = $value->getOccurMin(); @@ -1147,7 +1126,7 @@ class CommandLine { $nb = 0; /** * @var int $ordre - * @var IArgumentValue $argument + * @var IValueArgument $argument */ foreach (array_values($this->getValues()) as $ordre => $argument) { if ($ordre <= $ordre_start) { @@ -1169,7 +1148,7 @@ class CommandLine { * * @param string[] $argv La liste des arguments du script * @param stdClass $out Les valeurs de sortie - * @param IArgumentOption[] $options La liste des options + * @param IOptionArgument[] $options La liste des options * @param boolean $stop Arrêt du parsage ? * * @throws IncorrectParse Si le parsage d'une des options échoue @@ -1210,14 +1189,14 @@ class CommandLine { * * @param string[] $argv Liste des arguments du script * @param stdClass $out Les valeurs de sortie - * @param IArgumentValue $value L'argument "value" à parser + * @param IValueArgument $value L'argument "value" à parser * @param int $xTimes Le nombre de fois à parser * @param int $offset L'offset pour le n° d'occurence * * @throws MissingArgument Si l'argument n'est pas en quantité suffisante * @throws IncorrectParse Si l'argument échoue à se parser */ - protected static function _parseXTimes (array &$argv, stdClass &$out, IArgumentValue $value, int $xTimes, int $offset = 0) { + protected static function _parseXTimes (array &$argv, stdClass &$out, IValueArgument $value, int $xTimes, int $offset = 0) { if ($xTimes > count($argv)) { throw new MissingArgument('L\'argument ' . $value->getName() . ' est en quantité insuffisante (' . count($argv) . ' / ' . $xTimes . ')'); } diff --git a/src/CommandLine/ReturnCode/IReturnCode.php b/src/CommandLine/ReturnCode/IReturnCode.php new file mode 100644 index 0000000..b746a68 --- /dev/null +++ b/src/CommandLine/ReturnCode/IReturnCode.php @@ -0,0 +1,21 @@ +setCode($code); + $this->setDescription($description); + } + + /** + * @inheritDoc + */ + public function getCode (): int { + return $this->code; + } + /** + * Set the returned code + * + * @param int $code The returned code + * + * @return $this + */ + public function setCode (int $code): self { + $this->code = $code; + return $this; + } + + /** + * @inheritDoc + */ + public function getDescription (): ?string { + return $this->description; + } + /** + * Set the description of the return code + * + * @param string|null $description The description of the return code + * + * @return $this + */ + public function setDescription (?string $description): self { + $this->description = $description; + return $this; + } +} \ No newline at end of file diff --git a/src/CommandLine/ReturnCode/ReturnCodeList.php b/src/CommandLine/ReturnCode/ReturnCodeList.php new file mode 100644 index 0000000..c0f21b7 --- /dev/null +++ b/src/CommandLine/ReturnCode/ReturnCodeList.php @@ -0,0 +1,35 @@ + + */ +class ReturnCodeList extends ArrayClass { + /** + * @inheritDoc + */ + protected function checkArrayElementType ($key, $element): void { + if (!$element instanceof IReturnCode) { + throw new InvalidArgumentException('The "' . $key . '" element is not a ' . IReturnCode::class . ' instance'); + } + } + + /** + * Get the key of an element. Null if auto-generated + * + * @param IReturnCode $element The element + * + * @return int The key or Null + */ + protected function getKeyForElement ($element): int { + return $element->getCode(); + } +} \ No newline at end of file