diff --git a/src/IterableObject.php b/src/IterableObject.php index 3a07b04..4901e86 100644 --- a/src/IterableObject.php +++ b/src/IterableObject.php @@ -27,15 +27,27 @@ final class IterableObject implements IteratorAggregate /** * @param iterable|null $iterable */ - public function __construct(?iterable $iterable = null, ?callable $filter = null, ?callable $map = null) + private function __construct(?iterable $iterable = null, ?callable $filter = null, ?callable $map = null) { $this->iterable = $iterable ?? new EmptyIterator(); $this->filterFn = $filter; $this->mapFn = $map; } - public function filter(callable $filter): self + /** + * @param iterable|null $iterable + */ + public static function new(?iterable $iterable = null): self { + return new self($iterable); + } + + public function filter(?callable $filter = null): self + { + $filter = $filter ?? function ($value): bool { + return (bool) $value; + }; + return new self($this->iterable, $filter, $this->mapFn); } diff --git a/src/iterable-functions.php b/src/iterable-functions.php index df51b9d..510c335 100644 --- a/src/iterable-functions.php +++ b/src/iterable-functions.php @@ -111,7 +111,7 @@ function iterable_reduce(iterable $iterable, callable $reduce, $initial = null) /** * @param iterable $iterable */ -function iterable(iterable $iterable, ?callable $filter = null, ?callable $map = null): IterableObject +function iterable(iterable $iterable): IterableObject { - return new IterableObject($iterable, $filter, $map); + return IterableObject::new($iterable); } diff --git a/tests/IterableObjectTest.php b/tests/IterableObjectTest.php index 3eee1f5..c3d9377 100644 --- a/tests/IterableObjectTest.php +++ b/tests/IterableObjectTest.php @@ -8,11 +8,14 @@ use Generator; use SplFixedArray; +use function array_values; use function BenTools\IterableFunctions\iterable; +use function func_num_args; use function it; use function iterator_to_array; use function PHPUnit\Framework\assertEquals; use function PHPUnit\Framework\assertInstanceOf; +use function PHPUnit\Framework\assertSame; use function test; $dataProvider = static function (): Generator { @@ -52,11 +55,29 @@ static function ($value): bool { ]; }; +/** + * @param iterable $iterable + */ +function create_iterable(iterable $iterable, ?callable $filter = null, ?callable $map = null): IterableObject +{ + $object = iterable($iterable); + + if ($filter !== null && func_num_args() > 1) { + $object = $object->filter($filter); + } + + if ($map !== null) { + $object = $object->map($map); + } + + return $object; +} + test( 'input: array | output: traversable', /** @param array $data */ function (array $data, ?callable $filter, ?callable $map, array $expectedResult): void { - $iterableObject = iterable($data, $filter, $map); + $iterableObject = create_iterable($data, $filter, $map); assertEquals($expectedResult, iterator_to_array($iterableObject)); } )->with($dataProvider()); @@ -65,7 +86,7 @@ function (array $data, ?callable $filter, ?callable $map, array $expectedResult) 'input: array | output: array', /** @param array $data */ function (array $data, ?callable $filter, ?callable $map, array $expectedResult): void { - $iterableObject = iterable($data, $filter, $map); + $iterableObject = create_iterable($data, $filter, $map); assertEquals($expectedResult, $iterableObject->asArray()); } )->with($dataProvider()); @@ -75,7 +96,7 @@ function (array $data, ?callable $filter, ?callable $map, array $expectedResult) /** @param array $data */ function (array $data, ?callable $filter, ?callable $map, array $expectedResult): void { $data = SplFixedArray::fromArray($data); - $iterableObject = iterable($data, $filter, $map); + $iterableObject = create_iterable($data, $filter, $map); assertEquals($expectedResult, iterator_to_array($iterableObject)); } )->with($dataProvider()); @@ -85,11 +106,32 @@ function (array $data, ?callable $filter, ?callable $map, array $expectedResult) /** @param array $data */ function (array $data, ?callable $filter, ?callable $map, array $expectedResult): void { $data = SplFixedArray::fromArray($data); - $iterableObject = iterable($data, $filter, $map); + $iterableObject = create_iterable($data, $filter, $map); assertEquals($expectedResult, $iterableObject->asArray()); } )->with($dataProvider()); +it('does not filter by default', function (): void { + $data = [ + null, + false, + true, + 0, + 1, + '0', + '1', + '', + 'foo', + ]; + + $generator = function (array $data): Generator { + yield from $data; + }; + + assertSame($data, iterable($data)->asArray()); + assertSame($data, iterable($generator($data))->asArray()); +}); + it('filters the subject', function (): void { $filter = /** @param mixed $value */ @@ -100,6 +142,34 @@ static function ($value): bool { assertEquals([1 => 'bar'], iterator_to_array($iterableObject)); }); +it('uses a truthy filter by default when filter() is invoked without arguments', function (): void { + $data = [ + null, + false, + true, + 0, + 1, + '0', + '1', + '', + 'foo', + ]; + + $truthyValues = [ + true, + 1, + '1', + 'foo', + ]; + + $generator = function (array $data): Generator { + yield from $data; + }; + + assertSame($truthyValues, array_values(iterable($data)->filter()->asArray())); + assertSame($truthyValues, array_values(iterable($generator($data))->filter()->asArray())); +}); + it('maps the subject', function (): void { $map = 'strtoupper'; $iterableObject = iterable(['foo', 'bar'])->map($map);