diff --git a/.travis.yml b/.travis.yml
index 6c7b0e4..10f12dd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,6 @@
language: php
php:
+ - 7.0
- 5.6
- 5.5
- 5.4
diff --git a/src/Ulrichsg/Getopt/CommandLineParser.php b/src/Ulrichsg/Getopt/CommandLineParser.php
index 2020680..8327cec 100644
--- a/src/Ulrichsg/Getopt/CommandLineParser.php
+++ b/src/Ulrichsg/Getopt/CommandLineParser.php
@@ -2,6 +2,8 @@
namespace Ulrichsg\Getopt;
+use Ulrichsg\Getopt\Util\String;
+
/**
* Parses command line arguments according to a list of allowed options.
*/
@@ -10,9 +12,6 @@ class CommandLineParser
/** @var Option[] */
private $optionList;
- private $options = array();
- private $operands = array();
-
/**
* Creates a new instance.
*
@@ -27,12 +26,17 @@ public function __construct(array $optionList)
* Parses the given arguments and converts them into options and operands.
*
* @param mixed $arguments a string or an array with one argument per element
+ * @return Result
*/
public function parse($arguments)
{
if (!is_array($arguments)) {
- $arguments = explode(' ', $arguments);
+ $tokenizer = new Tokenizer();
+ // $arguments = explode(' ', $arguments);
+ $arguments = $tokenizer->tokenize($arguments);
}
+ echo json_encode($arguments)."\n";
+ $options = array();
$operands = array();
$numArgs = count($arguments);
for ($i = 0; $i < $numArgs; ++$i) {
@@ -40,141 +44,106 @@ public function parse($arguments)
if (empty($arg)) {
continue;
}
- if (($arg === '--') || ($arg === '-') || (mb_substr($arg, 0, 1) !== '-')){
+ if (($arg === '--') || ($arg === '-') || !String::startsWith($arg, '-')){
// no more options, treat the remaining arguments as operands
$firstOperandIndex = ($arg == '--') ? $i + 1 : $i;
$operands = array_slice($arguments, $firstOperandIndex);
break;
}
- if (mb_substr($arg, 0, 2) == '--') {
- $this->addLongOption($arguments, $i);
+ if (String::startsWith($arg, '--')) {
+ $options = $this->addLongOption($options, $arguments, $i);
} else {
- $this->addShortOption($arguments, $i);
- }
- } // endfor
-
- $this->addDefaultValues();
-
- // remove '--' from operands array
- foreach ($operands as $operand) {
- if ($operand !== '--') {
- $this->operands[] = $operand;
+ $options = $this->addShortOption($options, $arguments, $i);
}
}
- }
- /**
- * Returns the options created by a previous invocation of parse().
- *
- * @return array
- */
- public function getOptions()
- {
- return $this->options;
+ $options = $this->addDefaultValues($options);
+ $operands = array_values(array_diff($operands, array('--')));
+ return new Result($options, $operands);
}
-
- /**
- * Returns the operands created by a previous invocation of parse(),
- *
- * @return array
- */
- public function getOperands()
- {
- return $this->operands;
- }
-
- private function addShortOption($arguments, &$i)
+ private function addShortOption(array $options, $arguments, &$i)
{
- $numArgs = count($arguments);
- $option = mb_substr($arguments[$i], 1);
- if (mb_strlen($option) > 1) {
+ $nextArg = $this->nextElement($arguments, $i);
+ $option = String::substr($arguments[$i], 1);
+ if (String::length($option) > 1) {
// multiple options strung together
- $options = $this->splitString($option, 1);
- foreach ($options as $j => $ch) {
- if ($j < count($options) - 1
- || !(
- $i < $numArgs - 1
- && ((mb_substr($arguments[$i + 1], 0, 1) !== '-') || ($arguments[$i + 1] === '-'))
- && $this->optionHasArgument($ch)
- )
- ) {
- $this->addOption($ch, null);
- } else { // e.g. `ls -sw 100`
- $value = $arguments[$i + 1];
+ $flags = String::split($option);
+ foreach ($flags as $j => $flag) {
+ if ($j === count($flags) - 1 && $this->canBeArgument($nextArg) && $this->optionHasArgument($flag)) {
+ // e.g. `ls -sw 100`
+ $options = $this->addOption($options, $flag, $nextArg);
++$i;
- $this->addOption($ch, $value);
+ } else {
+ $options = $this->addOption($options, $flag, null);
}
}
} else {
- if ($i < $numArgs - 1
- && ((mb_substr($arguments[$i + 1], 0, 1) !== '-') || ($arguments[$i + 1] === '-'))
- && $this->optionHasArgument($option)
- ) {
- $value = $arguments[$i + 1];
+ if ($this->canBeArgument($nextArg) && $this->optionHasArgument($option)) {
+ $options = $this->addOption($options, $option, $nextArg);
++$i;
} else {
- $value = null;
+ $options = $this->addOption($options, $option, null);
}
- $this->addOption($option, $value);
}
+ return $options;
}
- private function addLongOption($arguments, &$i)
+ private function addLongOption(array $options, $arguments, &$i)
{
- $option = mb_substr($arguments[$i], 2);
- if (strpos($option, '=') === false) {
- if ($i < count($arguments) - 1
- && ((mb_substr($arguments[$i + 1], 0, 1) !== '-') || ($arguments[$i + 1] === '-'))
- && $this->optionHasArgument($option)
- ) {
- $value = $arguments[$i + 1];
+ $option = String::substr($arguments[$i], 2);
+ if (String::contains($option, '=')) {
+ list($option, $value) = explode('=', $option, 2);
+ } else {
+ $nextArg = $this->nextElement($arguments, $i);
+ if ($this->canBeArgument($nextArg) && $this->optionHasArgument($option)) {
+ $value = $nextArg;
++$i;
} else {
$value = null;
}
- } else {
- list($option, $value) = explode('=', $option, 2);
}
- $this->addOption($option, $value);
+ return $this->addOption($options, $option, $value);
}
/**
* Add an option to the list of known options.
*
+ * @param Option[] $options
* @param string $string the option's name
* @param string $value the option's value (or null)
* @throws \UnexpectedValueException
- * @return void
+ * @return Option[]
*/
- private function addOption($string, $value)
+ private function addOption(array $options, $string, $value)
{
foreach ($this->optionList as $option) {
- if ($option->matches($string)) {
- if ($option->mode() == Getopt::REQUIRED_ARGUMENT && !mb_strlen($value)) {
- throw new \UnexpectedValueException("Option '$string' must have a value");
- }
- if ($option->getArgument()->hasValidation()) {
- if ((mb_strlen($value) > 0) && !$option->getArgument()->validates($value)) {
- throw new \UnexpectedValueException("Option '$string' has an invalid value");
- }
- }
- // for no-argument options, check if they are duplicate
- if ($option->mode() == Getopt::NO_ARGUMENT) {
- $oldValue = isset($this->options[$string]) ? $this->options[$string] : null;
- $value = is_null($oldValue) ? 1 : $oldValue + 1;
- }
- // for optional-argument options, set value to 1 if none was given
- $value = (mb_strlen($value) > 0) ? $value : 1;
- // add both long and short names (if they exist) to the option array to facilitate lookup
- if ($option->short()) {
- $this->options[$option->short()] = $value;
- }
- if ($option->long()) {
- $this->options[$option->long()] = $value;
+ if (!$option->matches($string)) {
+ continue;
+ }
+ if ($option->mode() == Getopt::REQUIRED_ARGUMENT && String::length($value) === 0) {
+ throw new \UnexpectedValueException("Option '$string' must have a value");
+ }
+ if ($option->getArgument()->hasValidation()) {
+ if ((String::length($value) > 0) && !$option->getArgument()->validates($value)) {
+ throw new \UnexpectedValueException("Option '$string' has an invalid value");
}
- return;
}
+ // for no-argument options, check if they are duplicate (eg. '-vvv')
+ if ($option->mode() == Getopt::NO_ARGUMENT) {
+ $oldValue = isset($options[$string]) ? $options[$string] : null;
+ $value = is_null($oldValue) ? 1 : $oldValue + 1;
+ }
+ // for optional-argument options, set value to 1 if none was given
+ $value = (String::length($value) > 0) ? $value : 1;
+ // add both long and short names (if they exist) to the option array to facilitate lookup
+ if ($option->short()) {
+ $options[$option->short()] = $value;
+ }
+ if ($option->long()) {
+ $options[$option->long()] = $value;
+ }
+ return $options;
}
throw new \UnexpectedValueException("Option '$string' is unknown");
}
@@ -182,22 +151,26 @@ private function addOption($string, $value)
/**
* If there are options with default values that were not overridden by the parsed option string,
* add them to the list of known options.
+ *
+ * @param Option[] $options
+ * @return Option[]
*/
- private function addDefaultValues()
+ private function addDefaultValues(array $options)
{
foreach ($this->optionList as $option) {
if ($option->getArgument()->hasDefaultValue()
- && !isset($this->options[$option->short()])
- && !isset($this->options[$option->long()])
+ && !isset($options[$option->short()])
+ && !isset($options[$option->long()])
) {
if ($option->short()) {
- $this->addOption($option->short(), $option->getArgument()->getDefaultValue());
+ $options = $this->addOption($options, $option->short(), $option->getArgument()->getDefaultValue());
}
if ($option->long()) {
- $this->addOption($option->long(), $option->getArgument()->getDefaultValue());
+ $options = $this->addOption($options, $option->long(), $option->getArgument()->getDefaultValue());
}
}
}
+ return $options;
}
/**
@@ -216,18 +189,13 @@ private function optionHasArgument($name)
return false;
}
- /**
- * Split the string into individual characters,
- *
- * @param string $string string to split
- * @return array
- */
- private function splitString($string)
+ private function nextElement(array $array, $index)
{
- $result = array();
- for ($i = 0; $i < mb_strlen($string, "UTF-8"); ++$i) {
- $result[] = mb_substr($string, $i, 1, "UTF-8");
- }
- return $result;
+ return ($index < count($array) - 1) ? $array[$index + 1] : null;
+ }
+
+ private function canBeArgument($string)
+ {
+ return !is_null($string) && (($string === '-') || !String::startsWith($string, '-'));
}
}
diff --git a/src/Ulrichsg/Getopt/DefaultHelpTextFormatter.php b/src/Ulrichsg/Getopt/DefaultHelpTextFormatter.php
new file mode 100644
index 0000000..987234c
--- /dev/null
+++ b/src/Ulrichsg/Getopt/DefaultHelpTextFormatter.php
@@ -0,0 +1,61 @@
+getBanner(), $this->scriptName);
+ $helpText .= "Options:\n";
+ foreach ($options as $option) {
+ $mode = '';
+ switch ($option->mode()) {
+ case Getopt::NO_ARGUMENT:
+ $mode = '';
+ break;
+ case Getopt::REQUIRED_ARGUMENT:
+ $mode = "<".$option->getArgument()->getName().">";
+ break;
+ case Getopt::OPTIONAL_ARGUMENT:
+ $mode = "[<".$option->getArgument()->getName().">]";
+ break;
+ }
+ $short = ($option->short()) ? '-'.$option->short() : '';
+ $long = ($option->long()) ? '--'.$option->long() : '';
+ if ($short && $long) {
+ $options = $short.', '.$long;
+ } else {
+ $options = $short ? : $long;
+ }
+ $padded = str_pad(sprintf(" %s %s", $options, $mode), $padding);
+ $helpText .= sprintf("%s %s\n", $padded, $option->getDescription());
+ }
+ return $helpText;
+ }
+
+ public function getBanner()
+ {
+ return $this->banner;
+ }
+
+ public function setBanner($banner)
+ {
+ $this->banner = $banner;
+ }
+
+ public function setScriptName($scriptName)
+ {
+ $this->scriptName = $scriptName;
+ }
+}
diff --git a/src/Ulrichsg/Getopt/Getopt.php b/src/Ulrichsg/Getopt/Getopt.php
index bd6b7ad..3e1d4c2 100644
--- a/src/Ulrichsg/Getopt/Getopt.php
+++ b/src/Ulrichsg/Getopt/Getopt.php
@@ -6,11 +6,11 @@
* Getopt.PHP allows for easy processing of command-line arguments.
* It is a more powerful, object-oriented alternative to PHP's built-in getopt() function.
*
- * @version 2.1.0
+ * @version 3
* @license MIT
* @link http://ulrichsg.github.io/getopt-php
*/
-class Getopt implements \Countable, \ArrayAccess, \IteratorAggregate
+class Getopt
{
const NO_ARGUMENT = 0;
const REQUIRED_ARGUMENT = 1;
@@ -18,16 +18,10 @@ class Getopt implements \Countable, \ArrayAccess, \IteratorAggregate
/** @var OptionParser */
private $optionParser;
- /** @var string */
- private $scriptName;
/** @var Option[] */
- private $optionList = array();
- /** @var array */
- private $options = array();
- /** @var array */
- private $operands = array();
- /** @var string */
- private $banner = "Usage: %s [options] [operands]\n";
+ protected $optionList = array();
+ /** @var HelpTextFormatter */
+ protected $helpTextFormatter;
/**
* Creates a new Getopt object.
@@ -47,6 +41,7 @@ public function __construct($options = null, $defaultType = Getopt::NO_ARGUMENT)
if ($options !== null) {
$this->addOptions($options);
}
+ $this->helpTextFormatter = new DefaultHelpTextFormatter();
}
/**
@@ -83,10 +78,10 @@ private function mergeOptions(array $options)
if (($option === $otherOption) || in_array($otherOption, $duplicates)) {
continue;
}
- if ($this->optionsConflict($option, $otherOption)) {
+ if ($option->conflictsWith($otherOption)) {
throw new \InvalidArgumentException('Failed to add options due to conflict');
}
- if (($option->short() === $otherOption->short()) && ($option->long() === $otherOption->long())) {
+ if ($option->equals($otherOption)) {
$duplicates[] = $option;
}
}
@@ -99,15 +94,6 @@ private function mergeOptions(array $options)
$this->optionList = array_values($mergedList);
}
- private function optionsConflict(Option $option1, Option $option2) {
- if ((is_null($option1->short()) && is_null($option2->short()))
- || (is_null($option1->long()) && is_null($option2->long()))) {
- return false;
- }
- return ((($option1->short() === $option2->short()) && ($option1->long() !== $option2->long()))
- || (($option1->short() !== $option2->short()) && ($option1->long() === $option2->long())));
- }
-
/**
* Evaluate the given arguments. These can be passed either as a string or as an array.
* If nothing is passed, the running script's command line arguments are used.
@@ -116,180 +102,31 @@ private function optionsConflict(Option $option1, Option $option2) {
* when the arguments are not well-formed or do not conform to the options passed by the user.
*
* @param mixed $arguments optional ARGV array or space separated string
+ * @return Result
*/
public function parse($arguments = null)
{
- $this->options = array();
+ $scriptName = $_SERVER['PHP_SELF'];
if (!isset($arguments)) {
global $argv;
$arguments = $argv;
- $this->scriptName = array_shift($arguments); // $argv[0] is the script's name
+ $scriptName = array_shift($arguments); // $argv[0] is the script's name
} elseif (is_string($arguments)) {
- $this->scriptName = $_SERVER['PHP_SELF'];
$arguments = explode(' ', $arguments);
}
+ $this->helpTextFormatter->setScriptName($scriptName);
$parser = new CommandLineParser($this->optionList);
- $parser->parse($arguments);
- $this->options = $parser->getOptions();
- $this->operands = $parser->getOperands();
- }
-
- /**
- * Returns the value of the given option. Must be invoked after parse().
- *
- * The return value can be any of the following:
- *
- * - null if the option is not given and does not have a default value
- * - the default value if it has been defined and the option is not given
- * - an integer if the option is given without argument. The
- * returned value is the number of occurrences of the option.
- * - a string if the option is given with an argument. The returned value is that argument.
- *
- *
- * @param string $name The (short or long) option name.
- * @return mixed
- */
- public function getOption($name)
- {
- return isset($this->options[$name]) ? $this->options[$name] : null;
- }
-
- /**
- * Returns the list of options. Must be invoked after parse() (otherwise it returns an empty array).
- *
- * @return array
- */
- public function getOptions()
- {
- return $this->options;
- }
-
- /**
- * Returns the list of operands. Must be invoked after parse().
- *
- * @return array
- */
- public function getOperands()
- {
- return $this->operands;
+ return $parser->parse($arguments);
}
- /**
- * Returns the i-th operand (starting with 0), or null if it does not exist. Must be invoked after parse().
- *
- * @param int $i
- * @return string
- */
- public function getOperand($i)
+ public function setHelpTextFormatter(HelpTextFormatter $formatter)
{
- return ($i < count($this->operands)) ? $this->operands[$i] : null;
+ $this->helpTextFormatter = $formatter;
}
- /**
- * Returns the banner string
- *
- * @return string
- */
- public function getBanner()
- {
- return $this->banner;
- }
-
- /**
- * Set the banner string
- *
- * @param string $banner The banner string; will be passed to sprintf(), can include %s for current scripts name.
- * Be sure to include a trailing line feed.
- * @return Getopt
- */
- public function setBanner($banner)
- {
- $this->banner = $banner;
- return $this;
- }
-
- /**
- * Returns an usage information text generated from the given options.
- * @param int $padding Number of characters to pad output of options to
- * @return string
- */
public function getHelpText($padding = 25)
{
- $helpText = sprintf($this->getBanner(), $this->scriptName);
- $helpText .= "Options:\n";
- foreach ($this->optionList as $option) {
- $mode = '';
- switch ($option->mode()) {
- case self::NO_ARGUMENT:
- $mode = '';
- break;
- case self::REQUIRED_ARGUMENT:
- $mode = "<".$option->getArgument()->getName().">";
- break;
- case self::OPTIONAL_ARGUMENT:
- $mode = "[<".$option->getArgument()->getName().">]";
- break;
- }
- $short = ($option->short()) ? '-'.$option->short() : '';
- $long = ($option->long()) ? '--'.$option->long() : '';
- if ($short && $long) {
- $options = $short.', '.$long;
- } else {
- $options = $short ? : $long;
- }
- $padded = str_pad(sprintf(" %s %s", $options, $mode), $padding);
- $helpText .= sprintf("%s %s\n", $padded, $option->getDescription());
- }
- return $helpText;
- }
-
-
- /*
- * Interface support functions
- */
-
- public function count()
- {
- return count($this->options);
- }
-
- public function offsetExists($offset)
- {
- return isset($this->options[$offset]);
- }
-
- public function offsetGet($offset)
- {
- return $this->getOption($offset);
- }
-
- public function offsetSet($offset, $value)
- {
- throw new \LogicException('Getopt is read-only');
- }
-
- public function offsetUnset($offset)
- {
- throw new \LogicException('Getopt is read-only');
- }
-
- public function getIterator()
- {
- // For options that have both short and long names, $this->options has two entries.
- // We don't want this when iterating, so we have to filter the duplicates out.
- $filteredOptions = array();
- foreach ($this->options as $name => $value) {
- $keep = true;
- foreach ($this->optionList as $option) {
- if ($option->long() == $name && !is_null($option->short())) {
- $keep = false;
- }
- }
- if ($keep) {
- $filteredOptions[$name] = $value;
- }
- }
- return new \ArrayIterator($filteredOptions);
+ return $this->helpTextFormatter->getHelpText($this->optionList, $padding);
}
}
diff --git a/src/Ulrichsg/Getopt/Getoptv2.php b/src/Ulrichsg/Getopt/Getoptv2.php
new file mode 100644
index 0000000..42fac99
--- /dev/null
+++ b/src/Ulrichsg/Getopt/Getoptv2.php
@@ -0,0 +1,142 @@
+result = parent::parse($arguments);
+ return $this->result;
+ }
+
+ /**
+ * Returns the value of the given option. Must be invoked after parse().
+ *
+ * The return value can be any of the following:
+ *
+ * - null if the option is not given and does not have a default value
+ * - the default value if it has been defined and the option is not given
+ * - an integer if the option is given without argument. The
+ * returned value is the number of occurrences of the option.
+ * - a string if the option is given with an argument. The returned value is that argument.
+ *
+ *
+ * @param string $name The (short or long) option name.
+ * @return mixed
+ */
+ public function getOption($name)
+ {
+ return isset($this->result) ? $this->result->getOption($name) : null;
+ }
+
+ /**
+ * Returns the list of options. Must be invoked after parse() (otherwise it returns an empty array).
+ *
+ * @return array
+ */
+ public function getOptions()
+ {
+ return isset($this->result) ? $this->result->getOptions() : array();
+ }
+
+ /**
+ * Returns the list of operands. Must be invoked after parse().
+ *
+ * @return array
+ */
+ public function getOperands()
+ {
+ return isset($this->result) ? $this->result->getOperands() : array();
+ }
+
+ /**
+ * Returns the i-th operand (starting with 0), or null if it does not exist. Must be invoked after parse().
+ *
+ * @param int $i
+ * @return string
+ */
+ public function getOperand($i)
+ {
+ return isset($this->result) ? $this->result->getOperand($i) : null;
+ }
+
+
+ /*
+ * Interface support functions
+ */
+
+ public function count()
+ {
+ return isset($this->result) ? count($this->result->getOptions()) : 0;
+ }
+
+ public function offsetExists($offset)
+ {
+ $options = $this->getOptions();
+ return isset($options[$offset]);
+ }
+
+ public function offsetGet($offset)
+ {
+ return $this->getOption($offset);
+ }
+
+ public function offsetSet($offset, $value)
+ {
+ throw new \LogicException('Getopt is read-only');
+ }
+
+ public function offsetUnset($offset)
+ {
+ throw new \LogicException('Getopt is read-only');
+ }
+
+ public function getIterator()
+ {
+ // For options that have both short and long names, $this->options has two entries.
+ // We don't want this when iterating, so we have to filter the duplicates out.
+ $filteredOptions = array();
+ foreach ($this->getOptions() as $name => $value) {
+ $keep = true;
+ foreach ($this->optionList as $option) {
+ if ($option->long() == $name && !is_null($option->short())) {
+ $keep = false;
+ }
+ }
+ if ($keep) {
+ $filteredOptions[$name] = $value;
+ }
+ }
+ return new \ArrayIterator($filteredOptions);
+ }
+
+ /**
+ * Returns the banner string
+ *
+ * @return string
+ */
+ public function getBanner()
+ {
+ return $this->helpTextFormatter->getBanner();
+ }
+
+ /**
+ * Set the banner string
+ *
+ * @param string $banner The banner string; will be passed to sprintf(), can include %s for current scripts name.
+ * Be sure to include a trailing line feed.
+ * @return Getopt
+ */
+ public function setBanner($banner)
+ {
+ $this->helpTextFormatter->setBanner($banner);
+ return $this;
+ }
+}
diff --git a/src/Ulrichsg/Getopt/HelpTextFormatter.php b/src/Ulrichsg/Getopt/HelpTextFormatter.php
new file mode 100644
index 0000000..384722d
--- /dev/null
+++ b/src/Ulrichsg/Getopt/HelpTextFormatter.php
@@ -0,0 +1,12 @@
+argument = new Argument();
}
+ /**
+ * Fluent interface for constructor so options can be added during construction
+ * @see Options::__construct()
+ */
+ public static function create($short, $long, $mode = Getopt::NO_ARGUMENT)
+ {
+ return new self($short, $long, $mode);
+ }
+
/**
* Defines a description for the option. This is only used for generating usage information.
*
@@ -46,31 +55,31 @@ public function setDescription($description)
return $this;
}
- /**
- * Defines a default value for the option.
- *
- * @param mixed $value
+ /**
+ * Defines a default value for the option.
+ *
+ * @param mixed $value
* @return Option this object (for chaining calls)
- */
- public function setDefaultValue($value)
- {
- $this->argument->setDefaultValue($value);
- return $this;
- }
-
- /**
- * Defines a validation function for the option.
- *
- * @param callable $function
- * @return Option this object (for chaining calls)
- */
- public function setValidation($function)
- {
- $this->argument->setValidation($function);
- return $this;
- }
-
- /**
+ */
+ public function setDefaultValue($value)
+ {
+ $this->argument->setDefaultValue($value);
+ return $this;
+ }
+
+ /**
+ * Defines a validation function for the option.
+ *
+ * @param callable $function
+ * @return Option this object (for chaining calls)
+ */
+ public function setValidation($function)
+ {
+ $this->argument->setValidation($function);
+ return $this;
+ }
+
+ /**
* Sets the argument object directly.
*
* @param Argument $arg
@@ -96,6 +105,32 @@ public function matches($string)
return ($string === $this->short) || ($string === $this->long);
}
+ /**
+ * Returns true if the given option is considered a duplicate of this one.
+ *
+ * @param Option $other
+ * @return bool
+ */
+ public function equals(Option $other) {
+ return ($this->short() === $other->short() && $this->long() === $other->long());
+ }
+
+ /**
+ * Returns true if the given option cannot appear in the same option list as this one due to a name conflict.
+ *
+ * @param Option $other
+ * @return bool
+ */
+ public function conflictsWith(Option $other)
+ {
+ if ((is_null($this->short()) && is_null($other->short()))
+ || (is_null($this->long()) && is_null($other->long()))) {
+ return false;
+ }
+ return ((($this->short() === $other->short()) && ($this->long() !== $other->long()))
+ || (($this->short() !== $other->short()) && ($this->long() === $other->long())));
+ }
+
public function short()
{
return $this->short;
@@ -118,22 +153,13 @@ public function getDescription()
/**
* Retrieve the argument object
- *
+ *
* @return Argument
*/
public function getArgument()
{
return $this->argument;
}
-
- /**
- * Fluent interface for constructor so options can be added during construction
- * @see Options::__construct()
- */
- public static function create($short, $long, $mode = Getopt::NO_ARGUMENT)
- {
- return new self($short, $long, $mode);
- }
private function setShort($short)
{
diff --git a/src/Ulrichsg/Getopt/Result.php b/src/Ulrichsg/Getopt/Result.php
new file mode 100644
index 0000000..24dfb75
--- /dev/null
+++ b/src/Ulrichsg/Getopt/Result.php
@@ -0,0 +1,69 @@
+options = $options;
+ $this->operands = $operands;
+ }
+
+ /**
+ * Returns the value of the given option.
+ *
+ * The return value can be any of the following:
+ *
+ * - null if the option is not given and does not have a default value
+ * - the default value if it has been defined and the option is not given
+ * - an integer if the option is given without argument. The
+ * returned value is the number of occurrences of the option.
+ * - a string if the option is given with an argument. The returned value is that argument.
+ *
+ *
+ * @param string $name The (short or long) option name.
+ * @return mixed
+ */
+ public function getOption($name)
+ {
+ return isset($this->options[$name]) ? $this->options[$name] : null;
+ }
+
+ /**
+ * Returns the list of options. Must be invoked after parse() (otherwise it returns an empty array).
+ *
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * Returns the list of operands.
+ *
+ * @return array
+ */
+ public function getOperands()
+ {
+ return $this->operands;
+ }
+
+ /**
+ * Returns the i-th operand (starting with 0), or null if it does not exist.
+ *
+ * @param int $i
+ * @return string
+ */
+ public function getOperand($i)
+ {
+ return ($i < count($this->operands)) ? $this->operands[$i] : null;
+ }
+}
diff --git a/src/Ulrichsg/Getopt/Tokenizer.php b/src/Ulrichsg/Getopt/Tokenizer.php
new file mode 100644
index 0000000..4feff73
--- /dev/null
+++ b/src/Ulrichsg/Getopt/Tokenizer.php
@@ -0,0 +1,100 @@
+nextToken($string, $pos);
+ }
+ return $tokens;
+ }
+
+ private function nextToken($string, &$pos)
+ {
+ while (ctype_space($string[$pos])) {
+ ++$pos;
+ if ($pos >= String::length($string)) {
+ return null;
+ }
+ }
+ if (String::at($string, $pos) === '"') {
+ ++$pos;
+ return $this->getQuotedToken($string, $pos);
+ }
+ if (String::at($string, $pos) === '-') {
+ return $this->getHyphenatedToken($string, $pos);
+ }
+ return $this->getPlainToken($string, $pos);
+ }
+
+ private function getQuotedToken($string, &$pos)
+ {
+ $token = '';
+ while ($pos < String::length($string) && $string[$pos] !== '"') {
+ $token .= $this->nextChar($string, $pos);
+ echo "$token\n";
+ }
+ if (!String::isSpaceOrEnd($string, $pos)) {
+ throw new \UnexpectedValueException('Syntax error');
+ // error
+ }
+ return $token;
+ }
+
+ private function getHyphenatedToken($string, &$pos)
+ {
+ $hyphens = "";
+ while (String::at($string, $pos) === '-') {
+ $hyphens .= $string[$pos++];
+ }
+ if (String::isSpaceOrEnd($string, $pos)) {
+ return $hyphens;
+ }
+ if (!ctype_alnum($string[$pos])) {
+ // error
+ throw new \UnexpectedValueException("Syntax error: expected letter or digit, found {$string[$pos]} in ".$hyphens.String::substr($string, $pos));
+ }
+ $token = '';
+ while (ctype_alnum(String::at($string, $pos))) {
+ $token .= $string[$pos++];
+ }
+ if (String::at($string, $pos) === '=' || String::isSpaceOrEnd($string, $pos)) {
+ ++$pos;
+ echo $hyphens.$token."\n";
+ return $hyphens.$token;
+ }
+ throw new \UnexpectedValueException('Syntax error');
+ // error
+ }
+
+ private function getPlainToken($string, &$pos)
+ {
+ $token = '';
+ while (!String::isSpaceOrEnd($string, $pos)) {
+ $token .= $this->nextChar($string, $pos);
+ }
+ return $token;
+ }
+
+ private function nextChar($string, &$pos)
+ {
+ if ($string[$pos] === '\\') {
+ $followingChar = $string[$pos+1];
+ if (in_array($followingChar, array('\\', '"'))) {
+ $pos += 2;
+ return $followingChar;
+ } else {
+ throw new \UnexpectedValueException('Syntax error');
+ // error
+ }
+ }
+ return $string[$pos++];
+ }
+}
diff --git a/src/Ulrichsg/Getopt/Util/String.php b/src/Ulrichsg/Getopt/Util/String.php
new file mode 100644
index 0000000..b2cb536
--- /dev/null
+++ b/src/Ulrichsg/Getopt/Util/String.php
@@ -0,0 +1,57 @@
+= self::length($string)) {
+ return null;
+ }
+ return $string[$pos];
+ }
+
+ public static function length($string)
+ {
+ return mb_strlen($string, "UTF-8");
+ }
+
+ public static function substr($string, $start, $length = null)
+ {
+ return mb_substr($string, $start, $length, "UTF-8");
+ }
+
+ public static function startsWith($string, $prefix)
+ {
+ return self::substr($string, 0, self::length($prefix)) === $prefix;
+ }
+
+ /**
+ * Split the string into individual characters,
+ *
+ * @param string $string string to split
+ * @return array
+ */
+ public static function split($string)
+ {
+ $result = array();
+ for ($i = 0; $i < self::length($string); ++$i) {
+ $result[] = mb_substr($string, $i, 1, "UTF-8");
+ }
+ return $result;
+ }
+
+ public static function contains($string, $substr)
+ {
+ return mb_strpos($string, $substr, null, "UTF-8");
+ }
+
+ public static function isSpaceOrEnd($string, $pos)
+ {
+ if ($pos >= self::length($string)) {
+ return true;
+ }
+ return ctype_space($string[$pos]);
+ }
+}
diff --git a/test/Ulrichsg/Getopt/CommandLineParserTest.php b/test/Ulrichsg/Getopt/CommandLineParserTest.php
index 8f5cb3d..ff0ac23 100644
--- a/test/Ulrichsg/Getopt/CommandLineParserTest.php
+++ b/test/Ulrichsg/Getopt/CommandLineParserTest.php
@@ -9,9 +9,9 @@ public function testParseNoOptions()
$parser = new CommandLineParser(array(
new Option('a', null)
));
- $parser->parse('something');
- $this->assertCount(0, $parser->getOptions());
- $operands = $parser->getOperands();
+ $result = $parser->parse('something');
+ $this->assertCount(0, $result->getOptions());
+ $operands = $result->getOperands();
$this->assertCount(1, $operands);
$this->assertEquals('something', $operands[0]);
}
@@ -40,11 +40,10 @@ public function testParseMultipleOptionsWithOneHyphen()
new Option('a', null),
new Option('b', null)
));
- $parser->parse('-ab');
+ $result = $parser->parse('-ab');
- $options = $parser->getOptions();
- $this->assertEquals(1, $options['a']);
- $this->assertEquals(1, $options['b']);
+ $this->assertEquals(1, $result->getOption('a'));
+ $this->assertEquals(1, $result->getOption('b'));
}
public function testParseCumulativeOption()
@@ -53,11 +52,10 @@ public function testParseCumulativeOption()
new Option('a', null),
new Option('b', null)
));
- $parser->parse('-a -b -a -a');
+ $result = $parser->parse('-a -b -a -a');
- $options = $parser->getOptions();
- $this->assertEquals(3, $options['a']);
- $this->assertEquals(1, $options['b']);
+ $this->assertEquals(3, $result->getOption('a'));
+ $this->assertEquals(1, $result->getOption('b'));
}
public function testParseCumulativeOptionShort()
@@ -66,11 +64,10 @@ public function testParseCumulativeOptionShort()
new Option('a', null),
new Option('b', null)
));
- $parser->parse('-abaa');
+ $result = $parser->parse('-abaa');
- $options = $parser->getOptions();
- $this->assertEquals(3, $options['a']);
- $this->assertEquals(1, $options['b']);
+ $this->assertEquals(3, $result->getOption('a'));
+ $this->assertEquals(1, $result->getOption('b'));
}
public function testParseShortOptionWithArgument()
@@ -78,10 +75,20 @@ public function testParseShortOptionWithArgument()
$parser = new CommandLineParser(array(
new Option('a', null, Getopt::REQUIRED_ARGUMENT)
));
- $parser->parse('-a value');
+ $result = $parser->parse('-a value');
+
+ $this->assertEquals('value', $result->getOption('a'));
+ }
+
+ public function testParseShortOptionWithQuotedArgument()
+ {
+ $this->markTestSkipped();
+ $parser = new CommandLineParser(array(
+ new Option('a', null, Getopt::REQUIRED_ARGUMENT)
+ ));
+ $result = $parser->parse('-a "hello world"');
- $options = $parser->getOptions();
- $this->assertEquals('value', $options['a']);
+ $this->assertEquals('hello world', $result->getOption('a'));
}
public function testParseZeroArgument()
@@ -89,10 +96,9 @@ public function testParseZeroArgument()
$parser = new CommandLineParser(array(
new Option('a', null, Getopt::REQUIRED_ARGUMENT)
));
- $parser->parse('-a 0');
+ $result = $parser->parse('-a 0');
- $options = $parser->getOptions();
- $this->assertEquals('0', $options['a']);
+ $this->assertEquals('0', $result->getOption('a'));
}
public function testParseNumericOption()
@@ -101,11 +107,10 @@ public function testParseNumericOption()
new Option('a', null, Getopt::REQUIRED_ARGUMENT),
new Option('2', null)
));
- $parser->parse('-a 2 -2');
+ $result = $parser->parse('-a 2 -2');
- $options = $parser->getOptions();
- $this->assertEquals('2', $options['a']);
- $this->assertEquals(1, $options['2']);
+ $this->assertEquals('2', $result->getOption('a'));
+ $this->assertEquals(1, $result->getOption('2'));
}
public function testParseCollapsedShortOptionsRequiredArgumentMissing()
@@ -124,11 +129,10 @@ public function testParseCollapsedShortOptionsWithArgument()
new Option('a', null),
new Option('b', null, Getopt::REQUIRED_ARGUMENT)
));
- $parser->parse('-ab value');
+ $result = $parser->parse('-ab value');
- $options = $parser->getOptions();
- $this->assertEquals(1, $options['a']);
- $this->assertEquals('value', $options['b']);
+ $this->assertEquals(1, $result->getOption('a'));
+ $this->assertEquals('value', $result->getOption('b'));
}
public function testParseNoArgumentOptionAndOperand()
@@ -136,11 +140,10 @@ public function testParseNoArgumentOptionAndOperand()
$parser = new CommandLineParser(array(
new Option('a', null),
));
- $parser->parse('-a b');
+ $result = $parser->parse('-a b');
- $options = $parser->getOptions();
- $this->assertEquals(1, $options['a']);
- $operands = $parser->getOperands();
+ $this->assertEquals(1, $result->getOption('a'));
+ $operands = $result->getOperands();
$this->assertCount(1, $operands);
$this->assertEquals('b', $operands[0]);
}
@@ -151,10 +154,10 @@ public function testParseOperandsOnly()
new Option('a', null, Getopt::REQUIRED_ARGUMENT),
new Option('b', null)
));
- $parser->parse('-- -a -b');
+ $result = $parser->parse('-- -a -b');
- $this->assertCount(0, $parser->getOptions());
- $operands = $parser->getOperands();
+ $this->assertCount(0, $result->getOptions());
+ $operands = $result->getOperands();
$this->assertCount(2, $operands);
$this->assertEquals('-a', $operands[0]);
$this->assertEquals('-b', $operands[1]);
@@ -165,10 +168,9 @@ public function testParseLongOptionWithoutArgument()
$parser = new CommandLineParser(array(
new Option('o', 'option', Getopt::OPTIONAL_ARGUMENT)
));
- $parser->parse('--option');
+ $result = $parser->parse('--option');
- $options = $parser->getOptions();
- $this->assertEquals(1, $options['option']);
+ $this->assertEquals(1, $result->getOption('option'));
}
public function testParseLongOptionWithoutArgumentAndOperand()
@@ -176,11 +178,10 @@ public function testParseLongOptionWithoutArgumentAndOperand()
$parser = new CommandLineParser(array(
new Option('o', 'option', Getopt::NO_ARGUMENT)
));
- $parser->parse('--option something');
+ $result = $parser->parse('--option something');
- $options = $parser->getOptions();
- $this->assertEquals(1, $options['option']);
- $operands = $parser->getOperands();
+ $this->assertEquals(1, $result->getOption('option'));
+ $operands = $result->getOperands();
$this->assertCount(1, $operands);
$this->assertEquals('something', $operands[0]);
}
@@ -190,11 +191,10 @@ public function testParseLongOptionWithArgument()
$parser = new CommandLineParser(array(
new Option('o', 'option', Getopt::OPTIONAL_ARGUMENT)
));
- $parser->parse('--option value');
+ $result = $parser->parse('--option value');
- $options = $parser->getOptions();
- $this->assertEquals('value', $options['option']);
- $this->assertEquals('value', $options['o']);
+ $this->assertEquals('value', $result->getOption('option'));
+ $this->assertEquals('value', $result->getOption('o'));
}
public function testParseLongOptionWithEqualsSignAndArgument()
@@ -202,24 +202,23 @@ public function testParseLongOptionWithEqualsSignAndArgument()
$parser = new CommandLineParser(array(
new Option('o', 'option', Getopt::OPTIONAL_ARGUMENT)
));
- $parser->parse('--option=value something');
+ $result = $parser->parse('--option=value something');
- $options = $parser->getOptions();
- $this->assertEquals('value', $options['option']);
- $operands = $parser->getOperands();
+ $this->assertEquals('value', $result->getOption('option'));
+ $operands = $result->getOperands();
$this->assertCount(1, $operands);
$this->assertEquals('something', $operands[0]);
}
public function testParseLongOptionWithValueStartingWithHyphen()
{
+ //$this->markTestSkipped();
$parser = new CommandLineParser(array(
new Option('o', 'option', Getopt::REQUIRED_ARGUMENT)
));
- $parser->parse('--option=-value');
+ $result = $parser->parse('--option=-value');
- $options = $parser->getOptions();
- $this->assertEquals('-value', $options['option']);
+ $this->assertEquals('-value', $result->getOption('option'));
}
public function testParseNoValueStartingWithHyphenRequired()
@@ -238,11 +237,10 @@ public function testParseNoValueStartingWithHyphenOptional()
new Option('a', null, Getopt::OPTIONAL_ARGUMENT),
new Option('b', null)
));
- $parser->parse('-a -b');
+ $result = $parser->parse('-a -b');
- $options = $parser->getOptions();
- $this->assertEquals(1, $options['a']);
- $this->assertEquals(1, $options['b']);
+ $this->assertEquals(1, $result->getOption('a'));
+ $this->assertEquals(1, $result->getOption('b'));
}
public function testParseOptionWithDefaultValue()
@@ -252,12 +250,11 @@ public function testParseOptionWithDefaultValue()
$optionB = new Option('b', 'beta', Getopt::REQUIRED_ARGUMENT);
$optionB->setArgument(new Argument(20));
$parser = new CommandLineParser(array($optionA, $optionB));
- $parser->parse('-a 12');
+ $result = $parser->parse('-a 12');
- $options = $parser->getOptions();
- $this->assertEquals(12, $options['a']);
- $this->assertEquals(20, $options['b']);
- $this->assertEquals(20, $options['beta']);
+ $this->assertEquals(12, $result->getOption('a'));
+ $this->assertEquals(20, $result->getOption('b'));
+ $this->assertEquals(20, $result->getOption('beta'));
}
public function testDoubleHyphenNotInOperands()
@@ -265,11 +262,10 @@ public function testDoubleHyphenNotInOperands()
$parser = new CommandLineParser(array(
new Option('a', null, Getopt::REQUIRED_ARGUMENT)
));
- $parser->parse('-a 0 foo -- bar baz');
+ $result = $parser->parse('-a 0 foo -- bar baz');
- $options = $parser->getOptions();
- $this->assertEquals('0', $options['a']);
- $operands = $parser->getOperands();
+ $this->assertEquals('0', $result->getOption('a'));
+ $operands = $result->getOperands();
$this->assertCount(3, $operands);
$this->assertEquals('foo', $operands[0]);
$this->assertEquals('bar', $operands[1]);
@@ -282,18 +278,16 @@ public function testSingleHyphenValue()
new Option('a', 'alpha', Getopt::REQUIRED_ARGUMENT)
));
- $parser->parse('-a -');
+ $result = $parser->parse('-a -');
- $options = $parser->getOptions();
- $this->assertEquals('-', $options['a']);
- $operands = $parser->getOperands();
+ $this->assertEquals('-', $result->getOption('a'));
+ $operands = $result->getOperands();
$this->assertCount(0, $operands);
- $parser->parse('--alpha -');
+ $result = $parser->parse('--alpha -');
- $options = $parser->getOptions();
- $this->assertEquals('-', $options['a']);
- $operands = $parser->getOperands();
+ $this->assertEquals('-', $result->getOption('a'));
+ $operands = $result->getOperands();
$this->assertCount(0, $operands);
}
@@ -302,11 +296,10 @@ public function testSingleHyphenOperand()
$parser = new CommandLineParser(array(
new Option('a', null, Getopt::REQUIRED_ARGUMENT)
));
- $parser->parse('-a 0 -');
+ $result = $parser->parse('-a 0 -');
- $options = $parser->getOptions();
- $this->assertEquals('0', $options['a']);
- $operands = $parser->getOperands();
+ $this->assertEquals('0', $result->getOption('a'));
+ $operands = $result->getOperands();
$this->assertCount(1, $operands);
$this->assertEquals('-', $operands[0]);
}
@@ -321,12 +314,11 @@ public function testParseWithArgumentValidation()
$optionC = new Option('c', null, Getopt::OPTIONAL_ARGUMENT);
$optionC->setArgument(new Argument(null, $validation));
$parser = new CommandLineParser(array($optionA, $optionB, $optionC));
- $parser->parse('-a 1 -b 2 -c');
+ $result = $parser->parse('-a 1 -b 2 -c');
- $options = $parser->getOptions();
- $this->assertSame('1', $options['a']);
- $this->assertSame('2', $options['b']);
- $this->assertSame(1, $options['c']);
+ $this->assertSame('1', $result->getOption('a'));
+ $this->assertSame('2', $result->getOption('b'));
+ $this->assertSame(1, $result->getOption('c'));
}
public function testParseInvalidArgument()
diff --git a/test/Ulrichsg/Getopt/DefaultHelpTextFormatterTest.php b/test/Ulrichsg/Getopt/DefaultHelpTextFormatterTest.php
new file mode 100644
index 0000000..1a66c58
--- /dev/null
+++ b/test/Ulrichsg/Getopt/DefaultHelpTextFormatterTest.php
@@ -0,0 +1,66 @@
+setDescription('Short and long options with no argument');
+
+ $option2 = new Option(null, 'beta', Getopt::OPTIONAL_ARGUMENT);
+ $option2->setDescription('Long option only with an optional argument');
+
+ $option3 = new Option('c', null, Getopt::REQUIRED_ARGUMENT);
+ $option3->setDescription('Short option only with a mandatory argument');
+
+ $options = array($option1, $option2, $option3);
+
+ $expected = "Usage: test [options] [operands]\n";
+ $expected .= "Options:\n";
+ $expected .= " -a, --alpha Short and long options with no argument\n";
+ $expected .= " --beta [] Long option only with an optional argument\n";
+ $expected .= " -c Short option only with a mandatory argument\n";
+
+ $formatter = new DefaultHelpTextFormatter();
+ $formatter->setScriptName('test');
+ $this->assertEquals($expected, $formatter->getHelpText($options, 20));
+ }
+
+ public function testHelpTextWithoutDescriptions()
+ {
+ $options = array(
+ new Option('a', 'alpha', Getopt::NO_ARGUMENT),
+ new Option(null, 'beta', Getopt::OPTIONAL_ARGUMENT),
+ new Option('c', null, Getopt::REQUIRED_ARGUMENT)
+ );
+
+ $expected = "Usage: test [options] [operands]\n";
+ $expected .= "Options:\n";
+ $expected .= " -a, --alpha \n";
+ $expected .= " --beta [] \n";
+ $expected .= " -c \n";
+
+ $formatter = new DefaultHelpTextFormatter();
+ $formatter->setScriptName('test');
+ $this->assertEquals($expected, $formatter->getHelpText($options));
+ }
+
+ public function testHelpTextNoOptions()
+ {
+ $formatter = new DefaultHelpTextFormatter();
+ $expected = "Usage: [options] [operands]\nOptions:\n";
+ $this->assertSame($expected, $formatter->getHelpText(array()));
+ }
+
+ public function testHelpTextWithCustomBanner()
+ {
+ $formatter = new DefaultHelpTextFormatter();
+ $formatter->setBanner("My custom Banner %s\n");
+ $this->assertSame("My custom Banner \nOptions:\n", $formatter->getHelpText(array()));
+
+ $formatter->setScriptName('test');
+ $this->assertSame("My custom Banner test\nOptions:\n", $formatter->getHelpText(array()));
+ }
+}
diff --git a/test/Ulrichsg/Getopt/GetoptTest.php b/test/Ulrichsg/Getopt/GetoptTest.php
index 0fc13f4..6ea437f 100644
--- a/test/Ulrichsg/Getopt/GetoptTest.php
+++ b/test/Ulrichsg/Getopt/GetoptTest.php
@@ -16,10 +16,10 @@ public function testAddOptions()
)
);
- $getopt->parse('-a aparam -s sparam --long longparam');
- $this->assertEquals('aparam', $getopt->getOption('a'));
- $this->assertEquals('longparam', $getopt->getOption('long'));
- $this->assertEquals('sparam', $getopt->getOption('s'));
+ $result = $getopt->parse('-a aparam -s sparam --long longparam');
+ $this->assertEquals('aparam', $result->getOption('a'));
+ $this->assertEquals('longparam', $result->getOption('long'));
+ $this->assertEquals('sparam', $result->getOption('s'));
}
public function testAddOptionsChooseShortOrLongAutomatically()
@@ -32,9 +32,9 @@ public function testAddOptionsChooseShortOrLongAutomatically()
)
);
- $getopt->parse('-s --long longparam');
- $this->assertEquals('longparam', $getopt->getOption('long'));
- $this->assertEquals('1', $getopt->getOption('s'));
+ $result = $getopt->parse('-s --long longparam');
+ $this->assertEquals('longparam', $result->getOption('long'));
+ $this->assertEquals('1', $result->getOption('s'));
}
public function testAddOptionsUseDefaultArgumentType()
@@ -46,11 +46,11 @@ public function testAddOptionsUseDefaultArgumentType()
)
);
- $getopt->parse('-l something');
- $this->assertEquals('something', $getopt->getOption('l'));
+ $result = $getopt->parse('-l something');
+ $this->assertEquals('something', $result->getOption('l'));
- $getopt->parse('--long someOtherThing');
- $this->assertEquals('someOtherThing', $getopt->getOption('long'));
+ $result = $getopt->parse('--long someOtherThing');
+ $this->assertEquals('someOtherThing', $result->getOption('long'));
}
public function testAddOptionsFailsOnInvalidArgument()
@@ -68,10 +68,10 @@ public function testAddOptionsOverwritesExistingOptions()
$getopt->addOptions(array(
array('a', null, Getopt::NO_ARGUMENT)
));
- $getopt->parse('-a foo');
+ $result = $getopt->parse('-a foo');
- $this->assertEquals(1, $getopt->getOption('a'));
- $this->assertEquals('foo', $getopt->getOperand(0));
+ $this->assertEquals(1, $result->getOption('a'));
+ $this->assertEquals('foo', $result->getOperand(0));
}
public function testAddOptionsFailsOnConflict()
@@ -91,51 +91,8 @@ public function testParseUsesGlobalArgvWhenNoneGiven()
$argv = array('foo.php', '-a');
$getopt = new Getopt('a');
- $getopt->parse();
- $this->assertEquals(1, $getopt->getOption('a'));
- }
-
- public function testAccessMethods()
- {
- $getopt = new Getopt('a');
- $getopt->parse('-a foo');
-
- $options = $getopt->getOptions();
- $this->assertCount(1, $options);
- $this->assertEquals(1, $options['a']);
- $this->assertEquals(1, $getopt->getOption('a'));
-
- $operands = $getopt->getOperands();
- $this->assertCount(1, $operands);
- $this->assertEquals('foo', $operands[0]);
- $this->assertEquals('foo', $getopt->getOperand(0));
- }
-
- public function testCountable()
- {
- $getopt = new Getopt('abc');
- $getopt->parse('-abc');
- $this->assertEquals(3, count($getopt));
- }
-
- public function testArrayAccess()
- {
- $getopt = new Getopt('q');
- $getopt->parse('-q');
- $this->assertEquals(1, $getopt['q']);
- }
-
- public function testIterable()
- {
- $getopt = new Getopt(array(
- array(null, 'alpha', Getopt::NO_ARGUMENT),
- array('b', 'beta', Getopt::REQUIRED_ARGUMENT)
- ));
- $getopt->parse('--alpha -b foo');
- $expected = array('alpha' => 1, 'b' => 'foo'); // 'beta' should not occur
- foreach ($getopt as $option => $value) {
- $this->assertEquals($expected[$option], $value);
- }
+ $result = $getopt->parse();
+ $this->assertEquals(1, $result->getOption('a'));
}
public function testHelpText()
@@ -157,43 +114,4 @@ public function testHelpText()
$this->assertEquals($expected, $getopt->getHelpText());
}
-
- public function testHelpTextWithoutDescriptions()
- {
- $getopt = new Getopt(array(
- array('a', 'alpha', Getopt::NO_ARGUMENT),
- array(null, 'beta', Getopt::OPTIONAL_ARGUMENT),
- array('c', null, Getopt::REQUIRED_ARGUMENT)
- ));
- $getopt->parse('');
-
- $script = $_SERVER['PHP_SELF'];
-
- $expected = "Usage: $script [options] [operands]\n";
- $expected .= "Options:\n";
- $expected .= " -a, --alpha \n";
- $expected .= " --beta [] \n";
- $expected .= " -c \n";
-
- $this->assertEquals($expected, $getopt->getHelpText());
- }
-
- public function testHelpTextNoParse()
- {
- $getopt = new Getopt();
- $expected = "Usage: [options] [operands]\nOptions:\n";
- $this->assertSame($expected, $getopt->getHelpText());
- }
-
- public function testHelpTextWithCustomBanner()
- {
- $script = $_SERVER['PHP_SELF'];
-
- $getopt = new Getopt();
- $getopt->setBanner("My custom Banner %s\n");
- $this->assertSame("My custom Banner \nOptions:\n", $getopt->getHelpText());
-
- $getopt->parse('');
- $this->assertSame("My custom Banner $script\nOptions:\n", $getopt->getHelpText());
- }
}
diff --git a/test/Ulrichsg/Getopt/Getoptv2Test.php b/test/Ulrichsg/Getopt/Getoptv2Test.php
new file mode 100644
index 0000000..6b07dce
--- /dev/null
+++ b/test/Ulrichsg/Getopt/Getoptv2Test.php
@@ -0,0 +1,49 @@
+parse('-a foo');
+
+ $options = $getopt->getOptions();
+ $this->assertCount(1, $options);
+ $this->assertEquals(1, $options['a']);
+ $this->assertEquals(1, $getopt->getOption('a'));
+
+ $operands = $getopt->getOperands();
+ $this->assertCount(1, $operands);
+ $this->assertEquals('foo', $operands[0]);
+ $this->assertEquals('foo', $getopt->getOperand(0));
+ }
+
+ public function testCountable()
+ {
+ $getopt = new Getoptv2('abc');
+ $getopt->parse('-abc');
+ $this->assertEquals(3, count($getopt));
+ }
+
+ public function testArrayAccess()
+ {
+ $getopt = new Getoptv2('q');
+ $getopt->parse('-q');
+ $this->assertEquals(1, $getopt['q']);
+ }
+
+ public function testIterable()
+ {
+ $getopt = new Getoptv2(array(
+ array(null, 'alpha', Getopt::NO_ARGUMENT),
+ array('b', 'beta', Getopt::REQUIRED_ARGUMENT)
+ ));
+ $getopt->parse('--alpha -b foo');
+ $expected = array('alpha' => 1, 'b' => 'foo'); // 'beta' should not occur
+ foreach ($getopt as $option => $value) {
+ $this->assertEquals($expected[$option], $value);
+ }
+ }
+}
diff --git a/test/Ulrichsg/Getopt/OptionTest.php b/test/Ulrichsg/Getopt/OptionTest.php
index 2c88107..a59d30a 100644
--- a/test/Ulrichsg/Getopt/OptionTest.php
+++ b/test/Ulrichsg/Getopt/OptionTest.php
@@ -11,35 +11,72 @@ public function testConstruct()
$this->assertEquals('az-AZ09_', $option->long());
$this->assertEquals(Getopt::OPTIONAL_ARGUMENT, $option->mode());
}
-
- public function testConstructEmptyOption()
+
+ /** @dataProvider dataConstructFails */
+ public function testConstructFails($short, $long, $mode)
{
$this->setExpectedException('InvalidArgumentException');
- new Option(null, null, Getopt::NO_ARGUMENT);
+ new Option($short, $long, $mode);
+ }
+
+ public function dataConstructFails()
+ {
+ return array(
+ array(null, null, Getopt::NO_ARGUMENT), // long and short are both empty
+ array('?', null, Getopt::NO_ARGUMENT), // short name must be letter or digit
+ array(null, 'öption', Getopt::NO_ARGUMENT), // long name may contain only alphanumeric chars, _ and -
+ array('a', null, 'no_argument'), // invalid type
+ array(null, 'a', Getopt::NO_ARGUMENT) // long name must be at least 2 characters long
+ );
}
- public function testConstructNoLetter()
+ /** @dataProvider dataMatches */
+ public function testMatches(Option $option, $string, $matches)
{
- $this->setExpectedException('InvalidArgumentException');
- new Option('?', null, Getopt::NO_ARGUMENT);
+ $this->assertEquals($matches, $option->matches($string));
}
- public function testConstructInvalidCharacter()
+ public function dataMatches()
{
- $this->setExpectedException('InvalidArgumentException');
- new Option(null, 'öption', Getopt::NO_ARGUMENT);
+ return array(
+ array(new Option('v', null), 'v', true),
+ array(new Option(null, 'verbose'), 'verbose', true),
+ array(new Option(null, 'verbose'), 'v', false),
+ array(new Option('v', 'verbose'), 'v', true)
+ );
}
- public function testConstructInvalidArgumentType()
+ /** @dataProvider dataEquals */
+ public function testEquals(Option $first, Option $second, $equals)
{
- $this->setExpectedException('InvalidArgumentException');
- new Option('a', null, 'no_argument');
+ $this->assertEquals($equals, $first->equals($second));
}
- public function testConstructLongOptionTooShort()
+ public function dataEquals()
{
- $this->setExpectedException('InvalidArgumentException');
- new Option(null, 'a', Getopt::REQUIRED_ARGUMENT);
+ return array(
+ array(new Option('v', null), new Option('v', null), true),
+ array(new Option(null, 'verbose'), new Option(null, 'verbose'), true),
+ array(new Option('v', 'verbose'), new Option('v', 'verbose'), true),
+ array(new Option('v', 'verbose'), new Option('v', 'version'), false),
+ array(new Option('v', 'verbose'), new Option('V', 'verbose'), false)
+ );
+ }
+
+ /** @dataProvider dataConflictsWith */
+ public function testConflictsWith(Option $first, Option $second, $conflict)
+ {
+ $this->assertEquals($conflict, $first->conflictsWith($second));
+ }
+
+ public function dataConflictsWith()
+ {
+ return array(
+ array(new Option('v', 'verbose'), new Option('v', 'version'), true),
+ array(new Option('v', 'verbose'), new Option('v', 'verbose'), false),
+ array(new Option('v', 'verbose'), new Option('v', null), true),
+ array(new Option('v', null), new Option('v', null), false)
+ );
}
public function testSetArgument()
@@ -56,17 +93,17 @@ public function testSetArgumentWrongMode()
$option->setArgument(new Argument());
}
- public function testSetDefaultValue()
- {
- $option = new Option('a', null, Getopt::OPTIONAL_ARGUMENT);
- $this->assertEquals($option, $option->setDefaultValue(10));
- $this->assertEquals(10, $option->getArgument()->getDefaultValue());
- }
+ public function testSetDefaultValue()
+ {
+ $option = new Option('a', null, Getopt::OPTIONAL_ARGUMENT);
+ $this->assertEquals($option, $option->setDefaultValue(10));
+ $this->assertEquals(10, $option->getArgument()->getDefaultValue());
+ }
- public function testSetValidation()
- {
- $option = new Option('a', null, Getopt::OPTIONAL_ARGUMENT);
- $this->assertEquals($option, $option->setValidation('is_numeric'));
- $this->assertTrue($option->getArgument()->hasValidation());
- }
+ public function testSetValidation()
+ {
+ $option = new Option('a', null, Getopt::OPTIONAL_ARGUMENT);
+ $this->assertEquals($option, $option->setValidation('is_numeric'));
+ $this->assertTrue($option->getArgument()->hasValidation());
+ }
}