Skip to content

Commit

Permalink
Add more operations.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Aug 19, 2019
1 parent 2bb704b commit d658c49
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 78 deletions.
22 changes: 9 additions & 13 deletions spec/drupol/collection/CollectionSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,8 @@ public function it_can_chunk(): void

$this
->chunk(2)
->map(static function (CollectionInterface $item) {
return \implode('', \iterator_to_array($item));
})
->all()
->shouldReturn(['AB', 'CD', 'EF']);
->shouldReturn([[0 => 'A', 1 => 'B'], [2 => 'C', 3 => 'D'], [4 => 'E', 5 => 'F']]);

$this
->chunk(0)
Expand All @@ -204,11 +201,8 @@ public function it_can_chunk(): void

$this
->chunk(1)
->map(static function (CollectionInterface $item) {
return \implode('', \iterator_to_array($item));
})
->all()
->shouldReturn(['A', 'B', 'C', 'D', 'E', 'F']);
->shouldReturn([[0 => 'A'], [1 => 'B'], [2 => 'C'], [3 => 'D'], [4 => 'E'], [5 => 'F']]);
}

public function it_can_collapse(): void
Expand Down Expand Up @@ -646,9 +640,12 @@ public function it_can_reduce(): void
->beConstructedThrough('with', [\range(1, 100)]);

$this
->reduce(static function ($carry, $item) {
return $carry + $item;
}, 0)
->reduce(
static function ($carry, $item) {
return $carry + $item;
},
0
)
->shouldReturn(5050);
}

Expand All @@ -659,8 +656,7 @@ public function it_can_run_an_operation(Operation $operation): void
->shouldBeCalledOnce();

$this
->run($operation)
->shouldImplement(CollectionInterface::class);
->run($operation);
}

public function it_can_skip(): void
Expand Down
76 changes: 15 additions & 61 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@
use Closure;
use drupol\collection\Contract\Collection as CollectionInterface;
use drupol\collection\Contract\Operation;
use drupol\collection\Operation\All;
use drupol\collection\Operation\Append;
use drupol\collection\Operation\Apply;
use drupol\collection\Operation\Chunk;
use drupol\collection\Operation\Collapse;
use drupol\collection\Operation\Combine;
use drupol\collection\Operation\Contains;
use drupol\collection\Operation\Filter;
use drupol\collection\Operation\First;
use drupol\collection\Operation\Flatten;
use drupol\collection\Operation\Flip;
use drupol\collection\Operation\Forget;
use drupol\collection\Operation\Get;
use drupol\collection\Operation\Keys;
use drupol\collection\Operation\Limit;
use drupol\collection\Operation\Merge;
Expand All @@ -29,6 +33,7 @@
use drupol\collection\Operation\Proxy;
use drupol\collection\Operation\Range;
use drupol\collection\Operation\Rebase;
use drupol\collection\Operation\Reduce;
use drupol\collection\Operation\Skip;
use drupol\collection\Operation\Slice;
use drupol\collection\Operation\Walk;
Expand All @@ -50,17 +55,7 @@ final class Collection implements CollectionInterface
*/
public function all(): array
{
$result = [];

foreach ($this->getIterator() as $key => $item) {
if ($item instanceof CollectionInterface) {
$result[$key] = $item->all();
} else {
$result[$key] = $item;
}
}

return $result;
return $this->run(All::with([]));
}

/**
Expand Down Expand Up @@ -108,19 +103,7 @@ public function combine($keys): CollectionInterface
*/
public function contains($key): bool
{
if (!\is_string($key) && \is_callable($key)) {
$placeholder = new \stdClass();

return $this->first($key, $placeholder) !== $placeholder;
}

foreach ($this as $value) {
if ($value === $key) {
return true;
}
}

return false;
return $this->run(Contains::with($key));
}

/**
Expand All @@ -136,7 +119,7 @@ public function count(): int
*/
public static function empty(): CollectionInterface
{
return static::withArray([]);
return self::withArray([]);
}

/**
Expand All @@ -152,24 +135,7 @@ public function filter(callable $callback = null): CollectionInterface
*/
public function first(callable $callback = null, $default = null)
{
/** @var \Iterator $iterator */
$iterator = $this->getIterator();

if (null === $callback) {
if (!$iterator->valid()) {
return $default;
}

return $iterator->current();
}

foreach ($iterator as $key => $value) {
if ($callback($value, $key)) {
return $value;
}
}

return $default;
return $this->run(First::with($callback, $default));
}

/**
Expand Down Expand Up @@ -201,13 +167,7 @@ public function forget(...$keys): CollectionInterface
*/
public function get($key, $default = null)
{
foreach ($this->getIterator() as $outerKey => $outerValue) {
if ($outerKey === $key) {
return $outerValue;
}
}

return $default;
return $this->run(Get::with($key, $default));
}

