From 6ce8ecfd386d7697ebe5ea230fd09e53b1dacb49 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Wed, 26 Aug 2020 21:20:49 +0200 Subject: [PATCH 1/6] Convert Operations and Transformations into function object. --- src/Collection.php | 159 +++++++++--------- src/Contract/Operation.php | 5 - src/Contract/Transformation.php | 5 +- src/Contract/Transformation/Runable.php | 4 +- src/Contract/Transformation/Transformable.php | 10 +- src/Operation/Append.php | 20 +-- src/Operation/Apply.php | 36 ++-- src/Operation/Associate.php | 46 ++--- src/Operation/Cache.php | 25 ++- src/Operation/Chunk.php | 52 +++--- src/Operation/Column.php | 24 +-- src/Operation/Combinate.php | 61 +++---- src/Operation/Combine.php | 24 +-- src/Operation/Compact.php | 44 ++--- src/Operation/Cycle.php | 15 +- src/Operation/Diff.php | 20 +-- src/Operation/DiffKeys.php | 22 +-- src/Operation/Explode.php | 60 +++---- src/Operation/Filter.php | 44 ++--- src/Operation/First.php | 74 +++----- src/Operation/Flatten.php | 21 +-- src/Operation/Forget.php | 20 +-- src/Operation/Group.php | 87 +++++----- src/Operation/IfThenElse.php | 54 +++--- src/Operation/Intersect.php | 20 +-- src/Operation/IntersectKeys.php | 22 +-- src/Operation/Intersperse.php | 68 ++++---- src/Operation/Iterate.php | 38 ++--- src/Operation/Last.php | 72 +++----- src/Operation/Limit.php | 28 +-- src/Operation/Loop.php | 12 +- src/Operation/Map.php | 16 +- src/Operation/Merge.php | 20 +-- src/Operation/Normalize.php | 16 +- src/Operation/Nth.php | 34 ++-- src/Operation/Only.php | 22 +-- src/Operation/Pad.php | 43 ++--- src/Operation/Pair.php | 6 +- src/Operation/Pluck.php | 105 +++++------- src/Operation/Prepend.php | 20 +-- src/Operation/Product.php | 36 +--- src/Operation/RSample.php | 29 ++-- src/Operation/Random.php | 22 +-- src/Operation/Range.php | 23 ++- src/Operation/Reduction.php | 35 +--- src/Operation/Reverse.php | 2 +- src/Operation/Scale.php | 79 +++++---- src/Operation/Shuffle.php | 2 +- src/Operation/Since.php | 20 +-- src/Operation/Skip.php | 16 +- src/Operation/Slice.php | 38 ++--- src/Operation/Sort.php | 90 +++++----- src/Operation/Split.php | 67 ++++---- src/Operation/Tail.php | 2 +- src/Operation/Times.php | 41 ++--- src/Operation/Transpose.php | 24 +-- src/Operation/Until.php | 20 +-- src/Operation/Window.php | 46 ++--- src/Operation/Zip.php | 46 +++-- src/Transformation/All.php | 6 +- src/Transformation/Contains.php | 36 ++-- src/Transformation/Count.php | 7 +- src/Transformation/Falsy.php | 14 +- src/Transformation/FoldLeft.php | 49 ++---- src/Transformation/FoldRight.php | 44 ++--- src/Transformation/Get.php | 53 ++---- src/Transformation/Has.php | 42 ++--- src/Transformation/Implode.php | 57 +++---- src/Transformation/Nullsy.php | 17 +- src/Transformation/Reduce.php | 42 ++--- src/Transformation/Run.php | 39 ++--- src/Transformation/Transform.php | 45 ++--- src/Transformation/Truthy.php | 14 +- 73 files changed, 958 insertions(+), 1619 deletions(-) diff --git a/src/Collection.php b/src/Collection.php index 36f3b20ae..62066a950 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -8,7 +8,6 @@ use Generator; use loophp\collection\Contract\Collection as CollectionInterface; use loophp\collection\Contract\Operation; -use loophp\collection\Contract\Transformation; use loophp\collection\Iterator\ClosureIterator; use loophp\collection\Iterator\IterableIterator; use loophp\collection\Iterator\ResourceIterator; @@ -226,89 +225,89 @@ static function ($data): Generator { public function all(): array { - return $this->transform(new All()); + return $this->transform((new All())()); } public function append(...$items): CollectionInterface { - return $this->run(new Append(...$items)); + return $this->run((new Append())()(...$items)); } public function apply(callable ...$callables): CollectionInterface { - return $this->run(new Apply(...$callables)); + return $this->run((new Apply())()(...$callables)); } public function associate( ?callable $callbackForKeys = null, ?callable $callbackForValues = null ): CollectionInterface { - return $this->run(new Associate($callbackForKeys, $callbackForValues)); + return $this->run((new Associate())()($callbackForKeys)($callbackForValues)); } public function cache(?CacheItemPoolInterface $cache = null): CollectionInterface { - return $this->run(new Cache($cache ?? new ArrayAdapter())); + return $this->run((new Cache())()($cache ?? new ArrayAdapter())); } public function chunk(int ...$sizes): CollectionInterface { - return $this->run(new Chunk(...$sizes)); + return $this->run((new Chunk())()(...$sizes)); } public function collapse(): CollectionInterface { - return $this->run(new Collapse()); + return $this->run((new Collapse())()); } public function column($column): CollectionInterface { - return $this->run(new Column($column)); + return $this->run((new Column())()($column)); } public function combinate(?int $length = null): CollectionInterface { - return $this->run(new Combinate($length)); + return $this->run((new Combinate())()($length)); } public function combine(...$keys): CollectionInterface { - return $this->run(new Combine(...$keys)); + return $this->run((new Combine())()(...$keys)); } public function compact(...$values): CollectionInterface { - return $this->run(new Compact(...$values)); + return $this->run((new Compact())()(...$values)); } public function contains(...$value): bool { - return $this->transform(new Contains(...$value)); + return $this->transform((new Contains())()(...$value)); } public function count(): int { - return $this->transform(new Count()); + return $this->transform((new Count())()); } public function cycle(int $length = 0): CollectionInterface { - return $this->run(new Cycle($length)); + return $this->run((new Cycle())()($length)); } public function diff(...$values): CollectionInterface { - return $this->run(new Diff(...$values)); + return $this->run((new Diff())()(...$values)); } public function diffKeys(...$values): CollectionInterface { - return $this->run(new DiffKeys(...$values)); + return $this->run((new DiffKeys())()(...$values)); } public function distinct(): CollectionInterface { - return $this->run(new Distinct()); + return $this->run((new Distinct())()); } public static function empty(): Collection @@ -318,52 +317,52 @@ public static function empty(): Collection public function explode(...$explodes): CollectionInterface { - return $this->run(new Explode(...$explodes)); + return $this->run((new Explode())()(...$explodes)); } public function falsy(): bool { - return $this->transform(new Falsy()); + return $this->transform((new Falsy())()); } public function filter(callable ...$callbacks): CollectionInterface { - return $this->run(new Filter(...$callbacks)); + return $this->run((new Filter())()(...$callbacks)); } public function first(?callable $callback = null, int $size = 1): CollectionInterface { - return $this->run(new First($callback, $size)); + return $this->run((new First())()($callback)($size)); } public function flatten(int $depth = PHP_INT_MAX): CollectionInterface { - return $this->run(new Flatten($depth)); + return $this->run((new Flatten())()($depth)); } public function flip(): CollectionInterface { - return $this->run(new Flip()); + return $this->run((new Flip())()); } public function foldLeft(callable $callback, $initial = null) { - return $this->transform(new FoldLeft($callback, $initial)); + return $this->transform((new FoldLeft())()($callback)($initial)); } public function foldRight(callable $callback, $initial = null) { - return $this->transform(new FoldRight($callback, $initial)); + return $this->transform((new FoldRight())()($callback)($initial)); } public function forget(...$keys): CollectionInterface { - return $this->run(new Forget(...$keys)); + return $this->run((new Forget())()(...$keys)); } public function frequency(): CollectionInterface { - return $this->run(new Frequency()); + return $this->run((new Frequency())()); } public static function fromCallable(callable $callable, ...$parameters): Collection @@ -410,7 +409,7 @@ static function (string $string, string $delimiter): Generator { public function get($key, $default = null) { - return $this->transform(new Get($key, $default)); + return $this->transform((new Get())()($key)($default)); } public function getIterator(): ClosureIterator @@ -420,17 +419,17 @@ public function getIterator(): ClosureIterator public function group(?callable $callable = null): CollectionInterface { - return $this->run(new Group($callable)); + return $this->run((new Group())()($callable)); } public function has(callable $callback): bool { - return $this->transform(new Has($callback)); + return $this->transform((new Has())()($callback)); } public function head(): CollectionInterface { - return $this->run(new Head()); + return $this->run((new Head())()); } public function ifThenElse(callable $condition, callable $then, ?callable $else = null): CollectionInterface @@ -444,27 +443,27 @@ public function ifThenElse(callable $condition, callable $then, ?callable $else public function implode(string $glue = ''): string { - return $this->transform(new Implode($glue)); + return $this->transform((new Implode())()($glue)); } public function intersect(...$values): CollectionInterface { - return $this->run(new Intersect(...$values)); + return $this->run((new Intersect())()(...$values)); } public function intersectKeys(...$values): CollectionInterface { - return $this->run(new IntersectKeys(...$values)); + return $this->run((new IntersectKeys())()(...$values)); } public function intersperse($element, int $every = 1, int $startAt = 0): CollectionInterface { - return $this->run(new Intersperse($element, $every, $startAt)); + return $this->run((new Intersperse())()($element)($every)($startAt)); } public static function iterate(callable $callback, ...$parameters): CollectionInterface { - return (new self())->run(new Iterate($callback, $parameters)); + return (new self())->run((new Iterate())()($callback)($parameters)); } /** @@ -477,52 +476,52 @@ public function jsonSerialize(): array public function keys(): CollectionInterface { - return $this->run(new Keys()); + return $this->run((new Keys())()); } public function last(?callable $callback = null, int $size = 1): CollectionInterface { - return $this->run(new Last($callback, $size)); + return $this->run((new Last())()($callback)($size)); } public function limit(int $limit = -1, int $offset = 0): CollectionInterface { - return $this->run(new Limit($limit, $offset)); + return $this->run((new Limit())()($limit)($offset)); } public function loop(): CollectionInterface { - return $this->run(new Loop()); + return $this->run((new Loop())()); } public function map(callable ...$callbacks): CollectionInterface { - return $this->run(new Map(...$callbacks)); + return $this->run((new Map())()(...$callbacks)); } public function merge(iterable ...$sources): CollectionInterface { - return $this->run(new Merge(...$sources)); + return $this->run((new Merge())()(...$sources)); } public function normalize(): CollectionInterface { - return $this->run(new Normalize()); + return $this->run((new Normalize())()); } public function nth(int $step, int $offset = 0): CollectionInterface { - return $this->run(new Nth($step, $offset)); + return $this->run((new Nth())()($step)($offset)); } public function nullsy(): bool { - return $this->transform(new Nullsy()); + return $this->transform((new Nullsy())()); } public function only(...$keys): CollectionInterface { - return $this->run(new Only(...$keys)); + return $this->run((new Only())()(...$keys)); } public function pack(): CollectionInterface @@ -532,67 +531,67 @@ public function pack(): CollectionInterface public function pad(int $size, $value): CollectionInterface { - return $this->run(new Pad($size, $value)); + return $this->run((new Pad())()($size)($value)); } public function pair(): CollectionInterface { - return $this->run(new Pair()); + return $this->run((new Pair())()); } public function permutate(): CollectionInterface { - return $this->run(new Permutate()); + return $this->run((new Permutate())()); } public function pluck($pluck, $default = null): CollectionInterface { - return $this->run(new Pluck($pluck, $default)); + return $this->run((new Pluck())()($pluck)($default)); } public function prepend(...$items): CollectionInterface { - return $this->run(new Prepend(...$items)); + return $this->run((new Prepend())()(...$items)); } public function product(iterable ...$iterables): CollectionInterface { - return $this->run(new Product(...$iterables)); + return $this->run((new Product())()(...$iterables)); } public function random(int $size = 1): CollectionInterface { - return $this->run(new Random($size)); + return $this->run((new Random())()($size)); } public static function range(float $start = 0.0, float $end = INF, float $step = 1.0): CollectionInterface { - return (new self())->run(new Range($start, $end, $step)); + return (new self())->run((new Range())()($start)($end)($step)); } public function reduce(callable $callback, $initial = null) { - return $this->transform(new Reduce($callback, $initial)); + return $this->transform((new Reduce())()($callback)($initial)); } public function reduction(callable $callback, $initial = null): CollectionInterface { - return $this->run(new Reduction($callback, $initial)); + return $this->run((new Reduction())()($callback)($initial)); } public function reverse(): CollectionInterface { - return $this->run(new Reverse()); + return $this->run((new Reverse())()); } public function rsample(float $probability): CollectionInterface { - return $this->run(new RSample($probability)); + return $this->run((new RSample())()($probability)); } - public function run(Operation ...$operations) + public function run(callable ...$operations) { - return self::fromIterable((new Run(...$operations))($this->getIterator())); + return self::fromIterable((new Run())()(...$operations)($this->getIterator())); } public function scale( @@ -602,62 +601,62 @@ public function scale( float $wantedUpperBound = 1.0, float $base = 0.0 ): CollectionInterface { - return $this->run(new Scale($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base)); + return $this->run((new Scale())()($lowerBound)($upperBound)($wantedLowerBound)($wantedUpperBound)($base)); } public function shuffle(): CollectionInterface { - return $this->run(new Shuffle()); + return $this->run((new Shuffle())()); } public function since(callable ...$callbacks): CollectionInterface { - return $this->run(new Since(...$callbacks)); + return $this->run((new Since())()(...$callbacks)); } public function skip(int ...$counts): CollectionInterface { - return $this->run(new Skip(...$counts)); + return $this->run((new Skip())()(...$counts)); } public function slice(int $offset, int $length = -1): CollectionInterface { - return $this->run(new Slice($offset, $length)); + return $this->run((new Slice())()($offset)($length)); } public function sort(int $type = Operation\Sortable::BY_VALUES, ?callable $callback = null): CollectionInterface { - return $this->run(new Sort($type, $callback)); + return $this->run((new Sort())()($type)($callback)); } public function split(callable ...$callbacks): CollectionInterface { - return $this->run(new Split(...$callbacks)); + return $this->run((new Split())()(...$callbacks)); } public function tail(): CollectionInterface { - return $this->run(new Tail()); + return $this->run((new Tail())()); } public static function times(int $number = 0, ?callable $callback = null): CollectionInterface { - return (new self())->run(new Times($number, $callback)); + return (new self())->run((new Times())()($number)($callback)); } - public function transform(Transformation ...$transformers) + public function transform(callable ...$transformers) { - return (new Transform(...$transformers))($this->getIterator()); + return (new Transform())()(...$transformers)($this->getIterator()); } public function transpose(): CollectionInterface { - return $this->run(new Transpose()); + return $this->run((new Transpose())()); } public function truthy(): bool { - return $this->transform(new Truthy()); + return $this->transform((new Truthy())()); } public function unpack(): CollectionInterface @@ -667,22 +666,22 @@ public function unpack(): CollectionInterface public function unpair(): CollectionInterface { - return $this->run(new Unpair()); + return $this->run((new Unpair())()); } public function until(callable ...$callbacks): CollectionInterface { - return $this->run(new Until(...$callbacks)); + return $this->run((new Until())()(...$callbacks)); } public function unwrap(): CollectionInterface { - return $this->run(new Unwrap()); + return $this->run((new Unwrap())()); } public function window(int ...$length): CollectionInterface { - return $this->run(new Window(...$length)); + return $this->run((new Window())()(...$length)); } public static function with($data = [], ...$parameters): Collection @@ -692,11 +691,11 @@ public static function with($data = [], ...$parameters): Collection public function wrap(): CollectionInterface { - return $this->run(new Wrap()); + return $this->run((new Wrap())()); } public function zip(iterable ...$iterables): CollectionInterface { - return $this->run(new Zip(...$iterables)); + return $this->run((new Zip())()(...$iterables)); } } diff --git a/src/Contract/Operation.php b/src/Contract/Operation.php index 102c419d7..dfc7661d2 100644 --- a/src/Contract/Operation.php +++ b/src/Contract/Operation.php @@ -9,9 +9,4 @@ interface Operation { public function __invoke(): Closure; - - /** - * @return array - */ - public function getArguments(): array; } diff --git a/src/Contract/Transformation.php b/src/Contract/Transformation.php index 1b92ae10d..275c140c5 100644 --- a/src/Contract/Transformation.php +++ b/src/Contract/Transformation.php @@ -4,8 +4,6 @@ namespace loophp\collection\Contract; -use Iterator; - /** * @psalm-template TKey * @psalm-template TKey of array-key @@ -14,11 +12,10 @@ interface Transformation { /** - * @param iterable $collection * @psalm-param \Iterator $collection * * @return mixed * @psalm-return T|scalar|\Iterator|array|null */ - public function __invoke(Iterator $collection); + public function __invoke(); } diff --git a/src/Contract/Transformation/Runable.php b/src/Contract/Transformation/Runable.php index dff0e8e32..d70349234 100644 --- a/src/Contract/Transformation/Runable.php +++ b/src/Contract/Transformation/Runable.php @@ -4,8 +4,6 @@ namespace loophp\collection\Contract\Transformation; -use loophp\collection\Contract\Operation; - /** * @psalm-template TKey * @psalm-template TKey of array-key @@ -16,5 +14,5 @@ interface Runable /** * @psalm-return \loophp\collection\Contract\Collection */ - public function run(Operation ...$operations); + public function run(callable ...$operations); } diff --git a/src/Contract/Transformation/Transformable.php b/src/Contract/Transformation/Transformable.php index 0a70fb783..465631051 100644 --- a/src/Contract/Transformation/Transformable.php +++ b/src/Contract/Transformation/Transformable.php @@ -4,8 +4,6 @@ namespace loophp\collection\Contract\Transformation; -use loophp\collection\Contract\Transformation; - /** * @psalm-template TKey * @psalm-template TKey of array-key @@ -13,11 +11,5 @@ */ interface Transformable { - /** - * @param \loophp\collection\Contract\Transformation ...$transformers - * @psalm-param \loophp\collection\Contract\Transformation ...$transformers - * - * @return \loophp\collection\Iterator\ClosureIterator|mixed - */ - public function transform(Transformation ...$transformers); + public function transform(callable ...$transformers); } diff --git a/src/Operation/Append.php b/src/Operation/Append.php index 9a992dd4d..2720df8aa 100644 --- a/src/Operation/Append.php +++ b/src/Operation/Append.php @@ -16,25 +16,10 @@ */ final class Append extends AbstractOperation implements Operation { - /** - * @param mixed ...$items - * @psalm-param T ...$items - */ - public function __construct(...$items) - { - $this->storage['items'] = $items; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $items - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $items): Generator { + return static function (...$items): Closure { + return static function (Iterator $iterator) use ($items): Generator { foreach ($iterator as $key => $value) { yield $key => $value; } @@ -43,5 +28,6 @@ static function (Iterator $iterator, array $items): Generator { yield $key => $item; } }; + }; } } diff --git a/src/Operation/Apply.php b/src/Operation/Apply.php index 88d40d3a8..2271f98b0 100644 --- a/src/Operation/Apply.php +++ b/src/Operation/Apply.php @@ -16,15 +16,6 @@ */ final class Apply extends AbstractOperation implements Operation { - /** - * @param callable ...$callbacks - * @psalm-param callable(T, TKey):(bool) ...$callbacks - */ - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - /** * @psalm-return Closure(Iterator, list):(Generator) */ @@ -32,21 +23,26 @@ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator * @psalm-param list $callbacks */ - static function (Iterator $iterator, array $callbacks): Generator { - foreach ($iterator as $key => $value) { - foreach ($callbacks as $callback) { - if (true === $callback($value, $key)) { - continue; - } + static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param \Iterator $iterator + */ + static function (Iterator $iterator) use ($callbacks): Generator { + foreach ($iterator as $key => $value) { + foreach ($callbacks as $callback) { + if (true === $callback($value, $key)) { + continue; + } - break; - } + break; + } - yield $key => $value; - } + yield $key => $value; + } + }; }; } } diff --git a/src/Operation/Associate.php b/src/Operation/Associate.php index 349552bbf..d8cc002f3 100644 --- a/src/Operation/Associate.php +++ b/src/Operation/Associate.php @@ -16,22 +16,6 @@ */ final class Associate extends AbstractOperation implements Operation { - /** - * @psalm-param null|callable(TKey, T):(TKey) $callbackForKeys - * @psalm-param null|callable(TKey, T):(T) $callbackForValues - */ - public function __construct(?callable $callbackForKeys = null, ?callable $callbackForValues = null) - { - $this->storage = [ - 'callbackForKeys' => $callbackForKeys ?? static function ($key, $value) { - return $key; - }, - 'callbackForValues' => $callbackForValues ?? static function ($key, $value) { - return $value; - }, - ]; - } - /** * @psalm-return Closure(Iterator, callable(TKey, T):(TKey), callable(TKey, T):(T)):(Generator) */ @@ -39,14 +23,32 @@ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator * @psalm-param callable(TKey, T):(TKey) $callbackForKeys - * @psalm-param callable(TKey, T):(T) $callbackForValues */ - static function (Iterator $iterator, callable $callbackForKeys, callable $callbackForValues): Generator { - foreach ($iterator as $key => $value) { - yield $callbackForKeys($key, $value) => $callbackForValues($key, $value); - } + static function (?callable $callbackForKeys = null): Closure { + $callbackForKeys = $callbackForKeys ?? static function ($key, $value) { + return $key; + }; + + return + /** + * @psalm-param callable(TKey, T):(T) $callbackForValues + */ + static function (?callable $callbackForValues = null) use ($callbackForKeys): Closure { + $callbackForValues = $callbackForValues ?? static function ($key, $value) { + return $value; + }; + + return + /** + * @psalm-param \Iterator $iterator + */ + static function (Iterator $iterator) use ($callbackForKeys, $callbackForValues): Generator { + foreach ($iterator as $key => $value) { + yield $callbackForKeys($key, $value) => $callbackForValues($key, $value); + } + }; + }; }; } } diff --git a/src/Operation/Cache.php b/src/Operation/Cache.php index 43c6a1c69..4654ba56a 100644 --- a/src/Operation/Cache.php +++ b/src/Operation/Cache.php @@ -18,21 +18,18 @@ */ final class Cache extends AbstractOperation implements Operation { - public function __construct(CacheItemPoolInterface $cache) - { - $this->storage['cache'] = $cache; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, CacheItemPoolInterface $cache): Generator { - return yield from new CacheIterator($iterator, $cache); - }; + return static function (CacheItemPoolInterface $cache): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($cache): Generator { + return yield from new CacheIterator($iterator, $cache); + }; + }; } } diff --git a/src/Operation/Chunk.php b/src/Operation/Chunk.php index 7e7983574..d18385284 100644 --- a/src/Operation/Chunk.php +++ b/src/Operation/Chunk.php @@ -20,47 +20,47 @@ */ final class Chunk extends AbstractOperation implements Operation { - public function __construct(int ...$sizes) - { - $this->storage['sizes'] = new ArrayIterator($sizes); - } - /** - * @psalm-return Closure(Iterator, list):(Generator>) + * @psalm-return Closure(int...): Closure(Iterator): Generator> */ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param ArrayIterator $sizes - * - * @psalm-return Generator> + * @psalm-param int ...$sizes */ - static function (Iterator $iterator, ArrayIterator $sizes): Generator { - $sizesIterator = (new Run(new Loop()))($sizes); + static function (int ...$sizes): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($sizes): Generator { + $sizesIterator = (new Run())()((new Loop())())(new ArrayIterator($sizes)); - $values = []; + $values = []; - foreach ($iterator as $value) { - if (0 >= $sizesIterator->current()) { - return yield from []; - } + foreach ($iterator as $value) { + if (0 >= $sizesIterator->current()) { + return yield from []; + } - if (count($values) !== $sizesIterator->current()) { - $values[] = $value; + if (count($values) !== $sizesIterator->current()) { + $values[] = $value; - continue; - } + continue; + } - $sizesIterator->next(); + $sizesIterator->next(); - yield $values; + yield $values; - $values = [$value]; - } + $values = [$value]; + } - return yield $values; + return yield $values; + }; }; } } diff --git a/src/Operation/Column.php b/src/Operation/Column.php index 5b1df8481..5cc5e4251 100644 --- a/src/Operation/Column.php +++ b/src/Operation/Column.php @@ -17,39 +17,23 @@ */ final class Column extends AbstractOperation implements Operation { - /** - * @param int|string $column - * @psalm-param array-key $column - */ - public function __construct($column) - { - $this->storage['column'] = $column; - } - /** * @psalm-return Closure(Iterator, array-key):(Generator>) */ public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param array-key $column - * - * @psalm-return Generator> - * - * @param mixed $column - */ - static function (Iterator $iterator, $column): Generator { + return static function ($column): Closure { + return static function (Iterator $iterator) use ($column): Generator { /** * @psalm-var array-key $key * @psalm-var iterable $value */ - foreach ((new Run(new Transpose()))($iterator) as $key => $value) { + foreach ((new Run())()((new Transpose())())($iterator) as $key => $value) { if ($key === $column) { return yield from $value; } } }; + }; } } diff --git a/src/Operation/Combinate.php b/src/Operation/Combinate.php index 662c14c5f..d6ed9545c 100644 --- a/src/Operation/Combinate.php +++ b/src/Operation/Combinate.php @@ -19,26 +19,26 @@ */ final class Combinate extends AbstractOperation implements Operation { - public function __construct(?int $length = null) - { - $this->storage = [ - 'length' => $length, - 'getCombinations' => function (array $dataset, int $length): Generator { - return $this->getCombinations($dataset, $length); - }, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param callable(array, int): (array) $getCombinations - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, ?int $length, callable $getCombinations): Generator { + return static function (?int $length): Closure { + $getCombinations = static function (array $dataset, int $length) use (&$getCombinations): Generator { + for ($i = 0; count($dataset) - $length >= $i; ++$i) { + if (1 === $length) { + yield [$dataset[$i]]; + + continue; + } + + foreach ($getCombinations(array_slice($dataset, $i + 1), $length - 1) as $permutation) { + array_unshift($permutation, $dataset[$i]); + + yield $permutation; + } + } + }; + + return static function (Iterator $iterator) use ($length, $getCombinations): Generator { $dataset = iterator_to_array($iterator); if (0 < $length) { @@ -55,29 +55,6 @@ static function (Iterator $iterator, ?int $length, callable $getCombinations): G yield from $getCombinations($dataset, $i); } }; - } - - /** - * @param array $dataset - * @psalm-param array $dataset - * - * @return Generator> - * @psalm-return Generator> - */ - private function getCombinations(array $dataset, int $length): Generator - { - for ($i = 0; count($dataset) - $length >= $i; ++$i) { - if (1 === $length) { - yield [$dataset[$i]]; - - continue; - } - - foreach ($this->getCombinations(array_slice($dataset, $i + 1), $length - 1) as $permutation) { - array_unshift($permutation, $dataset[$i]); - - yield $permutation; - } - } + }; } } diff --git a/src/Operation/Combine.php b/src/Operation/Combine.php index 21c9e62f9..8c1ec8f61 100644 --- a/src/Operation/Combine.php +++ b/src/Operation/Combine.php @@ -19,27 +19,12 @@ */ final class Combine extends AbstractOperation implements Operation { - /** - * Combine constructor. - * - * @param mixed ...$keys - * @psalm-param TKey ...$keys - */ - public function __construct(...$keys) - { - $this->storage['keys'] = new ArrayIterator($keys); - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param ArrayIterator $keys - * - * @psalm-return Generator - */ - static function (Iterator $iterator, ArrayIterator $keys): Generator { + return static function (...$keys): Closure { + return static function (Iterator $iterator) use ($keys): Generator { + $keys = new ArrayIterator($keys); + while ($iterator->valid() && $keys->valid()) { yield $keys->current() => $iterator->current(); @@ -51,5 +36,6 @@ static function (Iterator $iterator, ArrayIterator $keys): Generator { trigger_error('Both keys and values must have the same amount of items.', E_USER_WARNING); } }; + }; } } diff --git a/src/Operation/Compact.php b/src/Operation/Compact.php index f02a6c3b7..d8b27c559 100644 --- a/src/Operation/Compact.php +++ b/src/Operation/Compact.php @@ -19,37 +19,23 @@ */ final class Compact extends AbstractOperation implements Operation { - /** - * @param mixed ...$values - * @psalm-param T ...$values - */ - public function __construct(...$values) - { - $this->storage['values'] = [] === $values ? [null] : $values; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $values): Generator { - return yield from - (new Run( - new Filter( - /** - * @param mixed $item - */ - static function ($item) use ($values): bool { - return !in_array($item, $values, true); - } - ) - ) - )($iterator); + return static function (...$values): Closure { + return static function (Iterator $iterator) use ($values): Generator { + $values = [] === $values ? [null] : $values; + + $filter = (new Filter())()( + /** + * @param mixed $item + */ + static function ($item) use ($values): bool { + return !in_array($item, $values, true); + } + ); + + return yield from (new Run())()($filter)($iterator); }; + }; } } diff --git a/src/Operation/Cycle.php b/src/Operation/Cycle.php index 99d1bad71..48bf5f50c 100644 --- a/src/Operation/Cycle.php +++ b/src/Operation/Cycle.php @@ -18,20 +18,10 @@ */ final class Cycle extends AbstractOperation implements Operation { - public function __construct(int $length) - { - $this->storage['length'] = $length; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $length): Generator { + return static function (int $length): Closure { + return static function (Iterator $iterator) use ($length): Generator { if (0 === $length) { return yield from []; } @@ -42,5 +32,6 @@ static function (Iterator $iterator, int $length): Generator { $length ); }; + }; } } diff --git a/src/Operation/Diff.php b/src/Operation/Diff.php index c1b364869..d43ab07a7 100644 --- a/src/Operation/Diff.php +++ b/src/Operation/Diff.php @@ -18,30 +18,16 @@ */ final class Diff extends AbstractOperation implements Operation { - /** - * @param mixed ...$values - * @psalm-param T ...$values - */ - public function __construct(...$values) - { - $this->storage['values'] = $values; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $values): Generator { + return static function (...$values): Closure { + return static function (Iterator $iterator) use ($values): Generator { foreach ($iterator as $key => $value) { if (false === in_array($value, $values, true)) { yield $key => $value; } } }; + }; } } diff --git a/src/Operation/DiffKeys.php b/src/Operation/DiffKeys.php index ea9e21bb0..a9e9cfad2 100644 --- a/src/Operation/DiffKeys.php +++ b/src/Operation/DiffKeys.php @@ -18,32 +18,16 @@ */ final class DiffKeys extends AbstractOperation implements Operation { - /** - * @param mixed ...$values - * @psalm-param TKey ...$values - */ - public function __construct(...$values) - { - $this->storage['values'] = $values; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator - * - * @param mixed $values - */ - static function (Iterator $iterator, array $values): Generator { + return static function (...$values): Closure { + return static function (Iterator $iterator) use ($values): Generator { foreach ($iterator as $key => $value) { if (false === in_array($key, $values, true)) { yield $key => $value; } } }; + }; } } diff --git a/src/Operation/Explode.php b/src/Operation/Explode.php index 7cb2f6123..ba28839bc 100644 --- a/src/Operation/Explode.php +++ b/src/Operation/Explode.php @@ -17,46 +17,32 @@ */ final class Explode extends AbstractOperation implements Operation { - /** - * @param mixed ...$explodes - * @psalm-param T ...$explodes - */ - public function __construct(...$explodes) - { - $this->storage['explodes'] = $explodes; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $explodes - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, array $explodes): Generator { - return yield from (new Run( - new Split( - ...array_map( - /** - * @param mixed $explode - * @psalm-param T $explode - */ - static function ($explode): Closure { - return - /** - * @param mixed $value - * @psalm-param T $value - */ - static function ($value) use ($explode): bool { - return $value === $explode; - }; - }, - $explodes - ) + return static function (...$explodes): Closure { + return static function (Iterator $iterator) use ($explodes): Generator { + $split = (new Split())()( + ...array_map( + /** + * @param mixed $explode + * @psalm-param T $explode + */ + static function ($explode): Closure { + return + /** + * @param mixed $value + * @psalm-param T $value + */ + static function ($value) use ($explode): bool { + return $value === $explode; + }; + }, + $explodes ) - ))($iterator); + ); + + return yield from (new Run())()($split)($iterator); }; + }; } } diff --git a/src/Operation/Filter.php b/src/Operation/Filter.php index cef23d1f1..aae60bea4 100644 --- a/src/Operation/Filter.php +++ b/src/Operation/Filter.php @@ -17,35 +17,26 @@ */ final class Filter extends AbstractOperation implements Operation { - public function __construct(callable ...$callbacks) + public function __invoke(): Closure { - $defaultCallback = - /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key - * @psalm-param Iterator $iterator - */ - static function ($value, $key, Iterator $iterator): bool { - return (bool) $value; - }; + return static function (callable ...$callbacks): Closure { + return static function (Iterator $iterator) use ($callbacks): Generator { + $defaultCallback = + /** + * @param mixed $value + * @param mixed $key + * @psalm-param T $value + * @psalm-param TKey $key + * @psalm-param Iterator $iterator + */ + static function ($value, $key, Iterator $iterator): bool { + return (bool) $value; + }; - $this->storage['callbacks'] = [] === $callbacks ? - [$defaultCallback] : - $callbacks; - } + $callbacks = [] === $callbacks ? + [$defaultCallback] : + $callbacks; - public function __invoke(): Closure - { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list):(bool)> $callbacks - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $callbacks): Generator { return yield from array_reduce( $callbacks, static function (Iterator $carry, callable $callback): CallbackFilterIterator { @@ -54,5 +45,6 @@ static function (Iterator $carry, callable $callback): CallbackFilterIterator { $iterator ); }; + }; } } diff --git a/src/Operation/First.php b/src/Operation/First.php index e352feb4f..d674998a0 100644 --- a/src/Operation/First.php +++ b/src/Operation/First.php @@ -19,59 +19,37 @@ */ final class First extends AbstractOperation implements Operation { - /** - * @var callable - * @psalm-var callable(T, TKey):(bool) - */ - private $callback; - - /** - * @psalm-param callable(T, TKey):(bool)|null $callback - * - * @psalm-param T|null $default - */ - public function __construct(?callable $callback = null, int $size = 1) - { - $defaultCallback = - /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key - * @psalm-param Iterator $iterator - */ - static function ($value, $key, Iterator $iterator): bool { - return true; - }; - - $this->storage = [ - 'callback' => $callback ?? $defaultCallback, - 'size' => $size, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, callable $callback, int $size): Generator { - $callback = + return static function (?callable $callback = null): Closure { + return static function (int $size = 1) use ($callback): Closure { + return /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key - * @psalm-param Iterator $iterator + * @psalm-param \Iterator $iterator + * + * @psalm-return \Generator */ - static function ($value, $key, Iterator $iterator) use ($callback): bool { - return true === $callback($value, $key, $iterator); + static function (Iterator $iterator) use ($callback, $size): Generator { + $defaultCallback = + /** + * @param mixed $value + * @param mixed $key + * @psalm-param T $value + * @psalm-param TKey $key + * @psalm-param Iterator $iterator + */ + static function ($value, $key, Iterator $iterator): bool { + return true; + }; + + $callback = $callback ?? $defaultCallback; + + $filter = (new Filter())()($callback); + $limit = (new Limit())()($size)(0); + + return yield from (new Run())()($filter, $limit)($iterator); }; - - return yield from (new Run(new Filter($callback), new Limit($size)))($iterator); }; + }; } } diff --git a/src/Operation/Flatten.php b/src/Operation/Flatten.php index 5b45e73b0..f0ead4ebb 100644 --- a/src/Operation/Flatten.php +++ b/src/Operation/Flatten.php @@ -18,20 +18,10 @@ */ final class Flatten extends AbstractOperation implements Operation { - public function __construct(int $depth) - { - $this->storage['depth'] = $depth; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $depth): Generator { + return static function (int $depth): Closure { + return static function (Iterator $iterator) use ($depth): Generator { foreach ($iterator as $key => $value) { if (false === is_iterable($value)) { yield $key => $value; @@ -41,14 +31,15 @@ static function (Iterator $iterator, int $depth): Generator { yield $subKey => $subValue; } } else { - /** @psalm-var IterableIterator $iterable */ - $iterable = (new Run(new Flatten($depth - 1)))(new IterableIterator($value)); + /** @psalm-var IterableIterator $flatten */ + $flatten = (new Flatten())()($depth - 1); - foreach ($iterable as $subKey => $subValue) { + foreach ((new Run())()($flatten)(new IterableIterator($value)) as $subKey => $subValue) { yield $subKey => $subValue; } } } }; + }; } } diff --git a/src/Operation/Forget.php b/src/Operation/Forget.php index 32cd3cc9e..fad9ef16e 100644 --- a/src/Operation/Forget.php +++ b/src/Operation/Forget.php @@ -18,25 +18,10 @@ */ final class Forget extends AbstractOperation implements Operation { - /** - * @param mixed ...$keys - * @psalm-param TKey ...$keys - */ - public function __construct(...$keys) - { - $this->storage['keys'] = $keys; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $keys - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $keys): Generator { + return static function (...$keys): Closure { + return static function (Iterator $iterator) use ($keys): Generator { $keys = array_flip($keys); foreach ($iterator as $key => $value) { @@ -45,5 +30,6 @@ static function (Iterator $iterator, array $keys): Generator { } } }; + }; } } diff --git a/src/Operation/Group.php b/src/Operation/Group.php index b834c298d..1850973c3 100644 --- a/src/Operation/Group.php +++ b/src/Operation/Group.php @@ -18,57 +18,62 @@ */ final class Group extends AbstractOperation implements Operation { - public function __construct(?callable $callable = null) - { - $this->storage['callable'] = $callable ?? - /** - * @param mixed $key - * @psalm-param TKey $key - * - * @param mixed $value - * @psalm-param T $value - * - * @return mixed - * @psalm-return TKey - */ - static function ($value, $key) { - return $key; - }; - } - + /** + * @psalm-return Closure(null|callable(TKey, T):(TKey)): Closure(Iterator): Generator> + */ public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * @psalm-param callable(TKey, T):(TKey) $callable - * - * @psalm-return Generator> + * @psalm-param null|callable(TKey, T):(T|TKey) $callable */ - static function (Iterator $iterator, callable $callable): Generator { - $callback = + static function (?callable $callable = null): Closure { + return /** - * @psalm-param array> $collect + * @psalm-param Iterator $iterator * - * @param mixed $value - * @psalm-param T $value - * - * @param mixed $key - * @psalm-param TKey $key - * - * @psalm-return array> + * @psalm-return Generator> */ - static function (array $collect, $value, $key) use ($callable): array { - if (null !== $groupKey = $callable($value, $key)) { - $collect[$groupKey][] = $value; - } else { - $collect[$key] = $value; - } + static function (Iterator $iterator) use ($callable): Generator { + $callable = $callable ?? + /** + * @param mixed $key + * @psalm-param TKey $key + * + * @param mixed $value + * @psalm-param T $value + * + * @return mixed + * @psalm-return TKey + */ + static function ($value, $key) { + return $key; + }; - return $collect; - }; + $callback = + /** + * @psalm-param array> $collect + * + * @param mixed $value + * @psalm-param T $value + * + * @param mixed $key + * @psalm-param TKey $key + * + * @psalm-return array> + */ + static function (array $collect, $value, $key) use ($callable): array { + if (null !== $groupKey = $callable($value, $key)) { + $collect[$groupKey][] = $value; + } else { + $collect[$key] = $value; + } - return yield from (new Transform(new FoldLeft($callback, [])))($iterator); + return $collect; + }; + + return yield from (new Transform(new FoldLeft($callback, [])))($iterator); + }; }; } } diff --git a/src/Operation/IfThenElse.php b/src/Operation/IfThenElse.php index fbce20e58..b04ec6300 100644 --- a/src/Operation/IfThenElse.php +++ b/src/Operation/IfThenElse.php @@ -16,33 +16,43 @@ */ final class IfThenElse extends AbstractOperation implements Operation { - /** - * @psalm-param callable(T, TKey): bool $condition - * @psalm-param callable(T, TKey): (T|TKey) $then - * @psalm-param callable(T, TKey): (T|TKey) $else - */ - public function __construct(callable $condition, callable $then, callable $else) - { - $this->storage = [ - 'condition' => $condition, - 'then' => $then, - 'else' => $else, - ]; - } - // phpcs:disable /** - * @psalm-return Closure(Iterator, callable(T, TKey): bool, callable(T, TKey): (T|TKey), callable(T, TKey): (T|TKey)): Generator + * @psalm-return Closure(callable(T, TKey): bool): Closure(callable(T, TKey): (T|TKey)): Closure(callable(T, TKey): (T|TKey)): Generator */ // phpcs:enable public function __invoke(): Closure { - return static function (Iterator $iterator, callable $condition, callable $then, callable $else): Generator { - foreach ($iterator as $key => $value) { - yield $key => $condition($value, $key) ? - $then($value, $key) : - $else($value, $key); - } - }; + return + /** + * @psalm-param callable(T, TKey): bool $condition + */ + static function (callable $condition): Closure { + return + /** + * @psalm-param callable(T, TKey): (T|TKey) $then + */ + static function (callable $then) use ($condition): Closure { + return + /** + * @psalm-param callable(T, TKey): (T|TKey) $else + */ + static function (callable $else) use ($condition, $then): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($condition, $then, $else): Generator { + foreach ($iterator as $key => $value) { + yield $key => $condition($value, $key) ? + $then($value, $key) : + $else($value, $key); + } + }; + }; + }; + }; } } diff --git a/src/Operation/Intersect.php b/src/Operation/Intersect.php index e64ccb3a0..abe6dcd94 100644 --- a/src/Operation/Intersect.php +++ b/src/Operation/Intersect.php @@ -18,25 +18,10 @@ */ final class Intersect extends AbstractOperation implements Operation { - /** - * @param mixed ...$values - * @psalm-param T ...$values - */ - public function __construct(...$values) - { - $this->storage['values'] = $values; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $values): Generator { + return static function (...$values): Closure { + return static function (Iterator $iterator) use ($values): Generator { foreach ($iterator as $key => $value) { if (false === in_array($value, $values, true)) { continue; @@ -45,5 +30,6 @@ static function (Iterator $iterator, array $values): Generator { yield $key => $value; } }; + }; } } diff --git a/src/Operation/IntersectKeys.php b/src/Operation/IntersectKeys.php index 3188fc1a9..15e3d59c2 100644 --- a/src/Operation/IntersectKeys.php +++ b/src/Operation/IntersectKeys.php @@ -18,27 +18,10 @@ */ final class IntersectKeys extends AbstractOperation implements Operation { - /** - * @param mixed ...$values - * @psalm-param TKey ...$values - */ - public function __construct(...$values) - { - $this->storage['values'] = $values; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $values - * - * @psalm-return Generator - * - * @param mixed $values - */ - static function (Iterator $iterator, array $values): Generator { + return static function (...$values): Closure { + return static function (Iterator $iterator) use ($values): Generator { foreach ($iterator as $key => $value) { if (false === in_array($key, $values, true)) { continue; @@ -47,5 +30,6 @@ static function (Iterator $iterator, array $values): Generator { yield $key => $value; } }; + }; } } diff --git a/src/Operation/Intersperse.php b/src/Operation/Intersperse.php index f22e92544..86a4b2c88 100644 --- a/src/Operation/Intersperse.php +++ b/src/Operation/Intersperse.php @@ -11,11 +11,6 @@ use loophp\collection\Contract\Operation; /** - * Class Intersperse. - * - * Insert a given value between each element of a collection. - * Indices are not preserved. - * * @psalm-template TKey * @psalm-template TKey of array-key * @psalm-template T @@ -23,45 +18,48 @@ final class Intersperse extends AbstractOperation implements Operation { /** - * @param mixed $element - * @psalm-param T $element + * @psalm-return Closure(T): Closure(int): Closure(int): Closure(Iterator): Generator */ - public function __construct($element, int $atEvery, int $startAt) - { - if (0 > $atEvery) { - throw new InvalidArgumentException('The second parameter must be a positive integer.'); - } - - if (0 > $startAt) { - throw new InvalidArgumentException('The third parameter must be a positive integer.'); - } - - $this->storage = [ - 'element' => $element, - 'atEvery' => $atEvery, - 'startAt' => $startAt, - ]; - } - public function __invoke(): Closure { return /** - * @psalm-param Iterator $iterator - * - * @param mixed $element * @psalm-param T $element * - * @psalm-return Generator + * @param mixed $element */ - static function (Iterator $iterator, $element, int $every, int $startAt): Generator { - foreach ($iterator as $key => $value) { - if (0 === $startAt++ % $every) { - yield $element; - } + static function ($element): Closure { + return static function (int $atEvery) use ($element): Closure { + return static function (int $startAt) use ($element, $atEvery): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($element, $atEvery, $startAt): Generator { + if (0 > $atEvery) { + throw new InvalidArgumentException( + 'The second parameter must be a positive integer.' + ); + } + + if (0 > $startAt) { + throw new InvalidArgumentException( + 'The third parameter must be a positive integer.' + ); + } + + foreach ($iterator as $key => $value) { + if (0 === $startAt++ % $atEvery) { + yield $element; + } - yield $key => $value; - } + yield $key => $value; + } + }; + }; + }; }; } } diff --git a/src/Operation/Iterate.php b/src/Operation/Iterate.php index 2bdd4738a..f44709c11 100644 --- a/src/Operation/Iterate.php +++ b/src/Operation/Iterate.php @@ -16,36 +16,18 @@ */ final class Iterate extends AbstractOperation implements Operation { - /** - * @param array $parameters - * @psalm-param array $parameters - * - * @psalm-param callable(...list):(array) $callback - */ - public function __construct(callable $callback, array $parameters = []) - { - $this->storage = [ - 'callback' => $callback, - 'parameters' => $parameters, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param callable(...list):(array) $callback - * - * @param array $parameters - * @psalm-param array $parameters - */ - static function (Iterator $iterator, callable $callback, array $parameters): Generator { - while (true) { - yield current( - $parameters = (array) $callback(...array_values((array) $parameters)) - ); - } + return static function (callable $callback): Closure { + return static function (...$parameters) use ($callback): Closure { + return static function (Iterator $iterator) use ($callback, $parameters): Generator { + while (true) { + yield current( + $parameters = (array) $callback(...array_values((array) $parameters)) + ); + } + }; }; + }; } } diff --git a/src/Operation/Last.php b/src/Operation/Last.php index 4394b5573..7ee285e70 100644 --- a/src/Operation/Last.php +++ b/src/Operation/Last.php @@ -17,58 +17,38 @@ */ final class Last extends AbstractOperation implements Operation { - /** - * @var callable|Closure - * @psalm-var callable(T, TKey):(bool)|Closure(T, TKey):(bool) - */ - private $callback; - - /** - * @psalm-param Closure(T, TKey):(bool)|callable(T, TKey):(bool)|null $callback - * @psalm-param T|null $default - */ - public function __construct(?callable $callback = null, int $size = 1) - { - $defaultCallback = - /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key - * @psalm-param Iterator $iterator - */ - static function ($value, $key, Iterator $iterator): bool { - return true; - }; - - $this->storage = [ - 'callback' => $callback ?? $defaultCallback, - 'size' => $size, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, callable $callback, int $size): Generator { - $callback = + return static function (?callable $callback = null): Closure { + return static function (int $size) use ($callback): Closure { + return /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key * @psalm-param Iterator $iterator + * + * @psalm-return Generator */ - static function ($value, $key, Iterator $iterator) use ($callback): bool { - return true === $callback($value, $key, $iterator); + static function (Iterator $iterator) use ($callback, $size): Generator { + $defaultCallback = + /** + * @param mixed $value + * @param mixed $key + * @psalm-param T $value + * @psalm-param TKey $key + * @psalm-param Iterator $iterator + */ + static function ($value, $key, Iterator $iterator): bool { + return true; + }; + + $callback = $callback ?? $defaultCallback; + + $filter = (new Filter())()($callback); + $reverse = (new Reverse())(); + $limit = (new Limit())()($size)(0); + + return yield from (new Run())()($filter, $reverse, $limit)($iterator); }; - - return yield from (new Run(new Filter($callback), new Reverse(), new Limit($size)))($iterator); }; + }; } } diff --git a/src/Operation/Limit.php b/src/Operation/Limit.php index 9c625ecf4..84f30a378 100644 --- a/src/Operation/Limit.php +++ b/src/Operation/Limit.php @@ -17,28 +17,18 @@ */ final class Limit extends AbstractOperation implements Operation { - public function __construct(int $limit, int $offset = 0) - { - $this->storage = [ - 'limit' => $limit, - 'offset' => $offset, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $limit, int $offset): Generator { - if (0 === $limit) { - return yield from []; - } + return static function (int $limit): Closure { + return static function (int $offset = 0) use ($limit): Closure { + return static function (Iterator $iterator) use ($limit, $offset): Generator { + if (0 === $limit) { + return yield from []; + } - return yield from new LimitIterator($iterator, $offset, $limit); + return yield from new LimitIterator($iterator, $offset, $limit); + }; }; + }; } } diff --git a/src/Operation/Loop.php b/src/Operation/Loop.php index 31ce8b1b6..f7309d46c 100644 --- a/src/Operation/Loop.php +++ b/src/Operation/Loop.php @@ -19,14 +19,8 @@ final class Loop extends AbstractOperation implements Operation { public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator): Generator { - return yield from new InfiniteIterator($iterator); - }; + return static function (Iterator $iterator): Generator { + return yield from new InfiniteIterator($iterator); + }; } } diff --git a/src/Operation/Map.php b/src/Operation/Map.php index 9376bb3a2..7fbc94256 100644 --- a/src/Operation/Map.php +++ b/src/Operation/Map.php @@ -16,21 +16,10 @@ */ final class Map extends AbstractOperation implements Operation { - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $callbacks): Generator { + return static function (callable ...$callbacks): Closure { + return static function (Iterator $iterator) use ($callbacks): Generator { foreach ($iterator as $key => $value) { $callback = /** @@ -46,5 +35,6 @@ static function ($carry, callable $callback) use ($value, $key) { yield $key => array_reduce($callbacks, $callback, $value); } }; + }; } } diff --git a/src/Operation/Merge.php b/src/Operation/Merge.php index 016bf1171..d3cea5e05 100644 --- a/src/Operation/Merge.php +++ b/src/Operation/Merge.php @@ -16,25 +16,10 @@ */ final class Merge extends AbstractOperation implements Operation { - /** - * @param iterable ...$sources - * @psalm-param Iterator ...$sources - */ - public function __construct(iterable ...$sources) - { - $this->storage['sources'] = $sources; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list> $sources - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $sources): Generator { + return static function (...$sources): Closure { + return static function (Iterator $iterator) use ($sources): Generator { foreach ($iterator as $key => $value) { yield $key => $value; } @@ -45,5 +30,6 @@ static function (Iterator $iterator, array $sources): Generator { } } }; + }; } } diff --git a/src/Operation/Normalize.php b/src/Operation/Normalize.php index 259d48bfb..a52c4b5a5 100644 --- a/src/Operation/Normalize.php +++ b/src/Operation/Normalize.php @@ -18,16 +18,10 @@ final class Normalize extends AbstractOperation implements Operation { public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator): Generator { - foreach ($iterator as $value) { - yield $value; - } - }; + return static function (Iterator $iterator): Generator { + foreach ($iterator as $value) { + yield $value; + } + }; } } diff --git a/src/Operation/Nth.php b/src/Operation/Nth.php index 8de721c94..0324a3b5d 100644 --- a/src/Operation/Nth.php +++ b/src/Operation/Nth.php @@ -16,32 +16,22 @@ */ final class Nth extends AbstractOperation implements Operation { - public function __construct(int $step, int $offset) - { - $this->storage = [ - 'step' => $step, - 'offset' => $offset, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $step, int $offset): Generator { - $position = 0; + return static function (int $step): Closure { + return static function (int $offset) use ($step): Closure { + return static function (Iterator $iterator) use ($step, $offset): Generator { + $position = 0; - foreach ($iterator as $key => $value) { - if ($position++ % $step !== $offset) { - continue; - } + foreach ($iterator as $key => $value) { + if ($position++ % $step !== $offset) { + continue; + } - yield $key => $value; - } + yield $key => $value; + } + }; }; + }; } } diff --git a/src/Operation/Only.php b/src/Operation/Only.php index d8a996b28..49b9384e2 100644 --- a/src/Operation/Only.php +++ b/src/Operation/Only.php @@ -18,27 +18,10 @@ */ final class Only extends AbstractOperation implements Operation { - /** - * @param mixed ...$keys - * @psalm-param TKey ...$keys - */ - public function __construct(...$keys) - { - $this->storage = [ - 'keys' => $keys, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $keys - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $keys): Generator { + return static function (...$keys): Closure { + return static function (Iterator $iterator) use ($keys): Generator { if ([] === $keys) { return yield from $iterator; } @@ -53,5 +36,6 @@ static function (Iterator $iterator, array $keys): Generator { yield $key => $value; } }; + }; } } diff --git a/src/Operation/Pad.php b/src/Operation/Pad.php index db684956b..3ef39dab7 100644 --- a/src/Operation/Pad.php +++ b/src/Operation/Pad.php @@ -16,41 +16,24 @@ */ final class Pad extends AbstractOperation implements Operation { - /** - * @param mixed $value - * @psalm-param T $value - */ - public function __construct(int $size, $value) - { - $this->storage = [ - 'size' => $size, - 'value' => $value, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param T $padValue - * - * @psalm-return Generator - * - * @param mixed $padValue - */ - static function (Iterator $iterator, int $size, $padValue): Generator { - $y = 0; + return static function (int $size): Closure { + return static function ($padValue) use ($size): Closure { + return static function (Iterator $iterator) use ($size, $padValue): Generator { + $y = 0; - foreach ($iterator as $key => $value) { - ++$y; + foreach ($iterator as $key => $value) { + ++$y; - yield $key => $value; - } + yield $key => $value; + } - while ($y++ < $size) { - yield $padValue; - } + while ($y++ < $size) { + yield $padValue; + } + }; }; + }; } } diff --git a/src/Operation/Pair.php b/src/Operation/Pair.php index 1d536d717..9eeb2969e 100644 --- a/src/Operation/Pair.php +++ b/src/Operation/Pair.php @@ -15,7 +15,7 @@ * @psalm-template TKey of array-key * @psalm-template T */ -final class Pair extends AbstractOperation implements Operation +final class Pair extends AbstractOperation extends AbstractOperation implements Operation { public function __invoke(): Closure { @@ -26,8 +26,10 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator): Generator { + $chunk = (new Chunk())()(2); + /** @psalm-var list $chunk */ - foreach ((new Run(new Chunk(2)))($iterator) as $chunk) { + foreach ((new Run())()($chunk)($iterator) as $chunk) { $chunk = array_values($chunk); yield $chunk[0] => $chunk[1]; diff --git a/src/Operation/Pluck.php b/src/Operation/Pluck.php index 39f5618b0..45128acbd 100644 --- a/src/Operation/Pluck.php +++ b/src/Operation/Pluck.php @@ -16,7 +16,6 @@ use loophp\collection\Transformation\Run; use loophp\collection\Transformation\Transform; use ReflectionClass; -use ReflectionException; use function array_key_exists; use function in_array; @@ -25,79 +24,53 @@ final class Pluck extends AbstractOperation implements Operation { - /** - * Pluck constructor. - * - * @param array|string $key - * @param mixed $default - */ - public function __construct($key, $default) - { - $this->storage = [ - 'key' => $key, - 'default' => $default, - 'operation' => Closure::fromCallable([$this, 'pick']), - ]; - } - public function __invoke(): Closure { - return - /** - * @param array|string $key - * @param mixed $default - */ - static function (Iterator $iterator, $key, $default, callable $pick): Generator { - $key = true === is_scalar($key) ? explode('.', trim((string) $key, '.')) : $key; + return static function ($key): Closure { + return static function ($default) use ($key): Closure { + return static function (Iterator $iterator) use ($key, $default): Generator { + $pick = static function (Iterator $iterator, $target, array $key, $default = null) use (&$pick) { + while (null !== $segment = array_shift($key)) { + if ('*' === $segment) { + if (false === is_iterable($target)) { + return $default; + } - foreach ($iterator as $value) { - yield $pick($iterator, $value, $key, $default); - } - }; - } + $result = []; - /** - * Get an item from an array or object using "dot" notation. - * - * @param Iterator $iterator - * @param mixed $target - * @param array $key - * @param mixed $default - * - * @throws ReflectionException - * - * @return mixed - */ - private function pick(Iterator $iterator, $target, array $key, $default = null) - { - while (null !== $segment = array_shift($key)) { - if ('*' === $segment) { - if (false === is_iterable($target)) { - return $default; - } + foreach ($target as $item) { + $result[] = $pick($iterator, $item, $key); + } - $result = []; + $collapse = (new Collapse())(); - foreach ($target as $item) { - $result[] = $this->pick($iterator, $item, $key); - } + return in_array('*', $key, true) ? (new Run())()($collapse)(new ArrayIterator($result)) : $result; + } - return in_array('*', $key, true) ? (new Run((new Collapse())))(new ArrayIterator($result)) : $result; - } + if ((true === is_array($target)) && (true === array_key_exists($segment, $target))) { + $target = $target[$segment]; + } elseif (($target instanceof ArrayAccess) && (true === $target->offsetExists($segment))) { + $target = $target[$segment]; + } elseif ($target instanceof Collection) { + $get = (new Get())()($segment)($default); + $target = (new Transform())()($get)(new IterableIterator($target)); + } elseif ((true === is_object($target)) && (true === property_exists($target, $segment))) { + $target = (new ReflectionClass($target))->getProperty($segment)->getValue($target); + } else { + $target = $default; + } + } - if ((true === is_array($target)) && (true === array_key_exists($segment, $target))) { - $target = $target[$segment]; - } elseif (($target instanceof ArrayAccess) && (true === $target->offsetExists($segment))) { - $target = $target[$segment]; - } elseif ($target instanceof Collection) { - $target = (new Transform(new Get($segment, $default)))(new IterableIterator($target)); - } elseif ((true === is_object($target)) && (true === property_exists($target, $segment))) { - $target = (new ReflectionClass($target))->getProperty($segment)->getValue($target); - } else { - $target = $default; - } - } + return $target; + }; - return $target; + $key = true === is_scalar($key) ? explode('.', trim((string) $key, '.')) : $key; + + foreach ($iterator as $value) { + yield $pick($iterator, $value, $key, $default); + } + }; + }; + }; } } diff --git a/src/Operation/Prepend.php b/src/Operation/Prepend.php index 1a92729a6..ff81bcbfa 100644 --- a/src/Operation/Prepend.php +++ b/src/Operation/Prepend.php @@ -16,25 +16,10 @@ */ final class Prepend extends AbstractOperation implements Operation { - /** - * @param mixed ...$items - * @psalm-param T ...$items - */ - public function __construct(...$items) - { - $this->storage['items'] = $items; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $items - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $items): Generator { + return static function (...$items): Closure { + return static function (Iterator $iterator) use ($items): Generator { foreach ($items as $key => $item) { yield $key => $item; } @@ -43,5 +28,6 @@ static function (Iterator $iterator, array $items): Generator { yield $key => $value; } }; + }; } } diff --git a/src/Operation/Product.php b/src/Operation/Product.php index 518498700..e4eb970e1 100644 --- a/src/Operation/Product.php +++ b/src/Operation/Product.php @@ -19,37 +19,14 @@ */ final class Product extends AbstractOperation implements Operation { - /** - * @param iterable ...$iterables - * @psalm-param Iterator ...$iterables - */ - public function __construct(iterable ...$iterables) - { - $this->storage = [ - 'iterables' => $iterables, - 'cartesian' => - /** - * @param array $input - * @psalm-param array> $input - * - * @psalm-return Generator> - */ - function (array $input): Generator { - return $this->cartesian($input); - }, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param array> $iterables - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, array $iterables, callable $cartesian): Generator { + $cartesian = function (array $input): Generator { + return $this->cartesian($input); + }; + + return static function (iterable ...$iterables) use ($cartesian): Closure { + return static function (Iterator $iterator) use ($cartesian, $iterables): Generator { $its = [$iterator]; foreach ($iterables as $iterable) { @@ -58,6 +35,7 @@ static function (Iterator $iterator, array $iterables, callable $cartesian): Gen return yield from $cartesian($its); }; + }; } /** diff --git a/src/Operation/RSample.php b/src/Operation/RSample.php index 581df41f3..255f4c6a4 100644 --- a/src/Operation/RSample.php +++ b/src/Operation/RSample.php @@ -17,27 +17,18 @@ */ final class RSample extends AbstractOperation implements Operation { - public function __construct(float $probability) - { - $this->storage['probability'] = $probability; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, float $probability): Generator { - return yield from (new Run( - new Filter( - static function () use ($probability): bool { - return (mt_rand() / mt_getrandmax()) < $probability; - } - ) - ))($iterator); + return static function (float $probability): Closure { + return static function (Iterator $iterator) use ($probability): Generator { + $filter = (new Filter())()( + static function () use ($probability): bool { + return (mt_rand() / mt_getrandmax()) < $probability; + } + ); + + return yield from (new Run())()($filter)($iterator); }; + }; } } diff --git a/src/Operation/Random.php b/src/Operation/Random.php index 9e373510e..dcab5073e 100644 --- a/src/Operation/Random.php +++ b/src/Operation/Random.php @@ -17,23 +17,15 @@ */ final class Random extends AbstractOperation implements Operation { - public function __construct(int $size) - { - $this->storage = [ - 'size' => $size, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $size): Generator { - return yield from (new Run(new Limit($size), new Shuffle()))($iterator); + return static function (int $size): Closure { + return static function (Iterator $iterator) use ($size): Generator { + $limit = (new Limit())()($size)(0); + $shuffle = (new Shuffle())(); + + return yield from (new Run())()($limit, $shuffle)($iterator); }; + }; } } diff --git a/src/Operation/Range.php b/src/Operation/Range.php index 6988ff30c..11798d9d3 100644 --- a/src/Operation/Range.php +++ b/src/Operation/Range.php @@ -13,21 +13,18 @@ final class Range extends AbstractOperation implements Operation { - public function __construct(float $start = 0.0, float $end = INF, float $step = 1.0) - { - $this->storage = [ - 'start' => $start, - 'end' => $end, - 'step' => $step, - ]; - } - public function __invoke(): Closure { - return static function (Iterator $iterator, float $start, float $end, float $step): Generator { - for ($current = $start; $current < $end; $current += $step) { - yield $current; - } + return static function (float $start = 0.0): Closure { + return static function (float $end = INF) use ($start): Closure { + return static function (float $step = 1.0) use ($start, $end): Closure { + return static function (Iterator $iterator) use ($start, $end, $step): Generator { + for ($current = $start; $current < $end; $current += $step) { + yield $current; + } + }; + }; + }; }; } } diff --git a/src/Operation/Reduction.php b/src/Operation/Reduction.php index bf6f6c51c..47dc59634 100644 --- a/src/Operation/Reduction.php +++ b/src/Operation/Reduction.php @@ -16,35 +16,16 @@ */ final class Reduction extends AbstractOperation implements Operation { - /** - * @param mixed|null $initial - * @psalm-param T|null $initial - * @psalm-param callable(T|null, T, TKey):(T|null) $callback - */ - public function __construct(callable $callback, $initial = null) - { - $this->storage = [ - 'callback' => $callback, - 'initial' => $initial, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param callable(T|null, T, TKey):(T|null) $callback - * - * @param mixed $initial - * @psalm-param T|null $initial - * - * @psalm-return Generator - */ - static function (Iterator $iterator, callable $callback, $initial): Generator { - foreach ($iterator as $key => $value) { - yield $key => ($initial = $callback($initial, $value, $key)); - } + return static function (callable $callback): Closure { + return static function ($initial = null) use ($callback): Closure { + return static function (Iterator $iterator) use ($callback, $initial): Generator { + foreach ($iterator as $key => $value) { + yield $key => ($initial = $callback($initial, $value, $key)); + } + }; }; + }; } } diff --git a/src/Operation/Reverse.php b/src/Operation/Reverse.php index d089b1dc2..c5617a1bb 100644 --- a/src/Operation/Reverse.php +++ b/src/Operation/Reverse.php @@ -27,7 +27,7 @@ public function __invoke(): Closure */ static function (Iterator $iterator): Generator { /** @psalm-var array $all */ - $all = iterator_to_array((new Run(new Pack()))($iterator)); + $all = iterator_to_array((new Run())()((new Pack())())($iterator)); for (end($all); null !== key($all); prev($all)) { $item = current($all); diff --git a/src/Operation/Scale.php b/src/Operation/Scale.php index 66fb9b996..85ad08f64 100644 --- a/src/Operation/Scale.php +++ b/src/Operation/Scale.php @@ -19,51 +19,50 @@ */ final class Scale extends AbstractOperation implements Operation { - public function __construct( - float $lowerBound, - float $upperBound, - float $wantedLowerBound = 0.0, - float $wantedUpperBound = 1.0, - float $base = 0.0 - ) { - $wantedLowerBound = (0.0 === $wantedLowerBound) ? (0.0 === $base ? 0.0 : 1.0) : $wantedLowerBound; // phpcs:ignore - $wantedUpperBound = (1.0 === $wantedUpperBound) ? (0.0 === $base ? 1.0 : $base) : $wantedUpperBound; // phpcs:ignore + public function __invoke(): Closure + { + return static function (float $lowerBound): Closure { + return static function (float $upperBound) use ($lowerBound): Closure { + return static function (float $wantedLowerBound = 0.0) use ($lowerBound, $upperBound): Closure { + return static function (float $wantedUpperBound = 1.0) use ($lowerBound, $upperBound, $wantedLowerBound): Closure { // phpcs:ignore + return static function (float $base = 0.0) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound): Closure { // phpcs:ignore + return static function (Iterator $iterator) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base): Generator { // phpcs:ignore + $wantedLowerBound = (0.0 === $wantedLowerBound) ? (0.0 === $base ? 0.0 : 1.0) : $wantedLowerBound; // phpcs:ignore + $wantedUpperBound = (1.0 === $wantedUpperBound) ? (0.0 === $base ? 1.0 : $base) : $wantedUpperBound; // phpcs:ignore - $this->storage['mapper'] = new Map( - /** - * @param float|int $v - */ - static function ($v) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base): float { // phpcs:ignore - $mx = 0.0 === $base ? - ($v - $lowerBound) / ($upperBound - $lowerBound) : - log($v - $lowerBound, $base) / log($upperBound - $lowerBound, $base); + $mapper = (new Map())()( + static function ($v) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base): float { // phpcs:ignore + $mx = 0.0 === $base ? + ($v - $lowerBound) / ($upperBound - $lowerBound) : + log($v - $lowerBound, $base) / log($upperBound - $lowerBound, $base); - $mx = $mx === -INF ? 0 : $mx; + $mx = $mx === -INF ? 0 : $mx; - return $wantedLowerBound + $mx * ($wantedUpperBound - $wantedLowerBound); - } - ); + return $wantedLowerBound + $mx * ($wantedUpperBound - $wantedLowerBound); + } + ); - $this->storage['filter'] = new Filter( - /** - * @param float|int $item - */ - static function ($item) use ($lowerBound): bool { - return $item >= $lowerBound; - }, - /** - * @param float|int $item - */ - static function ($item) use ($upperBound): bool { - return $item <= $upperBound; - } - ); - } + $filter = (new Filter())()( + /** + * @param float|int $item + */ + static function ($item) use ($lowerBound): bool { + return $item >= $lowerBound; + }, + /** + * @param float|int $item + */ + static function ($item) use ($upperBound): bool { + return $item <= $upperBound; + } + ); - public function __invoke(): Closure - { - return static function (Iterator $iterator, Map $mapper, Filter $filter): Generator { - return yield from (new Run($filter, $mapper))($iterator); + return yield from (new Run())()($filter, $mapper)($iterator); + }; + }; + }; + }; + }; }; } } diff --git a/src/Operation/Shuffle.php b/src/Operation/Shuffle.php index 7c549ca77..95125f8d1 100644 --- a/src/Operation/Shuffle.php +++ b/src/Operation/Shuffle.php @@ -27,7 +27,7 @@ public function __invoke(): Closure */ static function (Iterator $iterator): Generator { /** @psalm-var array $data */ - $data = iterator_to_array((new Run(new Pack()))($iterator)); + $data = iterator_to_array((new Run())()((new Pack())())($iterator)); while ([] !== $data) { $randomKey = array_rand($data); diff --git a/src/Operation/Since.php b/src/Operation/Since.php index a7d0a4436..18303c754 100644 --- a/src/Operation/Since.php +++ b/src/Operation/Since.php @@ -16,25 +16,10 @@ */ final class Since extends AbstractOperation implements Operation { - /** - * @param callable ...$callbacks - * @psalm-param callable(T, TKey):(bool) ...$callbacks - */ - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $callbacks): Generator { + return static function (callable ...$callbacks): Closure { + return static function (Iterator $iterator) use ($callbacks): Generator { while ($iterator->valid()) { $result = array_reduce( $callbacks, @@ -57,5 +42,6 @@ static function (bool $carry, callable $callable) use ($iterator): bool { yield $iterator->key() => $iterator->current(); } }; + }; } } diff --git a/src/Operation/Skip.php b/src/Operation/Skip.php index 6e3172a79..05e7d4dc5 100644 --- a/src/Operation/Skip.php +++ b/src/Operation/Skip.php @@ -16,21 +16,10 @@ */ final class Skip extends AbstractOperation implements Operation { - public function __construct(int ...$skip) - { - $this->storage['skip'] = $skip; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $skip - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $skip): Generator { + return static function (int ...$skip): Closure { + return static function (Iterator $iterator) use ($skip): Generator { $skip = array_sum($skip); foreach ($iterator as $key => $value) { @@ -41,5 +30,6 @@ static function (Iterator $iterator, array $skip): Generator { yield $key => $value; } }; + }; } } diff --git a/src/Operation/Slice.php b/src/Operation/Slice.php index f3983727a..8dfc72db9 100644 --- a/src/Operation/Slice.php +++ b/src/Operation/Slice.php @@ -17,30 +17,28 @@ */ final class Slice extends AbstractOperation implements Operation { - public function __construct(int $offset, int $length = -1) - { - $this->storage = [ - 'offset' => $offset, - 'length' => $length, - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $offset, int $length): Generator { - $skip = (new Run(new Skip($offset)))($iterator); + return static function (int $offset): Closure { + return static function (int $length = -1) use ($offset): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($offset, $length): Generator { + $skip = (new Skip())()($offset); + + if (-1 === $length) { + return yield from (new Run())()($skip)($iterator); + } - if (-1 === $length) { - return yield from $skip; - } + $limit = (new Limit())()($length)(0); - return yield from (new Run(new Limit($length)))($skip); + return yield from (new Run())()($skip, $limit)($iterator); + }; }; + }; } } diff --git a/src/Operation/Sort.php b/src/Operation/Sort.php index 666600da7..d23b6bdb2 100644 --- a/src/Operation/Sort.php +++ b/src/Operation/Sort.php @@ -19,63 +19,53 @@ */ final class Sort extends AbstractOperation implements Operation { - public function __construct(int $type = Operation\Sortable::BY_VALUES, ?callable $callback = null) - { - $this->storage = [ - 'type' => $type, - 'callback' => $callback ?? Closure::fromCallable([$this, 'compare']), - ]; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param callable(T, T):(int) $callback - * - * @psalm-return Generator - */ - static function (Iterator $iterator, int $type, callable $callback): Generator { - if (Operation\Sortable::BY_VALUES !== $type && Operation\Sortable::BY_KEYS !== $type) { - throw new Exception('Invalid sort type.'); - } + return static function (int $type = Operation\Sortable::BY_VALUES): Closure { + return static function (?callable $callback = null) use ($type): Closure { + $callback = $callback ?? static function ($left, $right): int { + return $left <=> $right; + }; - $operations = Operation\Sortable::BY_VALUES === $type ? - [ - 'before' => [new Pack()], - 'after' => [new Unpack()], - ] : - [ - 'before' => [new Flip(), new Pack()], - 'after' => [new Unpack(), new Flip()], - ]; - - $callback = + return /** - * @psalm-param array{0:TKey, 1:T} $left - * @psalm-param array{0:TKey, 1:T} $right + * @psalm-param \Iterator $iterator + * @psalm-param callable(T, T):(int) $callback + * + * @psalm-return \Generator */ - static function (array $left, array $right) use ($callback): int { - return $callback($left[1], $right[1]); - }; + static function (Iterator $iterator) use ($type, $callback): Generator { + if (Operation\Sortable::BY_VALUES !== $type && Operation\Sortable::BY_KEYS !== $type) { + throw new Exception('Invalid sort type.'); + } - $arrayIterator = new ArrayIterator(iterator_to_array((new Run(...$operations['before']))($iterator))); - $arrayIterator->uasort($callback); + $operations = Operation\Sortable::BY_VALUES === $type ? + [ + 'before' => [new Pack()], + 'after' => [new Unpack()], + ] : + [ + 'before' => [new Flip(), new Pack()], + 'after' => [new Unpack(), new Flip()], + ]; - return yield from (new Run(...$operations['after']))($arrayIterator); - }; - } + $callback = + /** + * @psalm-param array{0:TKey, 1:T} $left + * @psalm-param array{0:TKey, 1:T} $right + */ + static function (array $left, array $right) use ($defaultCallback): int { + return $defaultCallback($left[1], $right[1]); + }; - /** - * @psalm-param T $left - * @psalm-param T $right - * - * @param mixed $left - * @param mixed $right - */ - private function compare($left, $right): int - { - return $left <=> $right; + $arrayIterator = new ArrayIterator(iterator_to_array((new Run())()(...$operations['before'])($iterator))); + $arrayIterator->uasort($callback); + + return yield from ( + (new Run())()(...$operations['after'])($arrayIterator) + ); + }; + }; + }; } } diff --git a/src/Operation/Split.php b/src/Operation/Split.php index 090ecd0ac..96e5a8176 100644 --- a/src/Operation/Split.php +++ b/src/Operation/Split.php @@ -16,44 +16,41 @@ */ final class Split extends AbstractOperation implements Operation { - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, array $callbacks): Generator { - $carry = []; - - foreach ($iterator as $key => $value) { - $callbackReturn = array_reduce( - $callbacks, - static function (bool $carry, callable $callback) use ($key, $value): bool { - return $callback($value, $key) !== $carry; - }, - false - ); - - if (true === $callbackReturn && [] !== $carry) { - yield $carry; - - $carry = []; + return static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param \Iterator $iterator + * @psalm-param list $callbacks + * + * @psalm-return \Generator> + */ + static function (Iterator $iterator) use ($callbacks): Generator { + $carry = []; + + foreach ($iterator as $key => $value) { + $callbackReturn = array_reduce( + $callbacks, + static function (bool $carry, callable $callback) use ($key, $value): bool { + return $callback($value, $key) !== $carry; + }, + false + ); + + if (true === $callbackReturn && [] !== $carry) { + yield $carry; + + $carry = []; + } + + $carry[] = $value; } - $carry[] = $value; - } - - if ([] !== $carry) { - yield $carry; - } - }; + if ([] !== $carry) { + yield $carry; + } + }; + }; } } diff --git a/src/Operation/Tail.php b/src/Operation/Tail.php index db6fdade5..332dd454f 100644 --- a/src/Operation/Tail.php +++ b/src/Operation/Tail.php @@ -26,7 +26,7 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator): Generator { - return yield from (new Run(new Skip(1)))($iterator); + return yield from (new Run())()((new Skip())()(1))($iterator); }; } } diff --git a/src/Operation/Times.php b/src/Operation/Times.php index c73aa14d9..bf4cd5d27 100644 --- a/src/Operation/Times.php +++ b/src/Operation/Times.php @@ -17,35 +17,24 @@ */ final class Times extends AbstractOperation implements Operation { - public function __construct(?int $number = null, ?callable $callback = null) + public function __invoke(): Closure { - $number = $number ?? 0; - - if (1 > $number) { - throw new InvalidArgumentException('Invalid parameter. $number must be greater than 1.'); - } + return static function (int $number = 0): Closure { + return static function (?callable $callback = null) use ($number): Closure { + return static function (Iterator $iterator) use ($number, $callback): Generator { + if (1 > $number) { + throw new InvalidArgumentException('Invalid parameter. $number must be greater than 1.'); + } - $this->storage = [ - 'number' => $number, - 'callback' => $callback ?? static function (int $value): int { - return $value; - }, - ]; - } + $callback = $callback ?? static function (int $value): int { + return $value; + }; - public function __invoke(): Closure - { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param callable(int):(int) $callback - * - * @psalm-return Generator - */ - static function (Iterator $iterator, ?int $number, callable $callback): Generator { - for ($current = 1; $current <= $number; ++$current) { - yield $callback($current); - } + for ($current = 1; $current <= $number; ++$current) { + yield $callback($current); + } + }; }; + }; } } diff --git a/src/Operation/Transpose.php b/src/Operation/Transpose.php index bdf770ad4..f368cde6a 100644 --- a/src/Operation/Transpose.php +++ b/src/Operation/Transpose.php @@ -20,22 +20,16 @@ final class Transpose extends AbstractOperation implements Operation { public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * - * @psalm-return Generator> - */ - static function (Iterator $iterator): Generator { - $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); + return static function (Iterator $iterator): Generator { + $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); - foreach ($iterator as $collectionItem) { - $mit->attachIterator(new IterableIterator($collectionItem)); - } + foreach ($iterator as $collectionItem) { + $mit->attachIterator(new IterableIterator($collectionItem)); + } - foreach ($mit as $key => $value) { - yield current($key) => $value; - } - }; + foreach ($mit as $key => $value) { + yield current($key) => $value; + } + }; } } diff --git a/src/Operation/Until.php b/src/Operation/Until.php index ab870fd1f..c9941dcd8 100644 --- a/src/Operation/Until.php +++ b/src/Operation/Until.php @@ -16,25 +16,10 @@ */ final class Until extends AbstractOperation implements Operation { - /** - * @param callable ...$callbacks - * @psalm-param callable(T, TKey):(bool) ...$callbacks - */ - public function __construct(callable ...$callbacks) - { - $this->storage['callbacks'] = $callbacks; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list $callbacks - * - * @psalm-return Generator - */ - static function (Iterator $iterator, array $callbacks): Generator { + return static function (callable ...$callbacks): Closure { + return static function (Iterator $iterator) use ($callbacks): Generator { foreach ($iterator as $key => $value) { yield $key => $value; @@ -53,5 +38,6 @@ static function (bool $carry, callable $callable) use ($key, $value): bool { } } }; + }; } } diff --git a/src/Operation/Window.php b/src/Operation/Window.php index c9f130d43..6c449081b 100644 --- a/src/Operation/Window.php +++ b/src/Operation/Window.php @@ -18,30 +18,30 @@ */ final class Window extends AbstractOperation implements Operation { - public function __construct(int ...$length) - { - $this->storage['length'] = new ArrayIterator($length); - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param ArrayIterator $length - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, ArrayIterator $length): Generator { - /** @psalm-var Iterator $length */ - $length = (new Run(new Loop()))($length); - - for ($i = 0; iterator_count($iterator) > $i; ++$i) { - /** @psalm-var list $window */ - yield iterator_to_array((new Run(new Slice($i, $length->current())))($iterator)); - - $length->next(); - } - }; + return static function (int ...$lengths): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-param ArrayIterator $length + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($lengths): Generator { + $loop = (new Loop())(); + + /** @psalm-var Iterator $lengths */ + $lengths = (new Run())()($loop)(new ArrayIterator($lengths)); + + for ($i = 0; iterator_count($iterator) > $i; ++$i) { + $slice = (new Slice())()($i)($lengths->current()); + + yield iterator_to_array((new Run())()($slice)($iterator)); + + $lengths->next(); + } + }; + }; } } diff --git a/src/Operation/Zip.php b/src/Operation/Zip.php index 71d510238..1ed238456 100644 --- a/src/Operation/Zip.php +++ b/src/Operation/Zip.php @@ -18,36 +18,28 @@ */ final class Zip extends AbstractOperation implements Operation { - /** - * Zip constructor. - * - * @param iterable ...$iterables - */ - public function __construct(iterable ...$iterables) - { - $this->storage['iterables'] = $iterables; - } - public function __invoke(): Closure { - return - /** - * @psalm-param Iterator $iterator - * @psalm-param list> $iterables - * - * @psalm-return Generator> - */ - static function (Iterator $iterator, array $iterables): Generator { - $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); - $mit->attachIterator($iterator); + return static function (iterable ...$iterables): Closure { + return + /** + * @psalm-param \Iterator $iterator + * @psalm-param list> $iterables + * + * @psalm-return \Generator> + */ + static function (Iterator $iterator) use ($iterables): Generator { + $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); + $mit->attachIterator($iterator); - foreach ($iterables as $iterableIterator) { - $mit->attachIterator(new IterableIterator($iterableIterator)); - } + foreach ($iterables as $iterableIterator) { + $mit->attachIterator(new IterableIterator($iterableIterator)); + } - foreach ($mit as $values) { - yield $values; - } - }; + foreach ($mit as $values) { + yield $values; + } + }; + }; } } diff --git a/src/Transformation/All.php b/src/Transformation/All.php index bac2f6844..b179e5d59 100644 --- a/src/Transformation/All.php +++ b/src/Transformation/All.php @@ -21,8 +21,10 @@ final class All implements Transformation * @phpstan-return array * @psalm-return array */ - public function __invoke(Iterator $collection): array + public function __invoke() { - return iterator_to_array($collection); + return static function (Iterator $iterator): array { + return iterator_to_array($iterator); + }; } } diff --git a/src/Transformation/Contains.php b/src/Transformation/Contains.php index 4ffb76288..2cd5214c2 100644 --- a/src/Transformation/Contains.php +++ b/src/Transformation/Contains.php @@ -5,6 +5,7 @@ namespace loophp\collection\Transformation; use ArrayIterator; +use Closure; use Iterator; use loophp\collection\Contract\Transformation; @@ -32,27 +33,24 @@ public function __construct(...$values) $this->values = new ArrayIterator($values); } - /** - * @param Iterator $collection - * - * @return bool - */ - public function __invoke(Iterator $collection) + public function __invoke() { - $values = $this->values; - - foreach ($collection as $key => $value) { - foreach ($values as $k => $v) { - if ($v === $value) { - unset($values[$k]); - } - - if (0 === $values->count()) { - return true; + return static function (...$values): Closure { + return static function (Iterator $iterator) use ($values): bool { + foreach ($iterator as $key => $value) { + foreach ($values as $k => $v) { + if ($v === $value) { + unset($values[$k]); + } + + if ([] === $values) { + return true; + } + } } - } - } - return false; + return false; + }; + }; } } diff --git a/src/Transformation/Count.php b/src/Transformation/Count.php index de48eb9bf..a89b75516 100644 --- a/src/Transformation/Count.php +++ b/src/Transformation/Count.php @@ -6,7 +6,6 @@ use Iterator; use loophp\collection\Contract\Transformation; -use loophp\collection\Iterator\IterableIterator; /** * @psalm-template TKey @@ -17,8 +16,10 @@ */ final class Count implements Transformation { - public function __invoke(Iterator $collection) + public function __invoke() { - return iterator_count(new IterableIterator($collection)); + return static function (Iterator $iterator): int { + return iterator_count($iterator); + }; } } diff --git a/src/Transformation/Falsy.php b/src/Transformation/Falsy.php index 4dfb8861b..f1f56f84d 100644 --- a/src/Transformation/Falsy.php +++ b/src/Transformation/Falsy.php @@ -16,14 +16,16 @@ */ final class Falsy implements Transformation { - public function __invoke(Iterator $collection): bool + public function __invoke() { - foreach ($collection as $key => $value) { - if (false !== (bool) $value) { - return false; + return static function (Iterator $iterator): bool { + foreach ($iterator as $key => $value) { + if (false !== (bool) $value) { + return false; + } } - } - return true; + return true; + }; } } diff --git a/src/Transformation/FoldLeft.php b/src/Transformation/FoldLeft.php index 371d9aa17..405adec14 100644 --- a/src/Transformation/FoldLeft.php +++ b/src/Transformation/FoldLeft.php @@ -4,7 +4,7 @@ namespace loophp\collection\Transformation; -use Iterator; +use Closure; use loophp\collection\Contract\Transformation; /** @@ -17,44 +17,23 @@ final class FoldLeft implements Transformation { /** - * @var callable - * @psalm-var callable(T|null, T, TKey, \Iterator):(T|null) - */ - private $callback; - - /** - * @var mixed|null - * @psalm-var T|null - */ - private $initial; - - /** - * @psalm-param callable(T|null, T, TKey, \Iterator):(T|null) $callback - * - * @param mixed|null $initial - * @psalm-param T|null $initial - */ - public function __construct(callable $callback, $initial = null) - { - $this->callback = $callback; - $this->initial = $initial; - } - - /** - * @psalm-param Iterator $collection + * @psalm-param \Iterator $collection * * @return mixed|null * @psalm-return T|null */ - public function __invoke(Iterator $collection) + public function __invoke() { - $callback = $this->callback; - $initial = $this->initial; - - foreach ($collection as $key => $value) { - $initial = $callback($initial, $value, $key, $collection); - } - - return $initial; + return static function (callable $callback): Closure { + return static function ($initial = null) use ($callback): Closure { + return static function (iterable $iterable) use ($callback, $initial) { + foreach ($iterable as $key => $value) { + $initial = $callback($initial, $value, $key, $iterable); + } + + return $initial; + }; + }; + }; } } diff --git a/src/Transformation/FoldRight.php b/src/Transformation/FoldRight.php index a3d2f41ad..6f072c0d5 100644 --- a/src/Transformation/FoldRight.php +++ b/src/Transformation/FoldRight.php @@ -4,7 +4,7 @@ namespace loophp\collection\Transformation; -use Iterator; +use Closure; use loophp\collection\Contract\Transformation; use loophp\collection\Operation\Reverse; @@ -18,40 +18,22 @@ final class FoldRight implements Transformation { /** - * @var callable - * @psalm-var callable(T|null, T|null, TKey, \Iterator):(T|null) - */ - private $callback; - - /** - * @var mixed|null - * @psalm-var T|null - */ - private $initial; - - /** - * @psalm-param callable(T|null, T|null, TKey, \Iterator):(T|null) $callback - * - * @param mixed|null $initial - * @psalm-param T|null $initial - */ - public function __construct(callable $callback, $initial = null) - { - $this->callback = $callback; - $this->initial = $initial; - } - - /** - * @psalm-param Iterator $collection + * @psalm-param \Iterator $collection * * @return mixed|null * @psalm-return T|null */ - public function __invoke(Iterator $collection) + public function __invoke() { - $callback = $this->callback; - $initial = $this->initial; - - return (new Transform(new FoldLeft($callback, $initial)))((new Run(new Reverse()))($collection)); + return static function (callable $callback): Closure { + return static function ($initial = null) use ($callback): Closure { + return static function (iterable $iterable) use ($callback, $initial) { + $foldLeft = (new FoldLeft())()($callback)($initial); + $reverse = (new Reverse())(); + + return (new Transform())()($foldLeft)((new Run())()($reverse)($iterable)); + }; + }; + }; } } diff --git a/src/Transformation/Get.php b/src/Transformation/Get.php index 131227465..8809997ce 100644 --- a/src/Transformation/Get.php +++ b/src/Transformation/Get.php @@ -4,6 +4,7 @@ namespace loophp\collection\Transformation; +use Closure; use Iterator; use loophp\collection\Contract\Transformation; @@ -16,44 +17,20 @@ */ final class Get implements Transformation { - /** - * @var mixed - * @psalm-var T - */ - private $default; - - /** - * @var int|string - */ - private $key; - - /** - * @param int|string $key - * @param mixed $default - * @psalm-param T $default - */ - public function __construct($key, $default) + public function __invoke() { - $this->key = $key; - $this->default = $default; - } - - /** - * @param Iterator $collection - * - * @return T - */ - public function __invoke(Iterator $collection) - { - $keyToGet = $this->key; - $default = $this->default; - - foreach ($collection as $key => $value) { - if ($key === $keyToGet) { - return $value; - } - } - - return $default; + return static function ($keyToGet): Closure { + return static function ($default) use ($keyToGet): Closure { + return static function (Iterator $collection) use ($keyToGet, $default) { + foreach ($collection as $key => $value) { + if ($key === $keyToGet) { + return $value; + } + } + + return $default; + }; + }; + }; } } diff --git a/src/Transformation/Has.php b/src/Transformation/Has.php index d7a5be92a..ed030438f 100644 --- a/src/Transformation/Has.php +++ b/src/Transformation/Has.php @@ -4,6 +4,7 @@ namespace loophp\collection\Transformation; +use Closure; use Iterator; use loophp\collection\Contract\Transformation; @@ -16,35 +17,18 @@ */ final class Has implements Transformation { - /** - * @var callable - * @psalm-var callable(TKey, T):(bool) - */ - private $callback; - - /** - * @psalm-param callable(TKey, T):(bool) $callback - */ - public function __construct(callable $callback) - { - $this->callback = $callback; - } - - /** - * @param Iterator $collection - * - * @return bool - */ - public function __invoke(Iterator $collection) + public function __invoke() { - $callback = $this->callback; - - foreach ($collection as $key => $value) { - if ($callback($key, $value) === $value) { - return true; - } - } - - return false; + return static function (callable $callback): Closure { + return static function (Iterator $iterator) use ($callback): bool { + foreach ($iterator as $key => $value) { + if ($callback($key, $value) === $value) { + return true; + } + } + + return false; + }; + }; } } diff --git a/src/Transformation/Implode.php b/src/Transformation/Implode.php index aedaf15c3..09e63ee09 100644 --- a/src/Transformation/Implode.php +++ b/src/Transformation/Implode.php @@ -5,6 +5,7 @@ namespace loophp\collection\Transformation; use CachingIterator; +use Closure; use Iterator; use loophp\collection\Contract\Transformation; @@ -17,38 +18,32 @@ */ final class Implode implements Transformation { - /** - * @var string - */ - private $glue; - - public function __construct(string $glue) + public function __invoke() { - $this->glue = $glue; - } - - public function __invoke(Iterator $collection): string - { - $glue = $this->glue; - - $callback = - /** - * @psalm-param TKey $key - * @psalm-param CachingIterator $iterator - * - * @param mixed $key - * @param mixed $iterator - */ - static function (string $carry, string $item, $key, CachingIterator $iterator) use ($glue): string { - $carry .= $item; - - if ($iterator->hasNext()) { - $carry .= $glue; - } - - return $carry; + return static function (string $glue): Closure { + return static function (Iterator $iterator) use ($glue): string { + $callback = + /** + * @psalm-param TKey $key + * @psalm-param \CachingIterator $iterator + * + * @param mixed $key + * @param mixed $iterator + */ + static function (string $carry, string $item, $key, CachingIterator $iterator) use ($glue): string { + $carry .= $item; + + if ($iterator->hasNext()) { + $carry .= $glue; + } + + return $carry; + }; + + $foldLeft = (new FoldLeft())()($callback)(''); + + return (string) (new Transform())()($foldLeft)(new CachingIterator($iterator)); }; - - return (string) (new Transform(new FoldLeft($callback, '')))(new CachingIterator($collection)); + }; } } diff --git a/src/Transformation/Nullsy.php b/src/Transformation/Nullsy.php index 8b6d46aa4..0df940a39 100644 --- a/src/Transformation/Nullsy.php +++ b/src/Transformation/Nullsy.php @@ -16,17 +16,16 @@ */ final class Nullsy implements Transformation { - /** - * @psalm-param Iterator $collection - */ - public function __invoke(Iterator $collection): bool + public function __invoke() { - foreach ($collection as $key => $value) { - if (null !== $value) { - return false; + return static function (Iterator $iterator): bool { + foreach ($iterator as $key => $value) { + if (null !== $value) { + return false; + } } - } - return true; + return true; + }; } } diff --git a/src/Transformation/Reduce.php b/src/Transformation/Reduce.php index b777c0369..dc1d796f2 100644 --- a/src/Transformation/Reduce.php +++ b/src/Transformation/Reduce.php @@ -4,6 +4,7 @@ namespace loophp\collection\Transformation; +use Closure; use Iterator; use loophp\collection\Contract\Transformation; @@ -17,40 +18,21 @@ final class Reduce implements Transformation { /** - * @var callable - * @psalm-var callable(T|null, T|null, TKey):(T|null) - */ - private $callback; - - /** - * @var mixed|null - * @psalm-var T|null - */ - private $initial; - - /** - * @psalm-param callable(T|null, T|null, TKey):(T|null) $callback - * - * @param mixed|null $initial - * @psalm-param T|null $initial - */ - public function __construct(callable $callback, $initial = null) - { - $this->callback = $callback; - $this->initial = $initial; - } - - /** - * @psalm-param Iterator $collection + * @psalm-param \Iterator $collection * * @return mixed|null * @psalm-return T|scalar|null|\Iterator */ - public function __invoke(Iterator $collection) + public function __invoke() { - $callback = $this->callback; - $initial = $this->initial; - - return (new Transform(new FoldLeft($callback, $initial)))($collection); + return static function (callable $callback): Closure { + return static function ($initial = null) use ($callback): Closure { + return static function (Iterator $iterator) use ($callback, $initial) { + return (new Transform())()( + (new FoldLeft())()($callback)($initial) + )($iterator); + }; + }; + }; } } diff --git a/src/Transformation/Run.php b/src/Transformation/Run.php index 43ed7682f..54ae95d78 100644 --- a/src/Transformation/Run.php +++ b/src/Transformation/Run.php @@ -4,9 +4,8 @@ namespace loophp\collection\Transformation; -use ArrayIterator; +use Closure; use Iterator; -use loophp\collection\Contract\Operation; use loophp\collection\Contract\Transformation; use loophp\collection\Iterator\ClosureIterator; @@ -19,29 +18,19 @@ */ final class Run implements Transformation { - /** - * @var ArrayIterator - */ - private $operations; - - public function __construct(Operation ...$operations) - { - $this->operations = new ArrayIterator($operations); - } - - public function __invoke(Iterator $collection): Iterator + public function __invoke(): Closure { - return ( - new FoldLeft( - static function (Iterator $collection, Operation $operation): ClosureIterator { - return new ClosureIterator( - $operation(), - $collection, - ...array_values($operation->getArguments()) - ); - }, - $collection - ) - )($this->operations); + return static function (callable ...$operations): Closure { + return static function (Iterator $iterator) use ($operations) { + return (new FoldLeft())()( + static function (Iterator $collection, callable $operation): ClosureIterator { + return new ClosureIterator( + $operation, + $collection, + ); + } + )($iterator)($operations); + }; + }; } } diff --git a/src/Transformation/Transform.php b/src/Transformation/Transform.php index e316c7d50..f9fd2af86 100644 --- a/src/Transformation/Transform.php +++ b/src/Transformation/Transform.php @@ -4,7 +4,7 @@ namespace loophp\collection\Transformation; -use ArrayIterator; +use Closure; use Iterator; use loophp\collection\Contract\Transformation; @@ -18,40 +18,21 @@ final class Transform implements Transformation { /** - * @var ArrayIterator> - */ - private $transformers; - - /** - * @param \loophp\collection\Contract\Transformation ...$transformers - */ - public function __construct(Transformation ...$transformers) - { - $this->transformers = new ArrayIterator($transformers); - } - - /** - * @psalm-param Iterator $collection + * @psalm-param \Iterator $collection * * @return mixed|null - * @psalm-return Iterator|T + * @psalm-return T|scalar|null|\Iterator */ - public function __invoke(Iterator $collection) + public function __invoke() { - return (new FoldLeft( - /** - * @psalm-param Iterator $collection - * @psalm-param Transformation $transformer - * @psalm-param TKey $key - * - * @param mixed $key - * - * @psalm-return T - */ - static function (Iterator $collection, Transformation $transformer, $key) { - return $transformer($collection); - }, - $collection - ))($this->transformers); + return static function (callable ...$transformers): Closure { + return static function (Iterator $iterator) use ($transformers) { + return (new FoldLeft())()( + static function (Iterator $collection, callable $transformer, $key) { + return $transformer($collection); + } + )($iterator)($transformers); + }; + }; } } diff --git a/src/Transformation/Truthy.php b/src/Transformation/Truthy.php index c643a27b2..00143388e 100644 --- a/src/Transformation/Truthy.php +++ b/src/Transformation/Truthy.php @@ -16,14 +16,16 @@ */ final class Truthy implements Transformation { - public function __invoke(Iterator $collection): bool + public function __invoke() { - foreach ($collection as $key => $value) { - if (false === (bool) $value) { - return false; + return static function (Iterator $iterator): bool { + foreach ($iterator as $key => $value) { + if (false === (bool) $value) { + return false; + } } - } - return true; + return true; + }; } } From f40dc3b56628f165028c3047c4a635206d740efd Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Wed, 26 Aug 2020 21:21:13 +0200 Subject: [PATCH 2/6] Syntactic sugar to reduce the amount of parenthesis. --- src/Collection.php | 160 ++++++++++++++-------------- src/Contract/Operation.php | 2 + src/Operation/AbstractOperation.php | 19 ++-- src/Operation/Chunk.php | 4 +- src/Operation/Column.php | 37 ++++--- src/Operation/Compact.php | 39 ++++--- src/Operation/Explode.php | 53 +++++---- src/Operation/First.php | 9 +- src/Operation/Flatten.php | 41 ++++--- src/Operation/Group.php | 4 +- src/Operation/Iterate.php | 37 +++++-- src/Operation/Last.php | 11 +- src/Operation/Pair.php | 5 +- src/Operation/Pluck.php | 10 +- src/Operation/RSample.php | 11 +- src/Operation/Random.php | 9 +- src/Operation/Reverse.php | 6 +- src/Operation/Scale.php | 9 +- src/Operation/Shuffle.php | 6 +- src/Operation/Slice.php | 9 +- src/Operation/Sort.php | 46 ++++---- src/Operation/Tail.php | 3 +- src/Operation/Unpack.php | 2 +- src/Operation/Window.php | 16 +-- src/Transformation/All.php | 2 +- src/Transformation/Contains.php | 2 +- src/Transformation/Count.php | 2 +- src/Transformation/Falsy.php | 2 +- src/Transformation/FoldLeft.php | 2 +- src/Transformation/FoldRight.php | 8 +- src/Transformation/Get.php | 2 +- src/Transformation/Has.php | 2 +- src/Transformation/Implode.php | 6 +- src/Transformation/Nullsy.php | 2 +- src/Transformation/Reduce.php | 6 +- src/Transformation/Run.php | 11 +- src/Transformation/Transform.php | 4 +- src/Transformation/Truthy.php | 2 +- 38 files changed, 320 insertions(+), 281 deletions(-) diff --git a/src/Collection.php b/src/Collection.php index 62066a950..3053e0cb9 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -225,89 +225,89 @@ static function ($data): Generator { public function all(): array { - return $this->transform((new All())()); + return $this->transform(All::of()); } public function append(...$items): CollectionInterface { - return $this->run((new Append())()(...$items)); + return $this->run(Append::of()(...$items)); } public function apply(callable ...$callables): CollectionInterface { - return $this->run((new Apply())()(...$callables)); + return $this->run(Apply::of()(...$callables)); } public function associate( ?callable $callbackForKeys = null, ?callable $callbackForValues = null ): CollectionInterface { - return $this->run((new Associate())()($callbackForKeys)($callbackForValues)); + return $this->run(Associate::of()($callbackForKeys)($callbackForValues)); } public function cache(?CacheItemPoolInterface $cache = null): CollectionInterface { - return $this->run((new Cache())()($cache ?? new ArrayAdapter())); + return $this->run(Cache::of()($cache ?? new ArrayAdapter())); } public function chunk(int ...$sizes): CollectionInterface { - return $this->run((new Chunk())()(...$sizes)); + return $this->run(Chunk::of()(...$sizes)); } public function collapse(): CollectionInterface { - return $this->run((new Collapse())()); + return $this->run(Collapse::of()); } public function column($column): CollectionInterface { - return $this->run((new Column())()($column)); + return $this->run(Column::of()($column)); } public function combinate(?int $length = null): CollectionInterface { - return $this->run((new Combinate())()($length)); + return $this->run(Combinate::of()($length)); } public function combine(...$keys): CollectionInterface { - return $this->run((new Combine())()(...$keys)); + return $this->run(Combine::of()(...$keys)); } public function compact(...$values): CollectionInterface { - return $this->run((new Compact())()(...$values)); + return $this->run(Compact::of()(...$values)); } public function contains(...$value): bool { - return $this->transform((new Contains())()(...$value)); + return $this->transform(Contains::of()(...$value)); } public function count(): int { - return $this->transform((new Count())()); + return $this->transform(Count::of()); } public function cycle(int $length = 0): CollectionInterface { - return $this->run((new Cycle())()($length)); + return $this->run(Cycle::of()($length)); } public function diff(...$values): CollectionInterface { - return $this->run((new Diff())()(...$values)); + return $this->run(Diff::of()(...$values)); } public function diffKeys(...$values): CollectionInterface { - return $this->run((new DiffKeys())()(...$values)); + return $this->run(DiffKeys::of()(...$values)); } public function distinct(): CollectionInterface { - return $this->run((new Distinct())()); + return $this->run(Distinct::of()); } public static function empty(): Collection @@ -317,52 +317,52 @@ public static function empty(): Collection public function explode(...$explodes): CollectionInterface { - return $this->run((new Explode())()(...$explodes)); + return $this->run(Explode::of()(...$explodes)); } public function falsy(): bool { - return $this->transform((new Falsy())()); + return $this->transform(Falsy::of()); } public function filter(callable ...$callbacks): CollectionInterface { - return $this->run((new Filter())()(...$callbacks)); + return $this->run(Filter::of()(...$callbacks)); } public function first(?callable $callback = null, int $size = 1): CollectionInterface { - return $this->run((new First())()($callback)($size)); + return $this->run(First::of()($callback)($size)); } public function flatten(int $depth = PHP_INT_MAX): CollectionInterface { - return $this->run((new Flatten())()($depth)); + return $this->run(Flatten::of()($depth)); } public function flip(): CollectionInterface { - return $this->run((new Flip())()); + return $this->run(Flip::of()); } public function foldLeft(callable $callback, $initial = null) { - return $this->transform((new FoldLeft())()($callback)($initial)); + return $this->transform(FoldLeft::of()($callback)($initial)); } public function foldRight(callable $callback, $initial = null) { - return $this->transform((new FoldRight())()($callback)($initial)); + return $this->transform(Foldright::of()($callback)($initial)); } public function forget(...$keys): CollectionInterface { - return $this->run((new Forget())()(...$keys)); + return $this->run(Forget::of()(...$keys)); } public function frequency(): CollectionInterface { - return $this->run((new Frequency())()); + return $this->run(Frequency::of()); } public static function fromCallable(callable $callable, ...$parameters): Collection @@ -409,7 +409,7 @@ static function (string $string, string $delimiter): Generator { public function get($key, $default = null) { - return $this->transform((new Get())()($key)($default)); + return $this->transform(Get::of()($key)($default)); } public function getIterator(): ClosureIterator @@ -419,17 +419,17 @@ public function getIterator(): ClosureIterator public function group(?callable $callable = null): CollectionInterface { - return $this->run((new Group())()($callable)); + return $this->run(Group::of()($callable)); } public function has(callable $callback): bool { - return $this->transform((new Has())()($callback)); + return $this->transform(Has::of()($callback)); } public function head(): CollectionInterface { - return $this->run((new Head())()); + return $this->run(Head::of()); } public function ifThenElse(callable $condition, callable $then, ?callable $else = null): CollectionInterface @@ -438,32 +438,32 @@ public function ifThenElse(callable $condition, callable $then, ?callable $else return $value; }; - return $this->run(new IfThenElse($condition, $then, $else)); + return $this->run(IfThenElse::of()($condition)($then)($else)); } public function implode(string $glue = ''): string { - return $this->transform((new Implode())()($glue)); + return $this->transform(Implode::of()($glue)); } public function intersect(...$values): CollectionInterface { - return $this->run((new Intersect())()(...$values)); + return $this->run(Intersect::of()(...$values)); } public function intersectKeys(...$values): CollectionInterface { - return $this->run((new IntersectKeys())()(...$values)); + return $this->run(IntersectKeys::of()(...$values)); } public function intersperse($element, int $every = 1, int $startAt = 0): CollectionInterface { - return $this->run((new Intersperse())()($element)($every)($startAt)); + return $this->run(Intersperse::of()($element)($every)($startAt)); } public static function iterate(callable $callback, ...$parameters): CollectionInterface { - return (new self())->run((new Iterate())()($callback)($parameters)); + return (new self())->run(Iterate::of()($callback)(...$parameters)); } /** @@ -476,122 +476,122 @@ public function jsonSerialize(): array public function keys(): CollectionInterface { - return $this->run((new Keys())()); + return $this->run(Keys::of()); } public function last(?callable $callback = null, int $size = 1): CollectionInterface { - return $this->run((new Last())()($callback)($size)); + return $this->run(Last::of()($callback)($size)); } public function limit(int $limit = -1, int $offset = 0): CollectionInterface { - return $this->run((new Limit())()($limit)($offset)); + return $this->run(Limit::of()($limit)($offset)); } public function loop(): CollectionInterface { - return $this->run((new Loop())()); + return $this->run(Loop::of()); } public function map(callable ...$callbacks): CollectionInterface { - return $this->run((new Map())()(...$callbacks)); + return $this->run(Map::of()(...$callbacks)); } public function merge(iterable ...$sources): CollectionInterface { - return $this->run((new Merge())()(...$sources)); + return $this->run(Merge::of()(...$sources)); } public function normalize(): CollectionInterface { - return $this->run((new Normalize())()); + return $this->run(Normalize::of()); } public function nth(int $step, int $offset = 0): CollectionInterface { - return $this->run((new Nth())()($step)($offset)); + return $this->run(Nth::of()($step)($offset)); } public function nullsy(): bool { - return $this->transform((new Nullsy())()); + return $this->transform(Nullsy::of()); } public function only(...$keys): CollectionInterface { - return $this->run((new Only())()(...$keys)); + return $this->run(Only::of()(...$keys)); } public function pack(): CollectionInterface { - return $this->run(new Pack()); + return $this->run(Pack::of()); } public function pad(int $size, $value): CollectionInterface { - return $this->run((new Pad())()($size)($value)); + return $this->run(Pad::of()($size)($value)); } public function pair(): CollectionInterface { - return $this->run((new Pair())()); + return $this->run(Pair::of()); } public function permutate(): CollectionInterface { - return $this->run((new Permutate())()); + return $this->run(Permutate::of()); } public function pluck($pluck, $default = null): CollectionInterface { - return $this->run((new Pluck())()($pluck)($default)); + return $this->run(Pluck::of()($pluck)($default)); } public function prepend(...$items): CollectionInterface { - return $this->run((new Prepend())()(...$items)); + return $this->run(Prepend::of()(...$items)); } public function product(iterable ...$iterables): CollectionInterface { - return $this->run((new Product())()(...$iterables)); + return $this->run(Product::of()(...$iterables)); } public function random(int $size = 1): CollectionInterface { - return $this->run((new Random())()($size)); + return $this->run(Random::of()($size)); } public static function range(float $start = 0.0, float $end = INF, float $step = 1.0): CollectionInterface { - return (new self())->run((new Range())()($start)($end)($step)); + return (new self())->run(Range::of()($start)($end)($step)); } public function reduce(callable $callback, $initial = null) { - return $this->transform((new Reduce())()($callback)($initial)); + return $this->transform(Reduce::of()($callback)($initial)); } public function reduction(callable $callback, $initial = null): CollectionInterface { - return $this->run((new Reduction())()($callback)($initial)); + return $this->run(Reduction::of()($callback)($initial)); } public function reverse(): CollectionInterface { - return $this->run((new Reverse())()); + return $this->run(Reverse::of()); } public function rsample(float $probability): CollectionInterface { - return $this->run((new RSample())()($probability)); + return $this->run(RSample::of()($probability)); } public function run(callable ...$operations) { - return self::fromIterable((new Run())()(...$operations)($this->getIterator())); + return self::fromIterable(Run::of()(...$operations)($this->getIterator())); } public function scale( @@ -601,87 +601,87 @@ public function scale( float $wantedUpperBound = 1.0, float $base = 0.0 ): CollectionInterface { - return $this->run((new Scale())()($lowerBound)($upperBound)($wantedLowerBound)($wantedUpperBound)($base)); + return $this->run(Scale::of()($lowerBound)($upperBound)($wantedLowerBound)($wantedUpperBound)($base)); } public function shuffle(): CollectionInterface { - return $this->run((new Shuffle())()); + return $this->run(Shuffle::of()); } public function since(callable ...$callbacks): CollectionInterface { - return $this->run((new Since())()(...$callbacks)); + return $this->run(Since::of()(...$callbacks)); } public function skip(int ...$counts): CollectionInterface { - return $this->run((new Skip())()(...$counts)); + return $this->run(Skip::of()(...$counts)); } public function slice(int $offset, int $length = -1): CollectionInterface { - return $this->run((new Slice())()($offset)($length)); + return $this->run(Slice::of()($offset)($length)); } public function sort(int $type = Operation\Sortable::BY_VALUES, ?callable $callback = null): CollectionInterface { - return $this->run((new Sort())()($type)($callback)); + return $this->run(Sort::of()($type)($callback)); } public function split(callable ...$callbacks): CollectionInterface { - return $this->run((new Split())()(...$callbacks)); + return $this->run(Split::of()(...$callbacks)); } public function tail(): CollectionInterface { - return $this->run((new Tail())()); + return $this->run(Tail::of()); } public static function times(int $number = 0, ?callable $callback = null): CollectionInterface { - return (new self())->run((new Times())()($number)($callback)); + return (new self())->run(Times::of()($number)($callback)); } public function transform(callable ...$transformers) { - return (new Transform())()(...$transformers)($this->getIterator()); + return Transform::of()(...$transformers)($this->getIterator()); } public function transpose(): CollectionInterface { - return $this->run((new Transpose())()); + return $this->run(Transpose::of()); } public function truthy(): bool { - return $this->transform((new Truthy())()); + return $this->transform(Truthy::of()); } public function unpack(): CollectionInterface { - return $this->run(new Unpack()); + return $this->run(Unpack::of()); } public function unpair(): CollectionInterface { - return $this->run((new Unpair())()); + return $this->run(Unpair::of()); } public function until(callable ...$callbacks): CollectionInterface { - return $this->run((new Until())()(...$callbacks)); + return $this->run(Until::of()(...$callbacks)); } public function unwrap(): CollectionInterface { - return $this->run((new Unwrap())()); + return $this->run(Unwrap::of()); } public function window(int ...$length): CollectionInterface { - return $this->run((new Window())()(...$length)); + return $this->run(Window::of()(...$length)); } public static function with($data = [], ...$parameters): Collection @@ -691,11 +691,11 @@ public static function with($data = [], ...$parameters): Collection public function wrap(): CollectionInterface { - return $this->run((new Wrap())()); + return $this->run(Wrap::of()); } public function zip(iterable ...$iterables): CollectionInterface { - return $this->run((new Zip())()(...$iterables)); + return $this->run(Zip::of()(...$iterables)); } } diff --git a/src/Contract/Operation.php b/src/Contract/Operation.php index dfc7661d2..5646618a3 100644 --- a/src/Contract/Operation.php +++ b/src/Contract/Operation.php @@ -9,4 +9,6 @@ interface Operation { public function __invoke(): Closure; + + public static function of(): Closure; } diff --git a/src/Operation/AbstractOperation.php b/src/Operation/AbstractOperation.php index a9bf47445..5a3a781f5 100644 --- a/src/Operation/AbstractOperation.php +++ b/src/Operation/AbstractOperation.php @@ -4,18 +4,17 @@ namespace loophp\collection\Operation; -abstract class AbstractOperation +use Closure; +use loophp\collection\Contract\Operation; + +abstract class AbstractOperation implements Operation { - /** - * @var array - */ - protected $storage = []; + final public function __construct() + { + } - /** - * @return array - */ - public function getArguments(): array + public static function of(): Closure { - return $this->storage; + return (new static())->__invoke(); } } diff --git a/src/Operation/Chunk.php b/src/Operation/Chunk.php index d18385284..0c761515a 100644 --- a/src/Operation/Chunk.php +++ b/src/Operation/Chunk.php @@ -9,7 +9,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; use function count; @@ -37,7 +36,8 @@ static function (int ...$sizes): Closure { * @psalm-return Generator> */ static function (Iterator $iterator) use ($sizes): Generator { - $sizesIterator = (new Run())()((new Loop())())(new ArrayIterator($sizes)); + /** @var Iterator $sizesIterator */ + $sizesIterator = Loop::of()(new ArrayIterator($sizes)); $values = []; diff --git a/src/Operation/Column.php b/src/Operation/Column.php index 5cc5e4251..d6451864a 100644 --- a/src/Operation/Column.php +++ b/src/Operation/Column.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -22,18 +21,30 @@ final class Column extends AbstractOperation implements Operation */ public function __invoke(): Closure { - return static function ($column): Closure { - return static function (Iterator $iterator) use ($column): Generator { - /** - * @psalm-var array-key $key - * @psalm-var iterable $value - */ - foreach ((new Run())()((new Transpose())())($iterator) as $key => $value) { - if ($key === $column) { - return yield from $value; - } - } + return + /** + * @param int|string $column + * + * @psalm-param array-key $column + */ + static function ($column): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($column): Generator { + /** + * @psalm-var array-key $key + * @psalm-var iterable $value + */ + foreach (Transpose::of()($iterator) as $key => $value) { + if ($key === $column) { + return yield from $value; + } + } + }; }; - }; } } diff --git a/src/Operation/Compact.php b/src/Operation/Compact.php index d8b27c559..fb25ef576 100644 --- a/src/Operation/Compact.php +++ b/src/Operation/Compact.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; use function in_array; @@ -19,23 +18,37 @@ */ final class Compact extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(T...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$values): Closure { - return static function (Iterator $iterator) use ($values): Generator { - $values = [] === $values ? [null] : $values; - - $filter = (new Filter())()( + return + /** + * @psalm-param T ...$values + */ + static function (...$values): Closure { + return /** - * @param mixed $item + * @psalm-param Iterator $iterator + * @psalm-return Generator */ - static function ($item) use ($values): bool { - return !in_array($item, $values, true); - } - ); + static function (Iterator $iterator) use ($values): Generator { + $values = [] === $values ? [null] : $values; + + /** @psalm-var callable(Iterator):Generator $filter */ + $filter = Filter::of()( + /** + * @param mixed $value + * @psalm-param T $value + */ + static function ($value) use ($values): bool { + return !in_array($value, $values, true); + } + ); - return yield from (new Run())()($filter)($iterator); + return yield from $filter($iterator); + }; }; - }; } } diff --git a/src/Operation/Explode.php b/src/Operation/Explode.php index ba28839bc..1f58eb7d6 100644 --- a/src/Operation/Explode.php +++ b/src/Operation/Explode.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -19,30 +18,38 @@ final class Explode extends AbstractOperation implements Operation { public function __invoke(): Closure { - return static function (...$explodes): Closure { - return static function (Iterator $iterator) use ($explodes): Generator { - $split = (new Split())()( - ...array_map( - /** - * @param mixed $explode - * @psalm-param T $explode - */ - static function ($explode): Closure { - return + return + /** + * @psalm-param T ...$explodes + */ + static function (...$explodes): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($explodes): Generator { + return yield from Split::of()( + ...array_map( /** - * @param mixed $value - * @psalm-param T $value + * @param mixed $explode + * @psalm-param T $explode */ - static function ($value) use ($explode): bool { - return $value === $explode; - }; - }, - $explodes - ) - ); - - return yield from (new Run())()($split)($iterator); + static function ($explode): Closure { + return + /** + * @param mixed $value + * @psalm-param T $value + */ + static function ($value) use ($explode): bool { + return $value === $explode; + }; + }, + $explodes + ) + )($iterator); + }; }; - }; } } diff --git a/src/Operation/First.php b/src/Operation/First.php index d674998a0..c5587e9e2 100644 --- a/src/Operation/First.php +++ b/src/Operation/First.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -44,10 +43,10 @@ static function ($value, $key, Iterator $iterator): bool { $callback = $callback ?? $defaultCallback; - $filter = (new Filter())()($callback); - $limit = (new Limit())()($size)(0); - - return yield from (new Run())()($filter, $limit)($iterator); + return yield from Compose::of()( + Filter::of()($callback), + Limit::of()($size)(0) + )($iterator); }; }; }; diff --git a/src/Operation/Flatten.php b/src/Operation/Flatten.php index f0ead4ebb..085f88c2b 100644 --- a/src/Operation/Flatten.php +++ b/src/Operation/Flatten.php @@ -18,28 +18,37 @@ */ final class Flatten extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(int): Closure(Iterator): Generator + */ public function __invoke(): Closure { return static function (int $depth): Closure { - return static function (Iterator $iterator) use ($depth): Generator { - foreach ($iterator as $key => $value) { - if (false === is_iterable($value)) { - yield $key => $value; - } elseif (1 === $depth) { - /** @psalm-var T $subValue */ - foreach ($value as $subKey => $subValue) { - yield $subKey => $subValue; - } - } else { - /** @psalm-var IterableIterator $flatten */ - $flatten = (new Flatten())()($depth - 1); + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($depth): Generator { + foreach ($iterator as $key => $value) { + if (false === is_iterable($value)) { + yield $key => $value; + } elseif (1 === $depth) { + /** @psalm-var T $subValue */ + foreach ($value as $subKey => $subValue) { + yield $subKey => $subValue; + } + } else { + /** @psalm-var callable(Iterator): Generator $flatten */ + $flatten = Flatten::of()($depth - 1); - foreach ((new Run())()($flatten)(new IterableIterator($value)) as $subKey => $subValue) { - yield $subKey => $subValue; + foreach ($flatten(new IterableIterator($value)) as $subKey => $subValue) { + yield $subKey => $subValue; + } } } - } - }; + }; }; } } diff --git a/src/Operation/Group.php b/src/Operation/Group.php index 1850973c3..b85f8f3de 100644 --- a/src/Operation/Group.php +++ b/src/Operation/Group.php @@ -8,8 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\FoldLeft; -use loophp\collection\Transformation\Transform; /** * @psalm-template TKey @@ -72,7 +70,7 @@ static function (array $collect, $value, $key) use ($callable): array { return $collect; }; - return yield from (new Transform(new FoldLeft($callback, [])))($iterator); + return yield from (FoldLeft::of()($callback)([])($iterator))->current(); }; }; } diff --git a/src/Operation/Iterate.php b/src/Operation/Iterate.php index f44709c11..3bed2512c 100644 --- a/src/Operation/Iterate.php +++ b/src/Operation/Iterate.php @@ -16,18 +16,35 @@ */ final class Iterate extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(callable(T...):(array)): Closure(T...): Generator + */ public function __invoke(): Closure { - return static function (callable $callback): Closure { - return static function (...$parameters) use ($callback): Closure { - return static function (Iterator $iterator) use ($callback, $parameters): Generator { - while (true) { - yield current( - $parameters = (array) $callback(...array_values((array) $parameters)) - ); - } - }; + return + /** + * @psalm-param callable(T...):(array) $callback + */ + static function (callable $callback): Closure { + return + /** + * @psalm-param T ...$parameters + */ + static function (...$parameters) use ($callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback, $parameters): Generator { + while (true) { + yield current( + $parameters = (array) $callback(...array_values((array) $parameters)) + ); + } + }; + }; }; - }; } } diff --git a/src/Operation/Last.php b/src/Operation/Last.php index 7ee285e70..193359e2f 100644 --- a/src/Operation/Last.php +++ b/src/Operation/Last.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -42,11 +41,11 @@ static function ($value, $key, Iterator $iterator): bool { $callback = $callback ?? $defaultCallback; - $filter = (new Filter())()($callback); - $reverse = (new Reverse())(); - $limit = (new Limit())()($size)(0); - - return yield from (new Run())()($filter, $reverse, $limit)($iterator); + return yield from Compose::of()( + Filter::of()($callback), + Reverse::of(), + Limit::of()($size)(0) + )($iterator); }; }; }; diff --git a/src/Operation/Pair.php b/src/Operation/Pair.php index 9eeb2969e..3b7fd6efc 100644 --- a/src/Operation/Pair.php +++ b/src/Operation/Pair.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -26,10 +25,8 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator): Generator { - $chunk = (new Chunk())()(2); - /** @psalm-var list $chunk */ - foreach ((new Run())()($chunk)($iterator) as $chunk) { + foreach (Chunk::of()(2)($iterator) as $chunk) { $chunk = array_values($chunk); yield $chunk[0] => $chunk[1]; diff --git a/src/Operation/Pluck.php b/src/Operation/Pluck.php index 45128acbd..7f68ea9a5 100644 --- a/src/Operation/Pluck.php +++ b/src/Operation/Pluck.php @@ -12,9 +12,6 @@ use loophp\collection\Contract\Collection; use loophp\collection\Contract\Operation; use loophp\collection\Iterator\IterableIterator; -use loophp\collection\Transformation\Get; -use loophp\collection\Transformation\Run; -use loophp\collection\Transformation\Transform; use ReflectionClass; use function array_key_exists; @@ -42,9 +39,7 @@ public function __invoke(): Closure $result[] = $pick($iterator, $item, $key); } - $collapse = (new Collapse())(); - - return in_array('*', $key, true) ? (new Run())()($collapse)(new ArrayIterator($result)) : $result; + return in_array('*', $key, true) ? Collapse::of()(new ArrayIterator($result)) : $result; } if ((true === is_array($target)) && (true === array_key_exists($segment, $target))) { @@ -52,8 +47,7 @@ public function __invoke(): Closure } elseif (($target instanceof ArrayAccess) && (true === $target->offsetExists($segment))) { $target = $target[$segment]; } elseif ($target instanceof Collection) { - $get = (new Get())()($segment)($default); - $target = (new Transform())()($get)(new IterableIterator($target)); + $target = (Get::of()($segment)($default)(new IterableIterator($target)))->current(); } elseif ((true === is_object($target)) && (true === property_exists($target, $segment))) { $target = (new ReflectionClass($target))->getProperty($segment)->getValue($target); } else { diff --git a/src/Operation/RSample.php b/src/Operation/RSample.php index 255f4c6a4..47cc70027 100644 --- a/src/Operation/RSample.php +++ b/src/Operation/RSample.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -21,13 +20,11 @@ public function __invoke(): Closure { return static function (float $probability): Closure { return static function (Iterator $iterator) use ($probability): Generator { - $filter = (new Filter())()( - static function () use ($probability): bool { - return (mt_rand() / mt_getrandmax()) < $probability; - } - ); + $callback = static function () use ($probability): bool { + return (mt_rand() / mt_getrandmax()) < $probability; + }; - return yield from (new Run())()($filter)($iterator); + return yield from Filter::of()($callback)($iterator); }; }; } diff --git a/src/Operation/Random.php b/src/Operation/Random.php index dcab5073e..61a42f4c0 100644 --- a/src/Operation/Random.php +++ b/src/Operation/Random.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -21,10 +20,10 @@ public function __invoke(): Closure { return static function (int $size): Closure { return static function (Iterator $iterator) use ($size): Generator { - $limit = (new Limit())()($size)(0); - $shuffle = (new Shuffle())(); - - return yield from (new Run())()($limit, $shuffle)($iterator); + return yield from (Compose::of()( + Limit::of()($size)(0), + Shuffle::of() + )($iterator)); }; }; } diff --git a/src/Operation/Reverse.php b/src/Operation/Reverse.php index c5617a1bb..44990a2c3 100644 --- a/src/Operation/Reverse.php +++ b/src/Operation/Reverse.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -26,8 +25,9 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator): Generator { - /** @psalm-var array $all */ - $all = iterator_to_array((new Run())()((new Pack())())($iterator)); + /** @psalm-var Generator $pack */ + $pack = Pack::of()($iterator); + $all = iterator_to_array($pack); for (end($all); null !== key($all); prev($all)) { $item = current($all); diff --git a/src/Operation/Scale.php b/src/Operation/Scale.php index 85ad08f64..e59094da4 100644 --- a/src/Operation/Scale.php +++ b/src/Operation/Scale.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; use const INF; @@ -30,7 +29,8 @@ public function __invoke(): Closure $wantedLowerBound = (0.0 === $wantedLowerBound) ? (0.0 === $base ? 0.0 : 1.0) : $wantedLowerBound; // phpcs:ignore $wantedUpperBound = (1.0 === $wantedUpperBound) ? (0.0 === $base ? 1.0 : $base) : $wantedUpperBound; // phpcs:ignore - $mapper = (new Map())()( + /** @psalm-var callable(Generator): Generator $mapper */ + $mapper = Map::of()( static function ($v) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base): float { // phpcs:ignore $mx = 0.0 === $base ? ($v - $lowerBound) / ($upperBound - $lowerBound) : @@ -42,7 +42,8 @@ static function ($v) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUp } ); - $filter = (new Filter())()( + /** @psalm-var callable(Iterator): Generator $filter */ + $filter = Filter::of()( /** * @param float|int $item */ @@ -57,7 +58,7 @@ static function ($item) use ($upperBound): bool { } ); - return yield from (new Run())()($filter, $mapper)($iterator); + return yield from Compose::of()($filter, $mapper)($iterator); }; }; }; diff --git a/src/Operation/Shuffle.php b/src/Operation/Shuffle.php index 95125f8d1..cfe1f4d19 100644 --- a/src/Operation/Shuffle.php +++ b/src/Operation/Shuffle.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -26,8 +25,9 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator): Generator { - /** @psalm-var array $data */ - $data = iterator_to_array((new Run())()((new Pack())())($iterator)); + /** @psalm-var Iterator $pack */ + $pack = Pack::of()($iterator); + $data = iterator_to_array($pack); while ([] !== $data) { $randomKey = array_rand($data); diff --git a/src/Operation/Slice.php b/src/Operation/Slice.php index 8dfc72db9..75f2a98d0 100644 --- a/src/Operation/Slice.php +++ b/src/Operation/Slice.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -28,15 +27,13 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator) use ($offset, $length): Generator { - $skip = (new Skip())()($offset); + $skip = Skip::of()($offset); if (-1 === $length) { - return yield from (new Run())()($skip)($iterator); + return yield from $skip($iterator); } - $limit = (new Limit())()($length)(0); - - return yield from (new Run())()($skip, $limit)($iterator); + return yield from Compose::of()($skip, Limit::of()($length)(0))($iterator); }; }; }; diff --git a/src/Operation/Sort.php b/src/Operation/Sort.php index d23b6bdb2..c707a4254 100644 --- a/src/Operation/Sort.php +++ b/src/Operation/Sort.php @@ -10,7 +10,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -23,16 +22,24 @@ public function __invoke(): Closure { return static function (int $type = Operation\Sortable::BY_VALUES): Closure { return static function (?callable $callback = null) use ($type): Closure { - $callback = $callback ?? static function ($left, $right): int { - return $left <=> $right; - }; + $callback = $callback ?? + /** + * @param mixed $left + * @psalm-param T $left + * + * @param mixed $right + * @psalm-param T $right + */ + static function ($left, $right): int { + return $left <=> $right; + }; return /** - * @psalm-param \Iterator $iterator + * @psalm-param Iterator $iterator * @psalm-param callable(T, T):(int) $callback * - * @psalm-return \Generator + * @psalm-return Generator */ static function (Iterator $iterator) use ($type, $callback): Generator { if (Operation\Sortable::BY_VALUES !== $type && Operation\Sortable::BY_KEYS !== $type) { @@ -41,29 +48,28 @@ static function (Iterator $iterator) use ($type, $callback): Generator { $operations = Operation\Sortable::BY_VALUES === $type ? [ - 'before' => [new Pack()], - 'after' => [new Unpack()], + 'before' => [Pack::of()], + 'after' => [Unpack::of()], ] : [ - 'before' => [new Flip(), new Pack()], - 'after' => [new Unpack(), new Flip()], + 'before' => [Flip::of(), Pack::of()], + 'after' => [Unpack::of(), Flip::of()], ]; - $callback = + $arrayIterator = new ArrayIterator( + iterator_to_array(Compose::of()(...$operations['before'])($iterator)) + ); + $arrayIterator->uasort( /** * @psalm-param array{0:TKey, 1:T} $left * @psalm-param array{0:TKey, 1:T} $right */ - static function (array $left, array $right) use ($defaultCallback): int { - return $defaultCallback($left[1], $right[1]); - }; - - $arrayIterator = new ArrayIterator(iterator_to_array((new Run())()(...$operations['before'])($iterator))); - $arrayIterator->uasort($callback); - - return yield from ( - (new Run())()(...$operations['after'])($arrayIterator) + static function (array $left, array $right) use ($callback): int { + return $callback($left[1], $right[1]); + } ); + + return yield from Compose::of()(...$operations['after'])($arrayIterator); }; }; }; diff --git a/src/Operation/Tail.php b/src/Operation/Tail.php index 332dd454f..2e1ec995d 100644 --- a/src/Operation/Tail.php +++ b/src/Operation/Tail.php @@ -8,7 +8,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -26,7 +25,7 @@ public function __invoke(): Closure * @psalm-return Generator */ static function (Iterator $iterator): Generator { - return yield from (new Run())()((new Skip())()(1))($iterator); + return yield from Skip::of()(1)($iterator); }; } } diff --git a/src/Operation/Unpack.php b/src/Operation/Unpack.php index 63ec06a30..cb8a1f6a8 100644 --- a/src/Operation/Unpack.php +++ b/src/Operation/Unpack.php @@ -33,7 +33,7 @@ static function (Iterator $iterator): Generator { } /** @psalm-var array> $chunks */ - $chunks = (new Run((new Chunk(2))))(new IterableIterator($value)); + $chunks = Chunk::of()(2)(new IterableIterator($value)); foreach ($chunks as [$k, $v]) { yield $k => $v; diff --git a/src/Operation/Window.php b/src/Operation/Window.php index 6c449081b..5ad198c7d 100644 --- a/src/Operation/Window.php +++ b/src/Operation/Window.php @@ -9,7 +9,6 @@ use Generator; use Iterator; use loophp\collection\Contract\Operation; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey @@ -18,6 +17,9 @@ */ final class Window extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(int...): Closure(Iterator): Generator> + */ public function __invoke(): Closure { return static function (int ...$lengths): Closure { @@ -29,15 +31,13 @@ public function __invoke(): Closure * @psalm-return Generator> */ static function (Iterator $iterator) use ($lengths): Generator { - $loop = (new Loop())(); - - /** @psalm-var Iterator $lengths */ - $lengths = (new Run())()($loop)(new ArrayIterator($lengths)); + /** @psalm-var \Iterator $lengths */ + $lengths = Loop::of()(new ArrayIterator($lengths)); for ($i = 0; iterator_count($iterator) > $i; ++$i) { - $slice = (new Slice())()($i)($lengths->current()); - - yield iterator_to_array((new Run())()($slice)($iterator)); + yield iterator_to_array( + Slice::of()($i)($lengths->current())($iterator) + ); $lengths->next(); } diff --git a/src/Transformation/All.php b/src/Transformation/All.php index b179e5d59..10a126e91 100644 --- a/src/Transformation/All.php +++ b/src/Transformation/All.php @@ -14,7 +14,7 @@ * * @implements Transformation */ -final class All implements Transformation +final class All extends AbstractTransformation implements Transformation { /** * @return array diff --git a/src/Transformation/Contains.php b/src/Transformation/Contains.php index 2cd5214c2..ce5944a25 100644 --- a/src/Transformation/Contains.php +++ b/src/Transformation/Contains.php @@ -16,7 +16,7 @@ * * @implements Transformation */ -final class Contains implements Transformation +final class Contains extends AbstractTransformation implements Transformation { /** * @var ArrayIterator diff --git a/src/Transformation/Count.php b/src/Transformation/Count.php index a89b75516..daf2ec1f4 100644 --- a/src/Transformation/Count.php +++ b/src/Transformation/Count.php @@ -14,7 +14,7 @@ * * @implements Transformation */ -final class Count implements Transformation +final class Count extends AbstractTransformation implements Transformation { public function __invoke() { diff --git a/src/Transformation/Falsy.php b/src/Transformation/Falsy.php index f1f56f84d..4b987afd7 100644 --- a/src/Transformation/Falsy.php +++ b/src/Transformation/Falsy.php @@ -14,7 +14,7 @@ * * @implements Transformation */ -final class Falsy implements Transformation +final class Falsy extends AbstractTransformation implements Transformation { public function __invoke() { diff --git a/src/Transformation/FoldLeft.php b/src/Transformation/FoldLeft.php index 405adec14..e8ca5ec64 100644 --- a/src/Transformation/FoldLeft.php +++ b/src/Transformation/FoldLeft.php @@ -14,7 +14,7 @@ * * @implements Transformation */ -final class FoldLeft implements Transformation +final class FoldLeft extends AbstractTransformation implements Transformation { /** * @psalm-param \Iterator $collection diff --git a/src/Transformation/FoldRight.php b/src/Transformation/FoldRight.php index 6f072c0d5..ad29644a2 100644 --- a/src/Transformation/FoldRight.php +++ b/src/Transformation/FoldRight.php @@ -15,7 +15,7 @@ * * @implements Transformation */ -final class FoldRight implements Transformation +final class FoldRight extends AbstractTransformation implements Transformation { /** * @psalm-param \Iterator $collection @@ -28,10 +28,8 @@ public function __invoke() return static function (callable $callback): Closure { return static function ($initial = null) use ($callback): Closure { return static function (iterable $iterable) use ($callback, $initial) { - $foldLeft = (new FoldLeft())()($callback)($initial); - $reverse = (new Reverse())(); - - return (new Transform())()($foldLeft)((new Run())()($reverse)($iterable)); + // @todo: Unify this when operation and transformation are the same. + return Transform::of()(FoldLeft::of()($callback)($initial))(Run::of()(Reverse::of())($iterable)); }; }; }; diff --git a/src/Transformation/Get.php b/src/Transformation/Get.php index 8809997ce..09398bf13 100644 --- a/src/Transformation/Get.php +++ b/src/Transformation/Get.php @@ -15,7 +15,7 @@ * * @implements Transformation */ -final class Get implements Transformation +final class Get extends AbstractTransformation implements Transformation { public function __invoke() { diff --git a/src/Transformation/Has.php b/src/Transformation/Has.php index ed030438f..cbc37b414 100644 --- a/src/Transformation/Has.php +++ b/src/Transformation/Has.php @@ -15,7 +15,7 @@ * * @implements Transformation */ -final class Has implements Transformation +final class Has extends AbstractTransformation implements Transformation { public function __invoke() { diff --git a/src/Transformation/Implode.php b/src/Transformation/Implode.php index 09e63ee09..44348ef9c 100644 --- a/src/Transformation/Implode.php +++ b/src/Transformation/Implode.php @@ -16,7 +16,7 @@ * * @implements Transformation */ -final class Implode implements Transformation +final class Implode extends AbstractTransformation implements Transformation { public function __invoke() { @@ -40,9 +40,7 @@ static function (string $carry, string $item, $key, CachingIterator $iterator) u return $carry; }; - $foldLeft = (new FoldLeft())()($callback)(''); - - return (string) (new Transform())()($foldLeft)(new CachingIterator($iterator)); + return (string) Transform::of()(FoldLeft::of()($callback)(''))(new CachingIterator($iterator)); }; }; } diff --git a/src/Transformation/Nullsy.php b/src/Transformation/Nullsy.php index 0df940a39..1a265be24 100644 --- a/src/Transformation/Nullsy.php +++ b/src/Transformation/Nullsy.php @@ -14,7 +14,7 @@ * * @implements Transformation */ -final class Nullsy implements Transformation +final class Nullsy extends AbstractTransformation implements Transformation { public function __invoke() { diff --git a/src/Transformation/Reduce.php b/src/Transformation/Reduce.php index dc1d796f2..1bcdd06bb 100644 --- a/src/Transformation/Reduce.php +++ b/src/Transformation/Reduce.php @@ -15,7 +15,7 @@ * * @implements Transformation */ -final class Reduce implements Transformation +final class Reduce extends AbstractTransformation implements Transformation { /** * @psalm-param \Iterator $collection @@ -28,9 +28,7 @@ public function __invoke() return static function (callable $callback): Closure { return static function ($initial = null) use ($callback): Closure { return static function (Iterator $iterator) use ($callback, $initial) { - return (new Transform())()( - (new FoldLeft())()($callback)($initial) - )($iterator); + return Transform::of()(FoldLeft::of()($callback)($initial))($iterator); }; }; }; diff --git a/src/Transformation/Run.php b/src/Transformation/Run.php index 54ae95d78..db72d879f 100644 --- a/src/Transformation/Run.php +++ b/src/Transformation/Run.php @@ -4,6 +4,7 @@ namespace loophp\collection\Transformation; +use ArrayIterator; use Closure; use Iterator; use loophp\collection\Contract\Transformation; @@ -16,20 +17,20 @@ * * @implements Transformation */ -final class Run implements Transformation +final class Run extends AbstractTransformation implements Transformation { public function __invoke(): Closure { return static function (callable ...$operations): Closure { return static function (Iterator $iterator) use ($operations) { - return (new FoldLeft())()( - static function (Iterator $collection, callable $operation): ClosureIterator { + return FoldLeft::of()( + static function (Iterator $iterator, callable $operation): ClosureIterator { return new ClosureIterator( $operation, - $collection, + $iterator ); } - )($iterator)($operations); + )($iterator)(new ArrayIterator($operations)); }; }; } diff --git a/src/Transformation/Transform.php b/src/Transformation/Transform.php index f9fd2af86..abd75b865 100644 --- a/src/Transformation/Transform.php +++ b/src/Transformation/Transform.php @@ -15,7 +15,7 @@ * * @implements Transformation */ -final class Transform implements Transformation +final class Transform extends AbstractTransformation implements Transformation { /** * @psalm-param \Iterator $collection @@ -27,7 +27,7 @@ public function __invoke() { return static function (callable ...$transformers): Closure { return static function (Iterator $iterator) use ($transformers) { - return (new FoldLeft())()( + return FoldLeft::of()( static function (Iterator $collection, callable $transformer, $key) { return $transformer($collection); } diff --git a/src/Transformation/Truthy.php b/src/Transformation/Truthy.php index 00143388e..540bc0dab 100644 --- a/src/Transformation/Truthy.php +++ b/src/Transformation/Truthy.php @@ -14,7 +14,7 @@ * * @implements Transformation */ -final class Truthy implements Transformation +final class Truthy extends AbstractTransformation implements Transformation { public function __invoke() { From e36b03c66a412ef4c5a2601c56543c4b7e5017b5 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Wed, 26 Aug 2020 21:21:30 +0200 Subject: [PATCH 3/6] Convert Transformations into Operations. --- docs/pages/api.rst | 26 ++++---- src/Collection.php | 62 +++++++++---------- src/Contract/Collection.php | 28 ++++----- .../{Transformation => Operation}/Allable.php | 2 +- .../Containsable.php | 2 +- .../Falsyable.php | 2 +- .../FoldLeftable.php | 2 +- .../FoldRightable.php | 2 +- .../{Transformation => Operation}/Getable.php | 2 +- .../{Transformation => Operation}/Hasable.php | 2 +- .../Implodeable.php | 2 +- .../Nullsyable.php | 2 +- .../Reduceable.php | 2 +- .../Truthyable.php | 2 +- src/Contract/Transformation.php | 21 ------- src/Contract/Transformation/Runable.php | 18 ------ src/Contract/Transformation/Transformable.php | 15 ----- src/Operation/Compose.php | 52 ++++++++++++++++ src/Operation/Contains.php | 49 +++++++++++++++ src/Operation/Falsy.php | 39 ++++++++++++ src/Operation/Flatten.php | 1 - src/Operation/FoldLeft.php | 54 ++++++++++++++++ src/Operation/FoldRight.php | 55 ++++++++++++++++ src/Operation/Get.php | 53 ++++++++++++++++ src/Operation/Has.php | 45 ++++++++++++++ src/{Transformation => Operation}/Implode.php | 17 +++-- src/Operation/Nullsy.php | 39 ++++++++++++ src/{Transformation => Operation}/Reduce.php | 12 ++-- src/Operation/Truthy.php | 39 ++++++++++++ src/Operation/Unpack.php | 1 - src/Transformation/All.php | 30 --------- src/Transformation/Contains.php | 56 ----------------- src/Transformation/Count.php | 25 -------- src/Transformation/Falsy.php | 31 ---------- src/Transformation/FoldLeft.php | 39 ------------ src/Transformation/FoldRight.php | 37 ----------- src/Transformation/Get.php | 36 ----------- src/Transformation/Has.php | 34 ---------- src/Transformation/Nullsy.php | 31 ---------- src/Transformation/Run.php | 37 ----------- src/Transformation/Transform.php | 38 ------------ src/Transformation/Truthy.php | 31 ---------- 42 files changed, 503 insertions(+), 570 deletions(-) rename src/Contract/{Transformation => Operation}/Allable.php (86%) rename src/Contract/{Transformation => Operation}/Containsable.php (80%) rename src/Contract/{Transformation => Operation}/Falsyable.php (63%) rename src/Contract/{Transformation => Operation}/FoldLeftable.php (88%) rename src/Contract/{Transformation => Operation}/FoldRightable.php (88%) rename src/Contract/{Transformation => Operation}/Getable.php (89%) rename src/Contract/{Transformation => Operation}/Hasable.php (83%) rename src/Contract/{Transformation => Operation}/Implodeable.php (68%) rename src/Contract/{Transformation => Operation}/Nullsyable.php (64%) rename src/Contract/{Transformation => Operation}/Reduceable.php (88%) rename src/Contract/{Transformation => Operation}/Truthyable.php (64%) delete mode 100644 src/Contract/Transformation.php delete mode 100644 src/Contract/Transformation/Runable.php delete mode 100644 src/Contract/Transformation/Transformable.php create mode 100644 src/Operation/Compose.php create mode 100644 src/Operation/Contains.php create mode 100644 src/Operation/Falsy.php create mode 100644 src/Operation/FoldLeft.php create mode 100644 src/Operation/FoldRight.php create mode 100644 src/Operation/Get.php create mode 100644 src/Operation/Has.php rename src/{Transformation => Operation}/Implode.php (68%) create mode 100644 src/Operation/Nullsy.php rename src/{Transformation => Operation}/Reduce.php (64%) create mode 100644 src/Operation/Truthy.php delete mode 100644 src/Transformation/All.php delete mode 100644 src/Transformation/Contains.php delete mode 100644 src/Transformation/Count.php delete mode 100644 src/Transformation/Falsy.php delete mode 100644 src/Transformation/FoldLeft.php delete mode 100644 src/Transformation/FoldRight.php delete mode 100644 src/Transformation/Get.php delete mode 100644 src/Transformation/Has.php delete mode 100644 src/Transformation/Nullsy.php delete mode 100644 src/Transformation/Run.php delete mode 100644 src/Transformation/Transform.php delete mode 100644 src/Transformation/Truthy.php diff --git a/docs/pages/api.rst b/docs/pages/api.rst index 4112f9fd0..d024d71e4 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -1517,7 +1517,7 @@ truthy Interface: `Truthyable`_ -.. _Allable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Allable.php +.. _Allable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Allable.php .. _Appendable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Appendable.php .. _Applyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Applyable.php .. _Associateable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Associateable.php @@ -1528,28 +1528,28 @@ Interface: `Truthyable`_ .. _Combinateable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Combinateable.php .. _Combineable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Combineable.php .. _Compactable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Compactable.php -.. _Containsable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Containsable.php +.. _Containsable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Containsable.php .. _Cycleable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Cycleable.php .. _Diffable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Diffable.php .. _Diffkeysable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Diffkeysable.php .. _Distinctable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Distinctable.php .. _Explodeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Explodeable.php -.. _Falsyable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Falsyable.php +.. _Falsyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Falsyable.php .. _Filterable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Filterable.php .. _Firstable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Firstable.php .. _Flattenable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Flattenable.php .. _Flipable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Flipable.php .. _array_flip(): https://php.net/array_flip -.. _FoldLeftable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/FoldLeftable.php -.. _FoldRightable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/FoldRightable.php +.. _FoldLeftable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/FoldLeftable.php +.. _FoldRightable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/FoldRightable.php .. _Forgetable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Forgetable.php .. _Frequencyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Frequencyable.php -.. _Getable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Getable.php +.. _Getable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Getable.php .. _Groupable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Groupable.php -.. _Hasable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Hasable.php +.. _Hasable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Hasable.php .. _Headable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Headable.php .. _IfThenElseable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/IfThenElseable.php -.. _Implodeable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Implodeable.php +.. _Implodeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Implodeable.php .. _Intersectable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Intersectable.php .. _Intersectkeysable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Intersectkeysable.php .. _Intersperseable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Intersperseable.php @@ -1561,7 +1561,7 @@ Interface: `Truthyable`_ .. _Mergeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Mergeable.php .. _Normalizeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Normalizeable.php .. _Nthable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Nthable.php -.. _Nullsyable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Nullsyable.php +.. _Nullsyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Nullsyable.php .. _Onlyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Onlyable.php .. _Packable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Packable.php .. _Padable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Padable.php @@ -1571,10 +1571,10 @@ Interface: `Truthyable`_ .. _Prependable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Prependable.php .. _Productable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Productable.php .. _Randomable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Randomable.php -.. _Reduceable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Reduceable.php +.. _Reduceable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reduceable.php .. _Reductionable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reductionable.php .. _Reverseable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reverseable.php -.. _Runable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Runable.php +.. _Runable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Runable.php .. _Scaleable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Scaleable.php .. _Skipable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Skipable.php .. _Sinceable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sinceable.php @@ -1582,9 +1582,9 @@ Interface: `Truthyable`_ .. _Sortable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sortable.php .. _Splitable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Splitable.php .. _Tailable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Tailable.php -.. _Transformable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Transformable.php +.. _Transformable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Transformable.php .. _Transposeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Transposeable.php -.. _Truthyable: https://github.com/loophp/collection/blob/master/src/Contract/Transformation/Truthyable.php +.. _Truthyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Truthyable.php .. _Unpackable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Unpackagle.php .. _Unpairable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Unpairable.php .. _Untilable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Untilable.php diff --git a/src/Collection.php b/src/Collection.php index 3053e0cb9..034ce6cb5 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -22,20 +22,28 @@ use loophp\collection\Operation\Combinate; use loophp\collection\Operation\Combine; use loophp\collection\Operation\Compact; +use loophp\collection\Operation\Compose; +use loophp\collection\Operation\Contains; use loophp\collection\Operation\Cycle; use loophp\collection\Operation\Diff; use loophp\collection\Operation\DiffKeys; use loophp\collection\Operation\Distinct; use loophp\collection\Operation\Explode; +use loophp\collection\Operation\Falsy; use loophp\collection\Operation\Filter; use loophp\collection\Operation\First; use loophp\collection\Operation\Flatten; use loophp\collection\Operation\Flip; +use loophp\collection\Operation\FoldLeft; +use loophp\collection\Operation\FoldRight; use loophp\collection\Operation\Forget; use loophp\collection\Operation\Frequency; +use loophp\collection\Operation\Get; use loophp\collection\Operation\Group; +use loophp\collection\Operation\Has; use loophp\collection\Operation\Head; use loophp\collection\Operation\IfThenElse; +use loophp\collection\Operation\Implode; use loophp\collection\Operation\Intersect; use loophp\collection\Operation\IntersectKeys; use loophp\collection\Operation\Intersperse; @@ -48,6 +56,7 @@ use loophp\collection\Operation\Merge; use loophp\collection\Operation\Normalize; use loophp\collection\Operation\Nth; +use loophp\collection\Operation\Nullsy; use loophp\collection\Operation\Only; use loophp\collection\Operation\Pack; use loophp\collection\Operation\Pad; @@ -58,9 +67,11 @@ use loophp\collection\Operation\Product; use loophp\collection\Operation\Random; use loophp\collection\Operation\Range; +use loophp\collection\Operation\Reduce; use loophp\collection\Operation\Reduction; use loophp\collection\Operation\Reverse; use loophp\collection\Operation\RSample; +use loophp\collection\Operation\Run; use loophp\collection\Operation\Scale; use loophp\collection\Operation\Shuffle; use loophp\collection\Operation\Since; @@ -71,6 +82,7 @@ use loophp\collection\Operation\Tail; use loophp\collection\Operation\Times; use loophp\collection\Operation\Transpose; +use loophp\collection\Operation\Truthy; use loophp\collection\Operation\Unpack; use loophp\collection\Operation\Unpair; use loophp\collection\Operation\Until; @@ -78,20 +90,6 @@ use loophp\collection\Operation\Window; use loophp\collection\Operation\Wrap; use loophp\collection\Operation\Zip; -use loophp\collection\Transformation\All; -use loophp\collection\Transformation\Contains; -use loophp\collection\Transformation\Count; -use loophp\collection\Transformation\Falsy; -use loophp\collection\Transformation\FoldLeft; -use loophp\collection\Transformation\FoldRight; -use loophp\collection\Transformation\Get; -use loophp\collection\Transformation\Has; -use loophp\collection\Transformation\Implode; -use loophp\collection\Transformation\Nullsy; -use loophp\collection\Transformation\Reduce; -use loophp\collection\Transformation\Run; -use loophp\collection\Transformation\Transform; -use loophp\collection\Transformation\Truthy; use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; @@ -225,7 +223,7 @@ static function ($data): Generator { public function all(): array { - return $this->transform(All::of()); + return iterator_to_array($this); } public function append(...$items): CollectionInterface @@ -282,12 +280,12 @@ public function compact(...$values): CollectionInterface public function contains(...$value): bool { - return $this->transform(Contains::of()(...$value)); + return $this->run(Contains::of()(...$value))->getIterator()->current(); } public function count(): int { - return $this->transform(Count::of()); + return iterator_count($this); } public function cycle(int $length = 0): CollectionInterface @@ -322,7 +320,7 @@ public function explode(...$explodes): CollectionInterface public function falsy(): bool { - return $this->transform(Falsy::of()); + return $this->run(Falsy::of())->getIterator()->current(); } public function filter(callable ...$callbacks): CollectionInterface @@ -347,12 +345,12 @@ public function flip(): CollectionInterface public function foldLeft(callable $callback, $initial = null) { - return $this->transform(FoldLeft::of()($callback)($initial)); + return $this->run(FoldLeft::of()($callback)($initial))->getIterator()->current(); } public function foldRight(callable $callback, $initial = null) { - return $this->transform(Foldright::of()($callback)($initial)); + return $this->run(Foldright::of()($callback)($initial))->getIterator()->current(); } public function forget(...$keys): CollectionInterface @@ -409,7 +407,7 @@ static function (string $string, string $delimiter): Generator { public function get($key, $default = null) { - return $this->transform(Get::of()($key)($default)); + return $this->run(Get::of()($key)($default))->getIterator()->current(); } public function getIterator(): ClosureIterator @@ -424,7 +422,7 @@ public function group(?callable $callable = null): CollectionInterface public function has(callable $callback): bool { - return $this->transform(Has::of()($callback)); + return $this->run(Has::of()($callback))->getIterator()->current(); } public function head(): CollectionInterface @@ -443,7 +441,7 @@ public function ifThenElse(callable $condition, callable $then, ?callable $else public function implode(string $glue = ''): string { - return $this->transform(Implode::of()($glue)); + return $this->run(Implode::of()($glue))->getIterator()->current(); } public function intersect(...$values): CollectionInterface @@ -516,7 +514,7 @@ public function nth(int $step, int $offset = 0): CollectionInterface public function nullsy(): bool { - return $this->transform(Nullsy::of()); + return $this->run(Nullsy::of())->getIterator()->current(); } public function only(...$keys): CollectionInterface @@ -571,7 +569,7 @@ public static function range(float $start = 0.0, float $end = INF, float $step = public function reduce(callable $callback, $initial = null) { - return $this->transform(Reduce::of()($callback)($initial)); + return $this->run(Reduce::of()($callback)($initial))->getIterator()->current(); } public function reduction(callable $callback, $initial = null): CollectionInterface @@ -589,9 +587,12 @@ public function rsample(float $probability): CollectionInterface return $this->run(RSample::of()($probability)); } - public function run(callable ...$operations) + public function run(callable ...$operations): CollectionInterface { - return self::fromIterable(Run::of()(...$operations)($this->getIterator())); + return self::fromCallable( + Compose::of()(...$operations), + $this->getIterator() + ); } public function scale( @@ -644,11 +645,6 @@ public static function times(int $number = 0, ?callable $callback = null): Colle return (new self())->run(Times::of()($number)($callback)); } - public function transform(callable ...$transformers) - { - return Transform::of()(...$transformers)($this->getIterator()); - } - public function transpose(): CollectionInterface { return $this->run(Transpose::of()); @@ -656,7 +652,7 @@ public function transpose(): CollectionInterface public function truthy(): bool { - return $this->transform(Truthy::of()); + return $this->run(Truthy::of())->getIterator()->current(); } public function unpack(): CollectionInterface diff --git a/src/Contract/Collection.php b/src/Contract/Collection.php index b8f59047f..a968cdb99 100644 --- a/src/Contract/Collection.php +++ b/src/Contract/Collection.php @@ -6,6 +6,7 @@ use IteratorAggregate; use JsonSerializable; +use loophp\collection\Contract\Operation\Allable; use loophp\collection\Contract\Operation\Appendable; use loophp\collection\Contract\Operation\Applyable; use loophp\collection\Contract\Operation\Associateable; @@ -16,20 +17,27 @@ use loophp\collection\Contract\Operation\Combinateable; use loophp\collection\Contract\Operation\Combineable; use loophp\collection\Contract\Operation\Compactable; +use loophp\collection\Contract\Operation\Containsable; use loophp\collection\Contract\Operation\Cycleable; use loophp\collection\Contract\Operation\Diffable; use loophp\collection\Contract\Operation\Diffkeysable; use loophp\collection\Contract\Operation\Distinctable; use loophp\collection\Contract\Operation\Explodeable; +use loophp\collection\Contract\Operation\Falsyable; use loophp\collection\Contract\Operation\Filterable; use loophp\collection\Contract\Operation\Firstable; use loophp\collection\Contract\Operation\Flattenable; use loophp\collection\Contract\Operation\Flipable; +use loophp\collection\Contract\Operation\FoldLeftable; +use loophp\collection\Contract\Operation\FoldRightable; use loophp\collection\Contract\Operation\Forgetable; use loophp\collection\Contract\Operation\Frequencyable; +use loophp\collection\Contract\Operation\Getable; use loophp\collection\Contract\Operation\Groupable; +use loophp\collection\Contract\Operation\Hasable; use loophp\collection\Contract\Operation\Headable; use loophp\collection\Contract\Operation\IfThenElseable; +use loophp\collection\Contract\Operation\Implodeable; use loophp\collection\Contract\Operation\Intersectable; use loophp\collection\Contract\Operation\Intersectkeysable; use loophp\collection\Contract\Operation\Intersperseable; @@ -42,6 +50,7 @@ use loophp\collection\Contract\Operation\Mergeable; use loophp\collection\Contract\Operation\Normalizeable; use loophp\collection\Contract\Operation\Nthable; +use loophp\collection\Contract\Operation\Nullsyable; use loophp\collection\Contract\Operation\Onlyable; use loophp\collection\Contract\Operation\Padable; use loophp\collection\Contract\Operation\Pairable; @@ -51,9 +60,11 @@ use loophp\collection\Contract\Operation\Productable; use loophp\collection\Contract\Operation\Randomable; use loophp\collection\Contract\Operation\Rangeable; +use loophp\collection\Contract\Operation\Reduceable; use loophp\collection\Contract\Operation\Reductionable; use loophp\collection\Contract\Operation\Reverseable; use loophp\collection\Contract\Operation\RSampleable; +use loophp\collection\Contract\Operation\Runable; use loophp\collection\Contract\Operation\Scaleable; use loophp\collection\Contract\Operation\Shuffleable; use loophp\collection\Contract\Operation\Sinceable; @@ -64,25 +75,13 @@ use loophp\collection\Contract\Operation\Tailable; use loophp\collection\Contract\Operation\Timesable; use loophp\collection\Contract\Operation\Transposeable; +use loophp\collection\Contract\Operation\Truthyable; use loophp\collection\Contract\Operation\Unpairable; use loophp\collection\Contract\Operation\Untilable; use loophp\collection\Contract\Operation\Unwrapable; use loophp\collection\Contract\Operation\Windowable; use loophp\collection\Contract\Operation\Wrapable; use loophp\collection\Contract\Operation\Zipable; -use loophp\collection\Contract\Transformation\Allable; -use loophp\collection\Contract\Transformation\Containsable; -use loophp\collection\Contract\Transformation\Falsyable; -use loophp\collection\Contract\Transformation\FoldLeftable; -use loophp\collection\Contract\Transformation\FoldRightable; -use loophp\collection\Contract\Transformation\Getable; -use loophp\collection\Contract\Transformation\Hasable; -use loophp\collection\Contract\Transformation\Implodeable; -use loophp\collection\Contract\Transformation\Nullsyable; -use loophp\collection\Contract\Transformation\Reduceable; -use loophp\collection\Contract\Transformation\Runable; -use loophp\collection\Contract\Transformation\Transformable; -use loophp\collection\Contract\Transformation\Truthyable; /** * @psalm-template TKey @@ -159,7 +158,6 @@ * @template-extends Zipable * @template-extends \IteratorAggregate * @template-extends Runable - * @template-extends Transformable */ interface Collection extends Allable, @@ -222,7 +220,6 @@ interface Collection extends Reductionable, Reverseable, RSampleable, - Runable, Scaleable, Shuffleable, Sinceable, @@ -232,7 +229,6 @@ interface Collection extends Splitable, Tailable, Timesable, - Transformable, Transposeable, Truthyable, Unpairable, diff --git a/src/Contract/Transformation/Allable.php b/src/Contract/Operation/Allable.php similarity index 86% rename from src/Contract/Transformation/Allable.php rename to src/Contract/Operation/Allable.php index e1db99e93..7b8a40c4b 100644 --- a/src/Contract/Transformation/Allable.php +++ b/src/Contract/Operation/Allable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Containsable.php b/src/Contract/Operation/Containsable.php similarity index 80% rename from src/Contract/Transformation/Containsable.php rename to src/Contract/Operation/Containsable.php index 4c1ccc3af..b78e7779b 100644 --- a/src/Contract/Transformation/Containsable.php +++ b/src/Contract/Operation/Containsable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template T diff --git a/src/Contract/Transformation/Falsyable.php b/src/Contract/Operation/Falsyable.php similarity index 63% rename from src/Contract/Transformation/Falsyable.php rename to src/Contract/Operation/Falsyable.php index 93e5b4c3e..9e7ffd649 100644 --- a/src/Contract/Transformation/Falsyable.php +++ b/src/Contract/Operation/Falsyable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; interface Falsyable { diff --git a/src/Contract/Transformation/FoldLeftable.php b/src/Contract/Operation/FoldLeftable.php similarity index 88% rename from src/Contract/Transformation/FoldLeftable.php rename to src/Contract/Operation/FoldLeftable.php index 540d5833b..a4db77e6b 100644 --- a/src/Contract/Transformation/FoldLeftable.php +++ b/src/Contract/Operation/FoldLeftable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/FoldRightable.php b/src/Contract/Operation/FoldRightable.php similarity index 88% rename from src/Contract/Transformation/FoldRightable.php rename to src/Contract/Operation/FoldRightable.php index ab534aade..2c78afab8 100644 --- a/src/Contract/Transformation/FoldRightable.php +++ b/src/Contract/Operation/FoldRightable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Getable.php b/src/Contract/Operation/Getable.php similarity index 89% rename from src/Contract/Transformation/Getable.php rename to src/Contract/Operation/Getable.php index ef497b4dc..d556d2900 100644 --- a/src/Contract/Transformation/Getable.php +++ b/src/Contract/Operation/Getable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Hasable.php b/src/Contract/Operation/Hasable.php similarity index 83% rename from src/Contract/Transformation/Hasable.php rename to src/Contract/Operation/Hasable.php index 6da78652a..b4804c26a 100644 --- a/src/Contract/Transformation/Hasable.php +++ b/src/Contract/Operation/Hasable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Implodeable.php b/src/Contract/Operation/Implodeable.php similarity index 68% rename from src/Contract/Transformation/Implodeable.php rename to src/Contract/Operation/Implodeable.php index ce0bf4d9a..d906ebfda 100644 --- a/src/Contract/Transformation/Implodeable.php +++ b/src/Contract/Operation/Implodeable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; interface Implodeable { diff --git a/src/Contract/Transformation/Nullsyable.php b/src/Contract/Operation/Nullsyable.php similarity index 64% rename from src/Contract/Transformation/Nullsyable.php rename to src/Contract/Operation/Nullsyable.php index 74cdf626e..214cb2d3e 100644 --- a/src/Contract/Transformation/Nullsyable.php +++ b/src/Contract/Operation/Nullsyable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; interface Nullsyable { diff --git a/src/Contract/Transformation/Reduceable.php b/src/Contract/Operation/Reduceable.php similarity index 88% rename from src/Contract/Transformation/Reduceable.php rename to src/Contract/Operation/Reduceable.php index e23432271..fdc294bdd 100644 --- a/src/Contract/Transformation/Reduceable.php +++ b/src/Contract/Operation/Reduceable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; /** * @psalm-template TKey diff --git a/src/Contract/Transformation/Truthyable.php b/src/Contract/Operation/Truthyable.php similarity index 64% rename from src/Contract/Transformation/Truthyable.php rename to src/Contract/Operation/Truthyable.php index ced83bad9..9d7f7b521 100644 --- a/src/Contract/Transformation/Truthyable.php +++ b/src/Contract/Operation/Truthyable.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace loophp\collection\Contract\Transformation; +namespace loophp\collection\Contract\Operation; interface Truthyable { diff --git a/src/Contract/Transformation.php b/src/Contract/Transformation.php deleted file mode 100644 index 275c140c5..000000000 --- a/src/Contract/Transformation.php +++ /dev/null @@ -1,21 +0,0 @@ - $collection - * - * @return mixed - * @psalm-return T|scalar|\Iterator|array|null - */ - public function __invoke(); -} diff --git a/src/Contract/Transformation/Runable.php b/src/Contract/Transformation/Runable.php deleted file mode 100644 index d70349234..000000000 --- a/src/Contract/Transformation/Runable.php +++ /dev/null @@ -1,18 +0,0 @@ - - */ - public function run(callable ...$operations); -} diff --git a/src/Contract/Transformation/Transformable.php b/src/Contract/Transformation/Transformable.php deleted file mode 100644 index 465631051..000000000 --- a/src/Contract/Transformation/Transformable.php +++ /dev/null @@ -1,15 +0,0 @@ -):Generator)...): Closure(Iterator): Generator + */ + // phpcs:enable + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(Iterator): Generator ...$operations + */ + static function (callable ...$operations): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($operations): Generator { + $callback = + /** + * @psalm-param Iterator $iterator + * @psalm-param callable(Iterator): Generator $fn + * + * @psalm-return Generator + */ + static function (Iterator $iterator, callable $fn): Generator { + return $fn($iterator); + }; + + return yield from array_reduce($operations, $callback, $iterator); + }; + }; + } +} diff --git a/src/Operation/Contains.php b/src/Operation/Contains.php new file mode 100644 index 000000000..6cd1d10cd --- /dev/null +++ b/src/Operation/Contains.php @@ -0,0 +1,49 @@ + $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + foreach ($values as $k => $v) { + if ($v === $value) { + unset($values[$k]); + } + + if ([] === $values) { + return yield true; + } + } + } + + return yield false; + }; + }; + } +} diff --git a/src/Operation/Falsy.php b/src/Operation/Falsy.php new file mode 100644 index 000000000..a8d3d0fbe --- /dev/null +++ b/src/Operation/Falsy.php @@ -0,0 +1,39 @@ +): Generator + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator $iterator + */ + static function (Iterator $iterator): Generator { + foreach ($iterator as $key => $value) { + if (false !== (bool) $value) { + return yield false; + } + } + + return yield true; + }; + } +} diff --git a/src/Operation/Flatten.php b/src/Operation/Flatten.php index 085f88c2b..7515df706 100644 --- a/src/Operation/Flatten.php +++ b/src/Operation/Flatten.php @@ -9,7 +9,6 @@ use Iterator; use loophp\collection\Contract\Operation; use loophp\collection\Iterator\IterableIterator; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey diff --git a/src/Operation/FoldLeft.php b/src/Operation/FoldLeft.php new file mode 100644 index 000000000..2af8b323a --- /dev/null +++ b/src/Operation/FoldLeft.php @@ -0,0 +1,54 @@ +): T): Closure(T|null): Closure(Iterator): T|null + */ + // phpcs:enable + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(T|null, T, TKey, Iterator): T + */ + static function (callable $callback): Closure { + return + /** + * @psalm-param T|null $initial + * + * @param mixed|null $initial + */ + static function ($initial = null) use ($callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback, $initial): Generator { + foreach ($iterator as $key => $value) { + $initial = $callback($initial, $value, $key, $iterator); + } + + return yield $initial; + }; + }; + }; + } +} diff --git a/src/Operation/FoldRight.php b/src/Operation/FoldRight.php new file mode 100644 index 000000000..f09a4f381 --- /dev/null +++ b/src/Operation/FoldRight.php @@ -0,0 +1,55 @@ +): T): Closure(T|null): Closure(Iterator): T|null + */ + // phpcs:enable + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(T|null, T, TKey, Iterator): T + */ + static function (callable $callback): Closure { + return + /** + * @param mixed|null $initial + * @psalm-param T|null $initial + */ + static function ($initial = null) use ($callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback, $initial): Generator { + /** @psalm-var callable(Iterator): Generator $foldRight */ + $foldRight = Compose::of()( + Reverse::of(), + FoldLeft::of()($callback)($initial) + ); + + return yield from $foldRight($iterator); + }; + }; + }; + } +} diff --git a/src/Operation/Get.php b/src/Operation/Get.php new file mode 100644 index 000000000..59579f0b0 --- /dev/null +++ b/src/Operation/Get.php @@ -0,0 +1,53 @@ + $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($keyToGet, $default): Generator { + foreach ($iterator as $key => $value) { + if ($key === $keyToGet) { + return yield $value; + } + } + + return yield $default; + }; + }; + }; + } +} diff --git a/src/Operation/Has.php b/src/Operation/Has.php new file mode 100644 index 000000000..519261cae --- /dev/null +++ b/src/Operation/Has.php @@ -0,0 +1,45 @@ +): bool + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(TKey, T):(bool) $callback + */ + static function (callable $callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback): Generator { + foreach ($iterator as $key => $value) { + if ($callback($key, $value) === $value) { + return yield true; + } + } + + return yield false; + }; + }; + } +} diff --git a/src/Transformation/Implode.php b/src/Operation/Implode.php similarity index 68% rename from src/Transformation/Implode.php rename to src/Operation/Implode.php index 44348ef9c..4a1d830a4 100644 --- a/src/Transformation/Implode.php +++ b/src/Operation/Implode.php @@ -2,30 +2,29 @@ declare(strict_types=1); -namespace loophp\collection\Transformation; +namespace loophp\collection\Operation; use CachingIterator; use Closure; +use Generator; use Iterator; -use loophp\collection\Contract\Transformation; +use loophp\collection\Contract\Operation; /** * @psalm-template TKey * @psalm-template TKey of array-key * @psalm-template T - * - * @implements Transformation */ -final class Implode extends AbstractTransformation implements Transformation +final class Implode extends AbstractOperation implements Operation { - public function __invoke() + public function __invoke(): Closure { return static function (string $glue): Closure { - return static function (Iterator $iterator) use ($glue): string { + return static function (Iterator $iterator) use ($glue): Generator { $callback = /** * @psalm-param TKey $key - * @psalm-param \CachingIterator $iterator + * @psalm-param CachingIterator $iterator * * @param mixed $key * @param mixed $iterator @@ -40,7 +39,7 @@ static function (string $carry, string $item, $key, CachingIterator $iterator) u return $carry; }; - return (string) Transform::of()(FoldLeft::of()($callback)(''))(new CachingIterator($iterator)); + return yield from FoldLeft::of()($callback)('')(new CachingIterator($iterator)); }; }; } diff --git a/src/Operation/Nullsy.php b/src/Operation/Nullsy.php new file mode 100644 index 000000000..c4e45f385 --- /dev/null +++ b/src/Operation/Nullsy.php @@ -0,0 +1,39 @@ +): Generator + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator): Generator { + foreach ($iterator as $key => $value) { + if (null !== $value) { + return yield false; + } + } + + return yield true; + }; + } +} diff --git a/src/Transformation/Reduce.php b/src/Operation/Reduce.php similarity index 64% rename from src/Transformation/Reduce.php rename to src/Operation/Reduce.php index 1bcdd06bb..0aaa16b42 100644 --- a/src/Transformation/Reduce.php +++ b/src/Operation/Reduce.php @@ -2,20 +2,18 @@ declare(strict_types=1); -namespace loophp\collection\Transformation; +namespace loophp\collection\Operation; use Closure; use Iterator; -use loophp\collection\Contract\Transformation; +use loophp\collection\Contract\Operation; /** * @psalm-template TKey * @psalm-template TKey of array-key * @psalm-template T - * - * @implements Transformation */ -final class Reduce extends AbstractTransformation implements Transformation +final class Reduce extends AbstractOperation implements Operation { /** * @psalm-param \Iterator $collection @@ -23,12 +21,12 @@ final class Reduce extends AbstractTransformation implements Transformation * @return mixed|null * @psalm-return T|scalar|null|\Iterator */ - public function __invoke() + public function __invoke(): Closure { return static function (callable $callback): Closure { return static function ($initial = null) use ($callback): Closure { return static function (Iterator $iterator) use ($callback, $initial) { - return Transform::of()(FoldLeft::of()($callback)($initial))($iterator); + return yield from FoldLeft::of()($callback)($initial)($iterator); }; }; }; diff --git a/src/Operation/Truthy.php b/src/Operation/Truthy.php new file mode 100644 index 000000000..2f7020f69 --- /dev/null +++ b/src/Operation/Truthy.php @@ -0,0 +1,39 @@ +): Generator + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator $iterator + */ + static function (Iterator $iterator): Generator { + foreach ($iterator as $key => $value) { + if (false === (bool) $value) { + return yield false; + } + } + + return yield true; + }; + } +} diff --git a/src/Operation/Unpack.php b/src/Operation/Unpack.php index cb8a1f6a8..e2dcab460 100644 --- a/src/Operation/Unpack.php +++ b/src/Operation/Unpack.php @@ -9,7 +9,6 @@ use Iterator; use loophp\collection\Contract\Operation; use loophp\collection\Iterator\IterableIterator; -use loophp\collection\Transformation\Run; /** * @psalm-template TKey diff --git a/src/Transformation/All.php b/src/Transformation/All.php deleted file mode 100644 index 10a126e91..000000000 --- a/src/Transformation/All.php +++ /dev/null @@ -1,30 +0,0 @@ - - */ -final class All extends AbstractTransformation implements Transformation -{ - /** - * @return array - * @phpstan-return array - * @psalm-return array - */ - public function __invoke() - { - return static function (Iterator $iterator): array { - return iterator_to_array($iterator); - }; - } -} diff --git a/src/Transformation/Contains.php b/src/Transformation/Contains.php deleted file mode 100644 index ce5944a25..000000000 --- a/src/Transformation/Contains.php +++ /dev/null @@ -1,56 +0,0 @@ - - */ -final class Contains extends AbstractTransformation implements Transformation -{ - /** - * @var ArrayIterator - * @psalm-var ArrayIterator - */ - private $values; - - /** - * @param mixed ...$values - * @psalm-param T ...$values - */ - public function __construct(...$values) - { - $this->values = new ArrayIterator($values); - } - - public function __invoke() - { - return static function (...$values): Closure { - return static function (Iterator $iterator) use ($values): bool { - foreach ($iterator as $key => $value) { - foreach ($values as $k => $v) { - if ($v === $value) { - unset($values[$k]); - } - - if ([] === $values) { - return true; - } - } - } - - return false; - }; - }; - } -} diff --git a/src/Transformation/Count.php b/src/Transformation/Count.php deleted file mode 100644 index daf2ec1f4..000000000 --- a/src/Transformation/Count.php +++ /dev/null @@ -1,25 +0,0 @@ - - */ -final class Count extends AbstractTransformation implements Transformation -{ - public function __invoke() - { - return static function (Iterator $iterator): int { - return iterator_count($iterator); - }; - } -} diff --git a/src/Transformation/Falsy.php b/src/Transformation/Falsy.php deleted file mode 100644 index 4b987afd7..000000000 --- a/src/Transformation/Falsy.php +++ /dev/null @@ -1,31 +0,0 @@ - - */ -final class Falsy extends AbstractTransformation implements Transformation -{ - public function __invoke() - { - return static function (Iterator $iterator): bool { - foreach ($iterator as $key => $value) { - if (false !== (bool) $value) { - return false; - } - } - - return true; - }; - } -} diff --git a/src/Transformation/FoldLeft.php b/src/Transformation/FoldLeft.php deleted file mode 100644 index e8ca5ec64..000000000 --- a/src/Transformation/FoldLeft.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -final class FoldLeft extends AbstractTransformation implements Transformation -{ - /** - * @psalm-param \Iterator $collection - * - * @return mixed|null - * @psalm-return T|null - */ - public function __invoke() - { - return static function (callable $callback): Closure { - return static function ($initial = null) use ($callback): Closure { - return static function (iterable $iterable) use ($callback, $initial) { - foreach ($iterable as $key => $value) { - $initial = $callback($initial, $value, $key, $iterable); - } - - return $initial; - }; - }; - }; - } -} diff --git a/src/Transformation/FoldRight.php b/src/Transformation/FoldRight.php deleted file mode 100644 index ad29644a2..000000000 --- a/src/Transformation/FoldRight.php +++ /dev/null @@ -1,37 +0,0 @@ - - */ -final class FoldRight extends AbstractTransformation implements Transformation -{ - /** - * @psalm-param \Iterator $collection - * - * @return mixed|null - * @psalm-return T|null - */ - public function __invoke() - { - return static function (callable $callback): Closure { - return static function ($initial = null) use ($callback): Closure { - return static function (iterable $iterable) use ($callback, $initial) { - // @todo: Unify this when operation and transformation are the same. - return Transform::of()(FoldLeft::of()($callback)($initial))(Run::of()(Reverse::of())($iterable)); - }; - }; - }; - } -} diff --git a/src/Transformation/Get.php b/src/Transformation/Get.php deleted file mode 100644 index 09398bf13..000000000 --- a/src/Transformation/Get.php +++ /dev/null @@ -1,36 +0,0 @@ - - */ -final class Get extends AbstractTransformation implements Transformation -{ - public function __invoke() - { - return static function ($keyToGet): Closure { - return static function ($default) use ($keyToGet): Closure { - return static function (Iterator $collection) use ($keyToGet, $default) { - foreach ($collection as $key => $value) { - if ($key === $keyToGet) { - return $value; - } - } - - return $default; - }; - }; - }; - } -} diff --git a/src/Transformation/Has.php b/src/Transformation/Has.php deleted file mode 100644 index cbc37b414..000000000 --- a/src/Transformation/Has.php +++ /dev/null @@ -1,34 +0,0 @@ - - */ -final class Has extends AbstractTransformation implements Transformation -{ - public function __invoke() - { - return static function (callable $callback): Closure { - return static function (Iterator $iterator) use ($callback): bool { - foreach ($iterator as $key => $value) { - if ($callback($key, $value) === $value) { - return true; - } - } - - return false; - }; - }; - } -} diff --git a/src/Transformation/Nullsy.php b/src/Transformation/Nullsy.php deleted file mode 100644 index 1a265be24..000000000 --- a/src/Transformation/Nullsy.php +++ /dev/null @@ -1,31 +0,0 @@ - - */ -final class Nullsy extends AbstractTransformation implements Transformation -{ - public function __invoke() - { - return static function (Iterator $iterator): bool { - foreach ($iterator as $key => $value) { - if (null !== $value) { - return false; - } - } - - return true; - }; - } -} diff --git a/src/Transformation/Run.php b/src/Transformation/Run.php deleted file mode 100644 index db72d879f..000000000 --- a/src/Transformation/Run.php +++ /dev/null @@ -1,37 +0,0 @@ - - */ -final class Run extends AbstractTransformation implements Transformation -{ - public function __invoke(): Closure - { - return static function (callable ...$operations): Closure { - return static function (Iterator $iterator) use ($operations) { - return FoldLeft::of()( - static function (Iterator $iterator, callable $operation): ClosureIterator { - return new ClosureIterator( - $operation, - $iterator - ); - } - )($iterator)(new ArrayIterator($operations)); - }; - }; - } -} diff --git a/src/Transformation/Transform.php b/src/Transformation/Transform.php deleted file mode 100644 index abd75b865..000000000 --- a/src/Transformation/Transform.php +++ /dev/null @@ -1,38 +0,0 @@ - - */ -final class Transform extends AbstractTransformation implements Transformation -{ - /** - * @psalm-param \Iterator $collection - * - * @return mixed|null - * @psalm-return T|scalar|null|\Iterator - */ - public function __invoke() - { - return static function (callable ...$transformers): Closure { - return static function (Iterator $iterator) use ($transformers) { - return FoldLeft::of()( - static function (Iterator $collection, callable $transformer, $key) { - return $transformer($collection); - } - )($iterator)($transformers); - }; - }; - } -} diff --git a/src/Transformation/Truthy.php b/src/Transformation/Truthy.php deleted file mode 100644 index 540bc0dab..000000000 --- a/src/Transformation/Truthy.php +++ /dev/null @@ -1,31 +0,0 @@ - - */ -final class Truthy extends AbstractTransformation implements Transformation -{ - public function __invoke() - { - return static function (Iterator $iterator): bool { - foreach ($iterator as $key => $value) { - if (false === (bool) $value) { - return false; - } - } - - return true; - }; - } -} From 126994fc17640eb23235a76d568c01b80911c26d Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Thu, 27 Aug 2020 11:15:40 +0200 Subject: [PATCH 4/6] Update Psalm annotations. --- src/Collection.php | 26 ++++++- src/Contract/Collection.php | 18 ++--- src/Iterator/StringIterator.php | 4 +- src/Operation/Append.php | 29 +++++--- src/Operation/Apply.php | 8 +- src/Operation/Associate.php | 10 ++- src/Operation/Cache.php | 3 + src/Operation/Chunk.php | 2 +- src/Operation/Collapse.php | 3 + src/Operation/Combinate.php | 65 +++++++++------- src/Operation/Combine.php | 45 +++++++---- src/Operation/Cycle.php | 29 +++++--- src/Operation/Diff.php | 29 ++++++-- src/Operation/DiffKeys.php | 27 +++++-- src/Operation/Distinct.php | 3 + src/Operation/Filter.php | 56 ++++++++------ src/Operation/First.php | 18 ++--- src/Operation/Flatten.php | 5 ++ src/Operation/Forget.php | 31 +++++--- src/Operation/Group.php | 5 +- src/Operation/IfThenElse.php | 6 +- src/Operation/Intersect.php | 31 +++++--- src/Operation/IntersectKeys.php | 31 +++++--- src/Operation/Limit.php | 21 ++++-- src/Operation/Loop.php | 15 +++- src/Operation/Map.php | 47 ++++++++---- src/Operation/Merge.php | 32 +++++--- src/Operation/Normalize.php | 19 +++-- src/Operation/Nth.php | 26 ++++--- src/Operation/Only.php | 45 +++++++---- src/Operation/Pack.php | 3 + src/Operation/Pad.php | 37 ++++++--- src/Operation/Pair.php | 5 +- src/Operation/Pluck.php | 128 +++++++++++++++++++++++--------- src/Operation/Prepend.php | 29 +++++--- src/Operation/Reduction.php | 36 +++++++-- src/Operation/Scale.php | 9 +++ src/Operation/Skip.php | 27 ++++--- src/Operation/Slice.php | 16 +++- src/Operation/Sort.php | 15 ++-- src/Operation/Split.php | 4 +- src/Operation/Tail.php | 5 +- src/Operation/Transpose.php | 27 ++++--- src/Operation/Unpair.php | 3 + src/Operation/Until.php | 43 +++++++---- src/Operation/Window.php | 9 ++- src/Operation/Zip.php | 4 +- 47 files changed, 747 insertions(+), 342 deletions(-) diff --git a/src/Collection.php b/src/Collection.php index 034ce6cb5..2dbdc5b48 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -117,7 +117,7 @@ final class Collection implements CollectionInterface /** * @var Closure - * @psalm-var Closure(Closure|callable|iterable|mixed|resource|scalar|T):(T) + * @psalm-var Closure((Closure|callable|iterable|mixed|resource|scalar|T)...):Generator */ private $source; @@ -387,6 +387,11 @@ static function (iterable $iterable): Generator { public static function fromResource($resource): Collection { return new self( + /** + * @psalm-param resource $resource + * + * @param mixed $resource + */ static function ($resource): Generator { return yield from new ResourceIterator($resource); }, @@ -397,6 +402,9 @@ static function ($resource): Generator { public static function fromString(string $string, string $delimiter = ''): Collection { return new self( + /** + * @psalm-return Generator + */ static function (string $string, string $delimiter): Generator { return yield from new StringIterator($string, $delimiter); }, @@ -432,9 +440,19 @@ public function head(): CollectionInterface public function ifThenElse(callable $condition, callable $then, ?callable $else = null): CollectionInterface { - $else = $else ?? static function ($value, $key) { - return $value; - }; + $else = $else ?? + /** + * @psalm-param T $value + * @psalm-param TKey $key + * + * @psalm-return T + * + * @param mixed $value + * @param mixed $key + */ + static function ($value, $key) { + return $value; + }; return $this->run(IfThenElse::of()($condition)($then)($else)); } diff --git a/src/Contract/Collection.php b/src/Contract/Collection.php index a968cdb99..ce4f11a4a 100644 --- a/src/Contract/Collection.php +++ b/src/Contract/Collection.php @@ -82,6 +82,7 @@ use loophp\collection\Contract\Operation\Windowable; use loophp\collection\Contract\Operation\Wrapable; use loophp\collection\Contract\Operation\Zipable; +use loophp\collection\Iterator\ClosureIterator; /** * @psalm-template TKey @@ -273,25 +274,22 @@ public static function fromCallable(callable $callable, ...$parameters): \loophp public static function fromIterable(iterable $iterable): \loophp\collection\Collection; /** - * @psalm-template NewTKey - * @psalm-template NewTKey of array-key - * @psalm-template NewT - * * @param resource $resource * - * @psalm-return \loophp\collection\Collection + * @psalm-return \loophp\collection\Collection */ public static function fromResource($resource): \loophp\collection\Collection; /** - * @psalm-template NewTKey - * @psalm-template NewTKey of array-key - * @psalm-template NewT - * - * @psalm-return \loophp\collection\Collection + * @psalm-return \loophp\collection\Collection */ public static function fromString(string $string, string $delimiter = ''): \loophp\collection\Collection; + /** + * @psalm-return \loophp\collection\Iterator\ClosureIterator + */ + public function getIterator(): ClosureIterator; + /** * @psalm-template NewTKey * @psalm-template NewTKey of array-key diff --git a/src/Iterator/StringIterator.php b/src/Iterator/StringIterator.php index 10c682294..5478d5d60 100644 --- a/src/Iterator/StringIterator.php +++ b/src/Iterator/StringIterator.php @@ -14,7 +14,7 @@ * @psalm-template T of string * * @extends ProxyIterator - * @implements \Iterator + * @implements Iterator */ final class StringIterator extends ProxyIterator implements Iterator, OuterIterator { @@ -22,7 +22,7 @@ public function __construct(string $data, string $delimiter = '') { $this->iterator = new ClosureIterator( /** - * @psalm-return \Generator + * @psalm-return Generator */ static function (string $input, string $delimiter): Generator { $offset = 0; diff --git a/src/Operation/Append.php b/src/Operation/Append.php index 2720df8aa..16aa1e261 100644 --- a/src/Operation/Append.php +++ b/src/Operation/Append.php @@ -16,18 +16,29 @@ */ final class Append extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(T...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$items): Closure { - return static function (Iterator $iterator) use ($items): Generator { - foreach ($iterator as $key => $value) { - yield $key => $value; - } + return + /** + * @psalm-param T ...$items + */ + static function (...$items): Closure { + return + /** + * @psalm-param Iterator $iterator + */ + static function (Iterator $iterator) use ($items): Generator { + foreach ($iterator as $key => $value) { + yield $key => $value; + } - foreach ($items as $key => $item) { - yield $key => $item; - } + foreach ($items as $key => $item) { + yield $key => $item; + } + }; }; - }; } } diff --git a/src/Operation/Apply.php b/src/Operation/Apply.php index 2271f98b0..e4bf5c5d7 100644 --- a/src/Operation/Apply.php +++ b/src/Operation/Apply.php @@ -17,18 +17,20 @@ final class Apply extends AbstractOperation implements Operation { /** - * @psalm-return Closure(Iterator, list):(Generator) + * @psalm-return Closure((callable(T, TKey):(bool))...): Closure(Iterator): Generator */ public function __invoke(): Closure { return /** - * @psalm-param list $callbacks + * @psalm-param callable(T, TKey):(bool) ...$callbacks */ static function (callable ...$callbacks): Closure { return /** - * @psalm-param \Iterator $iterator + * @psalm-param Iterator $iterator + * + * @psalm-return Generator */ static function (Iterator $iterator) use ($callbacks): Generator { foreach ($iterator as $key => $value) { diff --git a/src/Operation/Associate.php b/src/Operation/Associate.php index d8cc002f3..10b02fa89 100644 --- a/src/Operation/Associate.php +++ b/src/Operation/Associate.php @@ -17,13 +17,13 @@ final class Associate extends AbstractOperation implements Operation { /** - * @psalm-return Closure(Iterator, callable(TKey, T):(TKey), callable(TKey, T):(T)):(Generator) + * @psalm-return Closure(null|callable(TKey, T):(TKey)): Closure(null|callable(TKey, T):(T)): Generator */ public function __invoke(): Closure { return /** - * @psalm-param callable(TKey, T):(TKey) $callbackForKeys + * @psalm-param null|callable(TKey, T):(TKey) $callbackForKeys */ static function (?callable $callbackForKeys = null): Closure { $callbackForKeys = $callbackForKeys ?? static function ($key, $value) { @@ -32,7 +32,7 @@ static function (?callable $callbackForKeys = null): Closure { return /** - * @psalm-param callable(TKey, T):(T) $callbackForValues + * @psalm-param null|callable(TKey, T):(T) $callbackForValues */ static function (?callable $callbackForValues = null) use ($callbackForKeys): Closure { $callbackForValues = $callbackForValues ?? static function ($key, $value) { @@ -41,7 +41,9 @@ static function (?callable $callbackForValues = null) use ($callbackForKeys): Cl return /** - * @psalm-param \Iterator $iterator + * @psalm-param Iterator $iterator + * + * @psalm-return Generator */ static function (Iterator $iterator) use ($callbackForKeys, $callbackForValues): Generator { foreach ($iterator as $key => $value) { diff --git a/src/Operation/Cache.php b/src/Operation/Cache.php index 4654ba56a..85f0358da 100644 --- a/src/Operation/Cache.php +++ b/src/Operation/Cache.php @@ -18,6 +18,9 @@ */ final class Cache extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(CacheItemPoolInterface): Closure(Iterator): Generator + */ public function __invoke(): Closure { return static function (CacheItemPoolInterface $cache): Closure { diff --git a/src/Operation/Chunk.php b/src/Operation/Chunk.php index 0c761515a..002ff7a81 100644 --- a/src/Operation/Chunk.php +++ b/src/Operation/Chunk.php @@ -36,7 +36,7 @@ static function (int ...$sizes): Closure { * @psalm-return Generator> */ static function (Iterator $iterator) use ($sizes): Generator { - /** @var Iterator $sizesIterator */ + /** @psalm-var Iterator $sizesIterator */ $sizesIterator = Loop::of()(new ArrayIterator($sizes)); $values = []; diff --git a/src/Operation/Collapse.php b/src/Operation/Collapse.php index a5eb37977..89495e02c 100644 --- a/src/Operation/Collapse.php +++ b/src/Operation/Collapse.php @@ -16,6 +16,9 @@ */ final class Collapse extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Combinate.php b/src/Operation/Combinate.php index d6ed9545c..815bb9943 100644 --- a/src/Operation/Combinate.php +++ b/src/Operation/Combinate.php @@ -21,40 +21,55 @@ final class Combinate extends AbstractOperation implements Operation { public function __invoke(): Closure { - return static function (?int $length): Closure { - $getCombinations = static function (array $dataset, int $length) use (&$getCombinations): Generator { - for ($i = 0; count($dataset) - $length >= $i; ++$i) { - if (1 === $length) { - yield [$dataset[$i]]; + return static function (?int $length = null): Closure { + $getCombinations = + /** + * @param array $dataset + * @psalm-param array $dataset + * + * @return Generator> + * @psalm-return Generator> + */ + static function (array $dataset, int $length) use (&$getCombinations): Generator { + for ($i = 0; count($dataset) - $length >= $i; ++$i) { + if (1 === $length) { + yield [$dataset[$i]]; - continue; - } + continue; + } - foreach ($getCombinations(array_slice($dataset, $i + 1), $length - 1) as $permutation) { - array_unshift($permutation, $dataset[$i]); + /** @psalm-var array $permutation */ + foreach ($getCombinations(array_slice($dataset, $i + 1), $length - 1) as $permutation) { + array_unshift($permutation, $dataset[$i]); - yield $permutation; + yield $permutation; + } } - } - }; + }; - return static function (Iterator $iterator) use ($length, $getCombinations): Generator { - $dataset = iterator_to_array($iterator); + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator) use ($length, $getCombinations): Generator { + $dataset = iterator_to_array($iterator); - if (0 < $length) { - return yield from $getCombinations($dataset, $length); - } + if (0 < $length) { + return yield from $getCombinations($dataset, $length); + } - $collectionSize = count($dataset); + $collectionSize = count($dataset); - if (0 === $length) { - return yield from $getCombinations($dataset, $collectionSize); - } + if (0 === $length) { + return yield from $getCombinations($dataset, $collectionSize); + } - for ($i = 1; $i <= $collectionSize; ++$i) { - yield from $getCombinations($dataset, $i); - } - }; + for ($i = 1; $i <= $collectionSize; ++$i) { + yield from $getCombinations($dataset, $i); + } + }; }; } } diff --git a/src/Operation/Combine.php b/src/Operation/Combine.php index 8c1ec8f61..214ae4b5c 100644 --- a/src/Operation/Combine.php +++ b/src/Operation/Combine.php @@ -19,23 +19,38 @@ */ final class Combine extends AbstractOperation implements Operation { + /** + * @return Closure(T...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$keys): Closure { - return static function (Iterator $iterator) use ($keys): Generator { - $keys = new ArrayIterator($keys); - - while ($iterator->valid() && $keys->valid()) { - yield $keys->current() => $iterator->current(); - - $iterator->next(); - $keys->next(); - } - - if ($iterator->valid() !== $keys->valid()) { - trigger_error('Both keys and values must have the same amount of items.', E_USER_WARNING); - } + return + /** + * @psalm-param T ...$keys + * + * @psalm-return Closure(Iterator): Generator + */ + static function (...$keys): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-retur Generator + */ + static function (Iterator $iterator) use ($keys): Generator { + $keys = new ArrayIterator($keys); + + while ($iterator->valid() && $keys->valid()) { + yield $keys->current() => $iterator->current(); + + $iterator->next(); + $keys->next(); + } + + if ($iterator->valid() !== $keys->valid()) { + trigger_error('Both keys and values must have the same amount of items.', E_USER_WARNING); + } + }; }; - }; } } diff --git a/src/Operation/Cycle.php b/src/Operation/Cycle.php index 48bf5f50c..7a707c9e2 100644 --- a/src/Operation/Cycle.php +++ b/src/Operation/Cycle.php @@ -18,20 +18,29 @@ */ final class Cycle extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(int): Closure(Iterator): Generator + */ public function __invoke(): Closure { return static function (int $length): Closure { - return static function (Iterator $iterator) use ($length): Generator { - if (0 === $length) { - return yield from []; - } + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($length): Generator { + if (0 === $length) { + return yield from []; + } - return yield from new LimitIterator( - new InfiniteIterator($iterator), - 0, - $length - ); - }; + return yield from new LimitIterator( + new InfiniteIterator($iterator), + 0, + $length + ); + }; }; } } diff --git a/src/Operation/Diff.php b/src/Operation/Diff.php index d43ab07a7..cdd147f3f 100644 --- a/src/Operation/Diff.php +++ b/src/Operation/Diff.php @@ -18,16 +18,29 @@ */ final class Diff extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(T...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$values): Closure { - return static function (Iterator $iterator) use ($values): Generator { - foreach ($iterator as $key => $value) { - if (false === in_array($value, $values, true)) { - yield $key => $value; - } - } + return + /** + * @psalm-param T ...$values + */ + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + if (false === in_array($value, $values, true)) { + yield $key => $value; + } + } + }; }; - }; } } diff --git a/src/Operation/DiffKeys.php b/src/Operation/DiffKeys.php index a9e9cfad2..096a3b1fe 100644 --- a/src/Operation/DiffKeys.php +++ b/src/Operation/DiffKeys.php @@ -18,16 +18,27 @@ */ final class DiffKeys extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(TKey...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$values): Closure { - return static function (Iterator $iterator) use ($values): Generator { - foreach ($iterator as $key => $value) { - if (false === in_array($key, $values, true)) { - yield $key => $value; - } - } + return + /** + * @psalm-param T ...$values + */ + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + if (false === in_array($key, $values, true)) { + yield $key => $value; + } + } + }; }; - }; } } diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index 4dfdb84c6..0d9b1d38d 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -18,6 +18,9 @@ */ final class Distinct extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Filter.php b/src/Operation/Filter.php index aae60bea4..baea1c623 100644 --- a/src/Operation/Filter.php +++ b/src/Operation/Filter.php @@ -17,34 +17,48 @@ */ final class Filter extends AbstractOperation implements Operation { + // phpcs:disable + /** + * @psalm-return Closure((callable(T, TKey, Iterator): bool)...): Closure(Iterator): Generator + */ + // phpcs:enable public function __invoke(): Closure { - return static function (callable ...$callbacks): Closure { - return static function (Iterator $iterator) use ($callbacks): Generator { - $defaultCallback = + return + /** + * @psalm-param callable(T, TKey, Iterator): bool ...$callbacks + */ + static function (callable ...$callbacks): Closure { + return /** - * @param mixed $value - * @param mixed $key - * @psalm-param T $value - * @psalm-param TKey $key * @psalm-param Iterator $iterator + * @psalm-return Generator */ - static function ($value, $key, Iterator $iterator): bool { - return (bool) $value; - }; + static function (Iterator $iterator) use ($callbacks): Generator { + $defaultCallback = + /** + * @param mixed $value + * @param mixed $key + * @psalm-param T $value + * @psalm-param TKey $key + * @psalm-param Iterator $iterator + */ + static function ($value, $key, Iterator $iterator): bool { + return (bool) $value; + }; - $callbacks = [] === $callbacks ? - [$defaultCallback] : - $callbacks; + $callbacks = [] === $callbacks ? + [$defaultCallback] : + $callbacks; - return yield from array_reduce( - $callbacks, - static function (Iterator $carry, callable $callback): CallbackFilterIterator { - return new CallbackFilterIterator($carry, $callback); - }, - $iterator - ); + return yield from array_reduce( + $callbacks, + static function (Iterator $carry, callable $callback): CallbackFilterIterator { + return new CallbackFilterIterator($carry, $callback); + }, + $iterator + ); + }; }; - }; } } diff --git a/src/Operation/First.php b/src/Operation/First.php index c5587e9e2..33bf3da64 100644 --- a/src/Operation/First.php +++ b/src/Operation/First.php @@ -13,20 +13,20 @@ * @psalm-template TKey * @psalm-template TKey of array-key * @psalm-template T - * - * @implements Operation */ final class First extends AbstractOperation implements Operation { public function __invoke(): Closure { - return static function (?callable $callback = null): Closure { - return static function (int $size = 1) use ($callback): Closure { - return + return + /** + * @psalm-param callable(T, TKey):(bool)|null $callback + */ + static function (?callable $callback = null): Closure { + return static function (int $size = 1) use ($callback): Closure { + return /** - * @psalm-param \Iterator $iterator - * - * @psalm-return \Generator + * @psalm-param Iterator $iterator */ static function (Iterator $iterator) use ($callback, $size): Generator { $defaultCallback = @@ -48,7 +48,7 @@ static function ($value, $key, Iterator $iterator): bool { Limit::of()($size)(0) )($iterator); }; + }; }; - }; } } diff --git a/src/Operation/Flatten.php b/src/Operation/Flatten.php index 7515df706..d6eb7b63a 100644 --- a/src/Operation/Flatten.php +++ b/src/Operation/Flatten.php @@ -34,6 +34,7 @@ static function (Iterator $iterator) use ($depth): Generator { if (false === is_iterable($value)) { yield $key => $value; } elseif (1 === $depth) { + /** @psalm-var TKey $subKey */ /** @psalm-var T $subValue */ foreach ($value as $subKey => $subValue) { yield $subKey => $subValue; @@ -42,6 +43,10 @@ static function (Iterator $iterator) use ($depth): Generator { /** @psalm-var callable(Iterator): Generator $flatten */ $flatten = Flatten::of()($depth - 1); + /** + * @psalm-var TKey $subKey + * @psalm-var T $subValue + */ foreach ($flatten(new IterableIterator($value)) as $subKey => $subValue) { yield $subKey => $subValue; } diff --git a/src/Operation/Forget.php b/src/Operation/Forget.php index fad9ef16e..1268f4054 100644 --- a/src/Operation/Forget.php +++ b/src/Operation/Forget.php @@ -18,18 +18,31 @@ */ final class Forget extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(TKey...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$keys): Closure { - return static function (Iterator $iterator) use ($keys): Generator { - $keys = array_flip($keys); + return + /** + * @psalm-param TKey ...$keys + */ + static function (...$keys): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($keys): Generator { + $keys = array_flip($keys); - foreach ($iterator as $key => $value) { - if (false === array_key_exists($key, $keys)) { - yield $key => $value; - } - } + foreach ($iterator as $key => $value) { + if (false === array_key_exists($key, $keys)) { + yield $key => $value; + } + } + }; }; - }; } } diff --git a/src/Operation/Group.php b/src/Operation/Group.php index b85f8f3de..cdae76aea 100644 --- a/src/Operation/Group.php +++ b/src/Operation/Group.php @@ -70,7 +70,10 @@ static function (array $collect, $value, $key) use ($callable): array { return $collect; }; - return yield from (FoldLeft::of()($callback)([])($iterator))->current(); + /** @psalm-var callable(Iterator): Generator $foldLeft */ + $foldLeft = FoldLeft::of()($callback)([]); + + return yield from ($foldLeft($iterator))->current(); }; }; } diff --git a/src/Operation/IfThenElse.php b/src/Operation/IfThenElse.php index b04ec6300..eb8e70cfb 100644 --- a/src/Operation/IfThenElse.php +++ b/src/Operation/IfThenElse.php @@ -18,7 +18,7 @@ final class IfThenElse extends AbstractOperation implements Operation { // phpcs:disable /** - * @psalm-return Closure(callable(T, TKey): bool): Closure(callable(T, TKey): (T|TKey)): Closure(callable(T, TKey): (T|TKey)): Generator + * @psalm-return Closure(callable(T, TKey): bool): Closure(callable(T, TKey): (T)): Closure(callable(T, TKey): (T)): Generator */ // phpcs:enable public function __invoke(): Closure @@ -30,12 +30,12 @@ public function __invoke(): Closure static function (callable $condition): Closure { return /** - * @psalm-param callable(T, TKey): (T|TKey) $then + * @psalm-param callable(T, TKey): (T) $then */ static function (callable $then) use ($condition): Closure { return /** - * @psalm-param callable(T, TKey): (T|TKey) $else + * @psalm-param callable(T, TKey): (T) $else */ static function (callable $else) use ($condition, $then): Closure { return diff --git a/src/Operation/Intersect.php b/src/Operation/Intersect.php index abe6dcd94..38e173682 100644 --- a/src/Operation/Intersect.php +++ b/src/Operation/Intersect.php @@ -18,18 +18,31 @@ */ final class Intersect extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(T...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$values): Closure { - return static function (Iterator $iterator) use ($values): Generator { - foreach ($iterator as $key => $value) { - if (false === in_array($value, $values, true)) { - continue; - } + return + /** + * @psalm-param T ...$values + */ + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + if (false === in_array($value, $values, true)) { + continue; + } - yield $key => $value; - } + yield $key => $value; + } + }; }; - }; } } diff --git a/src/Operation/IntersectKeys.php b/src/Operation/IntersectKeys.php index 15e3d59c2..7ef16770c 100644 --- a/src/Operation/IntersectKeys.php +++ b/src/Operation/IntersectKeys.php @@ -18,18 +18,31 @@ */ final class IntersectKeys extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(TKey...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$values): Closure { - return static function (Iterator $iterator) use ($values): Generator { - foreach ($iterator as $key => $value) { - if (false === in_array($key, $values, true)) { - continue; - } + return + /** + * @psalm-param TKey ...$values + */ + static function (...$values): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($values): Generator { + foreach ($iterator as $key => $value) { + if (false === in_array($key, $values, true)) { + continue; + } - yield $key => $value; - } + yield $key => $value; + } + }; }; - }; } } diff --git a/src/Operation/Limit.php b/src/Operation/Limit.php index 84f30a378..175dec154 100644 --- a/src/Operation/Limit.php +++ b/src/Operation/Limit.php @@ -17,17 +17,26 @@ */ final class Limit extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(int): Closure(int=): Closure(Iterator): Generator + */ public function __invoke(): Closure { return static function (int $limit): Closure { return static function (int $offset = 0) use ($limit): Closure { - return static function (Iterator $iterator) use ($limit, $offset): Generator { - if (0 === $limit) { - return yield from []; - } + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($limit, $offset): Generator { + if (0 === $limit) { + return yield from []; + } - return yield from new LimitIterator($iterator, $offset, $limit); - }; + return yield from new LimitIterator($iterator, $offset, $limit); + }; }; }; } diff --git a/src/Operation/Loop.php b/src/Operation/Loop.php index f7309d46c..04cef3e13 100644 --- a/src/Operation/Loop.php +++ b/src/Operation/Loop.php @@ -17,10 +17,19 @@ */ final class Loop extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (Iterator $iterator): Generator { - return yield from new InfiniteIterator($iterator); - }; + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Iterator + */ + static function (Iterator $iterator): Generator { + return yield from new InfiniteIterator($iterator); + }; } } diff --git a/src/Operation/Map.php b/src/Operation/Map.php index 7fbc94256..e8f0245f9 100644 --- a/src/Operation/Map.php +++ b/src/Operation/Map.php @@ -16,25 +16,40 @@ */ final class Map extends AbstractOperation implements Operation { + /** + * @psalm-return Closure((callable(T, TKey): T)...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (callable ...$callbacks): Closure { - return static function (Iterator $iterator) use ($callbacks): Generator { - foreach ($iterator as $key => $value) { - $callback = - /** - * @param mixed $carry - * @psalm-param T $carry - * @psalm-param callable(T, TKey): T $callback - * @psalm-return T - */ - static function ($carry, callable $callback) use ($value, $key) { - return $callback($value, $key); - }; + return + /** + * @psalm-param callable(T, TKey): T ...$callbacks + */ + static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callbacks): Generator { + foreach ($iterator as $key => $value) { + $callback = + /** + * @param mixed $carry + * @psalm-param T $carry + * + * @psalm-param callable(T, TKey): T $callback + * + * @psalm-return T + */ + static function ($carry, callable $callback) use ($value, $key) { + return $callback($value, $key); + }; - yield $key => array_reduce($callbacks, $callback, $value); - } + yield $key => array_reduce($callbacks, $callback, $value); + } + }; }; - }; } } diff --git a/src/Operation/Merge.php b/src/Operation/Merge.php index d3cea5e05..85d7f7d1e 100644 --- a/src/Operation/Merge.php +++ b/src/Operation/Merge.php @@ -16,20 +16,32 @@ */ final class Merge extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(iterable...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$sources): Closure { - return static function (Iterator $iterator) use ($sources): Generator { - foreach ($iterator as $key => $value) { - yield $key => $value; - } - - foreach ($sources as $source) { - foreach ($source as $key => $value) { + return + /** + * @psalm-param iterable ...$sources + */ + static function (iterable ...$sources): Closure { + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($sources): Generator { + foreach ($iterator as $key => $value) { yield $key => $value; } - } + + foreach ($sources as $source) { + foreach ($source as $key => $value) { + yield $key => $value; + } + } + }; }; - }; } } diff --git a/src/Operation/Normalize.php b/src/Operation/Normalize.php index a52c4b5a5..1162cd978 100644 --- a/src/Operation/Normalize.php +++ b/src/Operation/Normalize.php @@ -16,12 +16,21 @@ */ final class Normalize extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (Iterator $iterator): Generator { - foreach ($iterator as $value) { - yield $value; - } - }; + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator): Generator { + foreach ($iterator as $value) { + yield $value; + } + }; } } diff --git a/src/Operation/Nth.php b/src/Operation/Nth.php index 0324a3b5d..7c27e8dcc 100644 --- a/src/Operation/Nth.php +++ b/src/Operation/Nth.php @@ -16,21 +16,29 @@ */ final class Nth extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(int): Closure(int): Closure(Iterator): Generator + */ public function __invoke(): Closure { return static function (int $step): Closure { return static function (int $offset) use ($step): Closure { - return static function (Iterator $iterator) use ($step, $offset): Generator { - $position = 0; + return + /** + * @psalm-param Iterator $iterator + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($step, $offset): Generator { + $position = 0; - foreach ($iterator as $key => $value) { - if ($position++ % $step !== $offset) { - continue; - } + foreach ($iterator as $key => $value) { + if ($position++ % $step !== $offset) { + continue; + } - yield $key => $value; - } - }; + yield $key => $value; + } + }; }; }; } diff --git a/src/Operation/Only.php b/src/Operation/Only.php index 49b9384e2..58d83d32a 100644 --- a/src/Operation/Only.php +++ b/src/Operation/Only.php @@ -18,24 +18,37 @@ */ final class Only extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(TKey...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$keys): Closure { - return static function (Iterator $iterator) use ($keys): Generator { - if ([] === $keys) { - return yield from $iterator; - } - - $keys = array_flip($keys); - - foreach ($iterator as $key => $value) { - if (false === array_key_exists($key, $keys)) { - continue; - } - - yield $key => $value; - } + return + /** + * @psalm-param TKey ...$keys + */ + static function (...$keys): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($keys): Generator { + if ([] === $keys) { + return yield from $iterator; + } + + $keys = array_flip($keys); + + foreach ($iterator as $key => $value) { + if (false === array_key_exists($key, $keys)) { + continue; + } + + yield $key => $value; + } + }; }; - }; } } diff --git a/src/Operation/Pack.php b/src/Operation/Pack.php index 615f78c64..965fd0997 100644 --- a/src/Operation/Pack.php +++ b/src/Operation/Pack.php @@ -16,6 +16,9 @@ */ final class Pack extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Pad.php b/src/Operation/Pad.php index 3ef39dab7..6bd7df8f9 100644 --- a/src/Operation/Pad.php +++ b/src/Operation/Pad.php @@ -16,24 +16,39 @@ */ final class Pad extends AbstractOperation implements Operation { + /** + * @return Closure(int): Closure(T): Closure(Iterator): Generator + */ public function __invoke(): Closure { return static function (int $size): Closure { - return static function ($padValue) use ($size): Closure { - return static function (Iterator $iterator) use ($size, $padValue): Generator { - $y = 0; + return + /** + * @psalm-param T $padValue + * + * @param mixed $padValue + */ + static function ($padValue) use ($size): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($size, $padValue): Generator { + $y = 0; - foreach ($iterator as $key => $value) { - ++$y; + foreach ($iterator as $key => $value) { + ++$y; - yield $key => $value; - } + yield $key => $value; + } - while ($y++ < $size) { - yield $padValue; - } + while ($y++ < $size) { + yield $padValue; + } + }; }; - }; }; } } diff --git a/src/Operation/Pair.php b/src/Operation/Pair.php index 3b7fd6efc..96ecb52f2 100644 --- a/src/Operation/Pair.php +++ b/src/Operation/Pair.php @@ -14,8 +14,11 @@ * @psalm-template TKey of array-key * @psalm-template T */ -final class Pair extends AbstractOperation extends AbstractOperation implements Operation +final class Pair extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Pluck.php b/src/Operation/Pluck.php index 7f68ea9a5..a3e675b0e 100644 --- a/src/Operation/Pluck.php +++ b/src/Operation/Pluck.php @@ -11,7 +11,6 @@ use Iterator; use loophp\collection\Contract\Collection; use loophp\collection\Contract\Operation; -use loophp\collection\Iterator\IterableIterator; use ReflectionClass; use function array_key_exists; @@ -19,52 +18,109 @@ use function is_array; use function is_object; +/** + * @psalm-template TKey + * @psalm-template TKey of array-key + * @psalm-template T + */ final class Pluck extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(T): Closure(T): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function ($key): Closure { - return static function ($default) use ($key): Closure { - return static function (Iterator $iterator) use ($key, $default): Generator { - $pick = static function (Iterator $iterator, $target, array $key, $default = null) use (&$pick) { - while (null !== $segment = array_shift($key)) { - if ('*' === $segment) { - if (false === is_iterable($target)) { - return $default; - } + return + /** + * @psalm-param T $key + * + * @psalm-return Closure(T): Closure(Iterator): Generator, mixed, void> + * + * @param mixed $key + */ + static function ($key): Closure { + return + /** + * @psalm-param T $default + * + * @psalm-return Closure(Iterator): Generator, mixed, void> + * + * @param mixed $default + */ + static function ($default) use ($key): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator, mixed, void> + */ + static function (Iterator $iterator) use ($key, $default): Generator { + $pick = + // phpcs:disable + /** + * @psalm-param Iterator $iterator + * @psalm-param T|iterable $target + * @psalm-param array $key + * @psalm-param T $default + * + * @psalm-return T|iterable + * + * @param mixed $target + * @param mixed|null $default + */ + static function (Iterator $iterator, $target, array $key, $default = null) use (&$pick) { + // phpcs:enable + while (null !== $segment = array_shift($key)) { + if ('*' === $segment) { + if (false === is_iterable($target)) { + return $default; + } - $result = []; + /** @psalm-var array $result */ + $result = []; - foreach ($target as $item) { - $result[] = $pick($iterator, $item, $key); - } + foreach ($target as $item) { + $result[] = $pick($iterator, $item, $key); + } - return in_array('*', $key, true) ? Collapse::of()(new ArrayIterator($result)) : $result; - } + /** @psalm-var Generator $collapse */ + $collapse = Collapse::of()(new ArrayIterator($result)); - if ((true === is_array($target)) && (true === array_key_exists($segment, $target))) { - $target = $target[$segment]; - } elseif (($target instanceof ArrayAccess) && (true === $target->offsetExists($segment))) { - $target = $target[$segment]; - } elseif ($target instanceof Collection) { - $target = (Get::of()($segment)($default)(new IterableIterator($target)))->current(); - } elseif ((true === is_object($target)) && (true === property_exists($target, $segment))) { - $target = (new ReflectionClass($target))->getProperty($segment)->getValue($target); - } else { - $target = $default; - } - } + return in_array('*', $key, true) ? $collapse : $result; + } - return $target; - }; + // phpcs:disable + if ((true === is_array($target)) && (true === array_key_exists($segment, $target))) { + /** @psalm-var T $target */ + $target = $target[$segment]; + } elseif (($target instanceof ArrayAccess) && (true === $target->offsetExists($segment))) { + /** @psalm-var T $target */ + $target = $target[$segment]; + } elseif ($target instanceof Collection) { + /** @psalm-var T $target */ + $target = (Get::of()($segment)($default)($target->getIterator()))->current(); + } elseif ((true === is_object($target)) && (true === property_exists($target, $segment))) { + /** @psalm-var T $target */ + $target = (new ReflectionClass($target))->getProperty($segment)->getValue($target); + } else { + /** @psalm-var T $target */ + $target = $default; + } + // phpcs:enable + } - $key = true === is_scalar($key) ? explode('.', trim((string) $key, '.')) : $key; + return $target; + }; - foreach ($iterator as $value) { - yield $pick($iterator, $value, $key, $default); - } - }; + $key = true === is_scalar($key) ? explode('.', trim((string) $key, '.')) : $key; + + // phpcs:disable + foreach ($iterator as $value) { + yield $pick($iterator, $value, $key, $default); + } + // phpcs:enable + }; + }; }; - }; } } diff --git a/src/Operation/Prepend.php b/src/Operation/Prepend.php index ff81bcbfa..8db15f4c1 100644 --- a/src/Operation/Prepend.php +++ b/src/Operation/Prepend.php @@ -16,18 +16,29 @@ */ final class Prepend extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(T...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (...$items): Closure { - return static function (Iterator $iterator) use ($items): Generator { - foreach ($items as $key => $item) { - yield $key => $item; - } + return + /** + * @psalm-param T ...$items + */ + static function (...$items): Closure { + return + /** + * @psalm-param Iterator $iterator + */ + static function (Iterator $iterator) use ($items): Generator { + foreach ($items as $key => $item) { + yield $key => $item; + } - foreach ($iterator as $key => $value) { - yield $key => $value; - } + foreach ($iterator as $key => $value) { + yield $key => $value; + } + }; }; - }; } } diff --git a/src/Operation/Reduction.php b/src/Operation/Reduction.php index 47dc59634..0250a9e05 100644 --- a/src/Operation/Reduction.php +++ b/src/Operation/Reduction.php @@ -16,16 +16,36 @@ */ final class Reduction extends AbstractOperation implements Operation { + // phpcs:disable + /** + * @psalm-return Closure(callable(T|null, T, TKey):(T|null)): Closure(T|null): Closure(Iterator): Generator + */ + // phpcs:enable public function __invoke(): Closure { - return static function (callable $callback): Closure { - return static function ($initial = null) use ($callback): Closure { - return static function (Iterator $iterator) use ($callback, $initial): Generator { - foreach ($iterator as $key => $value) { - yield $key => ($initial = $callback($initial, $value, $key)); - } - }; + return + /** + * @psalm-param callable(T|null, T, TKey):(T|null) $callback + */ + static function (callable $callback): Closure { + return + /** + * @param mixed|null $initial + * @psalm-param T|null $initial + */ + static function ($initial = null) use ($callback): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callback, $initial): Generator { + foreach ($iterator as $key => $value) { + yield $key => ($initial = $callback($initial, $value, $key)); + } + }; + }; }; - }; } } diff --git a/src/Operation/Scale.php b/src/Operation/Scale.php index e59094da4..33fc60484 100644 --- a/src/Operation/Scale.php +++ b/src/Operation/Scale.php @@ -18,6 +18,11 @@ */ final class Scale extends AbstractOperation implements Operation { + // phpcs:disable + /** + * @psalm-return Closure(float): Closure(float): Closure(float): Closure(float): Closure(float): Closure(Iterator): Generator + */ + // phpcs:enable public function __invoke(): Closure { return static function (float $lowerBound): Closure { @@ -31,6 +36,10 @@ public function __invoke(): Closure /** @psalm-var callable(Generator): Generator $mapper */ $mapper = Map::of()( + /** + * @param mixed $v + * @psalm-param float|int $v + */ static function ($v) use ($lowerBound, $upperBound, $wantedLowerBound, $wantedUpperBound, $base): float { // phpcs:ignore $mx = 0.0 === $base ? ($v - $lowerBound) / ($upperBound - $lowerBound) : diff --git a/src/Operation/Skip.php b/src/Operation/Skip.php index 05e7d4dc5..873d9af34 100644 --- a/src/Operation/Skip.php +++ b/src/Operation/Skip.php @@ -16,20 +16,29 @@ */ final class Skip extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(int...): Closure(Iterator): Generator + */ public function __invoke(): Closure { return static function (int ...$skip): Closure { - return static function (Iterator $iterator) use ($skip): Generator { - $skip = array_sum($skip); + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($skip): Generator { + $skip = array_sum($skip); - foreach ($iterator as $key => $value) { - if (0 < $skip--) { - continue; - } + foreach ($iterator as $key => $value) { + if (0 < $skip--) { + continue; + } - yield $key => $value; - } - }; + yield $key => $value; + } + }; }; } } diff --git a/src/Operation/Slice.php b/src/Operation/Slice.php index 75f2a98d0..0dc46411a 100644 --- a/src/Operation/Slice.php +++ b/src/Operation/Slice.php @@ -16,17 +16,27 @@ */ final class Slice extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(int): Closure(int|null): Generator + */ public function __invoke(): Closure { return static function (int $offset): Closure { - return static function (int $length = -1) use ($offset): Closure { - return + return + /** + * @psalm-param int|null $length + * + * @psalm-return Closure(Iterator): Generator + */ + static function (int $length = -1) use ($offset): Closure { + return /** * @psalm-param Iterator $iterator * * @psalm-return Generator */ static function (Iterator $iterator) use ($offset, $length): Generator { + /** @psalm-var callable(Iterator): Generator $skip */ $skip = Skip::of()($offset); if (-1 === $length) { @@ -35,7 +45,7 @@ static function (Iterator $iterator) use ($offset, $length): Generator { return yield from Compose::of()($skip, Limit::of()($length)(0))($iterator); }; - }; + }; }; } } diff --git a/src/Operation/Sort.php b/src/Operation/Sort.php index c707a4254..35ebeb7d1 100644 --- a/src/Operation/Sort.php +++ b/src/Operation/Sort.php @@ -25,10 +25,10 @@ public function __invoke(): Closure $callback = $callback ?? /** * @param mixed $left - * @psalm-param T $left + * @psalm-param T|TKey $left * * @param mixed $right - * @psalm-param T $right + * @psalm-param T|TKey $right */ static function ($left, $right): int { return $left <=> $right; @@ -56,13 +56,14 @@ static function (Iterator $iterator) use ($type, $callback): Generator { 'after' => [Unpack::of(), Flip::of()], ]; - $arrayIterator = new ArrayIterator( - iterator_to_array(Compose::of()(...$operations['before'])($iterator)) - ); + /** @psalm-var callable(Iterator): Generator | callable(Iterator): Generator $before */ + $before = Compose::of()(...$operations['before']); + + $arrayIterator = new ArrayIterator(iterator_to_array($before($iterator))); $arrayIterator->uasort( /** - * @psalm-param array{0:TKey, 1:T} $left - * @psalm-param array{0:TKey, 1:T} $right + * @psalm-param array{0:TKey|T, 1:T|TKey} $left + * @psalm-param array{0:TKey|T, 1:T|TKey} $right */ static function (array $left, array $right) use ($callback): int { return $callback($left[1], $right[1]); diff --git a/src/Operation/Split.php b/src/Operation/Split.php index 96e5a8176..2ec57e485 100644 --- a/src/Operation/Split.php +++ b/src/Operation/Split.php @@ -21,10 +21,10 @@ public function __invoke(): Closure return static function (callable ...$callbacks): Closure { return /** - * @psalm-param \Iterator $iterator + * @psalm-param Iterator $iterator * @psalm-param list $callbacks * - * @psalm-return \Generator> + * @psalm-return Generator> */ static function (Iterator $iterator) use ($callbacks): Generator { $carry = []; diff --git a/src/Operation/Tail.php b/src/Operation/Tail.php index 2e1ec995d..2efc69972 100644 --- a/src/Operation/Tail.php +++ b/src/Operation/Tail.php @@ -16,13 +16,16 @@ */ final class Tail extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return /** * @psalm-param Iterator $iterator * - * @psalm-return Generator + * @psalm-return Generator */ static function (Iterator $iterator): Generator { return yield from Skip::of()(1)($iterator); diff --git a/src/Operation/Transpose.php b/src/Operation/Transpose.php index f368cde6a..219b38c9a 100644 --- a/src/Operation/Transpose.php +++ b/src/Operation/Transpose.php @@ -18,18 +18,27 @@ */ final class Transpose extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator> + */ public function __invoke(): Closure { - return static function (Iterator $iterator): Generator { - $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator> + */ + static function (Iterator $iterator): Generator { + $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); - foreach ($iterator as $collectionItem) { - $mit->attachIterator(new IterableIterator($collectionItem)); - } + foreach ($iterator as $collectionItem) { + $mit->attachIterator(new IterableIterator($collectionItem)); + } - foreach ($mit as $key => $value) { - yield current($key) => $value; - } - }; + foreach ($mit as $key => $value) { + yield current($key) => $value; + } + }; } } diff --git a/src/Operation/Unpair.php b/src/Operation/Unpair.php index ef34231c4..968408e15 100644 --- a/src/Operation/Unpair.php +++ b/src/Operation/Unpair.php @@ -16,6 +16,9 @@ */ final class Unpair extends AbstractOperation implements Operation { + /** + * @psalm-return Closure(Iterator): Generator + */ public function __invoke(): Closure { return diff --git a/src/Operation/Until.php b/src/Operation/Until.php index c9941dcd8..9af366b9c 100644 --- a/src/Operation/Until.php +++ b/src/Operation/Until.php @@ -16,28 +16,41 @@ */ final class Until extends AbstractOperation implements Operation { + /** + * @psalm-return Closure((callable(T, TKey):(bool))...): Closure(Iterator): Generator + */ public function __invoke(): Closure { - return static function (callable ...$callbacks): Closure { - return static function (Iterator $iterator) use ($callbacks): Generator { - foreach ($iterator as $key => $value) { - yield $key => $value; + return + /** + * @psalm-param callable(T, TKey):(bool) ...$callbacks + */ + static function (callable ...$callbacks): Closure { + return + /** + * @psalm-param Iterator $iterator + * + * @psalm-return Generator + */ + static function (Iterator $iterator) use ($callbacks): Generator { + foreach ($iterator as $key => $value) { + yield $key => $value; - $result = array_reduce( - $callbacks, - static function (bool $carry, callable $callable) use ($key, $value): bool { - return ($callable($value, $key)) ? + $result = array_reduce( + $callbacks, + static function (bool $carry, callable $callable) use ($key, $value): bool { + return ($callable($value, $key)) ? $carry : false; - }, - true - ); + }, + true + ); - if (false !== $result) { - break; + if (false !== $result) { + break; + } } - } + }; }; - }; } } diff --git a/src/Operation/Window.php b/src/Operation/Window.php index 5ad198c7d..47e475c97 100644 --- a/src/Operation/Window.php +++ b/src/Operation/Window.php @@ -31,13 +31,14 @@ public function __invoke(): Closure * @psalm-return Generator> */ static function (Iterator $iterator) use ($lengths): Generator { - /** @psalm-var \Iterator $lengths */ + /** @psalm-var Iterator $lengths */ $lengths = Loop::of()(new ArrayIterator($lengths)); for ($i = 0; iterator_count($iterator) > $i; ++$i) { - yield iterator_to_array( - Slice::of()($i)($lengths->current())($iterator) - ); + /** @psalm-var Generator $slice */ + $slice = Slice::of()($i)($lengths->current())($iterator); + + yield iterator_to_array($slice); $lengths->next(); } diff --git a/src/Operation/Zip.php b/src/Operation/Zip.php index 1ed238456..489af2dd0 100644 --- a/src/Operation/Zip.php +++ b/src/Operation/Zip.php @@ -23,10 +23,10 @@ public function __invoke(): Closure return static function (iterable ...$iterables): Closure { return /** - * @psalm-param \Iterator $iterator + * @psalm-param Iterator $iterator * @psalm-param list> $iterables * - * @psalm-return \Generator> + * @psalm-return Generator> */ static function (Iterator $iterator) use ($iterables): Generator { $mit = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); From a7c1ff3f015119e64a7bff650a1c9292520ba69b Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Wed, 26 Aug 2020 21:21:55 +0200 Subject: [PATCH 5/6] Update tests. --- spec/loophp/collection/CollectionSpec.php | 28 +++++++++-------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/spec/loophp/collection/CollectionSpec.php b/spec/loophp/collection/CollectionSpec.php index c38a1883a..259385eac 100644 --- a/spec/loophp/collection/CollectionSpec.php +++ b/spec/loophp/collection/CollectionSpec.php @@ -13,7 +13,6 @@ use JsonSerializable; use loophp\collection\Collection; use loophp\collection\Contract\Operation; -use loophp\collection\Contract\Transformation; use loophp\collection\Operation\AbstractOperation; use PhpSpec\ObjectBehavior; use stdClass; @@ -238,17 +237,6 @@ public function it_can_be_json_encoded() $this ->shouldImplement(JsonSerializable::class); - - $this - ->transform( - new class() implements Transformation { - public function __invoke(Iterator $collection) - { - return '{"a":"A","b":"B","c":"C"}'; - } - } - ) - ->shouldReturn(json_encode($this->getWrappedObject())); } public function it_can_be_returned_as_an_array(): void @@ -1212,12 +1200,14 @@ public function it_can_intersperse(): void ->shouldIterateAs($generator()); $this::fromIterable(range('A', 'F')) + ->intersperse('foo', -1, 1) ->shouldThrow(Exception::class) - ->during('intersperse', ['foo', -1, 1]); + ->during('all'); $this::fromIterable(range('A', 'F')) + ->intersperse('foo', 1, -1) ->shouldThrow(Exception::class) - ->during('intersperse', ['foo', 1, -1]); + ->during('all'); } public function it_can_iterate(): void @@ -1673,7 +1663,7 @@ public function __invoke(): Closure }; $this::fromIterable(range(1, 5)) - ->run($square, $sqrt, $map) + ->run($square(), $sqrt(), $map()) ->shouldIterateAs(range(1, 5)); } @@ -2087,6 +2077,10 @@ public function it_can_use_times_with_a_callback(): void return range(1, 5); }) ->shouldIterateAs($a); + + $this::times(-1, 'count') + ->shouldThrow(InvalidArgumentException::class) + ->during('all'); } public function it_can_use_times_without_a_callback(): void @@ -2094,9 +2088,9 @@ public function it_can_use_times_without_a_callback(): void $this::times(10) ->shouldIterateAs(range(1, 10)); - $this::times(10) + $this::times(-5) ->shouldThrow(InvalidArgumentException::class) - ->during('times', [-5]); + ->during('all'); $this::times(1) ->shouldIterateAs([1]); From f115d1ddf5b6cfc34dfd9cb219f993327cf64579 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Thu, 27 Aug 2020 19:52:16 +0200 Subject: [PATCH 6/6] Update documentation. --- README.md | 12 ++++- docs/pages/api.rst | 130 +++++++++++++++++++-------------------------- 2 files changed, 66 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 725c84c50..f07d1faf2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ On top of this, this library: * uses [S.O.L.I.D. principles][solid on wikipedia], * does not have any external dependency, * fully tested, - * type safe (_type safe @ > 98%_), + * type safe (_type safe @ > 93%_), * framework agnostic. Except a few methods, most methods are [pure][pure function on wikipedia] and return a @@ -111,6 +111,12 @@ If you can't contribute to the code, you can also sponsor me on [Github][github * [Reddit release 2.0.0 thread][reddit release 2.0.0] * [Featured in PHPStorm Annotated August 2020][phpstorm annotated august 2020] +## Changelog + +See [CHANGELOG.md][changelog-md] for a changelog based on [git commits][git-commits]. + +For more detailed changelogs, please read the per release changelogs. + [packagist collection]: https://packagist.org/packages/loophp/collection [latest stable version]: https://img.shields.io/packagist/v/loophp/collection.svg?style=flat-square [github stars]: https://img.shields.io/github/stars/loophp/collection.svg?style=flat-square @@ -160,4 +166,6 @@ If you can't contribute to the code, you can also sponsor me on [Github][github [paypal sponsor]: https://www.paypal.me/drupol [reddit announcement]: https://www.reddit.com/r/PHP/comments/csxw23/a_stateless_and_modular_collection_class/ [reddit release 2.0.0]: https://www.reddit.com/r/PHP/comments/i2u2le/release_of_version_200_of_loophpcollection/ -[phpstorm annotated august 2020]: https://blog.jetbrains.com/phpstorm/2020/08/php-annotated-august-2020/ \ No newline at end of file +[phpstorm annotated august 2020]: https://blog.jetbrains.com/phpstorm/2020/08/php-annotated-august-2020/ +[changelog-md]: https://github.com/loophp/collection/blob/master/CHANGELOG.md +[git-commits]: https://github.com/loophp/collection/commits/master \ No newline at end of file diff --git a/docs/pages/api.rst b/docs/pages/api.rst index d024d71e4..9bf8fd4c7 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -159,6 +159,11 @@ Methods (operations) Operations always returns a new collection object. +all +~~~ + +Interface: `Allable`_ + append ~~~~~~ @@ -366,6 +371,11 @@ Signature: ``Collection::compact(...$values);`` $collection = Collection::with(['a', 1 => 'b', null, false, 0, 'c'];) ->compact(null, 0); // ['a', 1 => 'b', 3 => false, 5 => 'c'] +contains +~~~~~~~~ + +Interface: `Containsable`_ + cycle ~~~~~ @@ -440,6 +450,11 @@ Signature: ``Collection::explode(...$items);`` $collection = Collection::with($string) ->explode('o'); +falsy +~~~~~ + +Interface: `Falsyable`_ + filter ~~~~~~ @@ -547,6 +562,16 @@ However, when using a collection: This example will return ``['a', 'b', 'c', 'd', 'a']``. +foldLeft +~~~~~~~~ + +Interface: `FoldLeftable`_ + +foldRight +~~~~~~~~~ + +Interface: `FoldRightable`_ + forget ~~~~~~ @@ -578,6 +603,12 @@ Signature: ``Collection::frequency();`` ->frequency() ->all(); // [1 => 'a', 2 => 'b', 3 => 'c']; +get +~~~ + +Interface: `Getable`_ + + group ~~~~~ @@ -607,6 +638,11 @@ Signature: ``Collection::group(callable $callable = null);`` $collection = Collection::with($callback) ->group(); +has +~~~ + +Interface: `Hasable`_ + head ~~~~ @@ -659,6 +695,11 @@ Signature: ``Collection::ifThenElse(callable $condition, callable $then, ?callab Collection::fromIterable($input) ->ifThenElse($condition, $then, $else) // [3, 4, 5, 16, 7] +implode +~~~~~~~ + +Interface: `Implodeable`_ + intersect ~~~~~~~~~ @@ -849,6 +890,11 @@ Signature: ``Collection::nth(int $step, int $offset = 0);`` $collection = Collection::with(range(10, 100)) ->nth(3); +nullsy +~~~~~~ + +Interface: `Nullsyable`_ + only ~~~~ @@ -1026,6 +1072,11 @@ Signature: ``Collection::random(int $size = 1);`` $collection = Collection::with(['4', '5', '6']) ->random(); // ['6'] +reduce +~~~~~~ + +Interface: `Reduceable`_ + reduction ~~~~~~~~~ @@ -1081,7 +1132,6 @@ rsample Work in progress... sorry. - scale ~~~~~ @@ -1235,7 +1285,6 @@ Signature: ``Collection::sort(?callable $callback = null);`` ->sort() // Sort the values (which are now the keys) ->flip(); // Flip again to put back the keys and values, sorted by keys. - split ~~~~~ @@ -1305,6 +1354,11 @@ Signature: ``Collection::transpose();`` $result = Collection::with($records) ->transpose(); +truthy +~~~~~~ + +Interface: `Truthyable`_ + unpack ~~~~~~ @@ -1447,76 +1501,6 @@ Signature: ``Collection::zip(iterable ...$iterables);`` ->limit(100) ->flatten(); -Methods (transformations) -------------------------- - -Transformations might returns something different from a collection. - -all -~~~ - -Interface: `Allable`_ - -contains -~~~~~~~~ - -Interface: `Containsable`_ - -falsy -~~~~~ - -Interface: `Falsyable`_ - -foldLeft -~~~~~~~~ - -Interface: `FoldLeftable`_ - -foldRight -~~~~~~~~~ - -Interface: `FoldRightable`_ - -get -~~~ - -Interface: `Getable`_ - -has -~~~ - -Interface: `Hasable`_ - -implode -~~~~~~~ - -Interface: `Implodeable`_ - -nullsy -~~~~~~ - -Interface: `Nullsyable`_ - -reduce -~~~~~~ - -Interface: `Reduceable`_ - -run -~~~ - -Interface: `Runable`_ - -transform -~~~~~~~~~ - -Interface: `Transformable`_ - -truthy -~~~~~~ - -Interface: `Truthyable`_ - .. _Allable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Allable.php .. _Appendable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Appendable.php .. _Applyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Applyable.php @@ -1574,7 +1558,6 @@ Interface: `Truthyable`_ .. _Reduceable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reduceable.php .. _Reductionable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reductionable.php .. _Reverseable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Reverseable.php -.. _Runable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Runable.php .. _Scaleable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Scaleable.php .. _Skipable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Skipable.php .. _Sinceable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sinceable.php @@ -1582,7 +1565,6 @@ Interface: `Truthyable`_ .. _Sortable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Sortable.php .. _Splitable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Splitable.php .. _Tailable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Tailable.php -.. _Transformable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Transformable.php .. _Transposeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Transposeable.php .. _Truthyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Truthyable.php .. _Unpackable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Unpackagle.php