/**
  * write a string to the stream
  *
  * @param  string $data
  * @return void
  */
 public function writeString($data)
 {
     // robustness!
     RequireStringy::check($data, E4xx_UnsupportedType::class);
     // let the StreamHead do all the work :)
     $this->tokeniseAndWriteToStream($data);
 }
 /**
  * throws exceptions if $item is empty
  *
  * this is a wrapper around our IsEmpty check
  *
  * @param  string $itemName
  *         human-readable name of $item
  * @param  mixed $item
  *         the data to check
  * @param  string $exception
  *         the class to use when throwing an exception
  * @return void
  */
 public static function check($itemName, $item, $exception = E4xx_DataCannotBeEmpty::class)
 {
     // robustness!
     RequireStringy::check($itemName);
     // make sure that $item is not empty
     if (IsEmpty::check($item)) {
         throw new $exception($itemName);
     }
 }
 /**
  * throws exceptions if $item is not a PHP class that exists
  *
  * this is a wrapper around our IsObjectOfType check
  *
  * @param  mixed $item
  *         the container to check
  * @param  string $type
  *         the class or interface that we want to check against
  * @param  string $exception
  *         the class to use when throwing an exception
  * @return void
  */
 public static function check($item, $type, $exception = E4xx_UnsupportedType::class)
 {
     // robustness!
     RequireStringy::check($type, $exception);
     // make sure we have a PHP class that exists
     if (!IsObjectOfType::check($item, $type)) {
         throw new $exception(SimpleType::from($item));
     }
 }
 /**
  * is the filename actually a folder?
  *
  * @param  mixed $path
  *         the filename to check
  * @return boolean
  *         TRUE if the filename is a folder
  *         FALSE otherwise
  */
 public static function check($path)
 {
     // defensive programming!!
     RequireStringy::check($path, E4xx_UnsupportedType::class);
     if (!is_dir($path)) {
         return false;
     }
     return true;
 }
 /**
  * throws exceptions if $path is not a valid dot.notation.support path
  *
  * @param  string $path
  *         the path to check
  * @param  string $eUnsupportedType
  *         the class to use when throwing an unsupported-type exception
  * @param  string $eNotDotNotationPath
  *         the class to use when throwing a not-dot-notation-path exception
  * @return void
  */
 public static function check($path, $eUnsupportedType = E4xx_UnsupportedType::class, $eNotDotNotationPath = E4xx_NotDotNotationPath::class)
 {
     // make sure we have a string
     RequireStringy::check($path, $eUnsupportedType);
     // make sure the string contains a dot.notation.support path
     if (!IsDotNotationPath::checkString($path)) {
         throw new $eNotDotNotationPath($path);
     }
 }
 /**
  * extract all but the end of a dot.notation.support string
  *
  * @param  string $dotNotation
  *         the string to extract from
  * @param  int $start
  *         which part do we want to start from?
  * @param  int $len
  *         how many parts do we want?
  * @return string
  *         the extracted parts
  */
 public static function fromString($dotNotation, $start, $len)
 {
     // robustness!
     RequireStringy::check($dotNotation, E4xx_UnsupportedType::class);
     RequireInteger::check($start, E4xx_UnsupportedType::class);
     RequireInteger::check($len, E4xx_UnsupportedType::class);
     $parts = explode(".", (string) $dotNotation);
     $parts = array_slice($parts, (int) $start, (int) $len);
     return implode(".", $parts);
 }
 /**
  * is the path a file on disk?
  *
  * @param  mixed $path
  *         path to the file to check
  * @return boolean
  *         TRUE if the path is a file on disk
  *         FALSE otherwise
  */
 public static function check($path)
 {
     // defensive programming!!
     RequireStringy::check($path, E4xx_UnsupportedType::class);
     if (!is_file($path)) {
         return false;
     }
     // if we get here, then we are happy
     return true;
 }
 /**
  * map a string such as '=' to the appropriate operator
  *
  * @param  string $input
  *         the input to map
  * @return string
  *         the class name of the operator to use
  */
 public static function to($input)
 {
     // robustness!
     RequireStringy::check($input, E4xx_UnsupportedType::class);
     if (!isset(self::$operatorMap[$input])) {
         throw new E4xx_UnknownOperator($input);
     }
     // send back our result
     return self::$operatorMap[$input];
 }
 /**
  * throws exceptions if $item is not a PHP class or interface that exists
  *
  * this is a wrapper around our IsDefinedObjectType check
  *
  * @param  mixed $item
  *         the container to check
  * @param  string $eNoSuchClass
  *         the exception to throw if $item isn't a valid PHP class
  * @param  string $eUnsupportedType
  *         the exception to throw if $item isn't something that we can check
  * @return void
  */
 public static function check($item, $eNoSuchClass = E4xx_NoSuchClass::class, $eUnsupportedType = E4xx_UnsupportedType::class)
 {
     RequireStringy::check($item, $eUnsupportedType);
     if (trait_exists($item)) {
         throw new $eUnsupportedType(SimpleType::from($item));
     }
     // make sure we have a PHP class that exists
     if (!IsDefinedObjectType::check($item)) {
         throw new $eNoSuchClass($item);
     }
 }
 public function __construct($command, $returnCode, $output)
 {
     // robustness!
     RequireTraversable::checkMixed($command, E4xx_UnsupportedType::class);
     RequireNumeric::check($returnCode, E4xx_UnsupportedType::class);
     RequireStringy::checkMixed($output, E4xx_UnsupportedType::class);
     $this->setCommand($command);
     $this->setReturnCode($returnCode);
     $this->setOutput($output);
     // all done
     $this->makeReadOnly();
 }
 /**
  * is $path a file, and can we run it?
  *
  * @param  string $path
  *         the file to check
  * @return void
  *
  * @throws E4xx_InvalidPath
  *         if $path is not a file, or otherwise does not exist
  * @throws E4xx_FileIsNotExecutable
  *         if $path is a file, but we do not have permissions to run it
  */
 public static function check($path)
 {
     // robustness
     RequireStringy::check($path);
     // do we have a file?
     if (!IsFile::check($path)) {
         throw new E4xx_InvalidPath($path);
     }
     // can we read it?
     if (!IsReadableFile::check($path)) {
         throw new E4xx_FileIsNotExecutable($path);
     }
 }
 /**
  * is the filename actually the absolute path to a folder?
  *
  * @param  mixed $filename
  *         the filename to check
  * @return boolean
  *         TRUE if the filename is a folder
  *         FALSE otherwise
  */
 public static function check($filename)
 {
     // defensive programming!
     RequireStringy::check($filename, E4xx_UnsupportedType::class);
     // if it is not a folder, no point in checking any further
     if (!is_dir((string) $filename)) {
         return false;
     }
     // check for absoluteness
     $absDir = BuildAbsolutePath::fromString((string) $filename);
     if ($filename !== $absDir && $filename[0] !== '/') {
         return false;
     }
     // if we get here, we are happy
     return true;
 }
 /**
  * do a very basic comparison of two strings
  *
  * @param  string $a
  *         the lhs string to use
  * @param  string $b
  *         the rhs string to use
  * @return int
  *         CompareTwoNumbers::A_IS_LESS, if $a < $b
  *         CompareTwoNumbers::A_IS_GREATER, if $a > $b
  *         CompareTwoNumbers::BOTH_ARE_EQUAL otherweise
  */
 public static function calculate($a, $b)
 {
     // robustness
     RequireStringy::check($a, E4xx_UnsupportedType::class);
     RequireStringy::check($b, E4xx_UnsupportedType::class);
     // unfortunately, strcmp() doesn't return -1 / 0 / 1
     $res = strcmp($a, $b);
     if ($res < 0) {
         return CompareTwoNumbers::A_IS_LESS;
     } else {
         if ($res > 0) {
             return CompareTwoNumbers::A_IS_GREATER;
         }
     }
     return CompareTwoNumbers::BOTH_ARE_EQUAL;
 }
 /**
  * is the given filename pointing at valid JSON?
  *
  * @param  mixed $path
  *         the filename to inspect
  * @return boolean
  *         TRUE if the file is valid JSON
  *         FALSE otherwise
  */
 public static function check($path)
 {
     // defensive programming!!
     RequireStringy::check($path, E4xx_UnsupportedType::class);
     if (!IsReadableFile::check($path)) {
         return false;
     }
     $contents = file_get_contents($path);
     if (empty($contents)) {
         return false;
     }
     $payload = json_decode($contents);
     if ($payload === null) {
         return false;
     }
     return true;
 }
 /**
  * do we have a dot.notation string at all?
  *
  * @param  string $item
  *         the item to examine
  * @return boolean
  *         TRUE if the string is in dot.notation
  *         FALSE otherwise
  */
 public static function checkString($item)
 {
     // robustness!!
     RequireStringy::check($item, E4xx_UnsupportedType::class);
     // make sure we have a dot somewhere we like
     if (!self::hasDotInAcceptablePlace((string) $item)) {
         return false;
     }
     // if we get here, we're happy
     return true;
 }
 /**
  * turn a single comparison strings into a ComparisonExpression object
  *
  * e.g.
  *
  *     >= 1.0.0
  *     <2.0
  *     !1.5.9
  *     ~1.1
  *
  * @param  string $expression
  *         the string to parse
  * @return ComparisonExpression
  */
 public static function from($expression, $parser)
 {
     // robustness!
     RequireStringy::check($expression, E4xx_UnsupportedType::class);
     // make sense of what we have
     list($operator, $versionString) = self::tokeniseExpression($expression);
     $version = $parser($versionString);
     // send back our result
     return new ComparisonExpression($operator, $version);
 }
 /**
  * filter an array of strings
  *
  * @param  array|Traversable $data
  *         the data to filter
  * @param  string $columnSeparator
  *         the column delimiter
  * @param  array $columnNos
  *         a list of the column numbers we are interested in
  * @return array
  *         the extracted columns
  */
 private static function filterArray($data, $columnSeparator, $columnNos)
 {
     $retval = [];
     foreach ($data as $line) {
         RequireStringy::checkMixed($line, E4xx_UnsupportedType::class);
         $retval[] = self::filterLine($line, $columnSeparator, $columnNos);
     }
     return $retval;
 }
 /**
  * remove leading and trailing whitespace from $data
  *
  * @param  array|Traversable $data
  *         the data that needs trimming
  * @return array
  *         the (possibly) changed $data
  */
 private static function fromArray($data)
 {
     $retval = [];
     foreach ($data as $datum) {
         RequireStringy::check($datum, E4xx_UnsupportedType::class);
         $retval[] = trim($datum);
     }
     return $retval;
 }
 /**
  * @covers ::__construct
  * @covers ::__toString
  * @dataProvider provideVersionNumbers
  */
 public function testCanConvertToString($versionNumber)
 {
     // ----------------------------------------------------------------
     // setup your test
     $obj = new HashedVersion($versionNumber);
     // ----------------------------------------------------------------
     // perform the change
     $actualResult = (string) $obj;
     // ----------------------------------------------------------------
     // test the results
     RequireStringy::check($obj);
     $this->assertTrue(is_string($actualResult));
     $this->assertEquals($versionNumber, $actualResult);
 }
 /**
  * @covers ::check
  * @covers ::checkMixed
  * @dataProvider provideNonStringys
  * @expectedException GanbaroDigital\Reflection\Exceptions\E4xx_UnsupportedType
  */
 public function testRejectsNonStringysWhenCalledStatically($item)
 {
     // ----------------------------------------------------------------
     // setup your test
     // ----------------------------------------------------------------
     // perform the change
     RequireStringy::check($item);
 }
 /**
  * search and replace on data
  *
  * @param  array|Traversable $data
  *         the data to be changed
  * @param  array|string $match
  *         the item(s) to search for
  * @param  array|string $replacement
  *         the item(s) to replace with
  * @return array
  *         the (possibly) changed data
  */
 private static function inArray($data, $match, $replacement)
 {
     $retval = [];
     foreach ($data as $datum) {
         RequireStringy::check($datum, E4xx_UnsupportedType::class);
         $retval[] = str_replace($match, $replacement, $datum);
     }
     return $retval;
 }
 /**
  * convert a string in the form 'X.Y[.Z][-<preRelease>][+R]' into an
  * array of version parts
  *
  * @param  string $versionString
  *         the string to parse
  *
  * @return SemanticVersion
  *
  * @throws E4xx_BadVersionString
  *         if we cannot parse $versionString
  *
  * @throws E4xx_NotAVersionString
  *         if we're asked to parse something that isn't a string
  */
 public static function from($versionString)
 {
     // do we have something we can safely attempt to parse?
     RequireStringy::check($versionString, E4xx_NotAVersionString::class);
     $matches = [];
     if (!preg_match(self::getRegex(), $versionString, $matches)) {
         // if we get here, then nothing matched
         throw new E4xx_BadVersionString($versionString);
     }
     // we need to sanitise the regex result before returning
     // our return value
     $parts = self::cleanupMatches($matches);
     return new SemanticVersion($parts['major'], $parts['minor'], $parts['patchLevel'], $parts['preRelease'], $parts['build']);
 }
 /**
  * search an array for values that do not contain the search string
  *
  * @param  array|Traversable $data
  *         the array to search
  * @param  string $searchString
  *         the string to search for
  * @return array
  *         only those values of $data that do not contain the search string
  */
 private static function matchArray($data, $searchString)
 {
     $retval = [];
     foreach ($data as $line) {
         RequireStringy::checkMixed($line, E4xx_UnsupportedType::class);
         $match = self::matchLine($line, $searchString);
         if (!empty($match)) {
             $retval[] = $match;
         }
     }
     // all done
     return $retval;
 }
 /**
  * is $data compatible with $constraint?
  *
  * @param  string $data
  *         the class name to check
  * @param  string|object $constraint
  *         the class or object that $data must be compatible with
  * @return boolean
  *         TRUE if $data is compatible
  *         FALSE otherwise
  */
 public static function checkString($data, $constraint)
 {
     // defensive programming!
     RequireStringy::check($data, E4xx_UnsupportedType::class);
     RequireAnyOneOf::check([new IsObject(), new IsStringy()], [$constraint], E4xx_UnsupportedType::class);
     $compatibleTypes = AllMatchingTypesList::from($data);
     if (is_object($constraint)) {
         $constraint = get_class($constraint);
     }
     // is our constraint in the list of data types that $data can be?
     if (in_array($constraint, $compatibleTypes)) {
         return true;
     }
     // if we get here, we have run out of ideas
     return false;
 }
 /**
  * turn one or more comparison strings into a VersionRangeList object
  *
  * e.g.
  *
  *     >= 1.0.0, <2.0, !1.5.9
  *     ~1.1
  *
  * @param  string $expression
  *         the string to parse
  * @param  VersionParser $parser
  *         the parser to use on the version numbers
  * @return VersionRange
  */
 public static function from($expression, VersionParser $parser)
 {
     // robustness!
     RequireStringy::check($expression, E4xx_UnsupportedType::class);
     // our final list
     $list = [];
     $parts = explode(",", (string) $expression);
     $parts = FilterOutEmptyValues::from($parts);
     foreach ($parts as $part) {
         $list[] = ParseComparisonExpression::from(trim($part), $parser);
     }
     return new VersionRange($list);
 }
 /**
  * descend inside an object, using dot.notation.support, and optionally
  * extending the object if the end of the dot.notation.path is missing
  *
  * @param  object $obj
  *         the object to dig into
  * @param  string $property
  *         the dot.notation.support path to descend
  * @param  array|callable|string|null $extendingItem
  *         if we need to extend, what data type do we extend using?
  * @return mixed
  */
 public static function &intoObject($obj, $property, $extendingItem = null)
 {
     // robustness!
     RequireAssignable::check($obj, E4xx_UnsupportedType::class);
     RequireStringy::check($property, E4xx_UnsupportedType::class);
     if (strlen($property) === 0) {
         throw new \InvalidArgumentException("'\$property' cannot be empty string");
     }
     $retval =& self::getPathFromRoot($obj, $property, $extendingItem);
     return $retval;
 }
 /**
  * expand a range in the form "n-m"
  *
  * @param  string $data
  *         the range to expand
  * @return array
  *         the values are the range
  */
 public static function fromString($data)
 {
     RequireStringy::checkMixed($data, E4xx_UnsupportedType::class);
     return self::parseString($data);
 }
 /**
  * convert a string in the form '[A-Za-z0-9]{4,}' into an
  * array of version parts
  *
  * @param  string $versionString
  *         the string to parse
  *
  * @return HashedVersion
  *
  * @throws E4xx_BadVersionString
  *         if we cannot parse $versionString
  *
  * @throws E4xx_NotAVersionString
  *         if we're asked to parse something that isn't a string
  */
 public static function from($versionString)
 {
     // do we have something we can safely attempt to parse?
     RequireStringy::check($versionString, E4xx_NotAVersionString::class);
     $matches = [];
     if (!preg_match(self::getRegex(), $versionString, $matches)) {
         // if we get here, then nothing matched
         throw new E4xx_BadVersionString($versionString);
     }
     return new HashedVersion($matches['version']);
 }