Skip to content

Commit

Permalink
add yield() method
Browse files Browse the repository at this point in the history
  • Loading branch information
johanrosenson committed Apr 1, 2021
1 parent f8c5b32 commit d2f3df1
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/Buffer.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Devlop\Buffer;

use Countable;
use Generator;
use InvalidArgumentException;

final class Buffer implements Countable
Expand Down Expand Up @@ -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<mixed> $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
*
Expand Down
52 changes: 52 additions & 0 deletions tests/YieldTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

declare(strict_types=1);

namespace Devlop\Buffer\Tests;

use Devlop\Buffer\Buffer;
use Generator;
use PHPUnit\Framework\TestCase;

final class YieldTest extends TestCase
{
/** @test */
public function yield_method_should_return_generator() : void
{
$this->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');
}
}

0 comments on commit d2f3df1

Please sign in to comment.