From c6ce9b43590b1c04a235a6b4750a35f0de8b820e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Haas?= Date: Thu, 17 Nov 2022 08:51:18 +0100 Subject: [PATCH 1/6] Fixes #188 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e2902a8d..b449c84b 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "symfony/process": ">=3.4", "symfony/filesystem": ">=3.4", "symfony/finder": ">=3.4", - "phpcollection/phpcollection": "~0.4|~0.5" + "phpoption/phpoption": "1.*" }, "require-dev": { "php": ">=7.2.0", From e2f57376a76256d827e3799ba2692f926b574858 Mon Sep 17 00:00:00 2001 From: jurgenhaas Date: Thu, 17 Nov 2022 09:12:44 +0100 Subject: [PATCH 2/6] Fixes #188 --- README.md | 6 +- src/GitElephant/Command/BaseCommand.php | 7 +- .../Sequence/AbstractCollection.php | 52 +++ src/GitElephant/Sequence/AbstractSequence.php | 364 ++++++++++++++++++ .../Sequence/CollectionInterface.php | 84 ++++ src/GitElephant/Sequence/Sequence.php | 38 ++ .../Sequence/SequenceInterface.php | 227 +++++++++++ src/GitElephant/Status/Status.php | 18 +- src/GitElephant/Status/StatusIndex.php | 8 +- src/GitElephant/Status/StatusWorkingTree.php | 6 +- 10 files changed, 787 insertions(+), 23 deletions(-) create mode 100644 src/GitElephant/Sequence/AbstractCollection.php create mode 100644 src/GitElephant/Sequence/AbstractSequence.php create mode 100644 src/GitElephant/Sequence/CollectionInterface.php create mode 100644 src/GitElephant/Sequence/Sequence.php create mode 100644 src/GitElephant/Sequence/SequenceInterface.php diff --git a/README.md b/README.md index 5e18ae05..789c5d94 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ If you build a GitElephant\Status\Status class, you will get a nice api for gett $status = $repo->getStatus(); $status = GitElephant\Status\Status::get($repo); // it's the same... -$status->all(); // A PhpCollection of StatusFile objects +$status->all(); // A Sequence of StatusFile objects $status->untracked(); $status->modified(); $status->added(); @@ -168,7 +168,7 @@ $status->renamed(); $status->copied(); ``` -all this methods returns a [PhpCollection](https://github.com/schmittjoh/php-collection) of StatusFile objects +all this methods returns a Sequence of StatusFile objects, credit to [PhpCollection](https://github.com/schmittjoh/php-collection) a StatusFile instance has all the information about the tree node changes. File names (and new file names for renamed objects), index and working tree status, and also a "git style" description like: *added to index* or *deleted in work tree* @@ -354,7 +354,7 @@ Dependencies - [symfony/process](https://packagist.org/packages/symfony/process) - [symfony/filesystem](https://packagist.org/packages/symfony/filesystem) - [symfony/finder](https://packagist.org/packages/symfony/finder) -- [phpcollection/phpcollection](https://github.com/schmittjoh/php-collection) +- [phpoption/phpoption](https://github.com/schmittjoh/php-option) *for tests* diff --git a/src/GitElephant/Command/BaseCommand.php b/src/GitElephant/Command/BaseCommand.php index 9486beaa..f82a5db5 100644 --- a/src/GitElephant/Command/BaseCommand.php +++ b/src/GitElephant/Command/BaseCommand.php @@ -21,7 +21,6 @@ namespace GitElephant\Command; use GitElephant\Repository; -use PhpCollection\Map; /** * BaseCommand @@ -177,7 +176,7 @@ protected function getCommandName(): string /** * Set Configs * - * @param array|Map $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" } + * @param array $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" } */ public function addConfigs($configs): void { @@ -189,7 +188,7 @@ public function addConfigs($configs): void /** * Set global configs * - * @param array|Map $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" } + * @param array $configs the config variable. i.e. { "color.status" => "false", "color.diff" => "true" } */ protected function addGlobalConfigs($configs): void { @@ -203,7 +202,7 @@ protected function addGlobalConfigs($configs): void /** * Set global option * - * @param array|Map $options a global option + * @param array $options a global option */ protected function addGlobalOptions($options): void { diff --git a/src/GitElephant/Sequence/AbstractCollection.php b/src/GitElephant/Sequence/AbstractCollection.php new file mode 100644 index 00000000..a79e7b2f --- /dev/null +++ b/src/GitElephant/Sequence/AbstractCollection.php @@ -0,0 +1,52 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace GitElephant\Sequence; + +use PhpOption\LazyOption; +use PhpOption\Some; +use PhpOption\None; + +abstract class AbstractCollection +{ + public function contains($searchedElem) + { + foreach ($this as $elem) { + if ($elem === $searchedElem) { + return true; + } + } + + return false; + } + + public function find($callable) + { + $self = $this; + + return new LazyOption(function() use ($callable, $self) { + foreach ($self as $elem) { + if (call_user_func($callable, $elem) === true) { + return new Some($elem); + } + } + + return None::create(); + }); + } +} \ No newline at end of file diff --git a/src/GitElephant/Sequence/AbstractSequence.php b/src/GitElephant/Sequence/AbstractSequence.php new file mode 100644 index 00000000..ba7fd8f3 --- /dev/null +++ b/src/GitElephant/Sequence/AbstractSequence.php @@ -0,0 +1,364 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace GitElephant\Sequence; + +use PhpOption\Some; +use PhpOption\None; +use OutOfBoundsException; + +/** + * A sequence with numerically indexed elements. + * + * This is rawly equivalent to an array with only numeric keys. + * There are no restrictions on how many same values may occur in the sequence. + * + * This sequence is mutable. + * + * @author Johannes M. Schmitt + */ +class AbstractSequence extends AbstractCollection implements \IteratorAggregate, SequenceInterface +{ + protected $elements; + + /** + * @param array $elements + */ + public function __construct(array $elements = array()) + { + $this->elements = array_values($elements); + } + + public function addSequence(SequenceInterface $seq) + { + $this->addAll($seq->all()); + } + + public function indexOf($searchedElement) + { + foreach ($this->elements as $i => $element) { + if ($searchedElement === $element) { + return $i; + } + } + + return -1; + } + + public function lastIndexOf($searchedElement) + { + for ($i=count($this->elements)-1; $i>=0; $i--) { + if ($this->elements[$i] === $searchedElement) { + return $i; + } + } + + return -1; + } + + public function reverse() + { + return $this->createNew(array_reverse($this->elements)); + } + + public function isDefinedAt($index) + { + return isset($this->elements[$index]); + } + + /** + * Returns a filtered sequence. + * + * @param callable $callable receives the element and must return true (= keep) or false (= remove). + * + * @return AbstractSequence + */ + public function filter($callable) + { + return $this->filterInternal($callable, true); + } + + public function map($callable) + { + $newElements = array(); + foreach ($this->elements as $i => $element) { + $newElements[$i] = $callable($element); + } + + return $this->createNew($newElements); + } + + /** + * Returns a filtered sequence. + * + * @param callable $callable receives the element and must return true (= remove) or false (= keep). + * + * @return AbstractSequence + */ + public function filterNot($callable) + { + return $this->filterInternal($callable, false); + } + + private function filterInternal($callable, $booleanKeep) + { + $newElements = array(); + foreach ($this->elements as $element) { + if ($booleanKeep !== call_user_func($callable, $element)) { + continue; + } + + $newElements[] = $element; + } + + return $this->createNew($newElements); + } + + public function foldLeft($initialValue, $callable) + { + $value = $initialValue; + foreach ($this->elements as $elem) { + $value = call_user_func($callable, $value, $elem); + } + + return $value; + } + + public function foldRight($initialValue, $callable) + { + $value = $initialValue; + foreach (array_reverse($this->elements) as $elem) { + $value = call_user_func($callable, $elem, $value); + } + + return $value; + } + + /** + * Finds the first index where the given callable returns true. + * + * @param callable $callable + * + * @return integer the index, or -1 if the predicate is not true for any element. + */ + public function indexWhere($callable) + { + foreach ($this->elements as $i => $element) { + if (call_user_func($callable, $element) === true) { + return $i; + } + } + + return -1; + } + + public function lastIndexWhere($callable) + { + for ($i=count($this->elements)-1; $i>=0; $i--) { + if (call_user_func($callable, $this->elements[$i]) === true) { + return $i; + } + } + + return -1; + } + + public function last() + { + if (empty($this->elements)) { + return None::create(); + } + + return new Some(end($this->elements)); + } + + public function first() + { + if (empty($this->elements)) { + return None::create(); + } + + return new Some(reset($this->elements)); + } + + public function indices() + { + return array_keys($this->elements); + } + + /** + * Returns an element based on its index (0-based). + * + * @param integer $index + * + * @return T + */ + public function get($index) + { + if ( ! isset($this->elements[$index])) { + throw new OutOfBoundsException(sprintf('The index "%s" does not exist in this sequence.', $index)); + } + + return $this->elements[$index]; + } + + /** + * Removes the element at the given index, and returns it. + * + * @param int $index + * + * @return T + * + * @throws \OutOfBoundsException If there is no element at the given index. + */ + public function remove($index) + { + if ( ! isset($this->elements[$index])) { + throw new OutOfBoundsException(sprintf('The index "%d" is not in the interval [0, %d).', $index, count($this->elements))); + } + + $element = $this->elements[$index]; + unset($this->elements[$index]); + $this->elements = array_values($this->elements); + + return $element; + } + + /** + * Updates the element at the given index (0-based). + * + * @param integer $index + * @param T $value + */ + public function update($index, $value) + { + if ( ! isset($this->elements[$index])) { + throw new \InvalidArgumentException(sprintf('There is no element at index "%d".', $index)); + } + + $this->elements[$index] = $value; + } + + public function isEmpty() + { + return empty($this->elements); + } + + public function all() + { + return $this->elements; + } + + public function add($newElement) + { + $this->elements[] = $newElement; + } + + public function addAll(array $addedElements) + { + foreach ($addedElements as $newElement) { + $this->elements[] = $newElement; + } + } + + public function take($number) + { + if ($number <= 0) { + throw new \InvalidArgumentException(sprintf('$number must be greater than 0, but got %d.', $number)); + } + + return $this->createNew(array_slice($this->elements, 0, $number)); + } + + /** + * Extracts element from the head while the passed callable returns true. + * + * @param callable $callable receives elements of this sequence as first argument, and returns true/false. + * + * @return Sequence + */ + public function takeWhile($callable) + { + $newElements = array(); + + for ($i=0,$c=count($this->elements); $i<$c; $i++) { + if (call_user_func($callable, $this->elements[$i]) !== true) { + break; + } + + $newElements[] = $this->elements[$i]; + } + + return $this->createNew($newElements); + } + + public function drop($number) + { + if ($number <= 0) { + throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); + } + + return $this->createNew(array_slice($this->elements, $number)); + } + + public function dropRight($number) + { + if ($number <= 0) { + throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); + } + + return $this->createNew(array_slice($this->elements, 0, -1 * $number)); + } + + public function dropWhile($callable) + { + for ($i=0,$c=count($this->elements); $i<$c; $i++) { + if (true !== call_user_func($callable, $this->elements[$i])) { + break; + } + } + + return $this->createNew(array_slice($this->elements, $i)); + } + + public function exists($callable) + { + foreach ($this as $elem) { + if ($callable($elem) === true) { + return true; + } + } + + return false; + } + + public function count(): int + { + return count($this->elements); + } + + public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->elements ?: []); + } + + protected function createNew(array $elements) + { + return new static($elements); + } +} diff --git a/src/GitElephant/Sequence/CollectionInterface.php b/src/GitElephant/Sequence/CollectionInterface.php new file mode 100644 index 00000000..c14dc165 --- /dev/null +++ b/src/GitElephant/Sequence/CollectionInterface.php @@ -0,0 +1,84 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace GitElephant\Sequence; + +/** + * Basic interface which adds some behaviors, and a few methods common to all collections. + * + * @author Johannes M. Schmitt + */ +interface CollectionInterface extends \Traversable, \Countable +{ + /** + * Returns whether this collection contains the passed element. + * + * @param mixed $elem + * + * @return boolean + */ + public function contains($elem); + + /** + * Returns whether the collection is empty. + * + * @return boolean + */ + public function isEmpty(); + + /** + * Returns a filtered collection of the same type. + * + * Removes all elements for which the provided callable returns false. + * + * @param callable $callable receives an element of the collection and must return true (= keep) or false (= remove). + * + * @return CollectionInterface + */ + public function filter($callable); + + /** + * Returns a filtered collection of the same type. + * + * Removes all elements for which the provided callable returns true. + * + * @param callable $callable receives an element of the collection and must return true (= remove) or false (= keep). + * + * @return CollectionInterface + */ + public function filterNot($callable); + + /** + * Applies the callable to an initial value and each element, going left to right. + * + * @param mixed $initialValue + * @param callable $callable receives the current value (the first time this equals $initialValue) and the element + * + * @return mixed the last value returned by $callable, or $initialValue if collection is empty. + */ + public function foldLeft($initialValue, $callable); + + /** + * Applies the callable to each element, and an initial value, going right to left. + * + * @param mixed $initialValue + * @param callable $callable receives the element, and the current value (the first time this equals $initialValue). + * @return mixed the last value returned by $callable, or $initialValue if collection is empty. + */ + public function foldRight($initialValue, $callable); +} \ No newline at end of file diff --git a/src/GitElephant/Sequence/Sequence.php b/src/GitElephant/Sequence/Sequence.php new file mode 100644 index 00000000..26229a0b --- /dev/null +++ b/src/GitElephant/Sequence/Sequence.php @@ -0,0 +1,38 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace GitElephant\Sequence; + +/** + * Unsorted sequence implementation. + * + * Characteristics: + * + * - Keys: consequentially numbered, without gaps + * - Values: anything, duplicates allowed + * - Ordering: same as input unless when explicitly sorted + * + * @author Johannes M. Schmitt + */ +class Sequence extends AbstractSequence implements SortableInterface +{ + public function sortWith($callable) + { + usort($this->elements, $callable); + } +} diff --git a/src/GitElephant/Sequence/SequenceInterface.php b/src/GitElephant/Sequence/SequenceInterface.php new file mode 100644 index 00000000..12daea76 --- /dev/null +++ b/src/GitElephant/Sequence/SequenceInterface.php @@ -0,0 +1,227 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace GitElephant\Sequence; + +use PhpOption\Option; + +/** + * Interface for mutable sequences. + * + * Equality of elements in the sequence is established via a shallow comparison (===). + * + * @author Johannes M. Schmitt + */ +interface SequenceInterface extends CollectionInterface +{ + /** + * Returns the first element in the collection if available. + * + * @return Option + */ + public function first(); + + /** + * Returns the last element in the collection if available. + * + * @return Option + */ + public function last(); + + /** + * Returns all elements in this sequence. + * + * @return array + */ + public function all(); + + /** + * Returns a new Sequence with all elements in reverse order. + * + * @return SequenceInterface + */ + public function reverse(); + + /** + * Adds the elements of another sequence to this sequence. + * + * @param SequenceInterface $seq + * + * @return SequenceInterface + */ + public function addSequence(SequenceInterface $seq); + + /** + * Returns the index of the passed element. + * + * @param mixed $elem + * + * @return integer the index (0-based), or -1 if not found + */ + public function indexOf($elem); + + /** + * Returns the last index of the passed element. + * + * @param mixed $elem + * @return integer the index (0-based), or -1 if not found + */ + public function lastIndexOf($elem); + + /** + * Returns whether the given index is defined in the sequence. + * + * @param integer $index (0-based) + * @return boolean + */ + public function isDefinedAt($index); + + /** + * Returns the first index where the given callable returns true. + * + * @param callable $callable receives the element as first argument, and returns true, or false + * + * @return integer the index (0-based), or -1 if the callable returns false for all elements + */ + public function indexWhere($callable); + + /** + * Returns the last index where the given callable returns true. + * + * @param callable $callable receives the element as first argument, and returns true, or false + * + * @return integer the index (0-based), or -1 if the callable returns false for all elements + */ + public function lastIndexWhere($callable); + + /** + * Returns all indices of this collection. + * + * @return integer[] + */ + public function indices(); + + /** + * Returns the element at the given index. + * + * @param integer $index (0-based) + * + * @return mixed + */ + public function get($index); + + /** + * Adds an element to the sequence. + * + * @param mixed $elem + * + * @return void + */ + public function add($elem); + + /** + * Removes the element at the given index, and returns it. + * + * @param integer $index + * + * @return mixed + */ + public function remove($index); + + /** + * Adds all elements to the sequence. + * + * @param array $elements + * + * @return void + */ + public function addAll(array $elements); + + /** + * Updates the value at the given index. + * + * @param integer $index + * @param mixed $value + * + * @return void + */ + public function update($index, $value); + + /** + * Returns a new sequence by omitting the given number of elements from the beginning. + * + * If the passed number is greater than the available number of elements, all will be removed. + * + * @param integer $number + * + * @return SequenceInterface + */ + public function drop($number); + + /** + * Returns a new sequence by omitting the given number of elements from the end. + * + * If the passed number is greater than the available number of elements, all will be removed. + * + * @param integer $number + * + * @return SequenceInterface + */ + public function dropRight($number); + + /** + * Returns a new sequence by omitting elements from the beginning for as long as the callable returns true. + * + * @param callable $callable Receives the element to drop as first argument, and returns true (drop), or false (stop). + * + * @return SequenceInterface + */ + public function dropWhile($callable); + + /** + * Creates a new collection by taking the given number of elements from the beginning + * of the current collection. + * + * If the passed number is greater than the available number of elements, then all elements + * will be returned as a new collection. + * + * @param integer $number + * + * @return CollectionInterface + */ + public function take($number); + + /** + * Creates a new collection by taking elements from the current collection + * for as long as the callable returns true. + * + * @param callable $callable + * + * @return CollectionInterface + */ + public function takeWhile($callable); + + /** + * Creates a new collection by applying the passed callable to all elements + * of the current collection. + * + * @param callable $callable + * @return CollectionInterface + */ + public function map($callable); +} diff --git a/src/GitElephant/Status/Status.php b/src/GitElephant/Status/Status.php index 157a63c2..0fd7de29 100644 --- a/src/GitElephant/Status/Status.php +++ b/src/GitElephant/Status/Status.php @@ -22,7 +22,7 @@ use GitElephant\Command\MainCommand; use GitElephant\Repository; -use PhpCollection\Sequence; +use GitElephant\Sequence\Sequence; /** * Class Status @@ -81,7 +81,7 @@ private function createFromCommand(): void * * @return Sequence */ - public function all(): \PhpCollection\Sequence + public function all(): \GitElephant\Sequence\Sequence { return new Sequence($this->files); } @@ -91,7 +91,7 @@ public function all(): \PhpCollection\Sequence * * @return Sequence */ - public function untracked(): \PhpCollection\Sequence + public function untracked(): \GitElephant\Sequence\Sequence { return $this->filterByType(StatusFile::UNTRACKED); } @@ -101,7 +101,7 @@ public function untracked(): \PhpCollection\Sequence * * @return Sequence */ - public function modified(): \PhpCollection\Sequence + public function modified(): \GitElephant\Sequence\Sequence { return $this->filterByType(StatusFile::MODIFIED); } @@ -111,7 +111,7 @@ public function modified(): \PhpCollection\Sequence * * @return Sequence */ - public function added(): \PhpCollection\Sequence + public function added(): \GitElephant\Sequence\Sequence { return $this->filterByType(StatusFile::ADDED); } @@ -121,7 +121,7 @@ public function added(): \PhpCollection\Sequence * * @return Sequence */ - public function deleted(): \PhpCollection\Sequence + public function deleted(): \GitElephant\Sequence\Sequence { return $this->filterByType(StatusFile::DELETED); } @@ -131,7 +131,7 @@ public function deleted(): \PhpCollection\Sequence * * @return Sequence */ - public function renamed(): \PhpCollection\Sequence + public function renamed(): \GitElephant\Sequence\Sequence { return $this->filterByType(StatusFile::RENAMED); } @@ -141,7 +141,7 @@ public function renamed(): \PhpCollection\Sequence * * @return Sequence */ - public function copied(): \PhpCollection\Sequence + public function copied(): \GitElephant\Sequence\Sequence { return $this->filterByType(StatusFile::COPIED); } @@ -185,7 +185,7 @@ protected function splitStatusLine(string $line) * * @return Sequence */ - protected function filterByType(string $type): \PhpCollection\Sequence + protected function filterByType(string $type): \GitElephant\Sequence\Sequence { if (!$this->files) { return new Sequence(); diff --git a/src/GitElephant/Status/StatusIndex.php b/src/GitElephant/Status/StatusIndex.php index 99e81a22..b120110b 100644 --- a/src/GitElephant/Status/StatusIndex.php +++ b/src/GitElephant/Status/StatusIndex.php @@ -20,7 +20,7 @@ namespace GitElephant\Status; -use PhpCollection\Sequence; +use GitElephant\Sequence\Sequence; /** * Class StatusIndex @@ -32,7 +32,7 @@ class StatusIndex extends Status /** * @return Sequence */ - public function untracked(): \PhpCollection\Sequence + public function untracked(): \GitElephant\Sequence\Sequence { return new Sequence(); } @@ -42,7 +42,7 @@ public function untracked(): \PhpCollection\Sequence * * @return Sequence */ - public function all(): \PhpCollection\Sequence + public function all(): \GitElephant\Sequence\Sequence { return new Sequence( array_filter( @@ -61,7 +61,7 @@ function (StatusFile $statusFile) { * * @return Sequence */ - protected function filterByType(string $type): \PhpCollection\Sequence + protected function filterByType(string $type): \GitElephant\Sequence\Sequence { if (!$this->files) { return new Sequence(); diff --git a/src/GitElephant/Status/StatusWorkingTree.php b/src/GitElephant/Status/StatusWorkingTree.php index 6a3137cc..bbaa65e6 100644 --- a/src/GitElephant/Status/StatusWorkingTree.php +++ b/src/GitElephant/Status/StatusWorkingTree.php @@ -20,7 +20,7 @@ namespace GitElephant\Status; -use PhpCollection\Sequence; +use GitElephant\Sequence\Sequence; /** * Class StatusWorkingTree @@ -34,7 +34,7 @@ class StatusWorkingTree extends Status * * @return Sequence */ - public function all(): \PhpCollection\Sequence + public function all(): \GitElephant\Sequence\Sequence { return new Sequence( array_filter( @@ -54,7 +54,7 @@ function (StatusFile $statusFile) { * * @return Sequence */ - protected function filterByType(string $type): \PhpCollection\Sequence + protected function filterByType(string $type): \GitElephant\Sequence\Sequence { if (!$this->files) { return new Sequence(); From a66f4c621e33752c793e9e0e5aa2c52f0ef037e6 Mon Sep 17 00:00:00 2001 From: jurgenhaas Date: Thu, 17 Nov 2022 10:21:40 +0100 Subject: [PATCH 3/6] Fixes #188 --- .../Sequence/AbstractCollection.php | 6 ++--- src/GitElephant/Sequence/AbstractSequence.php | 26 +++++++++---------- .../Sequence/CollectionInterface.php | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/GitElephant/Sequence/AbstractCollection.php b/src/GitElephant/Sequence/AbstractCollection.php index a79e7b2f..262aa3de 100644 --- a/src/GitElephant/Sequence/AbstractCollection.php +++ b/src/GitElephant/Sequence/AbstractCollection.php @@ -19,8 +19,8 @@ namespace GitElephant\Sequence; use PhpOption\LazyOption; -use PhpOption\Some; use PhpOption\None; +use PhpOption\Some; abstract class AbstractCollection { @@ -39,7 +39,7 @@ public function find($callable) { $self = $this; - return new LazyOption(function() use ($callable, $self) { + return new LazyOption(function () use ($callable, $self) { foreach ($self as $elem) { if (call_user_func($callable, $elem) === true) { return new Some($elem); @@ -49,4 +49,4 @@ public function find($callable) return None::create(); }); } -} \ No newline at end of file +} diff --git a/src/GitElephant/Sequence/AbstractSequence.php b/src/GitElephant/Sequence/AbstractSequence.php index ba7fd8f3..36fd7dff 100644 --- a/src/GitElephant/Sequence/AbstractSequence.php +++ b/src/GitElephant/Sequence/AbstractSequence.php @@ -18,9 +18,9 @@ namespace GitElephant\Sequence; -use PhpOption\Some; -use PhpOption\None; use OutOfBoundsException; +use PhpOption\None; +use PhpOption\Some; /** * A sequence with numerically indexed elements. @@ -39,7 +39,7 @@ class AbstractSequence extends AbstractCollection implements \IteratorAggregate, /** * @param array $elements */ - public function __construct(array $elements = array()) + public function __construct(array $elements = []) { $this->elements = array_values($elements); } @@ -62,7 +62,7 @@ public function indexOf($searchedElement) public function lastIndexOf($searchedElement) { - for ($i=count($this->elements)-1; $i>=0; $i--) { + for ($i = count($this->elements) - 1; $i >= 0; $i--) { if ($this->elements[$i] === $searchedElement) { return $i; } @@ -95,7 +95,7 @@ public function filter($callable) public function map($callable) { - $newElements = array(); + $newElements = []; foreach ($this->elements as $i => $element) { $newElements[$i] = $callable($element); } @@ -117,7 +117,7 @@ public function filterNot($callable) private function filterInternal($callable, $booleanKeep) { - $newElements = array(); + $newElements = []; foreach ($this->elements as $element) { if ($booleanKeep !== call_user_func($callable, $element)) { continue; @@ -169,7 +169,7 @@ public function indexWhere($callable) public function lastIndexWhere($callable) { - for ($i=count($this->elements)-1; $i>=0; $i--) { + for ($i = count($this->elements) - 1; $i >= 0; $i--) { if (call_user_func($callable, $this->elements[$i]) === true) { return $i; } @@ -210,7 +210,7 @@ public function indices() */ public function get($index) { - if ( ! isset($this->elements[$index])) { + if (!isset($this->elements[$index])) { throw new OutOfBoundsException(sprintf('The index "%s" does not exist in this sequence.', $index)); } @@ -228,7 +228,7 @@ public function get($index) */ public function remove($index) { - if ( ! isset($this->elements[$index])) { + if (!isset($this->elements[$index])) { throw new OutOfBoundsException(sprintf('The index "%d" is not in the interval [0, %d).', $index, count($this->elements))); } @@ -247,7 +247,7 @@ public function remove($index) */ public function update($index, $value) { - if ( ! isset($this->elements[$index])) { + if (!isset($this->elements[$index])) { throw new \InvalidArgumentException(sprintf('There is no element at index "%d".', $index)); } @@ -294,9 +294,9 @@ public function take($number) */ public function takeWhile($callable) { - $newElements = array(); + $newElements = []; - for ($i=0,$c=count($this->elements); $i<$c; $i++) { + for ($i = 0,$c = count($this->elements); $i < $c; $i++) { if (call_user_func($callable, $this->elements[$i]) !== true) { break; } @@ -327,7 +327,7 @@ public function dropRight($number) public function dropWhile($callable) { - for ($i=0,$c=count($this->elements); $i<$c; $i++) { + for ($i = 0,$c = count($this->elements); $i < $c; $i++) { if (true !== call_user_func($callable, $this->elements[$i])) { break; } diff --git a/src/GitElephant/Sequence/CollectionInterface.php b/src/GitElephant/Sequence/CollectionInterface.php index c14dc165..c59e75cc 100644 --- a/src/GitElephant/Sequence/CollectionInterface.php +++ b/src/GitElephant/Sequence/CollectionInterface.php @@ -81,4 +81,4 @@ public function foldLeft($initialValue, $callable); * @return mixed the last value returned by $callable, or $initialValue if collection is empty. */ public function foldRight($initialValue, $callable); -} \ No newline at end of file +} From 6fee2425c2f9258cb6d7c43b701a72b65d8072df Mon Sep 17 00:00:00 2001 From: jurgenhaas Date: Thu, 17 Nov 2022 10:41:44 +0100 Subject: [PATCH 4/6] Fixes #188 --- .../Sequence/AbstractCollection.php | 6 +- src/GitElephant/Sequence/AbstractSequence.php | 103 +++++++++--------- .../Sequence/CollectionInterface.php | 40 ++++--- src/GitElephant/Sequence/Sequence.php | 2 +- .../Sequence/SequenceInterface.php | 88 ++++++++------- .../Sequence/SortableInterface.php | 29 +++++ 6 files changed, 161 insertions(+), 107 deletions(-) create mode 100644 src/GitElephant/Sequence/SortableInterface.php diff --git a/src/GitElephant/Sequence/AbstractCollection.php b/src/GitElephant/Sequence/AbstractCollection.php index 262aa3de..c51cabe4 100644 --- a/src/GitElephant/Sequence/AbstractCollection.php +++ b/src/GitElephant/Sequence/AbstractCollection.php @@ -24,7 +24,7 @@ abstract class AbstractCollection { - public function contains($searchedElem) + public function contains($searchedElem): bool { foreach ($this as $elem) { if ($elem === $searchedElem) { @@ -35,13 +35,13 @@ public function contains($searchedElem) return false; } - public function find($callable) + public function find($callable): LazyOption { $self = $this; return new LazyOption(function () use ($callable, $self) { foreach ($self as $elem) { - if (call_user_func($callable, $elem) === true) { + if ($callable($elem) === true) { return new Some($elem); } } diff --git a/src/GitElephant/Sequence/AbstractSequence.php b/src/GitElephant/Sequence/AbstractSequence.php index 36fd7dff..31e0171f 100644 --- a/src/GitElephant/Sequence/AbstractSequence.php +++ b/src/GitElephant/Sequence/AbstractSequence.php @@ -49,10 +49,10 @@ public function addSequence(SequenceInterface $seq) $this->addAll($seq->all()); } - public function indexOf($searchedElement) + public function indexOf($elem) { foreach ($this->elements as $i => $element) { - if ($searchedElement === $element) { + if ($elem === $element) { return $i; } } @@ -60,10 +60,10 @@ public function indexOf($searchedElement) return -1; } - public function lastIndexOf($searchedElement) + public function lastIndexOf($elem): int { for ($i = count($this->elements) - 1; $i >= 0; $i--) { - if ($this->elements[$i] === $searchedElement) { + if ($this->elements[$i] === $elem) { return $i; } } @@ -71,12 +71,12 @@ public function lastIndexOf($searchedElement) return -1; } - public function reverse() + public function reverse(): CollectionInterface { return $this->createNew(array_reverse($this->elements)); } - public function isDefinedAt($index) + public function isDefinedAt(int $index): bool { return isset($this->elements[$index]); } @@ -84,16 +84,17 @@ public function isDefinedAt($index) /** * Returns a filtered sequence. * - * @param callable $callable receives the element and must return true (= keep) or false (= remove). + * @param callable $callable receives the element and must return true (= + * keep) or false (= remove). * - * @return AbstractSequence + * @return CollectionInterface */ - public function filter($callable) + public function filter(callable $callable): CollectionInterface { return $this->filterInternal($callable, true); } - public function map($callable) + public function map(callable $callable): CollectionInterface { $newElements = []; foreach ($this->elements as $i => $element) { @@ -106,20 +107,21 @@ public function map($callable) /** * Returns a filtered sequence. * - * @param callable $callable receives the element and must return true (= remove) or false (= keep). + * @param callable $callable receives the element and must return true (= + * remove) or false (= keep). * - * @return AbstractSequence + * @return CollectionInterface */ - public function filterNot($callable) + public function filterNot(callable $callable): CollectionInterface { return $this->filterInternal($callable, false); } - private function filterInternal($callable, $booleanKeep) + private function filterInternal($callable, $booleanKeep): CollectionInterface { $newElements = []; foreach ($this->elements as $element) { - if ($booleanKeep !== call_user_func($callable, $element)) { + if ($booleanKeep !== $callable($element)) { continue; } @@ -133,7 +135,7 @@ public function foldLeft($initialValue, $callable) { $value = $initialValue; foreach ($this->elements as $elem) { - $value = call_user_func($callable, $value, $elem); + $value = $callable($value, $elem); } return $value; @@ -143,7 +145,7 @@ public function foldRight($initialValue, $callable) { $value = $initialValue; foreach (array_reverse($this->elements) as $elem) { - $value = call_user_func($callable, $elem, $value); + $value = $callable($elem, $value); } return $value; @@ -154,12 +156,13 @@ public function foldRight($initialValue, $callable) * * @param callable $callable * - * @return integer the index, or -1 if the predicate is not true for any element. + * @return integer the index, or -1 if the predicate is not true for any + * element. */ - public function indexWhere($callable) + public function indexWhere(callable $callable): int { foreach ($this->elements as $i => $element) { - if (call_user_func($callable, $element) === true) { + if ($callable($element) === true) { return $i; } } @@ -167,10 +170,10 @@ public function indexWhere($callable) return -1; } - public function lastIndexWhere($callable) + public function lastIndexWhere(callable $callable): int { for ($i = count($this->elements) - 1; $i >= 0; $i--) { - if (call_user_func($callable, $this->elements[$i]) === true) { + if ($callable($this->elements[$i]) === true) { return $i; } } @@ -196,7 +199,7 @@ public function first() return new Some(reset($this->elements)); } - public function indices() + public function indices(): array { return array_keys($this->elements); } @@ -205,10 +208,8 @@ public function indices() * Returns an element based on its index (0-based). * * @param integer $index - * - * @return T */ - public function get($index) + public function get(int $index) { if (!isset($this->elements[$index])) { throw new OutOfBoundsException(sprintf('The index "%s" does not exist in this sequence.', $index)); @@ -222,11 +223,9 @@ public function get($index) * * @param int $index * - * @return T - * * @throws \OutOfBoundsException If there is no element at the given index. */ - public function remove($index) + public function remove(int $index) { if (!isset($this->elements[$index])) { throw new OutOfBoundsException(sprintf('The index "%d" is not in the interval [0, %d).', $index, count($this->elements))); @@ -243,9 +242,9 @@ public function remove($index) * Updates the element at the given index (0-based). * * @param integer $index - * @param T $value + * @param mixed $value */ - public function update($index, $value) + public function update(int $index, $value): void { if (!isset($this->elements[$index])) { throw new \InvalidArgumentException(sprintf('There is no element at index "%d".', $index)); @@ -254,29 +253,29 @@ public function update($index, $value) $this->elements[$index] = $value; } - public function isEmpty() + public function isEmpty(): bool { return empty($this->elements); } - public function all() + public function all(): array { return $this->elements; } - public function add($newElement) + public function add($elem): void { - $this->elements[] = $newElement; + $this->elements[] = $elem; } - public function addAll(array $addedElements) + public function addAll(array $elements): void { - foreach ($addedElements as $newElement) { + foreach ($elements as $newElement) { $this->elements[] = $newElement; } } - public function take($number) + public function take(int $number): CollectionInterface { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('$number must be greater than 0, but got %d.', $number)); @@ -288,26 +287,27 @@ public function take($number) /** * Extracts element from the head while the passed callable returns true. * - * @param callable $callable receives elements of this sequence as first argument, and returns true/false. + * @param callable $callable receives elements of this sequence as first + * argument, and returns true/false. * - * @return Sequence + * @return CollectionInterface */ - public function takeWhile($callable) + public function takeWhile(callable $callable): CollectionInterface { $newElements = []; - for ($i = 0,$c = count($this->elements); $i < $c; $i++) { - if (call_user_func($callable, $this->elements[$i]) !== true) { + foreach ($this->elements as $i => $iValue) { + if ($callable($this->elements[$i]) !== true) { break; } - $newElements[] = $this->elements[$i]; + $newElements[] = $iValue; } return $this->createNew($newElements); } - public function drop($number) + public function drop(int $number): CollectionInterface { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); @@ -316,7 +316,7 @@ public function drop($number) return $this->createNew(array_slice($this->elements, $number)); } - public function dropRight($number) + public function dropRight(int $number): CollectionInterface { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); @@ -325,10 +325,11 @@ public function dropRight($number) return $this->createNew(array_slice($this->elements, 0, -1 * $number)); } - public function dropWhile($callable) + public function dropWhile(callable $callable): CollectionInterface { - for ($i = 0,$c = count($this->elements); $i < $c; $i++) { - if (true !== call_user_func($callable, $this->elements[$i])) { + $i = 0; + foreach ($this->elements as $i => $iValue) { + if (true !== $callable($this->elements[$i])) { break; } } @@ -336,7 +337,7 @@ public function dropWhile($callable) return $this->createNew(array_slice($this->elements, $i)); } - public function exists($callable) + public function exists($callable): bool { foreach ($this as $elem) { if ($callable($elem) === true) { @@ -357,7 +358,7 @@ public function getIterator(): \ArrayIterator return new \ArrayIterator($this->elements ?: []); } - protected function createNew(array $elements) + protected function createNew(array $elements): CollectionInterface { return new static($elements); } diff --git a/src/GitElephant/Sequence/CollectionInterface.php b/src/GitElephant/Sequence/CollectionInterface.php index c59e75cc..721aaa04 100644 --- a/src/GitElephant/Sequence/CollectionInterface.php +++ b/src/GitElephant/Sequence/CollectionInterface.php @@ -19,7 +19,8 @@ namespace GitElephant\Sequence; /** - * Basic interface which adds some behaviors, and a few methods common to all collections. + * Basic interface which adds some behaviors, and a few methods common to all + * collections. * * @author Johannes M. Schmitt */ @@ -32,53 +33,62 @@ interface CollectionInterface extends \Traversable, \Countable * * @return boolean */ - public function contains($elem); + public function contains($elem): bool; /** * Returns whether the collection is empty. * * @return boolean */ - public function isEmpty(); + public function isEmpty(): bool; /** * Returns a filtered collection of the same type. * * Removes all elements for which the provided callable returns false. * - * @param callable $callable receives an element of the collection and must return true (= keep) or false (= remove). + * @param callable $callable receives an element of the collection and must + * return true (= keep) or false (= remove). * * @return CollectionInterface */ - public function filter($callable); + public function filter(callable $callable): CollectionInterface; /** * Returns a filtered collection of the same type. * * Removes all elements for which the provided callable returns true. * - * @param callable $callable receives an element of the collection and must return true (= remove) or false (= keep). + * @param callable $callable receives an element of the collection and must + * return true (= remove) or false (= keep). * * @return CollectionInterface */ - public function filterNot($callable); + public function filterNot(callable $callable): CollectionInterface; /** - * Applies the callable to an initial value and each element, going left to right. + * Applies the callable to an initial value and each element, going left to + * right. * * @param mixed $initialValue - * @param callable $callable receives the current value (the first time this equals $initialValue) and the element + * @param callable $callable receives the current value (the first time this + * equals $initialValue) and the element * - * @return mixed the last value returned by $callable, or $initialValue if collection is empty. + * @return mixed the last value returned by $callable, or $initialValue if + * collection is empty. */ - public function foldLeft($initialValue, $callable); + public function foldLeft($initialValue, callable $callable); /** - * Applies the callable to each element, and an initial value, going right to left. + * Applies the callable to each element, and an initial value, going right to + * left. * * @param mixed $initialValue - * @param callable $callable receives the element, and the current value (the first time this equals $initialValue). - * @return mixed the last value returned by $callable, or $initialValue if collection is empty. + * @param callable $callable receives the element, and the current value (the + * first time this equals $initialValue). + * + * @return mixed the last value returned by $callable, or $initialValue if + * collection is empty. */ - public function foldRight($initialValue, $callable); + public function foldRight($initialValue, callable $callable); } diff --git a/src/GitElephant/Sequence/Sequence.php b/src/GitElephant/Sequence/Sequence.php index 26229a0b..905bbd7e 100644 --- a/src/GitElephant/Sequence/Sequence.php +++ b/src/GitElephant/Sequence/Sequence.php @@ -31,7 +31,7 @@ */ class Sequence extends AbstractSequence implements SortableInterface { - public function sortWith($callable) + public function sortWith($callable): void { usort($this->elements, $callable); } diff --git a/src/GitElephant/Sequence/SequenceInterface.php b/src/GitElephant/Sequence/SequenceInterface.php index 12daea76..6ea23da0 100644 --- a/src/GitElephant/Sequence/SequenceInterface.php +++ b/src/GitElephant/Sequence/SequenceInterface.php @@ -23,7 +23,8 @@ /** * Interface for mutable sequences. * - * Equality of elements in the sequence is established via a shallow comparison (===). + * Equality of elements in the sequence is established via a shallow comparison + * (===). * * @author Johannes M. Schmitt */ @@ -34,28 +35,28 @@ interface SequenceInterface extends CollectionInterface * * @return Option */ - public function first(); + public function first(): Option; /** * Returns the last element in the collection if available. * * @return Option */ - public function last(); + public function last(): Option; /** * Returns all elements in this sequence. * * @return array */ - public function all(); + public function all(): array; /** * Returns a new Sequence with all elements in reverse order. * * @return SequenceInterface */ - public function reverse(); + public function reverse(): SequenceInterface; /** * Adds the elements of another sequence to this sequence. @@ -64,7 +65,7 @@ public function reverse(); * * @return SequenceInterface */ - public function addSequence(SequenceInterface $seq); + public function addSequence(SequenceInterface $seq): SequenceInterface; /** * Returns the index of the passed element. @@ -73,48 +74,54 @@ public function addSequence(SequenceInterface $seq); * * @return integer the index (0-based), or -1 if not found */ - public function indexOf($elem); + public function indexOf($elem): int; /** * Returns the last index of the passed element. * * @param mixed $elem + * * @return integer the index (0-based), or -1 if not found */ - public function lastIndexOf($elem); + public function lastIndexOf($elem): int; /** * Returns whether the given index is defined in the sequence. * * @param integer $index (0-based) + * * @return boolean */ - public function isDefinedAt($index); + public function isDefinedAt(int $index): bool; /** * Returns the first index where the given callable returns true. * - * @param callable $callable receives the element as first argument, and returns true, or false + * @param callable $callable receives the element as first argument, and + * returns true, or false * - * @return integer the index (0-based), or -1 if the callable returns false for all elements + * @return integer the index (0-based), or -1 if the callable returns false + * for all elements */ - public function indexWhere($callable); + public function indexWhere(callable $callable): int; /** * Returns the last index where the given callable returns true. * - * @param callable $callable receives the element as first argument, and returns true, or false + * @param callable $callable receives the element as first argument, and + * returns true, or false * - * @return integer the index (0-based), or -1 if the callable returns false for all elements + * @return integer the index (0-based), or -1 if the callable returns false + * for all elements */ - public function lastIndexWhere($callable); + public function lastIndexWhere(callable $callable): int; /** * Returns all indices of this collection. * * @return integer[] */ - public function indices(); + public function indices(): array; /** * Returns the element at the given index. @@ -123,7 +130,7 @@ public function indices(); * * @return mixed */ - public function get($index); + public function get(int $index); /** * Adds an element to the sequence. @@ -132,7 +139,7 @@ public function get($index); * * @return void */ - public function add($elem); + public function add($elem): void; /** * Removes the element at the given index, and returns it. @@ -141,7 +148,7 @@ public function add($elem); * * @return mixed */ - public function remove($index); + public function remove(int $index); /** * Adds all elements to the sequence. @@ -150,7 +157,7 @@ public function remove($index); * * @return void */ - public function addAll(array $elements); + public function addAll(array $elements): void; /** * Updates the value at the given index. @@ -160,51 +167,57 @@ public function addAll(array $elements); * * @return void */ - public function update($index, $value); + public function update(int $index, $value): void; /** - * Returns a new sequence by omitting the given number of elements from the beginning. + * Returns a new sequence by omitting the given number of elements from the + * beginning. * - * If the passed number is greater than the available number of elements, all will be removed. + * If the passed number is greater than the available number of elements, all + * will be removed. * * @param integer $number * * @return SequenceInterface */ - public function drop($number); + public function drop(int $number): SequenceInterface; /** - * Returns a new sequence by omitting the given number of elements from the end. + * Returns a new sequence by omitting the given number of elements from the + * end. * - * If the passed number is greater than the available number of elements, all will be removed. + * If the passed number is greater than the available number of elements, all + * will be removed. * * @param integer $number * * @return SequenceInterface */ - public function dropRight($number); + public function dropRight(int $number): SequenceInterface; /** - * Returns a new sequence by omitting elements from the beginning for as long as the callable returns true. + * Returns a new sequence by omitting elements from the beginning for as long + * as the callable returns true. * - * @param callable $callable Receives the element to drop as first argument, and returns true (drop), or false (stop). + * @param callable $callable Receives the element to drop as first argument, + * and returns true (drop), or false (stop). * * @return SequenceInterface */ - public function dropWhile($callable); + public function dropWhile(callable $callable): SequenceInterface; /** - * Creates a new collection by taking the given number of elements from the beginning - * of the current collection. + * Creates a new collection by taking the given number of elements from the + * beginning of the current collection. * - * If the passed number is greater than the available number of elements, then all elements - * will be returned as a new collection. + * If the passed number is greater than the available number of elements, + * then all elements will be returned as a new collection. * * @param integer $number * * @return CollectionInterface */ - public function take($number); + public function take(int $number): CollectionInterface; /** * Creates a new collection by taking elements from the current collection @@ -214,14 +227,15 @@ public function take($number); * * @return CollectionInterface */ - public function takeWhile($callable); + public function takeWhile(callable $callable): CollectionInterface; /** * Creates a new collection by applying the passed callable to all elements * of the current collection. * * @param callable $callable + * * @return CollectionInterface */ - public function map($callable); + public function map(callable $callable): CollectionInterface; } diff --git a/src/GitElephant/Sequence/SortableInterface.php b/src/GitElephant/Sequence/SortableInterface.php new file mode 100644 index 00000000..53f9236e --- /dev/null +++ b/src/GitElephant/Sequence/SortableInterface.php @@ -0,0 +1,29 @@ + + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace GitElephant\Sequence; + +/** + * Interface for sortable collections. + * + * @author Johannes M. Schmitt + */ +interface SortableInterface +{ + public function sortWith($callable); +} From 801a19542ccaeb3b908b3419c05a30bbb30368f6 Mon Sep 17 00:00:00 2001 From: jurgenhaas Date: Thu, 17 Nov 2022 10:53:50 +0100 Subject: [PATCH 5/6] Fixes #188 --- src/GitElephant/Sequence/AbstractSequence.php | 38 ++++++------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/GitElephant/Sequence/AbstractSequence.php b/src/GitElephant/Sequence/AbstractSequence.php index 31e0171f..31533cfb 100644 --- a/src/GitElephant/Sequence/AbstractSequence.php +++ b/src/GitElephant/Sequence/AbstractSequence.php @@ -20,6 +20,7 @@ use OutOfBoundsException; use PhpOption\None; +use PhpOption\Option; use PhpOption\Some; /** @@ -44,12 +45,13 @@ public function __construct(array $elements = []) $this->elements = array_values($elements); } - public function addSequence(SequenceInterface $seq) + public function addSequence(SequenceInterface $seq): SequenceInterface { $this->addAll($seq->all()); + return $this; } - public function indexOf($elem) + public function indexOf($elem): int { foreach ($this->elements as $i => $element) { if ($elem === $element) { @@ -71,7 +73,7 @@ public function lastIndexOf($elem): int return -1; } - public function reverse(): CollectionInterface + public function reverse(): SequenceInterface { return $this->createNew(array_reverse($this->elements)); } @@ -181,7 +183,7 @@ public function lastIndexWhere(callable $callable): int return -1; } - public function last() + public function last(): Option { if (empty($this->elements)) { return None::create(); @@ -190,7 +192,7 @@ public function last() return new Some(end($this->elements)); } - public function first() + public function first(): Option { if (empty($this->elements)) { return None::create(); @@ -204,11 +206,6 @@ public function indices(): array return array_keys($this->elements); } - /** - * Returns an element based on its index (0-based). - * - * @param integer $index - */ public function get(int $index) { if (!isset($this->elements[$index])) { @@ -218,13 +215,6 @@ public function get(int $index) return $this->elements[$index]; } - /** - * Removes the element at the given index, and returns it. - * - * @param int $index - * - * @throws \OutOfBoundsException If there is no element at the given index. - */ public function remove(int $index) { if (!isset($this->elements[$index])) { @@ -238,12 +228,6 @@ public function remove(int $index) return $element; } - /** - * Updates the element at the given index (0-based). - * - * @param integer $index - * @param mixed $value - */ public function update(int $index, $value): void { if (!isset($this->elements[$index])) { @@ -307,7 +291,7 @@ public function takeWhile(callable $callable): CollectionInterface return $this->createNew($newElements); } - public function drop(int $number): CollectionInterface + public function drop(int $number): SequenceInterface { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); @@ -316,7 +300,7 @@ public function drop(int $number): CollectionInterface return $this->createNew(array_slice($this->elements, $number)); } - public function dropRight(int $number): CollectionInterface + public function dropRight(int $number): SequenceInterface { if ($number <= 0) { throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number)); @@ -325,7 +309,7 @@ public function dropRight(int $number): CollectionInterface return $this->createNew(array_slice($this->elements, 0, -1 * $number)); } - public function dropWhile(callable $callable): CollectionInterface + public function dropWhile(callable $callable): SequenceInterface { $i = 0; foreach ($this->elements as $i => $iValue) { @@ -358,7 +342,7 @@ public function getIterator(): \ArrayIterator return new \ArrayIterator($this->elements ?: []); } - protected function createNew(array $elements): CollectionInterface + protected function createNew(array $elements): SequenceInterface { return new static($elements); } From adee7d9a753cb0e904432137c8ec26ff4232fa70 Mon Sep 17 00:00:00 2001 From: jurgenhaas Date: Thu, 17 Nov 2022 11:09:37 +0100 Subject: [PATCH 6/6] Fixes #188 --- src/GitElephant/Objects/Diff/DiffChunk.php | 8 ++++---- src/GitElephant/Objects/Diff/DiffObject.php | 2 +- src/GitElephant/Sequence/AbstractCollection.php | 14 ++++++++++++-- src/GitElephant/Sequence/AbstractSequence.php | 9 ++++++--- src/GitElephant/Sequence/Sequence.php | 2 +- src/GitElephant/Sequence/SortableInterface.php | 2 +- 6 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/GitElephant/Objects/Diff/DiffChunk.php b/src/GitElephant/Objects/Diff/DiffChunk.php index ed9d974c..d438af56 100644 --- a/src/GitElephant/Objects/Diff/DiffChunk.php +++ b/src/GitElephant/Objects/Diff/DiffChunk.php @@ -133,8 +133,8 @@ private function getLinesNumbers(string $line): void preg_match('/@@ -(.*) \+(.*) @@?(.*)/', $line, $matches); if (!strpos($matches[1], ',')) { // one line - $this->originStartLine = $matches[1]; - $this->originEndLine = $matches[1]; + $this->originStartLine = (int) $matches[1]; + $this->originEndLine = (int) $matches[1]; } else { $this->originStartLine = (int) explode(',', $matches[1])[0]; $this->originEndLine = (int) explode(',', $matches[1])[1]; @@ -142,8 +142,8 @@ private function getLinesNumbers(string $line): void if (!strpos($matches[2], ',')) { // one line - $this->destStartLine = $matches[2]; - $this->destEndLine = $matches[2]; + $this->destStartLine = (int) $matches[2]; + $this->destEndLine = (int) $matches[2]; } else { $this->destStartLine = (int) explode(',', $matches[2])[0]; $this->destEndLine = (int) explode(',', $matches[2])[1]; diff --git a/src/GitElephant/Objects/Diff/DiffObject.php b/src/GitElephant/Objects/Diff/DiffObject.php index 934106cf..3bd48c7c 100644 --- a/src/GitElephant/Objects/Diff/DiffObject.php +++ b/src/GitElephant/Objects/Diff/DiffObject.php @@ -188,7 +188,7 @@ private function findSimilarityIndex(string $line): void { $matches = []; if (preg_match('/^similarity index (.*)\%$/', $line, $matches)) { - $this->similarityIndex = $matches[1]; + $this->similarityIndex = (int) $matches[1]; } } diff --git a/src/GitElephant/Sequence/AbstractCollection.php b/src/GitElephant/Sequence/AbstractCollection.php index c51cabe4..9b8e809d 100644 --- a/src/GitElephant/Sequence/AbstractCollection.php +++ b/src/GitElephant/Sequence/AbstractCollection.php @@ -22,8 +22,13 @@ use PhpOption\None; use PhpOption\Some; -abstract class AbstractCollection +abstract class AbstractCollection implements \IteratorAggregate { + /** + * @param mixed $searchedElem + * + * @return bool + */ public function contains($searchedElem): bool { foreach ($this as $elem) { @@ -35,7 +40,12 @@ public function contains($searchedElem): bool return false; } - public function find($callable): LazyOption + /** + * @param callable $callable + * + * @return \PhpOption\LazyOption + */ + public function find(callable $callable): LazyOption { $self = $this; diff --git a/src/GitElephant/Sequence/AbstractSequence.php b/src/GitElephant/Sequence/AbstractSequence.php index 31533cfb..5d6e3bc3 100644 --- a/src/GitElephant/Sequence/AbstractSequence.php +++ b/src/GitElephant/Sequence/AbstractSequence.php @@ -33,8 +33,11 @@ * * @author Johannes M. Schmitt */ -class AbstractSequence extends AbstractCollection implements \IteratorAggregate, SequenceInterface +class AbstractSequence extends AbstractCollection implements SequenceInterface { + /** + * @var array + */ protected $elements; /** @@ -119,7 +122,7 @@ public function filterNot(callable $callable): CollectionInterface return $this->filterInternal($callable, false); } - private function filterInternal($callable, $booleanKeep): CollectionInterface + private function filterInternal(callable $callable, bool $booleanKeep): CollectionInterface { $newElements = []; foreach ($this->elements as $element) { @@ -321,7 +324,7 @@ public function dropWhile(callable $callable): SequenceInterface return $this->createNew(array_slice($this->elements, $i)); } - public function exists($callable): bool + public function exists(callable $callable): bool { foreach ($this as $elem) { if ($callable($elem) === true) { diff --git a/src/GitElephant/Sequence/Sequence.php b/src/GitElephant/Sequence/Sequence.php index 905bbd7e..e8a055bd 100644 --- a/src/GitElephant/Sequence/Sequence.php +++ b/src/GitElephant/Sequence/Sequence.php @@ -31,7 +31,7 @@ */ class Sequence extends AbstractSequence implements SortableInterface { - public function sortWith($callable): void + public function sortWith(callable $callable): void { usort($this->elements, $callable); } diff --git a/src/GitElephant/Sequence/SortableInterface.php b/src/GitElephant/Sequence/SortableInterface.php index 53f9236e..8f34d849 100644 --- a/src/GitElephant/Sequence/SortableInterface.php +++ b/src/GitElephant/Sequence/SortableInterface.php @@ -25,5 +25,5 @@ */ interface SortableInterface { - public function sortWith($callable); + public function sortWith(callable $callable): void; }