mirror of
https://github.com/danog/endtoend-test-psl.git
synced 2025-01-22 05:11:47 +01:00
[Fun] Add pipe and after combinators (#57)
This commit is contained in:
parent
25480b41fa
commit
40a4574e9d
41
src/Psl/Fun/after.php
Normal file
41
src/Psl/Fun/after.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Psl\Fun;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a function that calls the next function with the result of the first function.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* $runExpression = Fun\after(
|
||||||
|
* fn($i) => $i + 1,
|
||||||
|
* fn(int $i) => $i * 5
|
||||||
|
* );
|
||||||
|
* => $runExpression(1) === 10;
|
||||||
|
* => $runExpression(2) === 15;
|
||||||
|
* => $runExpression(3) === 20;
|
||||||
|
*
|
||||||
|
* $greet = Fun\after(
|
||||||
|
* fn($value) => 'Hello' . $value,
|
||||||
|
* fn($value) => $value . '!'
|
||||||
|
* );
|
||||||
|
* => $greet('World') === 'Hello World!';
|
||||||
|
* => $greet('Jim') === 'Hello Jim!';
|
||||||
|
*
|
||||||
|
* @template I
|
||||||
|
* @template O
|
||||||
|
* @template R
|
||||||
|
*
|
||||||
|
* @psalm-param callable(I): O $first
|
||||||
|
* @psalm-param callable(O): R $next
|
||||||
|
*
|
||||||
|
* @psalm-return callable(I): R
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
function after(callable $first, callable $next): callable
|
||||||
|
{
|
||||||
|
return static fn ($input) => $next($first($input));
|
||||||
|
}
|
43
src/Psl/Fun/pipe.php
Normal file
43
src/Psl/Fun/pipe.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Psl\Fun;
|
||||||
|
|
||||||
|
use function Psl\Iter\reduce;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs left-to-right function composition.
|
||||||
|
* Example
|
||||||
|
* $pipe = Fun\pipe(
|
||||||
|
* fn($value) => 'Hello' . $value,
|
||||||
|
* fn($value) => $value . '!',
|
||||||
|
* fn($value) => '¡' . $value
|
||||||
|
* );
|
||||||
|
* => $greet('World') === '¡Hello World!';
|
||||||
|
* => $greet('Jim') === '¡Hello Jim!';
|
||||||
|
*
|
||||||
|
* @template T
|
||||||
|
*
|
||||||
|
* @psalm-param callable(T): T ...$stages
|
||||||
|
*
|
||||||
|
* @psalm-return callable(T): T
|
||||||
|
*
|
||||||
|
* @psalm-pure
|
||||||
|
*/
|
||||||
|
function pipe(callable ...$stages): callable
|
||||||
|
{
|
||||||
|
return static fn ($input) => reduce(
|
||||||
|
$stages,
|
||||||
|
/**
|
||||||
|
* @template IO
|
||||||
|
*
|
||||||
|
* @param IO $input
|
||||||
|
* @param callable(IO): IO $next
|
||||||
|
*
|
||||||
|
* @return IO
|
||||||
|
*/
|
||||||
|
static fn ($input, int $key, callable $next) => $next($input),
|
||||||
|
$input
|
||||||
|
);
|
||||||
|
}
|
@ -95,6 +95,8 @@ final class Loader
|
|||||||
'Psl\Arr\map',
|
'Psl\Arr\map',
|
||||||
'Psl\Arr\map_keys',
|
'Psl\Arr\map_keys',
|
||||||
'Psl\Arr\map_with_key',
|
'Psl\Arr\map_with_key',
|
||||||
|
'Psl\Fun\after',
|
||||||
|
'Psl\Fun\pipe',
|
||||||
'Psl\Asio\wrap',
|
'Psl\Asio\wrap',
|
||||||
'Psl\Internal\boolean',
|
'Psl\Internal\boolean',
|
||||||
'Psl\Internal\type',
|
'Psl\Internal\type',
|
||||||
|
32
tests/Psl/Fun/AfterTest.php
Normal file
32
tests/Psl/Fun/AfterTest.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Psl\Tests\Fun;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psl\Fun;
|
||||||
|
use Psl\Str;
|
||||||
|
|
||||||
|
final class AfterTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testItCombinesAFunctionToExecuteAFunctionAfterAnotherFunction(): void
|
||||||
|
{
|
||||||
|
$x = Fun\after(
|
||||||
|
fn (string $x): string => $x . ' world',
|
||||||
|
fn (string $z): string => $z . '!!'
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame('Hello world!!', $x('Hello'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCombinesAFunctionThatDealWithDifferentTypes(): void
|
||||||
|
{
|
||||||
|
$x = Fun\after(
|
||||||
|
fn (string $x): int => Str\length($x),
|
||||||
|
fn (int $z): string => $z . '!'
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame('5!', $x('Hello'));
|
||||||
|
}
|
||||||
|
}
|
40
tests/Psl/Fun/PipeTest.php
Normal file
40
tests/Psl/Fun/PipeTest.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Psl\Tests\Fun;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psl\Fun;
|
||||||
|
use Psl\Str;
|
||||||
|
|
||||||
|
final class PipeTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testItCombinesMultipleFunctionToExecutesInOrder(): void
|
||||||
|
{
|
||||||
|
$x = Fun\pipe(
|
||||||
|
fn (string $x): string => $x . ' world',
|
||||||
|
fn (string $y): string => $y . '?',
|
||||||
|
fn (string $z): string => $z . '!',
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame('Hello world?!', $x('Hello'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCombinesMultipleFunctionsThatDealWithDifferentTypes(): void
|
||||||
|
{
|
||||||
|
$x = Fun\pipe(
|
||||||
|
fn (string $x): int => Str\length($x),
|
||||||
|
fn (int $y): string => $y . '!'
|
||||||
|
);
|
||||||
|
|
||||||
|
self::assertSame('5!', $x('Hello'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItCanCreateAnEmptyCombination(): void
|
||||||
|
{
|
||||||
|
$x = Fun\pipe();
|
||||||
|
|
||||||
|
self::assertSame('Hello', $x('Hello'));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user