/**
Expand Down Expand Up @@ -333,19 +293,13 @@ public function rebase(): CollectionInterface
*/
public function reduce(callable $callback, $initial = null)
{
$result = $initial;

foreach ($this as $value) {
$result = $callback($result, $value);
}

return $result;
return $this->run(Reduce::with($callback, $initial));
}

/**
* {@inheritdoc}
*/
public function run(Operation ...$operations): CollectionInterface
public function run(Operation ...$operations)
{
return \array_reduce($operations, [$this, 'doRun'], $this);
}
Expand Down Expand Up @@ -459,10 +413,10 @@ public function zip(...$items): CollectionInterface
* @param \drupol\collection\Contract\Operation $operation
* The operation.
*
* @return \drupol\collection\Contract\Collection
* A new collection.
* @return mixed
* The operation result.
*/
private function doRun(CollectionInterface $collection, Operation $operation): CollectionInterface
private function doRun(CollectionInterface $collection, Operation $operation)
{
return $operation->run($collection);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Contract/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ public function reduce(callable $callback, $initial = null);
/**
* @param \drupol\collection\Contract\Operation ...$operations
*
* @return \drupol\collection\Contract\Collection
* @return mixed
*/
public function run(Operation ...$operations): self;
public function run(Operation ...$operations);

/**
* Skip the first {$count} items.
Expand Down
4 changes: 2 additions & 2 deletions src/Contract/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ interface Operation
/**
* @param \drupol\collection\Contract\Collection $collection
*
* @return \drupol\collection\Contract\Collection
* @return mixed
*/
public function run(Collection $collection): Collection;
public function run(Collection $collection);

/**
* @param mixed ...$parameters
Expand Down
31 changes: 31 additions & 0 deletions src/Operation/All.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace drupol\collection\Operation;

use drupol\collection\Contract\Collection as CollectionInterface;

/**
* Class All.
*/
final class All extends Operation
{
/**
* {@inheritdoc}
*/
public function run(CollectionInterface $collection)
{
$result = [];

foreach ($collection as $key => $item) {
if ($item instanceof CollectionInterface) {
$result[$key] = $item->all();
} else {
$result[$key] = $item;
}
}

return $result;
}
}
35 changes: 35 additions & 0 deletions src/Operation/Contains.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace drupol\collection\Operation;

use drupol\collection\Contract\Collection as CollectionInterface;

/**
* Class Contains.
*/
final class Contains extends Operation
{
/**
* {@inheritdoc}
*/
public function run(CollectionInterface $collection)
{
[$key] = $this->parameters;

if (!\is_string($key) && \is_callable($key)) {
$placeholder = new \stdClass();

return $collection->first($key, $placeholder) !== $placeholder;
}

foreach ($collection as $value) {
if ($value === $key) {
return true;
}
}

return false;
}
}
40 changes: 40 additions & 0 deletions src/Operation/First.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

namespace drupol\collection\Operation;

use drupol\collection\Contract\Collection as CollectionInterface;

/**
* Class First.
*/
final class First extends Operation
{
/**
* {@inheritdoc}
*/
public function run(CollectionInterface $collection)
{
[$callback, $default] = $this->parameters;

/** @var \Iterator $iterator */
$iterator = $collection->getIterator();

if (null === $callback) {
if (!$iterator->valid()) {
return $default;
}

return $iterator->current();
}

foreach ($iterator as $key => $value) {
if ($callback($value, $key)) {
return $value;
}
}

return $default;
}
}
29 changes: 29 additions & 0 deletions src/Operation/Get.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace drupol\collection\Operation;

use drupol\collection\Contract\Collection as CollectionInterface;

/**
* Class Get.
*/
final class Get extends Operation
{
/**
* {@inheritdoc}
*/
public function run(CollectionInterface $collection)
{
[$key, $default] = $this->parameters;

foreach ($collection as $outerKey => $outerValue) {
if ($outerKey === $key) {
return $outerValue;
}
}

return $default;
}
}
29 changes: 29 additions & 0 deletions src/Operation/Reduce.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace drupol\collection\Operation;

use drupol\collection\Contract\Collection as CollectionInterface;

/**
* Class Reduce.
*/
final class Reduce extends Operation
{
/**
* {@inheritdoc}
*/
public function run(CollectionInterface $collection)
{
[$callback, $initial] = $this->parameters;

$result = $initial;

foreach ($collection as $value) {
$result = $callback($result, $value);
}

return $result;
}
}

0 comments on commit d658c49

Please sign in to comment.