From 50dabda2b6def2c3e37fb26e7aa48f0eb3fd81fe Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Wed, 22 Apr 2020 12:07:39 -0400 Subject: [PATCH] Add `takeUntil` and `takeWhile` collection methods --- src/Illuminate/Support/Collection.php | 33 ++-- src/Illuminate/Support/LazyCollection.php | 57 ++++-- .../Support/Traits/EnumeratesValues.php | 15 ++ tests/Support/SupportCollectionTest.php | 187 ++++++++++++------ .../SupportLazyCollectionIsLazyTest.php | 51 +++-- 5 files changed, 232 insertions(+), 111 deletions(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index fd534fa52194..f1bb1f257f12 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -736,17 +736,6 @@ public function union($items) return new static($this->items + $this->getArrayableItems($items)); } - /** - * Take items in the collection until the given condition is met. - * - * @param mixed $key - * @return static - */ - public function until($value) - { - return new static($this->lazy()->until($value)->all()); - } - /** * Create a new collection consisting of every n-th element. * @@ -1196,6 +1185,28 @@ public function take($limit) return $this->slice(0, $limit); } + /** + * Take items in the collection until the given condition is met. + * + * @param mixed $key + * @return static + */ + public function takeUntil($value) + { + return new static($this->lazy()->takeUntil($value)->all()); + } + + /** + * Take items in the collection while the given condition is met. + * + * @param mixed $key + * @return static + */ + public function takeWhile($value) + { + return new static($this->lazy()->takeWhile($value)->all()); + } + /** * Transform each item in the collection using a callback. * diff --git a/src/Illuminate/Support/LazyCollection.php b/src/Illuminate/Support/LazyCollection.php index 2aa527732d9b..a4da2c18aec4 100644 --- a/src/Illuminate/Support/LazyCollection.php +++ b/src/Illuminate/Support/LazyCollection.php @@ -737,27 +737,6 @@ public function union($items) return $this->passthru('union', func_get_args()); } - /** - * Take items in the collection until the given condition is met. - * - * @param mixed $key - * @return static - */ - public function until($value) - { - $callback = $this->useAsCallable($value) ? $value : $this->equality($value); - - return new static(function () use ($callback) { - foreach ($this as $key => $item) { - if ($callback($item, $key)) { - break; - } - - yield $key => $item; - } - }); - } - /** * Create a new collection consisting of every n-th element. * @@ -1135,6 +1114,42 @@ public function take($limit) }); } + /** + * Take items in the collection until the given condition is met. + * + * @param mixed $key + * @return static + */ + public function takeUntil($value) + { + $callback = $this->useAsCallable($value) ? $value : $this->equality($value); + + return new static(function () use ($callback) { + foreach ($this as $key => $item) { + if ($callback($item, $key)) { + break; + } + + yield $key => $item; + } + }); + } + + /** + * Take items in the collection while the given condition is met. + * + * @param mixed $key + * @return static + */ + public function takeWhile($value) + { + $callback = $this->useAsCallable($value) ? $value : $this->equality($value); + + return $this->takeUntil(function ($item, $key) use ($callback) { + return ! $callback($item, $key); + }); + } + /** * Pass each item in the collection to the given callback, lazily. * diff --git a/src/Illuminate/Support/Traits/EnumeratesValues.php b/src/Illuminate/Support/Traits/EnumeratesValues.php index a8db94e9a17d..177b441c46eb 100644 --- a/src/Illuminate/Support/Traits/EnumeratesValues.php +++ b/src/Illuminate/Support/Traits/EnumeratesValues.php @@ -65,6 +65,8 @@ trait EnumeratesValues 'sortBy', 'sortByDesc', 'sum', + 'takeUntil', + 'takeWhile', 'unique', 'until', ]; @@ -722,6 +724,19 @@ public function uniqueStrict($key = null) return $this->unique($key, true); } + /** + * Take items in the collection until the given condition is met. + * + * This is an alias to the "takeUntil" method. + * + * @param mixed $key + * @return static + */ + public function until($value) + { + return $this->takeUntil($value); + } + /** * Collect the values into a collection. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 441d55c38091..71bc55c22f46 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -1721,6 +1721,131 @@ public function testTakeLast($collection) $this->assertEquals([1 => 'dayle', 2 => 'shawn'], $data->all()); } + /** + * @dataProvider collectionClassProvider + */ + public function testTakeUntilUsingValue($collection) + { + $data = new $collection([1, 2, 3, 4]); + + $data = $data->takeUntil(3); + + $this->assertSame([1, 2], $data->toArray()); + } + + /** + * @dataProvider collectionClassProvider + */ + public function testTakeUntilUsingCallback($collection) + { + $data = new $collection([1, 2, 3, 4]); + + $data = $data->takeUntil(function ($item) { + return $item >= 3; + }); + + $this->assertSame([1, 2], $data->toArray()); + } + + /** + * @dataProvider collectionClassProvider + */ + public function testTakeUntilReturnsAllItemsForUnmetValue($collection) + { + $data = new $collection([1, 2, 3, 4]); + + $actual = $data->takeUntil(99); + + $this->assertSame($data->toArray(), $actual->toArray()); + + $actual = $data->takeUntil(function ($item) { + return $item >= 99; + }); + + $this->assertSame($data->toArray(), $actual->toArray()); + } + + /** + * @dataProvider collectionClassProvider + */ + public function testTakeUntilCanBeProxied($collection) + { + $data = new $collection([ + new TestSupportCollectionHigherOrderItem('Adam'), + new TestSupportCollectionHigherOrderItem('Taylor'), + new TestSupportCollectionHigherOrderItem('Jason'), + ]); + + $actual = $data->takeUntil->is('Jason'); + + $this->assertCount(2, $actual); + $this->assertSame('Adam', $actual->get(0)->name); + $this->assertSame('Taylor', $actual->get(1)->name); + } + + /** + * @dataProvider collectionClassProvider + */ + public function testTakeWhileUsingValue($collection) + { + $data = new $collection([1, 1, 2, 2, 3, 3]); + + $data = $data->takeWhile(1); + + $this->assertSame([1, 1], $data->toArray()); + } + + /** + * @dataProvider collectionClassProvider + */ + public function testTakeWhileUsingCallback($collection) + { + $data = new $collection([1, 2, 3, 4]); + + $data = $data->takeWhile(function ($item) { + return $item < 3; + }); + + $this->assertSame([1, 2], $data->toArray()); + } + + /** + * @dataProvider collectionClassProvider + */ + public function testTakeWhileReturnsNoItemsForUnmetValue($collection) + { + $data = new $collection([1, 2, 3, 4]); + + $actual = $data->takeWhile(2); + + $this->assertSame([], $actual->toArray()); + + $actual = $data->takeWhile(function ($item) { + return $item == 99; + }); + + $this->assertSame([], $actual->toArray()); + } + + /** + * @dataProvider collectionClassProvider + */ + public function testTakeWhileCanBeProxied($collection) + { + $data = new $collection([ + new TestSupportCollectionHigherOrderItem('Adam'), + new TestSupportCollectionHigherOrderItem('Adam'), + new TestSupportCollectionHigherOrderItem('Taylor'), + new TestSupportCollectionHigherOrderItem('Taylor'), + ]); + + $actual = $data->takeWhile->is('Adam'); + + $this->assertCount(2, $actual); + $this->assertSame('Adam', $actual->get(0)->name); + $this->assertSame('Adam', $actual->get(1)->name); + } + /** * @dataProvider collectionClassProvider */ @@ -4094,68 +4219,6 @@ public function testCollect($collection) ], $data->all()); } - /** - * @dataProvider collectionClassProvider - */ - public function testUntilUsingValue($collection) - { - $data = new $collection([1, 2, 3, 4]); - - $data = $data->until(3); - - $this->assertSame([1, 2], $data->toArray()); - } - - /** - * @dataProvider collectionClassProvider - */ - public function testUntilUsingCallback($collection) - { - $data = new $collection([1, 2, 3, 4]); - - $data = $data->until(function ($item) { - return $item >= 3; - }); - - $this->assertSame([1, 2], $data->toArray()); - } - - /** - * @dataProvider collectionClassProvider - */ - public function testUntilReturnsAllItemsForUnmetValue($collection) - { - $data = new $collection([1, 2, 3, 4]); - - $actual = $data->until(99); - - $this->assertSame($data->toArray(), $actual->toArray()); - - $actual = $data->until(function ($item) { - return $item >= 99; - }); - - $this->assertSame($data->toArray(), $actual->toArray()); - } - - /** - * @dataProvider collectionClassProvider - */ - public function testUntilCanBeProxied($collection) - { - $data = new $collection([ - new TestSupportCollectionHigherOrderItem('Adam'), - new TestSupportCollectionHigherOrderItem('Taylor'), - new TestSupportCollectionHigherOrderItem('Jason'), - ]); - - $actual = $data->until->is('Jason'); - - $this->assertCount(2, $actual); - $this->assertSame('Adam', $actual->get(0)->name); - $this->assertSame('Taylor', $actual->get(1)->name); - } - /** * Provides each collection class, respectively. * diff --git a/tests/Support/SupportLazyCollectionIsLazyTest.php b/tests/Support/SupportLazyCollectionIsLazyTest.php index 62a48ef05d8d..7131903b63d5 100644 --- a/tests/Support/SupportLazyCollectionIsLazyTest.php +++ b/tests/Support/SupportLazyCollectionIsLazyTest.php @@ -989,6 +989,40 @@ public function testTakeIsLazy() }); } + public function testTakeUntilIsLazy() + { + $this->assertDoesNotEnumerate(function ($collection) { + $collection->takeUntil(INF); + }); + + $this->assertEnumerates(10, function ($collection) { + $collection->takeUntil(10)->all(); + }); + + $this->assertEnumerates(10, function ($collection) { + $collection->takeUntil(function ($item) { + return $item === 10; + })->all(); + }); + } + + public function testTakeWhileIsLazy() + { + $this->assertDoesNotEnumerate(function ($collection) { + $collection->takeWhile(0); + }); + + $this->assertEnumerates(1, function ($collection) { + $collection->takeWhile(0)->all(); + }); + + $this->assertEnumerates(10, function ($collection) { + $collection->takeWhile(function ($item) { + return $item < 10; + })->all(); + }); + } + public function testTapDoesNotEnumerate() { $this->assertDoesNotEnumerate(function ($collection) { @@ -1100,23 +1134,6 @@ public function testUnlessNotEmptyIsLazy() }); } - public function testUntilIsLazy() - { - $this->assertDoesNotEnumerate(function ($collection) { - $collection->until(INF); - }); - - $this->assertEnumerates(10, function ($collection) { - $collection->until(10)->all(); - }); - - $this->assertEnumerates(10, function ($collection) { - $collection->until(function ($item) { - return $item === 10; - })->all(); - }); - } - public function testUnwrapEnumeratesOne() { $this->assertEnumeratesOnce(function ($collection) {