From 4c73fe487798bc557008ce29404d776db71e6ca3 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sat, 14 Sep 2019 18:21:27 +0200 Subject: [PATCH] Add the Until operation with tests and example in README. --- README.md | 22 ++++++++++- spec/drupol/collection/CollectionSpec.php | 20 ++++++++++ src/Collection.php | 11 ++++++ src/Contract/Collection.php | 1 + src/Contract/Untilable.php | 18 +++++++++ src/Operation/Until.php | 46 +++++++++++++++++++++++ 6 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 src/Contract/Untilable.php create mode 100644 src/Operation/Until.php diff --git a/README.md b/README.md index 784574b34..8db9b1df5 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,23 @@ $string = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Collection::with($string) ->explode(' ') ->count(); // 71 + +// The Collatz conjecture (https://en.wikipedia.org/wiki/Collatz_conjecture) +$collatz = static function (int $initial = 1): int +{ + return 0 === $initial % 2 ? + $initial / 2: + $initial * 3 + 1; +}; + +Collection::iterate($collatz, 10) + ->until(static function ($number): bool { + return 1 === $number; + }) + ->all(); // [5, 16, 8, 4, 2, 1] + + + ``` ## Advanced usage @@ -311,8 +328,8 @@ include 'vendor/autoload.php'; use drupol\collection\Base; use drupol\collection\Contract\Allable; use drupol\collection\Contract\Runable; -use drupol\collection\Operation\All; -use drupol\collection\Operation\Run; +use drupol\collection\Transformation\All; +use drupol\collection\Transformation\Run; use drupol\collection\Contract\Operation; $customCollectionClass = new class extends Base implements Allable { @@ -389,6 +406,7 @@ the methods always return the same values for the same inputs. | `slice` | new Collection object | [Slice.php](./src/Operation/Slice.php) | `sort` | new Collection object | [Sort.php](./src/Operation/Sort.php) | `split` | new Collection object | [Split.php](./src/Operation/Split.php) +| `until` | new Collection object | [Until.php](./src/Operation/Until.php) | `walk` | new Collection object | [Walk.php](./src/Operation/Walk.php) | `zip` | new Collection object | [Zip.php](./src/Operation/Zip.php) diff --git a/spec/drupol/collection/CollectionSpec.php b/spec/drupol/collection/CollectionSpec.php index 21474d6a2..dfbc0d229 100644 --- a/spec/drupol/collection/CollectionSpec.php +++ b/spec/drupol/collection/CollectionSpec.php @@ -1036,6 +1036,26 @@ public function it_can_split(): void ->shouldIterateAs([0 => [1, 2, 3], 1 => [4, 5, 6], 2 => [7, 8, 9], 3 => [10, 11, 12], 4 => [13, 14, 15]]); } + public function it_can_until(): void + { + $collatz = static function (int $initial = 1): int { + return 0 === $initial % 2 ? + $initial / 2 : + $initial * 3 + 1; + }; + + $this + ->beConstructedThrough('iterate', [$collatz, 10]); + + $until = static function (int $number): bool { + return 1 === $number; + }; + + $this + ->until($until) + ->shouldIterateAs([5, 16, 8, 4, 2, 1]); + } + public function it_can_use_range(): void { $this diff --git a/src/Collection.php b/src/Collection.php index 7b6c410eb..e599b82b1 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -34,6 +34,7 @@ use drupol\collection\Operation\Slice; use drupol\collection\Operation\Sort; use drupol\collection\Operation\Split; +use drupol\collection\Operation\Until; use drupol\collection\Operation\Walk; use drupol\collection\Operation\Zip; use drupol\collection\Transformation\All; @@ -480,6 +481,16 @@ static function () use ($number) { return null === $callback ? $instance : $instance->run(new Walk($callback)); } + /** + * {@inheritdoc} + * + * @return \drupol\collection\Contract\Collection + */ + public function until(callable $callback): BaseInterface + { + return $this->run(new Until($callback)); + } + /** * {@inheritdoc} * diff --git a/src/Contract/Collection.php b/src/Contract/Collection.php index 43668463a..98e9745ab 100644 --- a/src/Contract/Collection.php +++ b/src/Contract/Collection.php @@ -46,6 +46,7 @@ interface Collection extends Sliceable, Sortable, Splitable, + Untilable, Walkable, Zipable { diff --git a/src/Contract/Untilable.php b/src/Contract/Untilable.php new file mode 100644 index 000000000..31aefab8b --- /dev/null +++ b/src/Contract/Untilable.php @@ -0,0 +1,18 @@ +callable = $until; + } + + /** + * {@inheritdoc} + */ + public function on(iterable $collection): \Closure + { + $until = $this->callable; + + return static function () use ($until, $collection): \Generator { + foreach ($collection as $key => $value) { + yield $key => $value; + + if (true === $until($value, $key)) { + break; + } + } + }; + } +}