From 6e8f1728cee21a682b5950f5f60971b189879fc5 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sat, 15 May 2021 17:45:08 +0200 Subject: [PATCH 1/9] feat: Add Squash operation. --- src/Collection.php | 6 ++++ src/Operation/Squash.php | 72 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 src/Operation/Squash.php diff --git a/src/Collection.php b/src/Collection.php index 4f4807bd6..d1b11ab62 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -100,6 +100,7 @@ use loophp\collection\Operation\Sort; use loophp\collection\Operation\Span; use loophp\collection\Operation\Split; +use loophp\collection\Operation\Squash; use loophp\collection\Operation\Tail; use loophp\collection\Operation\Tails; use loophp\collection\Operation\TakeWhile; @@ -712,6 +713,11 @@ public function split(int $type = Operation\Splitable::BEFORE, callable ...$call return new self(Split::of()($type)(...$callbacks), $this->getIterator()); } + public function squash(bool $throwOnException = true): CollectionInterface + { + return new self(Squash::of()($throwOnException)($this->getIterator()), $this->getIterator()); + } + public function tail(): CollectionInterface { return new self(Tail::of(), $this->getIterator()); diff --git a/src/Operation/Squash.php b/src/Operation/Squash.php new file mode 100644 index 000000000..478f9fa9f --- /dev/null +++ b/src/Operation/Squash.php @@ -0,0 +1,72 @@ +): Closure(Iterator): Iterator + */ + public function __invoke(): Closure + { + return + /** + * @psalm-return Closure(Iterator): Closure(Iterator): Iterator + */ + static function (bool $throwOnException): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Closure(Iterator): Generator + */ + static function (Iterator $iterator) use ($throwOnException): Closure { + // As keys can be of any type in this library.We cannot use + // iterator_to_array() because it expect keys to be int|string. + try { + foreach ($iterator as $key => $value) { + } + } catch (Throwable $e) { + if (true === $throwOnException) { + throw $e; + } + } + + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($throwOnException): Generator { + try { + foreach ($iterator as $key => $value) { + yield $key => $value; + } + } catch (Throwable $e) { + if (true === $throwOnException) { + throw $e; + } + } + }; + }; + }; + } +} From fca446069ad1214141ce5eb2159890c5fafdf9f5 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sat, 15 May 2021 22:55:28 +0200 Subject: [PATCH 2/9] Remove $throwOnException parameter. --- src/Collection.php | 4 ++-- src/Operation/Squash.php | 47 ++++++++++++---------------------------- 2 files changed, 16 insertions(+), 35 deletions(-) diff --git a/src/Collection.php b/src/Collection.php index d1b11ab62..780ef3758 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -713,9 +713,9 @@ public function split(int $type = Operation\Splitable::BEFORE, callable ...$call return new self(Split::of()($type)(...$callbacks), $this->getIterator()); } - public function squash(bool $throwOnException = true): CollectionInterface + public function squash(): CollectionInterface { - return new self(Squash::of()($throwOnException)($this->getIterator()), $this->getIterator()); + return new self(Squash::of()($this->getIterator()), $this->getIterator()); } public function tail(): CollectionInterface diff --git a/src/Operation/Squash.php b/src/Operation/Squash.php index 478f9fa9f..2f89140a6 100644 --- a/src/Operation/Squash.php +++ b/src/Operation/Squash.php @@ -12,7 +12,6 @@ use Closure; use Generator; use Iterator; -use Throwable; /** * @psalm-template TKey @@ -22,50 +21,32 @@ final class Squash extends AbstractOperation { /** - * @psalm-return Closure(bool): Closure(Iterator): Closure(Iterator): Iterator + * @psalm-return Closure(Iterator): Closure(Iterator): Iterator */ public function __invoke(): Closure { return /** - * @psalm-return Closure(Iterator): Closure(Iterator): Iterator + * @psalm-param Iterator $iterator + * + * @psalm-return Closure(Iterator): Generator */ - static function (bool $throwOnException): Closure { + static function (Iterator $iterator): Closure { + // As keys can be of any type in this library.We cannot use + // iterator_to_array() because it expect keys to be int|string. + foreach ($iterator as $key => $value) { + } + return /** * @psalm-param Iterator $iterator * - * @psalm-return Closure(Iterator): Generator + * @psalm-return Generator */ - static function (Iterator $iterator) use ($throwOnException): Closure { - // As keys can be of any type in this library.We cannot use - // iterator_to_array() because it expect keys to be int|string. - try { - foreach ($iterator as $key => $value) { - } - } catch (Throwable $e) { - if (true === $throwOnException) { - throw $e; - } + static function (Iterator $iterator): Generator { + foreach ($iterator as $key => $value) { + yield $key => $value; } - - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator) use ($throwOnException): Generator { - try { - foreach ($iterator as $key => $value) { - yield $key => $value; - } - } catch (Throwable $e) { - if (true === $throwOnException) { - throw $e; - } - } - }; }; }; } From d025eaba1a6986bc036a9095e0025ceee1393efb Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sat, 15 May 2021 22:55:38 +0200 Subject: [PATCH 3/9] Add tests. --- spec/loophp/collection/CollectionSpec.php | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/spec/loophp/collection/CollectionSpec.php b/spec/loophp/collection/CollectionSpec.php index f5e9ea799..117bdddd4 100644 --- a/spec/loophp/collection/CollectionSpec.php +++ b/spec/loophp/collection/CollectionSpec.php @@ -2623,6 +2623,24 @@ public function it_can_split(): void ->shouldIterateAs([[0], [1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]); } + public function it_can_squash(): void + { + $input = [16, 4, -9, 9]; + + $this::fromIterable($input) + ->map( + static function (int $value): int { + if (0 > $value) { + throw new Exception('Error'); + } + + return (int) sqrt($value); + } + ) + ->shouldThrow(Exception::class) + ->during('squash'); + } + public function it_can_tail(): void { $this::fromIterable(range('A', 'F')) @@ -3443,7 +3461,7 @@ public function it_is_initializable(): void $this->shouldHaveType(Collection::class); } - public function let() + public function let(): void { $this->beConstructedThrough('empty'); } From 93f86a7fbcb8c25e862cdc2719dd8b298565ec3b Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sat, 15 May 2021 22:57:28 +0200 Subject: [PATCH 4/9] Add Interfaces. --- src/Contract/Collection.php | 3 +++ src/Contract/Operation/Squashable.php | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/Contract/Operation/Squashable.php diff --git a/src/Contract/Collection.php b/src/Contract/Collection.php index d0e0e07b7..1ff6456f2 100644 --- a/src/Contract/Collection.php +++ b/src/Contract/Collection.php @@ -97,6 +97,7 @@ use loophp\collection\Contract\Operation\Sortable; use loophp\collection\Contract\Operation\Spanable; use loophp\collection\Contract\Operation\Splitable; +use loophp\collection\Contract\Operation\Squashable; use loophp\collection\Contract\Operation\Tailable; use loophp\collection\Contract\Operation\Tailsable; use loophp\collection\Contract\Operation\TakeWhileable; @@ -204,6 +205,7 @@ * @template-extends Sortable * @template-extends Spanable * @template-extends Splitable + * @template-extends Squashable * @template-extends Tailable * @template-extends Tailsable * @template-extends TakeWhileable @@ -311,6 +313,7 @@ interface Collection extends Sortable, Spanable, Splitable, + Squashable, Tailable, Tailsable, TakeWhileable, diff --git a/src/Contract/Operation/Squashable.php b/src/Contract/Operation/Squashable.php new file mode 100644 index 000000000..367e0a264 --- /dev/null +++ b/src/Contract/Operation/Squashable.php @@ -0,0 +1,25 @@ + + */ + public function squash(): Collection; +} From 85899d13ddd72e7e12542960dd868d6812435cc7 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sat, 15 May 2021 23:36:49 +0200 Subject: [PATCH 5/9] Simplify things - there is no need to have an Operation for this. --- src/Collection.php | 2 +- src/Operation/Squash.php | 53 ---------------------------------------- 2 files changed, 1 insertion(+), 54 deletions(-) delete mode 100644 src/Operation/Squash.php diff --git a/src/Collection.php b/src/Collection.php index 780ef3758..f1e878ca6 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -715,7 +715,7 @@ public function split(int $type = Operation\Splitable::BEFORE, callable ...$call public function squash(): CollectionInterface { - return new self(Squash::of()($this->getIterator()), $this->getIterator()); + return self::fromIterable(iterator_to_array($this->pack()))->unpack(); } public function tail(): CollectionInterface diff --git a/src/Operation/Squash.php b/src/Operation/Squash.php deleted file mode 100644 index 2f89140a6..000000000 --- a/src/Operation/Squash.php +++ /dev/null @@ -1,53 +0,0 @@ -): Closure(Iterator): Iterator - */ - public function __invoke(): Closure - { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Closure(Iterator): Generator - */ - static function (Iterator $iterator): Closure { - // As keys can be of any type in this library.We cannot use - // iterator_to_array() because it expect keys to be int|string. - foreach ($iterator as $key => $value) { - } - - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator): Generator { - foreach ($iterator as $key => $value) { - yield $key => $value; - } - }; - }; - } -} From cade3813ad4b284ff1f7ff48152e8cc1771fd42d Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sun, 16 May 2021 07:23:29 +0200 Subject: [PATCH 6/9] Simplify even more. --- src/Collection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Collection.php b/src/Collection.php index f1e878ca6..868a40f83 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -715,7 +715,7 @@ public function split(int $type = Operation\Splitable::BEFORE, callable ...$call public function squash(): CollectionInterface { - return self::fromIterable(iterator_to_array($this->pack()))->unpack(); + return self::fromIterable($this->pack()->all())->unpack(); } public function tail(): CollectionInterface From b9f152c445912174c340ee955b4db10a7456f575 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sun, 16 May 2021 08:03:38 +0200 Subject: [PATCH 7/9] Remove unused use statement. --- src/Collection.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Collection.php b/src/Collection.php index 868a40f83..9d4b7cd29 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -100,7 +100,6 @@ use loophp\collection\Operation\Sort; use loophp\collection\Operation\Span; use loophp\collection\Operation\Split; -use loophp\collection\Operation\Squash; use loophp\collection\Operation\Tail; use loophp\collection\Operation\Tails; use loophp\collection\Operation\TakeWhile; From b188f0be62166c3fe5eed8e47a0f2c2a50870020 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sun, 16 May 2021 10:11:30 +0200 Subject: [PATCH 8/9] Add documentation. --- docs/pages/api.rst | 13 ++++++++++ docs/pages/code/operations/squash.php | 37 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 docs/pages/code/operations/squash.php diff --git a/docs/pages/api.rst b/docs/pages/api.rst index 158086b19..fc2e26b29 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -1824,6 +1824,18 @@ Signature: ``Collection::split(int $type = Splitable::BEFORE, callable ...$callb $collection = Collection::fromIterable(range(0, 10)) ->split(Splitable::REMOVE, $splitter); [[1, 2], [4, 5], [7, 8], [10]] +squash +~~~~~~ + +Eagerly apply operations in a collection rather than lazily. + +Interface: `Squashable`_ + +Signature: ``Collection::squash();`` + +.. code-block:: php + + tail ~~~~ @@ -2265,6 +2277,7 @@ Signature: ``Collection::zip(iterable ...$iterables);`` .. _Sortable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sortable.php .. _Spanable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Spanable.php .. _Splitable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Splitable.php +.. _Squashable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Squashable.php .. _Tailable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Tailable.php .. _Tailsable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Tailsable.php .. _TakeWhileable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/TakeWhileable.php diff --git a/docs/pages/code/operations/squash.php b/docs/pages/code/operations/squash.php new file mode 100644 index 000000000..cd4c1c5cd --- /dev/null +++ b/docs/pages/code/operations/squash.php @@ -0,0 +1,37 @@ +filter(static fn (int $int) => 0 === $int % 2) + ->map(static fn (int $int) => 'document' . $int . '.pdf') + ->map( + static function (string $doc): bool { + if (false === file_exists('/doc/' . $doc)) { + throw new Exception('Unexistent file'); + } + + return file_get_contents($doc); + } + ) + ->squash(); // Instantly trigger an exception if a file does not exist. + +// If no exception, you can continue the processing... +$results = $results + ->filter( + static function (string $document): bool { + return false !== strpos($document, 'foobar'); + } + ); From 34020aecdd5e5971a26379f0788d3c143c5e76cf Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sun, 16 May 2021 10:22:58 +0200 Subject: [PATCH 9/9] Fix missing include in documentation. --- docs/pages/api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/api.rst b/docs/pages/api.rst index fc2e26b29..480bf3a0a 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -1833,8 +1833,8 @@ Interface: `Squashable`_ Signature: ``Collection::squash();`` -.. code-block:: php - +.. literalinclude:: code/operations/squash.php + :language: php tail ~~~~