Skip to content

Commit

Permalink
feat(option): add Option::match() method
Browse files Browse the repository at this point in the history
  • Loading branch information
devnix committed Dec 11, 2023
1 parent 0aa7117 commit 1a069eb
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/Psl/Option/Option.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,30 @@ public function contains(mixed $value): bool
return false;
}

/**
* Matches the contained option value with the provided closures and returns the result.
*
* @template TNone
* @template TSome
*
* @param (Closure(): TNone) $none A closure to be called when the option is none.
* The closure must not accept any arguments and can return a value.
* Example: `fn() => 'Default value'`
* @param (Closure(T): TSome) $some A closure to be called when the option is some.
* The closure must accept the option value as its only argument and can return a value.
* Example: `fn($value) => $value + 10`
*
* @return TNone|TSome The result of calling the appropriate closure.
*/
public function match(Closure $none, Closure $some): mixed
{
if ($this->option !== null) {
return $some($this->option[0]);
}

return $none();
}

/**
* Maps an `Option<T>` to `Option<Tu>` by applying a function to a contained value.
*
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/Option/NoneTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ public function testContains(): void
static::assertFalse($option->contains(4));
}

public function testMatch(): void
{
$checked_divisor = static function (int $dividend, int $divisor): Option\Option {
if ($divisor === 0) {
return Option\none();
}

return Option\some($dividend / $divisor);
};

$try_division = static function (int $dividend, int $divisor) use ($checked_divisor): string {
return $checked_divisor($dividend, $divisor)->match(
none: static fn () => sprintf('%s / %s failed!', $dividend, $divisor),
some: static fn ($value) => sprintf('%s / %s = %s', $dividend, $divisor, $value),
);
};

static::assertSame('2 / 0 failed!', $try_division(2, 0));
}

public function testMap(): void
{
$option = Option\none();
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/Option/SomeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,26 @@ public function testContains(): void
static::assertTrue($option->contains(2));
}

public function testMatch(): void
{
$checked_divisor = static function (int $dividend, int $divisor): Option\Option {
if ($divisor === 0) {
return Option\none();
}

return Option\some($dividend / $divisor);
};

$try_division = static function (int $dividend, int $divisor) use ($checked_divisor): string {
return $checked_divisor($dividend, $divisor)->match(
none: static fn () => sprintf('%s / %s failed!', $dividend, $divisor),
some: static fn ($value) => sprintf('%s / %s = %s', $dividend, $divisor, $value),
);
};

static::assertSame('10 / 2 = 5', $try_division(10, 2));
}

public function testMap(): void
{
$option = Option\some(2);
Expand Down

0 comments on commit 1a069eb

Please sign in to comment.