Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new functions #53

Merged
merged 11 commits into from
Dec 11, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
engines:
phpcodesniffer:
enabled: true
checks:
Generic WhiteSpace ScopeIndent IncorrectExact:
enabled: false
phpmd:
enabled: true
checks:
UnusedLocalVariable:
enabled: false
CleanCode/StaticAccess:
enabled: false

sonar-php:
enabled: true
checks:
php:S1448:
enabled: false
8 changes: 8 additions & 0 deletions examples/example/ArrayValue-skip.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

use GW\Value\Wrap;

$letters = Wrap::array(['a', 'b', 'c', 'd', 'e', 'f', 'g']);

var_export($letters->skip(2)->toArray());
echo PHP_EOL;
15 changes: 15 additions & 0 deletions examples/example/ArrayValue-take.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

use GW\Value\Wrap;

$letters = Wrap::array(['a', 'b', 'c', 'd', 'e', 'f', 'g']);

var_export($letters->skip(2)->take(4)->toArray());
echo PHP_EOL;

var_export($letters->take(3)->toArray());
echo PHP_EOL;

var_export($letters->take(100)->toArray());
echo PHP_EOL;

12 changes: 12 additions & 0 deletions examples/example/AssocValue-keys.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

use GW\Value\Wrap;

$assoc = Wrap::assocArray(['0' => 'zero', '1' => 'one']);

$keys = $assoc
->map(fn(string $val, int $key): string => $val)
->keys()
->toArray();

var_dump($keys);
29 changes: 29 additions & 0 deletions examples/example/IterableValue-keys.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

use GW\Value\Wrap;

$assoc = Wrap::iterable(['0' => 'zero', '1' => 'one']);

$keys = $assoc
->map(fn(string $val, int $key): string => $val)
->keys()
->toArray();

var_dump($keys);

$pairs = [['0', 'zero'], ['1', 'one'], ['1', 'one one']];

$iterator = function () use ($pairs) {
foreach ($pairs as [$key, $item]) {
yield $key => $item;
}
};

$assoc = Wrap::iterable($iterator());

$keys = $assoc
->map(fn(string $val, string $key): string => $val)
->keys()
->toArray();

var_dump($keys);
18 changes: 18 additions & 0 deletions examples/example/IterableValue-take.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

use GW\Value\Wrap;

$range = function (int $start, int $end): iterable {
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
};

var_export(Wrap::iterable($range(0, PHP_INT_MAX))->skip(2)->take(4)->toArray());
echo PHP_EOL;

var_export(Wrap::iterable($range(0, PHP_INT_MAX))->take(3)->toArray());
echo PHP_EOL;

var_export(Wrap::iterable($range(0, PHP_INT_MAX))->skip(5000)->take(2)->toArray());
echo PHP_EOL;
7 changes: 7 additions & 0 deletions spec/AssocArraySpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -422,4 +422,11 @@ function it_does_not_allow_mutations_trough_ArrayAccess()
$this->shouldThrow(\BadMethodCallException::class)->during('offsetSet', ['a', 'mutated 1']);
$this->shouldThrow(\BadMethodCallException::class)->during('offsetUnset', ['a']);
}

function it_handles_numeric_strings_key_as_int_from_array()
{
$this->beConstructedWith(['0' => 'zero', '1' => 'one']);
$this->map(fn(string $val, int $key): string => $val)
->keys()->toArray()->shouldEqual([0, 1]);
}
}
130 changes: 127 additions & 3 deletions spec/InfiniteIterableValueSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use GW\Value\Wrap;
use PhpSpec\Exception\Example\FailureException;
use PhpSpec\ObjectBehavior;
use function range;

final class InfiniteIterableValueSpec extends ObjectBehavior
{
Expand All @@ -19,13 +20,45 @@ function it_can_be_converted_to_array_value()
$this->toArrayValue()->shouldBeLike(Wrap::array($items));
}

function it_can_be_converted_to_simple_assoc_array()
{
$items = ['item 1', 'item 2', 'item 3'];
$this->beConstructedWith($items);
$this->toAssocArray()->shouldBeLike([0 => 'item 1', 1 => 'item 2', 2 => 'item 3']);
}

function it_can_be_converted_to_keyed_assoc_array()
{
$items = ['foo' => 'item 1', 'bar' => 'item 2'];
$this->beConstructedWith($items);
$this->toAssocArray()->shouldBeLike(['foo' => 'item 1', 'bar' => 'item 2']);
}

