add reflection for applied function
This commit is contained in:
parent
fd3288a4ad
commit
596031d09e
16
src/Decorator.php
Normal file
16
src/Decorator.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2018 Kacper Donat
|
||||
*
|
||||
* @author Kacper "Kadet" Donat <kacper@kadet.net>
|
||||
*
|
||||
* Full license available in separate LICENSE file
|
||||
*/
|
||||
|
||||
namespace Kadet\Functional;
|
||||
|
||||
|
||||
interface Decorator
|
||||
{
|
||||
public function getDecorated();
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
namespace Kadet\Functional\Predicate;
|
||||
|
||||
|
||||
class ClosurePredicate extends AbstractPredicate
|
||||
use Kadet\Functional\Decorator;
|
||||
|
||||
class ClosurePredicate extends AbstractPredicate implements Decorator
|
||||
{
|
||||
/**
|
||||
* @var \Closure
|
||||
@ -31,4 +33,9 @@ class ClosurePredicate extends AbstractPredicate
|
||||
{
|
||||
return ($this->closure)(...$args);
|
||||
}
|
||||
|
||||
public function getDecorated()
|
||||
{
|
||||
return $this->closure;
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@ use function Kadet\Functional\predicate;
|
||||
* @param $expected
|
||||
*
|
||||
* @return \Kadet\Functional\Predicate
|
||||
* @throws \Exception
|
||||
*/
|
||||
function equals($expected): Predicate
|
||||
{
|
||||
@ -29,7 +28,6 @@ function equals($expected): Predicate
|
||||
* @param $expected
|
||||
*
|
||||
* @return \Kadet\Functional\Predicate
|
||||
* @throws \Exception
|
||||
*/
|
||||
function same($expected): Predicate
|
||||
{
|
||||
@ -42,7 +40,6 @@ function same($expected): Predicate
|
||||
* @param $expected
|
||||
*
|
||||
* @return \Kadet\Functional\Predicate
|
||||
* @throws \Exception
|
||||
*/
|
||||
function gt($expected): Predicate
|
||||
{
|
||||
@ -55,7 +52,6 @@ function gt($expected): Predicate
|
||||
* @param $expected
|
||||
*
|
||||
* @return \Kadet\Functional\Predicate
|
||||
* @throws \Exception
|
||||
*/
|
||||
function ge($expected): Predicate
|
||||
{
|
||||
@ -68,7 +64,6 @@ function ge($expected): Predicate
|
||||
* @param $expected
|
||||
*
|
||||
* @return \Kadet\Functional\Predicate
|
||||
* @throws \Exception
|
||||
*/
|
||||
function lt($expected): Predicate
|
||||
{
|
||||
@ -81,7 +76,6 @@ function lt($expected): Predicate
|
||||
* @param $expected
|
||||
*
|
||||
* @return \Kadet\Functional\Predicate
|
||||
* @throws \Exception
|
||||
*/
|
||||
function le($expected): Predicate
|
||||
{
|
||||
|
27
src/Reflection/ReflectionAppliedParameter.php
Normal file
27
src/Reflection/ReflectionAppliedParameter.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2018 Kacper Donat
|
||||
*
|
||||
* @author Kacper "Kadet" Donat <kacper@kadet.net>
|
||||
*
|
||||
* Full license available in separate LICENSE file
|
||||
*/
|
||||
|
||||
namespace Kadet\Functional\Reflection;
|
||||
|
||||
|
||||
class ReflectionAppliedParameter extends \ReflectionParameter
|
||||
{
|
||||
private $value;
|
||||
|
||||
public function __construct($function, string $parameter, $value)
|
||||
{
|
||||
parent::__construct($function, $parameter);
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
58
src/Reflection/ReflectionPartiallyAppliedFunction.php
Normal file
58
src/Reflection/ReflectionPartiallyAppliedFunction.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2018 Kacper Donat
|
||||
*
|
||||
* @author Kacper "Kadet" Donat <kacper@kadet.net>
|
||||
*
|
||||
* Full license available in separate LICENSE file
|
||||
*/
|
||||
|
||||
namespace Kadet\Functional\Reflection;
|
||||
|
||||
|
||||
use Kadet\Functional\Utils\PartiallyAppliedFunction;
|
||||
|
||||
class ReflectionPartiallyAppliedFunction extends \ReflectionFunction
|
||||
{
|
||||
public $applied;
|
||||
|
||||
public function __construct(PartiallyAppliedFunction $applied)
|
||||
{
|
||||
parent::__construct($applied->getDecorated());
|
||||
$this->applied = $applied;
|
||||
}
|
||||
|
||||
public function getNumberOfParameters()
|
||||
{
|
||||
return max(parent::getNumberOfParameters() - count($this->applied->getArguments()), 0);
|
||||
}
|
||||
|
||||
public function getNumberOfRequiredParameters()
|
||||
{
|
||||
return max(parent::getNumberOfRequiredParameters() - count($this->applied->getArguments()), 0);
|
||||
}
|
||||
|
||||
public function getNumberOfAppliedParameters()
|
||||
{
|
||||
return count($this->applied->getArguments());
|
||||
}
|
||||
|
||||
public function getAppliedParameters()
|
||||
{
|
||||
$applied = $this->applied->getArguments();
|
||||
$parameters = array_intersect_key(parent::getParameters(), $applied);
|
||||
|
||||
return array_map(function (\ReflectionParameter $parameter) use ($applied) {
|
||||
return new ReflectionAppliedParameter(
|
||||
$this->applied->getDecorated(),
|
||||
$parameter->name,
|
||||
$applied[$parameter->getPosition()]
|
||||
);
|
||||
}, $parameters);
|
||||
}
|
||||
|
||||
public function getParameters()
|
||||
{
|
||||
return array_diff_key(parent::getParameters(), $this->applied->getArguments());
|
||||
}
|
||||
}
|
@ -10,8 +10,11 @@
|
||||
namespace Kadet\Functional\Utils;
|
||||
|
||||
use const Kadet\Functional\_ as PLACEHOLDER;
|
||||
use Kadet\Functional\Decorator;
|
||||
use function Kadet\Functional\not;
|
||||
use function Kadet\Functional\Predicates\same;
|
||||
|
||||
class PartiallyAppliedFunction
|
||||
class PartiallyAppliedFunction implements Decorator
|
||||
{
|
||||
protected $callable;
|
||||
protected $arguments = [];
|
||||
@ -30,6 +33,11 @@ class PartiallyAppliedFunction
|
||||
}
|
||||
}
|
||||
|
||||
public function getArguments()
|
||||
{
|
||||
return array_filter($this->arguments, not(same(PLACEHOLDER)));
|
||||
}
|
||||
|
||||
public function __invoke(...$args)
|
||||
{
|
||||
$arguments = $this->prepareArguments($args);
|
||||
@ -50,4 +58,9 @@ class PartiallyAppliedFunction
|
||||
array_values($args)
|
||||
);
|
||||
}
|
||||
|
||||
public function getDecorated()
|
||||
{
|
||||
return $this->callable;
|
||||
}
|
||||
}
|
@ -48,10 +48,27 @@ class PartialApplicationTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
public function testPartialApplicationOfAppliedFunction()
|
||||
{
|
||||
|
||||
$applied = f\partial('array_merge', ['a'], _, ['c']);
|
||||
$double = f\partial($applied, _, ['d']);
|
||||
|
||||
$this->assertEquals(['a', 'b', 'c', 'd', 'e'], $double(['b'], ['e']));
|
||||
}
|
||||
|
||||
public function testDecoration()
|
||||
{
|
||||
$x = function() {};
|
||||
$applied = f\partial($x);
|
||||
|
||||
$this->assertSame($applied->getDecorated(), $x);
|
||||
}
|
||||
|
||||
public function testArgumentProviding()
|
||||
{
|
||||
$applied = f\partial('array_merge', ['a'], _, ['c']);
|
||||
|
||||
$this->assertSame(
|
||||
[0 => ['a'], 2 => ['c']],
|
||||
$applied->getArguments()
|
||||
);
|
||||
}
|
||||
}
|
70
tests/ReflectionPartialAppliedFunctionTest.php
Normal file
70
tests/ReflectionPartialAppliedFunctionTest.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright 2018 Kacper Donat
|
||||
*
|
||||
* @author Kacper "Kadet" Donat <kacper@kadet.net>
|
||||
*
|
||||
* Full license available in separate LICENSE file
|
||||
*/
|
||||
|
||||
use Kadet\Functional as f;
|
||||
use const Kadet\Functional\_;
|
||||
use Kadet\Functional\Reflection\ReflectionAppliedParameter;
|
||||
use Kadet\Functional\Reflection\ReflectionPartiallyAppliedFunction;
|
||||
|
||||
|
||||
class ReflectionPartialAppliedFunctionTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
private $function;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->function = f\partial(function (array $a, array $b, array $c, array $d = ['d']) {
|
||||
return array_merge($a, $b, $c, $d);
|
||||
}, ['a'], _, ['c']);
|
||||
}
|
||||
|
||||
public function testNumberOfParameters()
|
||||
{
|
||||
$reflection = new ReflectionPartiallyAppliedFunction($this->function);
|
||||
|
||||
$this->assertSame(2, $reflection->getNumberOfParameters());
|
||||
}
|
||||
|
||||
public function testNumberOfRequiredParameters()
|
||||
{
|
||||
$reflection = new ReflectionPartiallyAppliedFunction($this->function);
|
||||
|
||||
$this->assertSame(1, $reflection->getNumberOfRequiredParameters());
|
||||
}
|
||||
|
||||
public function testNumberOfAppliedParameters()
|
||||
{
|
||||
$reflection = new ReflectionPartiallyAppliedFunction($this->function);
|
||||
|
||||
$this->assertSame(2, $reflection->getNumberOfAppliedParameters());
|
||||
}
|
||||
|
||||
public function testParameters()
|
||||
{
|
||||
$reflection = new ReflectionPartiallyAppliedFunction($this->function);
|
||||
$parameters = $reflection->getParameters();
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(ReflectionParameter::class, $parameters);
|
||||
$this->assertCount(2, $parameters);
|
||||
$this->assertEquals([1, 3], array_keys($parameters));
|
||||
}
|
||||
|
||||
public function testAppliedParameters()
|
||||
{
|
||||
$reflection = new ReflectionPartiallyAppliedFunction($this->function);
|
||||
$parameters = $reflection->getAppliedParameters();
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(ReflectionAppliedParameter::class, $parameters);
|
||||
$this->assertCount(2, $parameters);
|
||||
$this->assertEquals([0, 2], array_keys($parameters));
|
||||
$this->assertEquals([0 => ['a'], 2 => ['c']], array_map(function(ReflectionAppliedParameter $parameter) {
|
||||
return $parameter->getValue();
|
||||
}, $parameters));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user