From d2f3df107991e69bbac7788254834a41a227d2b0 Mon Sep 17 00:00:00 2001 From: Johan Date: Thu, 1 Apr 2021 11:43:42 +0700 Subject: [PATCH] add yield() method --- src/Buffer.php | 45 +++++++++++++++++++++++++++++++++++++++ tests/YieldTest.php | 52 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 tests/YieldTest.php diff --git a/src/Buffer.php b/src/Buffer.php index afd2354..7141252 100644 --- a/src/Buffer.php +++ b/src/Buffer.php @@ -5,6 +5,7 @@ namespace Devlop\Buffer; use Countable; +use Generator; use InvalidArgumentException; final class Buffer implements Countable @@ -59,6 +60,50 @@ public static function iterate(iterable $iterable, int $size, callable $callback $buffer->flush(); } + /** + * Iterate over an iterable and allow yielding of + * individual items from inside the callback + * + * @param iterable $iterable + * @param int $size + * @param callable $callback + * @return Generator + */ + public static function yield(iterable $iterable, int $size, callable $callback) : Generator + { + $stack = []; + + /** + * Create the buffer with a "wrapper" callback that catches the yields emitted + * by the callback and puts them into a seperate $stack variable. + */ + $buffer = new static($size, function (array $items) use ($callback, &$stack) : void { + foreach (call_user_func($callback, $items) as $item) { + $stack[] = $item; + } + }); + + foreach ($iterable as $value) { + $buffer->push($value); + + /** + * Yield everything in the stack (if the callback was applied). + */ + while (count($stack) > 0) { + yield array_shift($stack); + } + } + + $buffer->flush(); + + /** + * And lastly we have to yield everything remaining in the stack. + */ + while (count($stack) > 0) { + yield array_shift($stack); + } + } + /** * Push an item onto the stack * diff --git a/tests/YieldTest.php b/tests/YieldTest.php new file mode 100644 index 0000000..68030a2 --- /dev/null +++ b/tests/YieldTest.php @@ -0,0 +1,52 @@ +assertInstanceOf( + Generator::class, + Buffer::yield([], 2, fn () => null), + ); + } + + /** @test */ + public function yield_method_should_yield_each_input_value() : void + { + $items = [ + 'value1', + 'value2', + 'value3', + ]; + + $callback = function ($items) : Generator { + foreach ($items as $item) { + yield $item; + } + }; + + $index = 0; + + $yieldedValues = 0; + + foreach (Buffer::yield($items, 2, $callback) as $item) { + $this->assertEquals( + $items[$index++], + $item, + ); + + $yieldedValues++; + } + + $this->assertGreaterThan(0, $yieldedValues, 'No values was yielded'); + } +}