Skip to content

Commit

Permalink
Add ::Rebase() operation, update code and tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Aug 19, 2019
1 parent 660f8ad commit a9127d8
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 26 deletions.
48 changes: 48 additions & 0 deletions spec/drupol/collection/CollectionSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,22 @@ public function it_can_combine(): void
->during('all');
}

public function it_can_contains(): void
{
$this
->beConstructedThrough('with', [\range('A', 'C')]);

$this
->contains('A')
->shouldReturn(true);

$this
->contains(static function ($item) {
return 'A' === $item;
})
->shouldReturn(true);
}

public function it_can_convert_use_a_string_as_parameter(): void
{
$this
Expand Down Expand Up @@ -369,6 +385,18 @@ public function it_can_get(): void
->shouldReturn('default');
}

public function it_can_get_an_iterator(): void
{
$this
->beConstructedThrough('with', [\range('A', 'J')]);

$collection = Collection::with(\range(1, 5));

$this::with($collection)
->getIterator()
->shouldImplement(\Iterator::class);
}

public function it_can_get_items_with_only_specific_keys(): void
{
$this
Expand Down Expand Up @@ -579,6 +607,17 @@ public function it_can_prepend(): void
->shouldReturn(['A', 'B', 'C', 'D', 'E', 'F']);
}

public function it_can_rebase(): void
{
$this
->beConstructedThrough('with', [\range('A', 'C')]);

$this
->rebase()
->all()
->shouldBeEqualTo($this->all());
}

public function it_can_reduce(): void
{
$this
Expand Down Expand Up @@ -737,11 +776,20 @@ public function it_can_zip(): void

$this
->zip(['D', 'E', 'F'])
->all()
->shouldIterateAs([['A', 'D'], ['B', 'E'], ['C', 'F']]);

$this::with(['A', 'C', 'E'])
->zip(['B', 'D', 'F', 'H'])
->all()
->shouldIterateAs([['A', 'B'], ['C', 'D'], ['E', 'F'], [null, 'H']]);

$collection = Collection::with(\range(1, 5));

$this::with($collection)
->zip(\range('A', 'E'))
->all()
->shouldReturn([[1, 'A'], [2, 'B'], [3, 'C'], [4, 'D'], [5, 'E']]);
}

public function it_is_initializable(): void
Expand Down
17 changes: 12 additions & 5 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use drupol\collection\Operation\Pluck;
use drupol\collection\Operation\Prepend;
use drupol\collection\Operation\Range;
use drupol\collection\Operation\Rebase;
use drupol\collection\Operation\Skip;
use drupol\collection\Operation\Slice;
use drupol\collection\Operation\Walk;
Expand Down Expand Up @@ -73,7 +74,9 @@ public function append(...$items): CollectionInterface
*/
public function apply(callable $callback): CollectionInterface
{
foreach ($this as $key => $item) {
$clone = clone $this;

foreach ($clone as $key => $item) {
if (false === $callback($item, $key)) {
break;
}
Expand Down Expand Up @@ -315,6 +318,14 @@ public static function range(int $start = 0, $end = \INF, $step = 1): Collection
return self::withArray([])->run(Range::with($start, $end, $step));
}

/**
* {@inheritdoc}
*/
public function rebase(): CollectionInterface
{
return $this->run(Rebase::with());
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -483,10 +494,6 @@ private static function getArrayableItems($items): array
*/
private function makeIterator($source): \Iterator
{
if ($source instanceof CollectionInterface) {
return $source->getIterator();
}

if (\is_callable($source)) {
return $source();
}
Expand Down
5 changes: 5 additions & 0 deletions src/Contract/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ public function pluck($pluck, $default = null): self;
*/
public function prepend(...$items): self;

/**
* @return \drupol\collection\Contract\Collection
*/
public function rebase(): self;

/**
* Reduce the collection to a single value.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Contract/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace drupol\collection\Contract;

/**
* Interface CollectionOperation.
* Interface Operation.
*/
interface Operation
{
Expand Down
22 changes: 22 additions & 0 deletions src/Operation/Rebase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace drupol\collection\Operation;

use drupol\collection\Collection;
use drupol\collection\Contract\Collection as CollectionInterface;

/**
* Class Rebase.
*/
final class Rebase extends Operation
{
/**
* {@inheritdoc}
*/
public function run(CollectionInterface $collection): CollectionInterface
{
return Collection::with($collection->all());
}
}
41 changes: 21 additions & 20 deletions src/Operation/Zip.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,33 @@ public function run(CollectionInterface $collection): CollectionInterface

return Collection::withClosure(
static function () use ($iterables, $collection) {
$iterators = Collection::with(
Collection::with($iterables)
$iterators =
Collection::empty()
->append($collection, ...$iterables)
->map(
static function ($iterable) {
return Collection::with($iterable)->getIterator();
}
)
->prepend($collection->getIterator())
);
);

while ($iterators->map(static function (\Iterator $iterator) {
$iteratorCurrent = static function (\Iterator $iterator) {
return $iterator->current();
};

$iteratorIsValid = static function (\Iterator $iterator) {
return $iterator->valid();
})->contains(true)) {
yield Collection::with(
$iterators->map(
static function (\Iterator $item) {
return $item->current();
}
)
)->all();

$iterators->apply(
static function (\Iterator $item): void {
$item->next();
}
);
};

$iteratorNext = static function (\Iterator $iterator) {
$iterator->next();

return $iterator;
};

while ($iterators->map($iteratorIsValid)->contains(true)) {
yield Collection::with($iterators->map($iteratorCurrent));

$iterators = $iterators->map($iteratorNext);
}
}
);
Expand Down

0 comments on commit a9127d8

Please sign in to comment.