Skip to content

Commit

Permalink
Merge pull request #9 from petrknap/map-and-map-flat
Browse files Browse the repository at this point in the history
Implemented `map` and `flatMap` methods
  • Loading branch information
petrknap authored May 13, 2024
2 parents 831ce77 + 50f5b81 commit 366e124
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ $optionalString->ifPresent(function (string $value): void { echo $value; });
if ($optionalString->equals('value')) {
echo 'It is `value`.';
}

echo $optionalString->map(fn ($s) => "`{$s}`")->orElse('empty');
echo $optionalString->flatMap(fn ($s) => OptionalString::of("`{$s}`"))->orElse('empty');
```

### Create and use your own typed optional
Expand Down
42 changes: 41 additions & 1 deletion src/AbstractOptional.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,25 @@ public function equals(mixed $obj): bool
return ($obj === null || static::isSupported($obj)) && $this->value == $obj;
}

/**
* @template U of mixed
*
* @param callable(T): self<U> $mapper
*
* @return self<U>
*/
public function flatMap(callable $mapper): self
{
if ($this->value !== null) {
$mapped = $mapper($this->value);
if (!$mapped instanceof self) {
throw new InvalidArgumentException('Mapper must return instance of ' . self::class . '.');
}
return $mapped;
}
return $this;
}

/**
* @return T
*
Expand Down Expand Up @@ -94,6 +113,27 @@ public function isPresent(): bool
return $this->wasPresent = $this->value !== null;
}

/**
* @template U of mixed
*
* @param callable(T): U $mapper
*
* @return self<U>
*/
public function map(callable $mapper): self
{
/** @var callable(T): self<U> $flatMapper */
$flatMapper = static function (mixed $value) use ($mapper): self {
$mapped = $mapper($value);
try {
return TypedOptional::of($mapped);
} catch (Exception\CouldNotFindTypedOptionalForValue) {
return Optional::of($mapped);
}
};
return $this->flatMap($flatMapper);
}

/**
* @param T $other
*
Expand Down Expand Up @@ -140,7 +180,7 @@ public function orElseThrow(callable $exceptionSupplier): mixed
}

/**
* @param T|mixed $value not null
* @param mixed $value not null
*/
abstract protected static function isSupported(mixed $value): bool;
}
28 changes: 28 additions & 0 deletions tests/OptionalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ public static function dataMethodEqualsWorks(): array
];
}

#[DataProvider('dataMethodFlatMapWorks')]
public function testMethodFlatMapWorks(Optional $optional, Optional $expectedResult): void
{
self::assertTrue($expectedResult->equals($optional->flatMap(fn (string $v): Optional => Optional::of($v . 'x'))));
}

public static function dataMethodFlatMapWorks(): array
{
return self::makeDataSet([
[Optional::of(self::VALUE . 'x')],
[Optional::empty()],
]);
}

#[DataProvider('dataMethodGetWorks')]
public function testMethodGetWorks(Optional $optional, ?string $expectedValue, ?string $expectedException): void
{
Expand Down Expand Up @@ -127,6 +141,20 @@ public static function dataMethodIsPresentWorks(): array
]);
}

#[DataProvider('dataMethodMapWorks')]
public function testMethodMapWorks(Optional $optional, mixed $expectedResult): void
{
self::assertTrue($expectedResult->equals($optional->map(fn (string $v): string => $v . 'x')));
}

public static function dataMethodMapWorks(): array
{
return self::makeDataSet([
[OptionalString::of(self::VALUE . 'x')],
[Optional::empty()],
]);
}

#[DataProvider('dataMethodOrElseWorks')]
public function testMethodOrElseWorks(Optional $optional, string $expectedValue): void
{
Expand Down
2 changes: 2 additions & 0 deletions tests/ReadmeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public static function getExpectedOutputsOfPhpExamples(): iterable
. 'value'
. 'value'
. 'It is `value`.'
. '`value`'
. '`value`'
,
'create--and-use-your-own-typed-optional' => '',
];
Expand Down

0 comments on commit 366e124

Please sign in to comment.