From 0d3f3aee975bdda7a0fa432e0a33a88f8df0a971 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Tue, 8 Nov 2022 00:21:22 +0900 Subject: [PATCH] Introduce append(), prepend(), push(), unshift() Fixes #103 Fixes #107 Fixes #106 --- src/Standard.php | 78 +++++++++++++++++++++++++++++++++++++++++ src/functions.php | 15 ++++++-- tests/FunctionsTest.php | 20 +++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) diff --git a/src/Standard.php b/src/Standard.php index 19a13f1..7db8076 100644 --- a/src/Standard.php +++ b/src/Standard.php @@ -22,6 +22,7 @@ use function array_filter; use function array_flip; use function array_map; +use function array_merge; use function array_reduce; use function array_shift; use function array_slice; @@ -72,6 +73,83 @@ public function __construct(iterable $input = null) $this->pipeline = $input; } + public function append(iterable $values = null): self + { + // Do we need to do anything here? + if ($this->willReplace($values)) { + return $this; + } + + return $this->join($this->pipeline, $values); + } + + public function push(...$vector): self + { + return $this->append($vector); + } + + public function prepend(iterable $values = null): self + { + // Do we need to do anything here? + if ($this->willReplace($values)) { + return $this; + } + + return $this->join($values, $this->pipeline); + } + + public function unshift(...$vector): self + { + return $this->prepend($vector); + } + + /** + * Utility method for appending/prepending methods. + */ + private function willReplace(iterable $values = null): bool + { + // Nothing needs to be done here. + if (null === $values || [] === $values) { + return true; + } + + // No shortcuts are applicable if the pipeline was initialized. + if ([] !== $this->pipeline && null !== $this->pipeline) { + return false; + } + + // Install an array as it is. + if (is_array($values)) { + $this->pipeline = $values; + + return true; + } + + // Else we use ownself to handle edge cases. + $this->pipeline = new self($values); + + return true; + } + + /** + * Utility method for appending/prepending methods. + */ + private function join(iterable $left, iterable $right): self + { + // We got two arrays, that's what we will use. + if (is_array($left) && is_array($right)) { + $this->pipeline = array_merge($left, $right); + + return $this; + } + + // Last, join the hard way. + return $this->map(function () use ($left, $right) { + yield from $left; + yield from $right; + }); + } + /** * An extra variant of `map` which unpacks arrays into arguments. Flattens inputs if no callback provided. * diff --git a/src/functions.php b/src/functions.php index 195401f..d3eeead 100644 --- a/src/functions.php +++ b/src/functions.php @@ -30,9 +30,15 @@ function map(callable $func = null): Standard return $pipeline->map($func); } -function take(iterable $input = null): Standard +function take(iterable $input = null, iterable ...$inputs): Standard { - return new Standard($input); + $pipeline = new Standard($input); + + foreach ($inputs as $input) { + $pipeline->append($input); + } + + return $pipeline; } function fromArray(array $input): Standard @@ -40,6 +46,11 @@ function fromArray(array $input): Standard return new Standard($input); } +function fromValues(...$values): Standard +{ + return new Standard($values); +} + function zip(iterable $base, iterable ...$inputs): Standard { $result = take($base); diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index da6695a..0af983e 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -24,6 +24,7 @@ use function iterator_to_array; use PHPUnit\Framework\TestCase; use function Pipeline\fromArray; +use function Pipeline\fromValues; use function Pipeline\map; use Pipeline\Standard; use function Pipeline\take; @@ -81,6 +82,25 @@ public function testTakeArray(): void $this->assertSame([1, 2, 3, 4, 5], take([1, 2, 3, 4, 5])->toArray()); } + /** + * @covers \Pipeline\take + */ + public function testTakeMany(): void + { + $this->assertSame([1, 2, 3, 4, 5], take([1, 2], [3, 4], [5])->toArray()); + + $this->assertSame([1, 2, 3, 4, 5], take(take([1, 2]), take([3, 4]), fromValues(5))->toArray()); + } + + /** + * @covers \Pipeline\fromValues + */ + public function testFromValues(): void + { + $this->assertSame([1, 2, 3, 4, 5], fromValues(1, 2, 3, 4, 5)->toArray()); + $this->assertSame([1, 2, 3], fromValues(...[1, 2, 3])->toArray()); + } + /** * @covers \Pipeline\fromArray */