function it_can_be_converted_to_keyed_assoc_array_with_map_filter()
{
$items = ['foo' => 'item 1', 'bar' => 'item 2'];
$this->beConstructedWith($items);
$this
->map(fn(string $value, string $key): string => "{$value} mod")
->filter(fn(string $value): bool => true)
->toAssocArray()
->shouldBeLike(['foo' => 'item 1 mod', 'bar' => 'item 2 mod']);
}

function it_returns_items()
{
$items = ['item 1', 'item 2', 'item 3'];
$this->beConstructedWith($items);
$this->toArray()->shouldReturn($items);
}

function it_returns_keys()
{
$items = ['item 1', 'item 2', 'item 3'];
$this->beConstructedWith($items);
$this->keys()->toArray()->shouldReturn([0, 1, 2]);
}

function it_maps_string_items_with_closure()
{
$this->beConstructedWith(['item 1', 'item 2', 'item 3']);
Expand All @@ -41,8 +74,7 @@ function it_maps_string_items_with_closure()
function it_maps_items_with_php_callable()
{
$this->beConstructedWith(['100', '50.12', '', true, false]);

$mapped = $this->map('intval');
$mapped = $this->map(fn($value): int => (int)$value);

$mapped->shouldNotBe($this);
$mapped->toArray()->shouldBeLike([100, 50, 0, 1, 0]);
Expand Down Expand Up @@ -184,12 +216,22 @@ function it_slices_given_part()
{
$this->beConstructedWith(['item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6']);

$this->slice(0, 1)->shouldNotBe($this);
$this->slice(0, 1)->toArray()->shouldNotBe($this->toArray());
$this->slice(0, 1)->toArray()->shouldBeLike(['item 1']);
$this->slice(1, 4)->toArray()->shouldBeLike(['item 2', 'item 3', 'item 4', 'item 5']);
$this->slice(5, 1)->toArray()->shouldBeLike(['item 6']);
}

function it_skips_and_takes_given_part()
{
$this->beConstructedWith(['item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6']);

$this->take(1)->toArray()->shouldNotBe($this->toArray());
$this->take(1)->toArray()->shouldBeLike(['item 1']);
$this->skip(1)->take(4)->toArray()->shouldBeLike(['item 2', 'item 3', 'item 4', 'item 5']);
$this->skip(5)->take(1)->toArray()->shouldBeLike(['item 6']);
}

function it_slice_and_do_not_take_elements_above_end_index()
{
$takenElements = 0;
Expand Down Expand Up @@ -518,6 +560,88 @@ function it_finds_null_when_no_item_matches_condition()
->shouldReturn(null);
}

function it_handles_repeated_keys_properly_with_toArray()
{
$iterator = function () {
foreach (range(0, 5) as $item) {
yield 0 => $item;
}
};

$this->beConstructedWith($iterator());
$this->toArray()->shouldEqual([0, 1, 2, 3, 4, 5]);
}

function it_handles_repeated_keys_properly_with_toAssocArray()
{
$iterator = function () {
foreach (range(0, 5) as $item) {
yield 0 => $item;
}
};

$this->beConstructedWith($iterator());
$this->toAssocArray()->shouldEqual([0 => 5]);
}

function it_handles_repeated_keys_properly_with_keys()
{
$iterator = function () {
foreach (range(0, 5) as $item) {
yield 0 => $item;
}
};

$this->beConstructedWith($iterator());
$this->keys()->toArray()->shouldEqual([0, 0, 0, 0, 0, 0]);
}

function it_handles_repeated_keys_properly_with_map()
{
$iterator = function () {
foreach (range(0, 5) as $item) {
yield 0 => $item;
}
};

$this->beConstructedWith($iterator());
$this->map(fn(int $value, int $key): int => $key)->toArray()->shouldEqual([0, 0, 0, 0, 0, 0]);
}

function it_handles_repeated_keys_properly_with_slice()
{
$iterator = function () {
foreach (range(0, 5) as $item) {
yield 0 => $item;
}
};

$this->beConstructedWith($iterator());
$this->slice(1, 2)->toArray()->shouldEqual([1, 2]);
}

function it_handles_numeric_strings_key_as_int_from_array()
{
$this->beConstructedWith(['0' => 'zero', '1' => 'one']);
$this->map(fn(string $val, int $key): string => $val)
->keys()->toArray()->shouldEqual([0, 1]);
}

function it_handles_numeric_strings_key_as_string_from_iterator()
{
$pairs = [['0', 'zero'], ['1', 'one'], ['1', 'one one']];

$iterator = function () use ($pairs) {
foreach ($pairs as [$key, $item]) {
yield $key => $item;
}
};

$this->beConstructedWith($iterator());
$this->map(fn(string $val, string $key): string => $val)
->keys()->toArray()->shouldEqual(['0', '1', '1']);
}

private function entityComparator(): \Closure
{
return function (DummyEntity $entityA, DummyEntity $entityB): int {
Expand Down
14 changes: 12 additions & 2 deletions spec/PlainArraySpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function it_maps_items_with_php_callable()
{
$this->beConstructedWith(['100', '50.12', '', true, false]);

$mapped = $this->map('intval');
$mapped = $this->map(fn($value): int => (int)$value);

$mapped->shouldNotBe($this);
$mapped->toArray()->shouldBeLike([100, 50, 0, 1, 0]);
Expand Down Expand Up @@ -341,12 +341,22 @@ function it_slices_given_part()
{
$this->beConstructedWith(['item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6']);

$this->slice(0, 1)->shouldNotBe($this);
$this->slice(0, 1)->toArray()->shouldNotBe($this->toArray());
$this->slice(0, 1)->toArray()->shouldBeLike(['item 1']);
$this->slice(1, 4)->toArray()->shouldBeLike(['item 2', 'item 3', 'item 4', 'item 5']);
$this->slice(5, 1)->toArray()->shouldBeLike(['item 6']);
}

function it_skips_and_takes_given_part()
{
$this->beConstructedWith(['item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6']);

$this->take(1)->toArray()->shouldNotBe($this->toArray());
$this->take(1)->toArray()->shouldBeLike(['item 1']);
$this->skip(1)->take(4)->toArray()->shouldBeLike(['item 2', 'item 3', 'item 4', 'item 5']);
$this->skip(5)->take(1)->toArray()->shouldBeLike(['item 6']);
}

function it_allows_to_remove_slice_from_array_with_splice()
{
$this->beConstructedWith(['item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6']);
Expand Down
13 changes: 12 additions & 1 deletion spec/PlainStringsArraySpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,25 @@ function it_can_be_sliced()
$strings = ['string 1', 'string 2', 'string 3', 'string 4'];
$this->beConstructedWithStrings(...$strings);

$this->slice(0, 1)->shouldNotBe($this);
$this->slice(0, 1)->toNativeStrings()->shouldNotBe($this->toNativeStrings());
$this->slice(0, 1)->toNativeStrings()->shouldBeLike(['string 1']);
$this->slice(3, 1)->toNativeStrings()->shouldBeLike(['string 4']);
$this->slice(1, 2)->toNativeStrings()->shouldBeLike(['string 2', 'string 3']);
$this->slice(0, 4)->toNativeStrings()->shouldBeLike($strings);
$this->slice(0, 500)->toNativeStrings()->shouldBeLike($strings);
}

function it_skips_and_takes_given_part()
{
$strings = ['item 1', 'item 2', 'item 3', 'item 4', 'item 5', 'item 6'];
$this->beConstructedWithStrings(...$strings);

$this->take(1)->toNativeStrings()->shouldNotBe($this->toNativeStrings());
$this->take(1)->toNativeStrings()->shouldBeLike(['item 1']);
$this->skip(1)->take(4)->toNativeStrings()->shouldBeLike(['item 2', 'item 3', 'item 4', 'item 5']);
$this->skip(5)->take(1)->toNativeStrings()->shouldBeLike(['item 6']);
}

function it_can_be_spliced()
{
$this->beConstructedWithStrings('string 1', 'string 2', 'string 3', 'string 4');
Expand Down
10 changes: 10 additions & 0 deletions src/ArrayValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,16 @@ public function join(ArrayValue $other): ArrayValue;
*/
public function slice(int $offset, int $length): ArrayValue;

/**
* @phpstan-return ArrayValue<TValue>
*/
public function skip(int $length): ArrayValue;

/**
* @phpstan-return ArrayValue<TValue>
*/
public function take(int $length): ArrayValue;

/**
* @phpstan-param ArrayValue<TValue> $replacement
* @phpstan-return ArrayValue<TValue>
Expand Down
2 changes: 1 addition & 1 deletion src/AssocValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function filterEmpty(): AssocValue;

/**
* @template TNewValue
* @param callable(TValue $value, TKey $key=):TNewValue $transformer
* @param callable(TValue,TKey $key=):TNewValue $transformer
* @phpstan-return AssocValue<TKey, TNewValue>
*/
public function map(callable $transformer): AssocValue;
Expand Down
Loading