From d68cd6be64a1fe7355fc02669cc6fa6440294799 Mon Sep 17 00:00:00 2001 From: Pablo Morra Date: Tue, 3 Sep 2024 11:18:44 -0300 Subject: [PATCH] feat(collections): add fromItems and containsKey (#484) * feat(collections): add fromItems to MutableVector * adding fromItems all around * add containsKey alias * adding tests for containsKey * psalm types * coding standards fix * documenter --- docs/component/collection.md | 2 +- src/Psl/Collection/IndexAccessInterface.php | 11 +++++++ src/Psl/Collection/Map.php | 25 ++++++++++++++ src/Psl/Collection/MutableMap.php | 25 ++++++++++++++ src/Psl/Collection/MutableSet.php | 34 ++++++++++++++++++++ src/Psl/Collection/MutableVector.php | 33 +++++++++++++++++++ src/Psl/Collection/Set.php | 34 ++++++++++++++++++++ src/Psl/Collection/Vector.php | 32 ++++++++++++++++++ tests/unit/Collection/AbstractMapTest.php | 3 +- tests/unit/Collection/AbstractSetTest.php | 2 ++ tests/unit/Collection/AbstractVectorTest.php | 2 ++ tests/unit/Collection/MapTest.php | 13 ++++++++ tests/unit/Collection/MutableMapTest.php | 15 ++++++++- tests/unit/Collection/MutableSetTest.php | 6 ++++ tests/unit/Collection/MutableVectorTest.php | 7 +++- tests/unit/Collection/SetTest.php | 13 ++++++++ tests/unit/Collection/VectorTest.php | 6 ++++ 17 files changed, 259 insertions(+), 4 deletions(-) diff --git a/docs/component/collection.md b/docs/component/collection.md index 9a08d2c41..31a6317ce 100644 --- a/docs/component/collection.md +++ b/docs/component/collection.md @@ -30,7 +30,7 @@ - [Map](./../../src/Psl/Collection/Map.php#L25) - [MutableMap](./../../src/Psl/Collection/MutableMap.php#L25) - [MutableSet](./../../src/Psl/Collection/MutableSet.php#L22) -- [MutableVector](./../../src/Psl/Collection/MutableVector.php#L23) +- [MutableVector](./../../src/Psl/Collection/MutableVector.php#L24) - [Set](./../../src/Psl/Collection/Set.php#L23) - [Vector](./../../src/Psl/Collection/Vector.php#L22) diff --git a/src/Psl/Collection/IndexAccessInterface.php b/src/Psl/Collection/IndexAccessInterface.php index 797d23cdb..25940b84d 100644 --- a/src/Psl/Collection/IndexAccessInterface.php +++ b/src/Psl/Collection/IndexAccessInterface.php @@ -34,6 +34,17 @@ public function at(int|string $k): mixed; */ public function contains(int|string $k): bool; + /** + * Alias of `contains`. + * + * @param Tk $k + * + * @see contains() method + * + * @psalm-mutation-free + */ + public function containsKey(int|string $k): bool; + /** * Returns the value at the specified key in the current collection. * diff --git a/src/Psl/Collection/Map.php b/src/Psl/Collection/Map.php index 55e1ed08e..3f486fe6c 100644 --- a/src/Psl/Collection/Map.php +++ b/src/Psl/Collection/Map.php @@ -66,6 +66,19 @@ public static function fromArray(array $elements): Map return new self($elements); } + /** + * @template Tsk of array-key + * @template Tsv + * + * @param array $items + * + * @return Map + */ + public static function fromItems(iterable $items): Map + { + return self::fromArray(iterator_to_array($items)); + } + /** * Returns the first value in the current collection. * @@ -240,6 +253,18 @@ public function contains(int|string $k): bool return array_key_exists($k, $this->elements); } + /** + * Alias of `contains`. + * + * @param Tk $k + * + * @psalm-mutation-free + */ + public function containsKey(int|string $k): bool + { + return $this->contains($k); + } + /** * Returns the value at the specified key in the current map. * diff --git a/src/Psl/Collection/MutableMap.php b/src/Psl/Collection/MutableMap.php index cbe40aca4..7dd1d252c 100644 --- a/src/Psl/Collection/MutableMap.php +++ b/src/Psl/Collection/MutableMap.php @@ -66,6 +66,19 @@ public static function fromArray(array $elements): MutableMap return new self($elements); } + /** + * @template Tsk of array-key + * @template Tsv + * + * @param array $items + * + * @return MutableMap + */ + public static function fromItems(iterable $items): MutableMap + { + return self::fromArray(iterator_to_array($items)); + } + /** * Returns the first value in the current collection. * @@ -240,6 +253,18 @@ public function contains(int|string $k): bool return array_key_exists($k, $this->elements); } + /** + * Alias of `contains`. + * + * @param Tk $k + * + * @psalm-mutation-free + */ + public function containsKey(int|string $k): bool + { + return $this->contains($k); + } + /** * Returns the value at the specified key in the current map. * diff --git a/src/Psl/Collection/MutableSet.php b/src/Psl/Collection/MutableSet.php index edf6e69d6..7def68cb4 100644 --- a/src/Psl/Collection/MutableSet.php +++ b/src/Psl/Collection/MutableSet.php @@ -71,6 +71,26 @@ public static function fromArray(array $elements): MutableSet return new self($elements); } + /** + * Create a set from the given iterable, using the values of the iterable as the set values. + * + * @template Ts of array-key + * + * @param iterable $items + * + * @return MutableSet + */ + public static function fromItems(iterable $items): MutableSet + { + /** + * @psalm-suppress InvalidArgument + * + * @var array + */ + $array = iterator_to_array($items); + return self::fromArray($array); + } + /** * Create a set from the given $elements array, using the keys of the array as the set values. * @@ -219,6 +239,20 @@ public function contains(int|string $k): bool return array_key_exists($k, $this->elements); } + /** + * Alias of `contains`. + * + * @param T $k + * + * @return bool True if the value is in the set, false otherwise. + * + * @psalm-mutation-free + */ + public function containsKey(int|string $k): bool + { + return $this->contains($k); + } + /** * Returns the provided value if it is part of the set, or null if it is not. * diff --git a/src/Psl/Collection/MutableVector.php b/src/Psl/Collection/MutableVector.php index f6d7f360d..1ade1cc91 100644 --- a/src/Psl/Collection/MutableVector.php +++ b/src/Psl/Collection/MutableVector.php @@ -14,6 +14,7 @@ use function array_keys; use function array_values; use function count; +use function iterator_to_array; /** * @template T @@ -69,6 +70,26 @@ public static function fromArray(array $elements): MutableVector return new self($elements); } + /** + * Create a vector from the given $items iterable. + * + * @template Ts + * + * @param iterable $items + * + * @return MutableVector + */ + public static function fromItems(iterable $items): MutableVector + { + /** + * @psalm-suppress InvalidArgument + * + * @var array + */ + $array = iterator_to_array($items); + return self::fromArray($array); + } + /** * Returns the first value in the current `MutableVector`. * @@ -189,6 +210,18 @@ public function contains(int|string $k): bool return array_key_exists($k, $this->elements); } + /** + * Alias of `contains`. + * + * @param int<0, max> $k + * + * @psalm-mutation-free + */ + public function containsKey(int|string $k): bool + { + return $this->contains($k); + } + /** * Returns the value at the specified key in the current `MutableVector`. * diff --git a/src/Psl/Collection/Set.php b/src/Psl/Collection/Set.php index 54a1e2764..c87c65d86 100644 --- a/src/Psl/Collection/Set.php +++ b/src/Psl/Collection/Set.php @@ -72,6 +72,26 @@ public static function fromArray(array $elements): Set return new self($elements); } + /** + * Create a set from the given items, using the keys of the array as the set values. + * + * @template Ts of array-key + * + * @param iterable $items + * + * @return Set + */ + public static function fromItems(iterable $items): Set + { + /** + * @var array + * + * @psalm-suppress InvalidArgument + */ + $array = iterator_to_array($items); + return self::fromArray($array); + } + /** * Create a set from the given $elements array, using the keys of the array as the set values. * @@ -220,6 +240,20 @@ public function contains(int|string $k): bool return array_key_exists($k, $this->elements); } + /** + * Alias of `contains`. + * + * @param T $k + * + * @return bool True if the value is in the set, false otherwise. + * + * @psalm-mutation-free + */ + public function containsKey(int|string $k): bool + { + return $this->contains($k); + } + /** * Returns the provided value if it is part of the set, or null if it is not. * diff --git a/src/Psl/Collection/Vector.php b/src/Psl/Collection/Vector.php index 2e34ef178..83f6e557e 100644 --- a/src/Psl/Collection/Vector.php +++ b/src/Psl/Collection/Vector.php @@ -69,6 +69,26 @@ public static function fromArray(array $elements): Vector return new self($elements); } + /** + * Create a vector from the given $items iterable. + * + * @template Ts + * + * @param iterable $items + * + * @return Vector + */ + public static function fromItems(iterable $items): Vector + { + /** + * @psalm-suppress InvalidArgument + * + * @var array + */ + $array = iterator_to_array($items); + return self::fromArray($array); + } + /** * Returns the first value in the current `Vector`. * @@ -190,6 +210,18 @@ public function contains(int|string $k): bool return array_key_exists($k, $this->elements); } + /** + * Alias of `contains`. + * + * @param int<0, max> $k + * + * @psalm-mutation-free + */ + public function containsKey(int|string $k): bool + { + return $this->contains($k); + } + /** * Returns the value at the specified key in the current `Vector`. * diff --git a/tests/unit/Collection/AbstractMapTest.php b/tests/unit/Collection/AbstractMapTest.php index de3aef1bb..6e7ef4a00 100644 --- a/tests/unit/Collection/AbstractMapTest.php +++ b/tests/unit/Collection/AbstractMapTest.php @@ -555,8 +555,9 @@ public function testContains(): void ]); static::assertTrue($map->contains('foo')); + static::assertTrue($map->containsKey('foo')); static::assertTrue($map->contains('bar')); - static::assertFalse($map->contains('baz')); + static::assertFalse($map->containsKey('baz')); } public function testGet(): void diff --git a/tests/unit/Collection/AbstractSetTest.php b/tests/unit/Collection/AbstractSetTest.php index 759cc7705..70fa28c4d 100644 --- a/tests/unit/Collection/AbstractSetTest.php +++ b/tests/unit/Collection/AbstractSetTest.php @@ -484,8 +484,10 @@ public function testContains(): void ]); static::assertTrue($vector->contains('hello')); + static::assertTrue($vector->containsKey('hello')); static::assertTrue($vector->contains('world')); static::assertFalse($vector->contains('foo')); + static::assertFalse($vector->containsKey('foo')); } public function testGet(): void diff --git a/tests/unit/Collection/AbstractVectorTest.php b/tests/unit/Collection/AbstractVectorTest.php index 142696db2..31c12ddfb 100644 --- a/tests/unit/Collection/AbstractVectorTest.php +++ b/tests/unit/Collection/AbstractVectorTest.php @@ -529,7 +529,9 @@ public function testContains(): void static::assertTrue($vector->contains(0)); static::assertTrue($vector->contains(1)); + static::assertTrue($vector->containsKey(1)); static::assertFalse($vector->contains(2)); + static::assertFalse($vector->containsKey(2)); } public function testGet(): void diff --git a/tests/unit/Collection/MapTest.php b/tests/unit/Collection/MapTest.php index 3cb5b2dc3..34d680508 100644 --- a/tests/unit/Collection/MapTest.php +++ b/tests/unit/Collection/MapTest.php @@ -19,6 +19,19 @@ final class MapTest extends AbstractMapTest */ protected string $vectorClass = Vector::class; + public function testFromItems(): void + { + $map = Map::fromItems([ + 'foo' => 'bar', + 'bar' => 'baz', + 'baz' => 'qux', + ]); + + static::assertSame('bar', $map->at('foo')); + static::assertSame('baz', $map->at('bar')); + static::assertSame('qux', $map->at('baz')); + } + /** * @template Tk of array-key * @template Tv diff --git a/tests/unit/Collection/MutableMapTest.php b/tests/unit/Collection/MutableMapTest.php index 619a71ca8..df2ae4688 100644 --- a/tests/unit/Collection/MutableMapTest.php +++ b/tests/unit/Collection/MutableMapTest.php @@ -153,7 +153,7 @@ public function testArrayAccess(): void static::assertTrue(isset($map['foo'])); static::assertSame('1', $map['foo']); - + unset($map['foo']); static::assertFalse(isset($map['foo'])); @@ -235,6 +235,19 @@ public function testOffsetGetThrowsForInvalidOffsetType(): void $map[false]; } + public function testFromItems(): void + { + $map = MutableMap::fromItems([ + 'foo' => 'bar', + 'bar' => 'baz', + 'baz' => 'qux', + ]); + + static::assertSame('bar', $map->at('foo')); + static::assertSame('baz', $map->at('bar')); + static::assertSame('qux', $map->at('baz')); + } + /** * @template Tk of array-key * @template Tv diff --git a/tests/unit/Collection/MutableSetTest.php b/tests/unit/Collection/MutableSetTest.php index 5f741f720..0356dd15b 100644 --- a/tests/unit/Collection/MutableSetTest.php +++ b/tests/unit/Collection/MutableSetTest.php @@ -191,6 +191,12 @@ public function testOffsetGetThrowsForInvalidOffsetType(): void $set[false]; } + public function testFromItems(): void + { + $set = MutableSet::fromItems(['a', 'b', 'b', 'c']); + static::assertSame(['a' => 'a', 'b' => 'b', 'c' => 'c'], $set->toArray()); + } + public function testFromArrayKeysConstructor() { $set = MutableSet::fromArrayKeys(['foo' => 1, 'bar' => 1, 'baz' => 1]); diff --git a/tests/unit/Collection/MutableVectorTest.php b/tests/unit/Collection/MutableVectorTest.php index 2fd0e75a9..c8dd5bbc1 100644 --- a/tests/unit/Collection/MutableVectorTest.php +++ b/tests/unit/Collection/MutableVectorTest.php @@ -149,7 +149,7 @@ public function testArrayAccess(): void static::assertTrue(isset($vector[0])); static::assertSame('foo', $vector[0]); - + unset($vector[0]); static::assertFalse(isset($vector[2])); @@ -230,6 +230,11 @@ public function testOffsetGetThrowsForInvalidOffsetType(): void $vector[false]; } + public function testFromItems(): void + { + $vector = MutableVector::fromItems([1, 2, 3]); + static::assertSame([1, 2, 3], $vector->toArray()); + } /** * @template T diff --git a/tests/unit/Collection/SetTest.php b/tests/unit/Collection/SetTest.php index 1e07d0087..8d61363f9 100644 --- a/tests/unit/Collection/SetTest.php +++ b/tests/unit/Collection/SetTest.php @@ -15,6 +15,19 @@ final class SetTest extends AbstractSetTest */ protected string $setClass = Set::class; + public function testFromItems(): void + { + $set = Set::fromItems([ + 'foo', + 'bar', + 'baz', + ]); + + static::assertTrue($set->contains('foo')); + static::assertTrue($set->contains('bar')); + static::assertTrue($set->contains('baz')); + } + /** * @template T of array-key * diff --git a/tests/unit/Collection/VectorTest.php b/tests/unit/Collection/VectorTest.php index 24afb7189..190872753 100644 --- a/tests/unit/Collection/VectorTest.php +++ b/tests/unit/Collection/VectorTest.php @@ -15,6 +15,12 @@ final class VectorTest extends AbstractVectorTest */ protected string $vectorClass = Vector::class; + public function testFromItems(): void + { + $vector = Vector::fromItems([1, 2, 3]); + static::assertSame([1, 2, 3], $vector->toArray()); + } + /** * @template T *