diff --git a/src/Arguments/Argument.php b/src/Arguments/Argument.php index 4a43d7f..cf667ca 100755 --- a/src/Arguments/Argument.php +++ b/src/Arguments/Argument.php @@ -2,11 +2,7 @@ namespace RayanLevert\Cli\Arguments; -use function array_key_exists; -use function is_string; use function is_bool; -use function is_double; -use function is_int; use function gettype; use function is_numeric; use function implode; @@ -35,64 +31,35 @@ class Argument private bool $hasBeenHandled = false; /** - * Creates an argument with a name and differents options + * Creates an argument with a name and different options * - * @param array $options - * - description (string) Description of the argument - * - defaultValue (float|int|string) Default value if the argument is not handled - * - required (bool) If the argument must be present and parsed - * - castTo (string) PHP type - If the argument has a type other than string, its value will be casted - * - noValue (bool) If a prefixed argument doesn't need a value -> boolean cast - * - prefix (string) Short prefix (-u) - * - longPrefix (string) Long prefix (--user) + * @param array $options See Arguments\Option cases for more informations * - * @throws \RayanLevert\Cli\Arguments\Exception If options are incompatible or incorrectes + * @throws \RayanLevert\Cli\Arguments\Exception If options are incompatible or incorrect */ final public function __construct(protected readonly string $name, array $options = []) { - if (array_key_exists('description', $options) && is_string($options['description'])) { - $this->description = $options['description']; - } - - if (array_key_exists('required', $options) && is_bool($options['required'])) { - $this->isRequired = $options['required']; - } - - if (array_key_exists('noValue', $options) && is_bool($options['noValue'])) { - $this->noValue = $options['noValue']; - } - - if (array_key_exists('prefix', $options) && is_string($options['prefix'])) { - $this->prefix = $options['prefix']; - } + foreach ($options as $name => $value) { + if (!($option = Option::tryFrom($name)) || !$option->verifiesType($value)) { + continue; + } - if (array_key_exists('longPrefix', $options) && is_string($options['longPrefix'])) { - $this->longPrefix = $options['longPrefix']; + $this->{$option->getPhpProperty()} = $value; } - if (array_key_exists('castTo', $options) && is_string($options['castTo'])) { - $this->castTo = match ($options['castTo']) { + if ($this->castTo) { + $this->castTo = match ($this->castTo) { 'int', 'integer' => 'integer', 'bool', 'boolean' => throw new Exception('castTo cannot be of type bool, use the option "noValue"'), 'double', 'float' => 'double', 'string' => 'string', - default => throw new Exception($options['castTo'] . ' is not a native PHP type') + default => throw new Exception($this->castTo . ' is not a native PHP type') }; } - if (array_key_exists('defaultValue', $options)) { - $defaultValue = $options['defaultValue']; - - if (!is_string($defaultValue) && !is_double($defaultValue) && !is_int($defaultValue)) { - throw new Exception('Default value must be of type float, integer or string'); - } - - $this->defaultValue = $defaultValue; - - // Asserts the default value type is the same as the castTo option - if (gettype($this->defaultValue) !== $this->castTo) { - throw new Exception("Default value is not the same type as castTo option ({$this->castTo})"); - } + // Asserts the default value type is the same as the castTo option + if ($this->defaultValue && gettype($this->defaultValue) !== $this->castTo) { + throw new Exception("Default value is not the same type as castTo option ({$this->castTo})"); } if (($this->noValue || $this->isRequired) && $this->defaultValue) { @@ -137,7 +104,7 @@ public function setValueParsed(bool|string $value): void return; } - // Thorws an exception if the value is not of casted type + // Throws an exception if the value is not of casted type if ($this->castTo === 'integer') { if (!is_numeric($value)) { throw new ParseException("Argument {$this->name} is not a numeric string (must cast to integer)"); diff --git a/src/Arguments/Option.php b/src/Arguments/Option.php new file mode 100644 index 0000000..5602af4 --- /dev/null +++ b/src/Arguments/Option.php @@ -0,0 +1,57 @@ + verifies only its presence by a boolean status (ex: --help) */ + case NO_VALUE = 'noValue'; + + /** (string) Short prefix (-u=) */ + case PREFIX = 'prefix'; + + /** (string) Long prefix (--user=) */ + case LONG_PREFIX = 'longPrefix'; + + /** (string) PHP type - If the argument has a type other than string -> its value will be casted */ + case CAST_TO = 'castTo'; + + /** (string|int|float) Default value if the argument is not handled */ + case DEFAULT_VALUE = 'defaultValue'; + + /** From a value, verifies the type the option must require */ + public function verifiesType(mixed $value): bool + { + return match ($this) { + self::DESCRIPTION => is_string($value), + self::REQUIRED => is_bool($value), + self::NO_VALUE => is_bool($value), + self::PREFIX => is_string($value), + self::LONG_PREFIX => is_string($value), + self::CAST_TO => is_string($value), + self::DEFAULT_VALUE => is_string($value) || is_int($value) || is_float($value) + }; + } + + /** Returns the php property for the Arguments\Argument class */ + public function getPhpProperty(): string + { + return match ($this) { + self::REQUIRED => 'isRequired', + default => $this->value + }; + } +} diff --git a/tests/Arguments/ArgumentTest.php b/tests/Arguments/ArgumentTest.php index 0b01110..8eaecb2 100755 --- a/tests/Arguments/ArgumentTest.php +++ b/tests/Arguments/ArgumentTest.php @@ -157,16 +157,11 @@ public function testDefaultValue(): void $oArgument = new Argument('test'); $this->assertNull($oArgument->getDefaultValue()); - // we recover every incorrect PHP type = throws an exception + // we recover every incorrect PHP type = does not assign the value foreach ([true, false, [], new \stdClass(), fopen(__FILE__, 'r')] as $incorrectValue) { - try { - $oArgument = new Argument('test', ['defaultValue' => $incorrectValue]); - - $this->fail('expected exception pour la valeur ' . var_export($incorrectValue, true)); - } catch (\Exception $e) { - $this->assertSame('Default value must be of type float, integer or string', $e->getMessage()); - $this->assertInstanceOf(Exception::class, $e); - } + $oArgument = new Argument('test', ['defaultValue' => $incorrectValue]); + + $this->assertNull($oArgument->getDefaultValue()); } // castTo string and defaultValue string OK