From b6298b0d3565151d3564ab3658dc105666f57cb0 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Mon, 28 Oct 2024 14:35:53 -0300 Subject: [PATCH 1/8] Accept any callable --- src/Enums.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Enums.php b/src/Enums.php index 1ddc0aa..3c0d781 100644 --- a/src/Enums.php +++ b/src/Enums.php @@ -7,7 +7,7 @@ use Closure; /** - * The global behavior for all enums. + * The enums manager. */ class Enums { @@ -35,31 +35,31 @@ class Enums /** * Set the logic to run when an inaccessible enum method is called. * - * @param Closure(class-string $enum, string $name, array $arguments): mixed $callback + * @param callable(class-string $enum, string $name, array $arguments): mixed $callback */ - public static function onStaticCall(Closure $callback): void + public static function onStaticCall(callable $callback): void { - static::$onStaticCall = $callback; + static::$onStaticCall = $callback(...); } /** * Set the logic to run when an inaccessible case method is called. * - * @param Closure(object $case, string $name, array $arguments): mixed $callback + * @param callable(object $case, string $name, array $arguments): mixed $callback */ - public static function onCall(Closure $callback): void + public static function onCall(callable $callback): void { - static::$onCall = $callback; + static::$onCall = $callback(...); } /** * Set the logic to run when a case is invoked. * - * @param Closure(object $case, mixed ...$arguments): mixed $callback + * @param callable(object $case, mixed ...$arguments): mixed $callback */ - public static function onInvoke(Closure $callback): void + public static function onInvoke(callable $callback): void { - static::$onInvoke = $callback; + static::$onInvoke = $callback(...); } /** From 61ddbbd0d823f1787ef6ea3d544b4e77af10ebf3 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Mon, 28 Oct 2024 14:40:04 -0300 Subject: [PATCH 2/8] Allow meta inheritance --- src/Concerns/SelfAware.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Concerns/SelfAware.php b/src/Concerns/SelfAware.php index 4fa8834..5b257d2 100644 --- a/src/Concerns/SelfAware.php +++ b/src/Concerns/SelfAware.php @@ -41,12 +41,12 @@ public static function metaNames(): array $meta = []; $enum = new ReflectionEnum(self::class); - foreach ($enum->getAttributes(Meta::class) as $attribute) { + foreach ($enum->getAttributes(Meta::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) { array_push($meta, ...$attribute->newInstance()->names()); } foreach ($enum->getCases() as $case) { - foreach ($case->getAttributes(Meta::class) as $attribute) { + foreach ($case->getAttributes(Meta::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) { array_push($meta, ...$attribute->newInstance()->names()); } } From c9af21d0860ad5e9cec873286e6abd4ff18be338 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Mon, 28 Oct 2024 14:57:23 -0300 Subject: [PATCH 3/8] Implement JsonSerializable and Stringable --- src/CasesCollection.php | 22 +++++++++++++++++++++- tests/CasesCollectionTest.php | 10 ++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/CasesCollection.php b/src/CasesCollection.php index c50fbea..5872450 100644 --- a/src/CasesCollection.php +++ b/src/CasesCollection.php @@ -5,6 +5,8 @@ use BackedEnum; use Countable; use IteratorAggregate; +use JsonSerializable; +use Stringable; use Traversable; /** @@ -15,7 +17,7 @@ * * @implements IteratorAggregate */ -class CasesCollection implements Countable, IteratorAggregate +class CasesCollection implements Countable, IteratorAggregate, JsonSerializable, Stringable { /** * Whether the cases belong to a backed enum. @@ -32,6 +34,24 @@ final public function __construct(protected array $cases) $this->enumIsBacked = reset($cases) instanceof BackedEnum; } + /** + * Turn the collection into a string. + */ + public function __toString(): string + { + return (string) json_encode($this->jsonSerialize()); + } + + /** + * Turn the collection into a JSON serializable array. + * + * @return array + */ + public function jsonSerialize(): array + { + return $this->enumIsBacked ? $this->values() : $this->names(); + } + /** * Retrieve the count of cases. */ diff --git a/tests/CasesCollectionTest.php b/tests/CasesCollectionTest.php index 54e7bd7..397c257 100644 --- a/tests/CasesCollectionTest.php +++ b/tests/CasesCollectionTest.php @@ -5,6 +5,16 @@ use Cerbero\Enum\PureEnum; use Pest\Expectation; +it('turns into a JSON with pure cases', function() { + expect((string) new CasesCollection(PureEnum::cases())) + ->toBe('["one","two","three"]'); +}); + +it('turns into a JSON with backed cases', function() { + expect((string) new CasesCollection(BackedEnum::cases())) + ->toBe('[1,2,3]'); +}); + it('retrieves all the cases') ->expect(new CasesCollection(PureEnum::cases())) ->all() From 65d7e198cc31a1fca0bcfddd6b3e9432f8db7d4d Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Mon, 28 Oct 2024 15:08:44 -0300 Subject: [PATCH 4/8] Improve generics --- src/CasesCollection.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/CasesCollection.php b/src/CasesCollection.php index 5872450..93e08c2 100644 --- a/src/CasesCollection.php +++ b/src/CasesCollection.php @@ -12,10 +12,9 @@ /** * The collection of enum cases. * - * @template TKey of array-key * @template TValue * - * @implements IteratorAggregate + * @implements IteratorAggregate */ class CasesCollection implements Countable, IteratorAggregate, JsonSerializable, Stringable { @@ -27,7 +26,7 @@ class CasesCollection implements Countable, IteratorAggregate, JsonSerializable, /** * Instantiate the class. * - * @param array $cases + * @param array $cases */ final public function __construct(protected array $cases) { @@ -45,7 +44,7 @@ public function __toString(): string /** * Turn the collection into a JSON serializable array. * - * @return array + * @return list */ public function jsonSerialize(): array { @@ -63,7 +62,7 @@ public function count(): int /** * Retrieve the iterable cases. * - * @return Traversable + * @return Traversable */ public function getIterator(): Traversable { @@ -73,7 +72,7 @@ public function getIterator(): Traversable /** * Retrieve all the cases as a plain array. * - * @return array + * @return array */ public function all(): array { @@ -83,7 +82,7 @@ public function all(): array /** * Retrieve all the cases as a plain array recursively. * - * @return array + * @return array */ public function toArray(): array { @@ -99,7 +98,7 @@ public function toArray(): array /** * Retrieve the first case. * - * @param (callable(TValue, TKey): bool)|null $callback + * @param (callable(TValue, array-key): bool)|null $callback * @return ?TValue */ public function first(callable $callback = null): mixed @@ -164,8 +163,8 @@ public function pluck(callable|string $value, callable|string $key = null): arra * * @template TMapValue * - * @param callable(TValue, TKey): TMapValue $callback - * @return array + * @param callable(TValue, array-key): TMapValue $callback + * @return array */ public function map(callable $callback): array { From 4e357c26dc99f614e7463c2c7e76aee6580245e5 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Mon, 28 Oct 2024 17:41:23 -0300 Subject: [PATCH 5/8] Negate methods --- src/Concerns/Compares.php | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/Concerns/Compares.php b/src/Concerns/Compares.php index 4e4ba4c..5b8431c 100644 --- a/src/Concerns/Compares.php +++ b/src/Concerns/Compares.php @@ -26,13 +26,7 @@ public static function has(mixed $target): bool */ public static function doesntHave(mixed $target): bool { - foreach (self::cases() as $case) { - if ($case->is($target)) { - return false; - } - } - - return true; + return !self::has($target); } /** @@ -74,12 +68,6 @@ public function in(iterable $targets): bool */ public function notIn(iterable $targets): bool { - foreach ($targets as $target) { - if ($this->is($target)) { - return false; - } - } - - return true; + return !$this->in($targets); } } From ce404f8e35dcf1fd50fbdbcf0a7f2edb9e49f6bc Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Mon, 28 Oct 2024 17:56:04 -0300 Subject: [PATCH 6/8] Add has() method --- src/CasesCollection.php | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/CasesCollection.php b/src/CasesCollection.php index 93e08c2..60fff23 100644 --- a/src/CasesCollection.php +++ b/src/CasesCollection.php @@ -28,7 +28,7 @@ class CasesCollection implements Countable, IteratorAggregate, JsonSerializable, * * @param array $cases */ - final public function __construct(protected array $cases) + final public function __construct(protected readonly array $cases) { $this->enumIsBacked = reset($cases) instanceof BackedEnum; } @@ -79,6 +79,20 @@ public function all(): array return $this->cases; } + /** + * Determine whether the collection contains the given case. + */ + public function has(mixed $case): bool + { + foreach ($this->cases as $instance) { + if ($instance->is($case)) { + return true; + } + } + + return false; + } + /** * Retrieve all the cases as a plain array recursively. * @@ -89,7 +103,7 @@ public function toArray(): array $array = []; foreach ($this->cases as $key => $value) { - $array[$key] = $value instanceof self ? $value->toArray() : $value; + $array[$key] = $value instanceof static ? $value->toArray() : $value; } return $array; From 29126297f8c37e21236c1426b35704c80ca0e7b2 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Mon, 28 Oct 2024 17:56:09 -0300 Subject: [PATCH 7/8] Add has() method --- tests/CasesCollectionTest.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/CasesCollectionTest.php b/tests/CasesCollectionTest.php index 397c257..7dcaeb6 100644 --- a/tests/CasesCollectionTest.php +++ b/tests/CasesCollectionTest.php @@ -20,6 +20,26 @@ ->all() ->toBe([PureEnum::one, PureEnum::two, PureEnum::three]); +it('determines whether a pure collection contains an item', function() { + $collection = new CasesCollection(PureEnum::cases()); + + expect($collection->has(PureEnum::one))->toBeTrue(); + expect($collection->has('one'))->toBeTrue(); + expect($collection->has(BackedEnum::one))->toBeFalse(); + expect($collection->has('four'))->toBeFalse(); + expect($collection->has(1))->toBeFalse(); +}); + +it('determines whether a backed collection contains an item', function() { + $collection = new CasesCollection(BackedEnum::cases()); + + expect($collection->has(BackedEnum::one))->toBeTrue(); + expect($collection->has(1))->toBeTrue(); + expect($collection->has(PureEnum::one))->toBeFalse(); + expect($collection->has(4))->toBeFalse(); + expect($collection->has('one'))->toBeFalse(); +}); + it('retrieves the count of all the cases') ->expect(new CasesCollection(PureEnum::cases())) ->count() From c5d249254e100718e2a5049f459b488879a564b9 Mon Sep 17 00:00:00 2001 From: Andrea Marco Sartori Date: Mon, 28 Oct 2024 18:13:49 -0300 Subject: [PATCH 8/8] Add methods to check backing type --- src/Concerns/SelfAware.php | 16 ++++++++++++++++ tests/BackedEnumTest.php | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Concerns/SelfAware.php b/src/Concerns/SelfAware.php index 5b257d2..db42c81 100644 --- a/src/Concerns/SelfAware.php +++ b/src/Concerns/SelfAware.php @@ -31,6 +31,22 @@ public static function isBacked(): bool return is_subclass_of(self::class, BackedEnum::class); } + /** + * Determine whether the enum is backed by integer. + */ + public static function isBackedByInteger(): bool + { + return (new ReflectionEnum(self::class))->getBackingType()?->getName() === 'int'; + } + + /** + * Determine whether the enum is backed by string. + */ + public static function isBackedByString(): bool + { + return (new ReflectionEnum(self::class))->getBackingType()?->getName() === 'string'; + } + /** * Retrieve all the meta names of the enum. * diff --git a/tests/BackedEnumTest.php b/tests/BackedEnumTest.php index 74379ea..0d2545f 100644 --- a/tests/BackedEnumTest.php +++ b/tests/BackedEnumTest.php @@ -3,6 +3,7 @@ use Cerbero\Enum\CasesCollection; use Cerbero\Enum\BackedEnum; use Cerbero\Enum\Enums; +use Cerbero\Enum\PureEnum; use Pest\Expectation; it('determines whether the enum is pure') @@ -13,6 +14,13 @@ ->expect(BackedEnum::isBacked()) ->toBeTrue(); +it('determines whether the enum is backed by integer or string', function() { + expect(BackedEnum::isBackedByInteger())->toBeTrue(); + expect(BackedEnum::isBackedByString())->toBeFalse(); + expect(PureEnum::isBackedByInteger())->toBeFalse(); + expect(PureEnum::isBackedByString())->toBeFalse(); +}); + it('retrieves all the names of the cases') ->expect(BackedEnum::names()) ->toBe(['one', 'two', 'three']);