diff --git a/composer.json b/composer.json index b84ab0da..e844e20f 100644 --- a/composer.json +++ b/composer.json @@ -122,7 +122,9 @@ "src/Functional/True.php", "src/Functional/Truthy.php", "src/Functional/Unique.php", + "src/Functional/Unless.php", "src/Functional/ValueToKey.php", + "src/Functional/When.php", "src/Functional/With.php", "src/Functional/Zip.php", "src/Functional/ZipAll.php" diff --git a/docs/functional-php.md b/docs/functional-php.md index 4cf3fafa..36c12766 100644 --- a/docs/functional-php.md +++ b/docs/functional-php.md @@ -1036,6 +1036,35 @@ use function Functional\tap; tap(create_user('John Doe'), fn ($user) => send_welcome_email($user))->login(); ``` +## when() + +``mixed when(mixed|Closure $condition, mixed|Closure $value, mixed|Closure $default = null)`` +Return a value if the given condition is true. All three arguments can be closures — `$condition` is evaluated, and `$value` or `$default` is resolved accordingly. + +```php +use function Functional\when; + +when(true, 'yes'); // 'yes' +when(false, 'yes'); // null +when(false, 'yes', 'no'); // 'no' +when(fn () => true, 'yes'); // 'yes' +when(true, fn () => 'computed'); // 'computed' +``` + +## unless() + +``mixed unless(mixed|Closure $condition, mixed|Closure $value, mixed|Closure $default = null)`` +Return a value if the given condition is false. The inverse of `when()`. + +```php +use function Functional\unless; + +unless(false, 'yes'); // 'yes' +unless(true, 'yes'); // null +unless(true, 'yes', 'no'); // 'no' +unless(fn () => false, 'yes'); // 'yes' +``` + ## repeat() Creates and returns a function that can be used to execute the given closure multiple times. diff --git a/src/Functional/Functional.php b/src/Functional/Functional.php index b57edf9f..119c5ac6 100644 --- a/src/Functional/Functional.php +++ b/src/Functional/Functional.php @@ -493,11 +493,21 @@ final class Functional */ const unique = '\Functional\unique'; + /** + * @see \Functional\unless + */ + const unless = '\Functional\unless'; + /** * @see \Functional\value_to_key */ const value_to_key = '\Functional\value_to_key'; + /** + * @see \Functional\when + */ + const when = '\Functional\when'; + /** * @see \Functional\with */ diff --git a/src/Functional/Unless.php b/src/Functional/Unless.php new file mode 100644 index 00000000..9d7fe555 --- /dev/null +++ b/src/Functional/Unless.php @@ -0,0 +1,32 @@ + + * @copyright 2011-2021 Lars Strojny + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/lstrojny/functional-php + */ + +namespace Functional; + +/** + * Return a value if the given condition is false. + * + * @param mixed|\Closure $condition + * @param mixed|\Closure $value + * @param mixed|\Closure $default + * + * @return mixed + * @no-named-arguments + */ +function unless($condition, $value, $default = null) +{ + $condition = $condition instanceof \Closure ? $condition() : $condition; + + if (!$condition) { + return $value instanceof \Closure ? $value($condition) : $value; + } + + return $default instanceof \Closure ? $default($condition) : $default; +} diff --git a/src/Functional/When.php b/src/Functional/When.php new file mode 100644 index 00000000..75455a6f --- /dev/null +++ b/src/Functional/When.php @@ -0,0 +1,32 @@ + + * @copyright 2011-2021 Lars Strojny + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/lstrojny/functional-php + */ + +namespace Functional; + +/** + * Return a value if the given condition is true. + * + * @param mixed|\Closure $condition + * @param mixed|\Closure $value + * @param mixed|\Closure $default + * + * @return mixed + * @no-named-arguments + */ +function when($condition, $value, $default = null) +{ + $condition = $condition instanceof \Closure ? $condition() : $condition; + + if ($condition) { + return $value instanceof \Closure ? $value($condition) : $value; + } + + return $default instanceof \Closure ? $default($condition) : $default; +} diff --git a/tests/Functional/UnlessTest.php b/tests/Functional/UnlessTest.php new file mode 100644 index 00000000..7371f44f --- /dev/null +++ b/tests/Functional/UnlessTest.php @@ -0,0 +1,59 @@ + + * @copyright 2011-2021 Lars Strojny + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/lstrojny/functional-php + */ + +namespace Functional\Tests; + +use function Functional\unless; + +class UnlessTest extends AbstractTestCase +{ + public function testUnlessConditionIsFalsy(): void + { + self::assertEquals('yes', unless(false, 'yes')); + } + + public function testUnlessConditionIsTruthy(): void + { + self::assertNull(unless(true, 'yes')); + } + + public function testUnlessConditionIsTruthyWithDefault(): void + { + self::assertEquals('no', unless(true, 'yes', 'no')); + } + + public function testUnlessValueIsClosure(): void + { + self::assertEquals('fallback', unless(false, function () { + return 'fallback'; + })); + } + + public function testUnlessDefaultIsClosure(): void + { + self::assertEquals('default', unless(true, 'yes', function () { + return 'default'; + })); + } + + public function testUnlessConditionIsClosure(): void + { + self::assertEquals('yes', unless(function () { + return false; + }, 'yes')); + } + + public function testUnlessConditionIsClosureReturningTruthy(): void + { + self::assertNull(unless(function () { + return true; + }, 'yes')); + } +} diff --git a/tests/Functional/WhenTest.php b/tests/Functional/WhenTest.php new file mode 100644 index 00000000..1f721ee9 --- /dev/null +++ b/tests/Functional/WhenTest.php @@ -0,0 +1,59 @@ + + * @copyright 2011-2021 Lars Strojny + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/lstrojny/functional-php + */ + +namespace Functional\Tests; + +use function Functional\when; + +class WhenTest extends AbstractTestCase +{ + public function testWhenConditionIsTruthy(): void + { + self::assertEquals('yes', when(true, 'yes')); + } + + public function testWhenConditionIsFalsy(): void + { + self::assertNull(when(false, 'yes')); + } + + public function testWhenConditionIsFalsyWithDefault(): void + { + self::assertEquals('no', when(false, 'yes', 'no')); + } + + public function testWhenValueIsClosure(): void + { + self::assertEquals('condition was true', when(true, function ($condition) { + return $condition ? 'condition was true' : 'condition was false'; + })); + } + + public function testWhenDefaultIsClosure(): void + { + self::assertEquals('fallback', when(false, 'yes', function () { + return 'fallback'; + })); + } + + public function testWhenConditionIsClosure(): void + { + self::assertEquals('yes', when(function () { + return true; + }, 'yes')); + } + + public function testWhenConditionIsClosureReturningFalsy(): void + { + self::assertNull(when(function () { + return false; + }, 'yes')); + } +}