Skip to content

Commit

Permalink
introduce Option::ensure(), Result::ensure()
Browse files Browse the repository at this point in the history
  • Loading branch information
someniatko committed Aug 3, 2022
1 parent 780fd1b commit a3147f9
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/Error.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,9 @@ public function getOrThrow(\Throwable $e)
{
throw $e;
}

public function ensure(callable $condition, $else): ResultInterface
{
return $this;
}
}
5 changes: 5 additions & 0 deletions src/None.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public function getOrThrow(\Throwable $e)
{
throw $e;
}

public function ensure(callable $condition): Option
{
return $this;
}
}
13 changes: 13 additions & 0 deletions src/Option.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ abstract class Option
private static ?None $none = null;

/**
* @psalm-pure
* @template TNew
* @param TNew $value
* @return Some<TNew>
Expand All @@ -24,10 +25,12 @@ public static function some($value): Some
}

/**
* @psalm-pure
* @return None
*/
public static function none(): None
{
/** @psalm-suppress ImpureStaticProperty */
return self::$none ??= new None();
}

Expand Down Expand Up @@ -113,6 +116,16 @@ abstract public function getOrElse($else);
*/
abstract public function getOrThrow(\Throwable $e);

/**
* Ensures that Some value also validates against the given condition,
* Otherwise returns None.
*
* @return Option<TValue>
*
* @param callable(TValue):bool $condition
*/
abstract public function ensure(callable $condition): Option;

/**
* @template TElse
* @param TElse $else
Expand Down
2 changes: 2 additions & 0 deletions src/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
abstract class Result implements ResultInterface
{
/**
* @psalm-pure
* @template T
* @param T $value
* @return Success<T>
Expand All @@ -23,6 +24,7 @@ public static function success($value): Success
}

/**
* @psalm-pure
* @template T
* @param T $value
* @return Error<T>
Expand Down
14 changes: 14 additions & 0 deletions src/ResultInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,18 @@ public function getOr(callable $map);
* @return TSuccess|never-return
*/
public function getOrThrow(\Throwable $e);

/**
* Ensures that the Success value also validates against the given condition,
* Otherwise returns an Error with a given value.
*
* If this Result is already an Error, nothing will change.
*
* @template TNewError
*
* @param callable(TSuccess):bool $condition
* @param TNewError $else
* @return ResultInterface<TSuccess, TError|TNewError>
*/
public function ensure(callable $condition, $else): self;
}
7 changes: 7 additions & 0 deletions src/Some.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,11 @@ public function getOrThrow(\Throwable $e)
{
return $this->value;
}

public function ensure(callable $condition): Option
{
return $condition($this->value)
? $this
: Option::none();
}
}
7 changes: 7 additions & 0 deletions src/Success.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,11 @@ public function getOrThrow(\Throwable $e)
{
return $this->value;
}

public function ensure(callable $condition, $else): ResultInterface
{
return $condition($this->value)
? $this
: Result::error($else);
}
}
22 changes: 22 additions & 0 deletions test/OptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,26 @@ public function testToNullableNone(): void
$nullable = $option->toNullable();
self::assertNull($nullable);
}

public function testEnsureSomeReturningTrue(): void
{
$option = Option::some(111);
$ensured = $option->ensure(fn (int $i) => $i > 100);
self::assertEquals(111, $ensured->getOrElse(null));
}

public function testEnsureSomeReturningFalse(): void
{
$option = Option::some(111);
$ensured = $option->ensure(fn (int $i) => $i < 100);
self::assertEquals(null, $ensured->getOrElse(null));
}

public function testEnsureNone(): void
{
/** @var Option<int> $option */
$option = Option::none();
$ensured = $option->ensure(fn (int $i) => $i > 100);
self::assertEquals(null, $ensured->getOrElse(null));
}
}
21 changes: 21 additions & 0 deletions test/ResultTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,25 @@ public function testErrors(): void

self::assertEquals([ 3, 5 ], Result::extractErrors($results));
}

public function testEnsureSuccessReturningTrue(): void
{
$result = Result::success(123);
$ensured = $result->ensure(fn(int $i) => $i > 100, 'failed');
self::assertEquals(123, $ensured->get());
}

public function testEnsureSuccessReturningFalse(): void
{
$result = Result::success(123);
$ensured = $result->ensure(fn(int $i) => $i < 100, 'failed');
self::assertEquals('failed', $ensured->get());
}

public function testEnsureErrorDoesNotChangePreviousError(): void
{
$result = Result::error('old error');
$ensured = $result->ensure(fn(int $i) => $i > 100, 'new error');
self::assertEquals('old error', $ensured->get());
}
}

0 comments on commit a3147f9

Please sign in to comment.