-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
251028e
commit 0c865b9
Showing
7 changed files
with
381 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
|
||
# Result | ||
|
||
|
||
Factory class to make new `Ok` and `Error` instances. | ||
|
||
This class cannot be instantiated. | ||
|
||
|
||
## Static Methods | ||
|
||
|
||
### of | ||
|
||
```php | ||
public static function of(mixed $value): Ok|Error; | ||
``` | ||
|
||
Makes an `Ok` with the given `value`. | ||
|
||
**Note:** If `value` is a closure, this method will call it and | ||
use the returned value to make the result, returning an `Error` | ||
if any exception is thrown. | ||
|
||
|
||
### fromFalsable | ||
|
||
```php | ||
public static function fromFalsable(mixed $value): Ok|Error; | ||
``` | ||
|
||
Makes an empty `Error` if the value is `false`. Otherwise, | ||
makes an `Ok` with the given `value`. | ||
|
||
**Note:** If `value` is a closure, this method will call it and | ||
use the returned value to make the result. | ||
|
||
|
||
### fromNullable | ||
|
||
```php | ||
public static function fromNullable(mixed $value): Ok|Error; | ||
``` | ||
|
||
Makes an empty `Error` if the value is `null`. Otherwise, | ||
makes an `Ok` with the given `value`. | ||
|
||
**Note:** If `value` is a closure, this method will call it and | ||
use the returned value to make the result. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Hereldar\Results; | ||
|
||
use Closure; | ||
use RuntimeException; | ||
use Throwable; | ||
|
||
/** | ||
* Factory class to make new `Ok` and `Error` instances. | ||
* | ||
* This class cannot be instantiated. | ||
*/ | ||
final class Result | ||
{ | ||
private function __construct() {} | ||
|
||
/** | ||
* Makes an `Ok` with the given `value`. | ||
* | ||
* **Note:** If `value` is a closure, this method will call it and | ||
* use the returned value to make the result, returning an `Error` | ||
* if any exception is thrown. | ||
* | ||
* @template U | ||
* | ||
* @param U|Closure():U $value | ||
* | ||
* @return Ok<U>|Error<Throwable> | ||
* | ||
* @psalm-suppress MixedAssignment | ||
*/ | ||
public static function of(mixed $value): Ok|Error | ||
{ | ||
if ($value instanceof Closure) { | ||
try { | ||
$value = $value(); | ||
} catch (Throwable $e) { | ||
return Error::withException($e); | ||
} | ||
} | ||
|
||
return Ok::withValue($value); | ||
} | ||
|
||
/** | ||
* Makes an empty `Error` if the value is `null`. Otherwise, makes | ||
* an `Ok` with the given `value`. | ||
* | ||
* **Note:** If `value` is a closure, this method will call it and | ||
* use the returned value to make the result. | ||
* | ||
* @template U | ||
* | ||
* @param (U|null)|Closure():(U|null) $value | ||
* | ||
* @return Ok<U>|Error<RuntimeException> | ||
* | ||
* @psalm-suppress MixedAssignment | ||
*/ | ||
public static function fromNullable(mixed $value): Ok|Error | ||
{ | ||
if ($value instanceof Closure) { | ||
$value = $value(); | ||
} | ||
|
||
return ($value === null) | ||
? Error::empty() | ||
: Ok::withValue($value); | ||
} | ||
|
||
/** | ||
* Makes an empty `Error` if the value is `false`. Otherwise, | ||
* makes an `Ok` with the given `value`. | ||
* | ||
* **Note:** If `value` is a closure, this method will call it and | ||
* use the returned value to make the result. | ||
* | ||
* @template U | ||
* | ||
* @param (U|false)|Closure():(U|false) $value | ||
* | ||
* @return Ok<U>|Error<RuntimeException> | ||
* | ||
* @psalm-suppress MixedAssignment | ||
*/ | ||
public static function fromFalsable(mixed $value): Ok|Error | ||
{ | ||
if ($value instanceof Closure) { | ||
$value = $value(); | ||
} | ||
|
||
return ($value === false) | ||
? Error::empty() | ||
: Ok::withValue($value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Hereldar\Results\Tests; | ||
|
||
use Hereldar\Results\Error; | ||
use Hereldar\Results\Ok; | ||
use Hereldar\Results\Result; | ||
use RuntimeException; | ||
|
||
final class ResultTest extends TestCase | ||
{ | ||
/** | ||
* @psalm-suppress InaccessibleMethod | ||
*/ | ||
public function testPrivateConstructor(): void | ||
{ | ||
self::assertException( | ||
\Error::class, | ||
fn() => new Result() // @phpstan-ignore-line | ||
); | ||
} | ||
|
||
public function testOfValue(): void | ||
{ | ||
$result = Result::of(null); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertNull($result->value()); | ||
|
||
$result = Result::of(false); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertFalse($result->value()); | ||
|
||
$value = $this->random()->randomNumber(); | ||
$result = Result::of($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->randomFloat(); | ||
$result = Result::of($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->word(); | ||
$result = Result::of($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
} | ||
|
||
public function testOfClosure(): void | ||
{ | ||
$result = Result::of(fn() => null); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertNull($result->value()); | ||
|
||
$result = Result::of(fn() => false); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertFalse($result->value()); | ||
|
||
$value = $this->random()->randomNumber(); | ||
$result = Result::of(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->randomFloat(); | ||
$result = Result::of(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->word(); | ||
$result = Result::of(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$exception = new RuntimeException(); | ||
$result = Result::of(fn() => throw $exception); | ||
self::assertInstanceOf(Error::class, $result); | ||
self::assertSame($exception, $result->exception()); | ||
} | ||
|
||
public function testFromNullableValue(): void | ||
{ | ||
$result = Result::fromNullable(null); | ||
self::assertInstanceOf(Error::class, $result); | ||
|
||
$result = Result::fromNullable(false); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertFalse($result->value()); | ||
|
||
$value = $this->random()->randomNumber(); | ||
$result = Result::fromNullable($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->randomFloat(); | ||
$result = Result::fromNullable($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->word(); | ||
$result = Result::fromNullable($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
} | ||
|
||
public function testFromNullableClosure(): void | ||
{ | ||
$result = Result::fromNullable(fn() => null); | ||
self::assertInstanceOf(Error::class, $result); | ||
|
||
$result = Result::fromNullable(fn() => false); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertFalse($result->value()); | ||
|
||
$value = $this->random()->randomNumber(); | ||
$result = Result::fromNullable(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->randomFloat(); | ||
$result = Result::fromNullable(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->word(); | ||
$result = Result::fromNullable(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$exception = new RuntimeException(); | ||
self::assertException( | ||
$exception, | ||
fn() => Result::fromNullable(fn() => throw $exception) | ||
); | ||
} | ||
|
||
public function testFromFalsableValue(): void | ||
{ | ||
$result = Result::fromFalsable(null); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertNull($result->value()); | ||
|
||
$result = Result::fromFalsable(false); | ||
self::assertInstanceOf(Error::class, $result); | ||
|
||
$value = $this->random()->randomNumber(); | ||
$result = Result::fromFalsable($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->randomFloat(); | ||
$result = Result::fromFalsable($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->word(); | ||
$result = Result::fromFalsable($value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
} | ||
|
||
public function testFromFalsableClosure(): void | ||
{ | ||
$result = Result::fromFalsable(fn() => null); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertNull($result->value()); | ||
|
||
$result = Result::fromFalsable(fn() => false); | ||
self::assertInstanceOf(Error::class, $result); | ||
|
||
$value = $this->random()->randomNumber(); | ||
$result = Result::fromFalsable(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->randomFloat(); | ||
$result = Result::fromFalsable(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$value = $this->random()->word(); | ||
$result = Result::fromFalsable(fn() => $value); | ||
self::assertInstanceOf(Ok::class, $result); | ||
self::assertSame($value, $result->value()); | ||
|
||
$exception = new RuntimeException(); | ||
self::assertException( | ||
$exception, | ||
fn() => Result::fromFalsable(fn() => throw $exception) | ||
); | ||
} | ||
} |
Oops, something went wrong.