Compare commits
3 Commits
0b58a4c620
...
12918eb3cb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12918eb3cb | ||
|
|
fff1013711 | ||
|
|
9e348d929c |
@ -12,6 +12,8 @@ namespace Kadet\Functional\Predicates;
|
|||||||
|
|
||||||
use function Kadet\Functional\predicate;
|
use function Kadet\Functional\predicate;
|
||||||
use Kadet\Functional\Predicate\ClosurePredicate;
|
use Kadet\Functional\Predicate\ClosurePredicate;
|
||||||
|
use Kadet\Functional\Transforms as t;
|
||||||
|
use Kadet\Functional as f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $method
|
* @param string $method
|
||||||
@ -22,11 +24,7 @@ use Kadet\Functional\Predicate\ClosurePredicate;
|
|||||||
*/
|
*/
|
||||||
function method(string $method, $predicate, ...$args)
|
function method(string $method, $predicate, ...$args)
|
||||||
{
|
{
|
||||||
$predicate = predicate($predicate);
|
return predicate(f\pipe(t\method($method, ...$args), $predicate));
|
||||||
|
|
||||||
return new ClosurePredicate(function ($object) use ($method, $predicate, $args) {
|
|
||||||
return $predicate($object->{$method}($args));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,18 +33,20 @@ function method(string $method, $predicate, ...$args)
|
|||||||
*
|
*
|
||||||
* @return \Kadet\Functional\Predicate
|
* @return \Kadet\Functional\Predicate
|
||||||
*/
|
*/
|
||||||
function property(string $property, $predicate) {
|
function property(string $property, $predicate)
|
||||||
$predicate = predicate($predicate);
|
{
|
||||||
|
return predicate(f\pipe(t\property($property), $predicate));
|
||||||
return new ClosurePredicate(function ($object) use ($property, $predicate) {
|
|
||||||
if (isset($object->$property)) {
|
|
||||||
return $predicate($object->$property);
|
|
||||||
} elseif (method_exists($object, $getter = 'get'.ucfirst($property))) {
|
|
||||||
return $predicate($object->$getter());
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
/**
|
||||||
|
* @param string $field
|
||||||
|
* @param $predicate
|
||||||
|
*
|
||||||
|
* @return \Kadet\Functional\Predicate
|
||||||
|
*/
|
||||||
|
function field(string $field, $predicate)
|
||||||
|
{
|
||||||
|
return predicate(f\pipe(t\field($field), $predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
function instance(string $class)
|
function instance(string $class)
|
||||||
|
|||||||
@ -23,126 +23,176 @@ class ReflectionDecoratedFunction extends \ReflectionFunction
|
|||||||
$this->reflection = reflect($decorated);
|
$this->reflection = reflect($decorated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function inNamespace()
|
public function inNamespace()
|
||||||
{
|
{
|
||||||
return $this->reflection->inNamespace();
|
return $this->reflection->inNamespace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function isClosure()
|
public function isClosure()
|
||||||
{
|
{
|
||||||
return $this->reflection->isVariadic();
|
return $this->reflection->isVariadic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function isDeprecated()
|
public function isDeprecated()
|
||||||
{
|
{
|
||||||
return $this->reflection->isDeprecated();
|
return $this->reflection->isDeprecated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function isInternal()
|
public function isInternal()
|
||||||
{
|
{
|
||||||
return $this->reflection->isInternal();
|
return $this->reflection->isInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function isUserDefined()
|
public function isUserDefined()
|
||||||
{
|
{
|
||||||
return $this->reflection->isUserDefined();
|
return $this->reflection->isUserDefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getClosureThis()
|
public function getClosureThis()
|
||||||
{
|
{
|
||||||
return $this->reflection->getClosureThis();
|
return $this->reflection->getClosureThis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getClosureScopeClass()
|
public function getClosureScopeClass()
|
||||||
{
|
{
|
||||||
return $this->reflection->getClosureScopeClass();
|
return $this->reflection->getClosureScopeClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getDocComment()
|
public function getDocComment()
|
||||||
{
|
{
|
||||||
return $this->reflection->getDocComment();
|
return $this->reflection->getDocComment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getEndLine()
|
public function getEndLine()
|
||||||
{
|
{
|
||||||
return $this->reflection->getEndLine();
|
return $this->reflection->getEndLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getExtension()
|
public function getExtension()
|
||||||
{
|
{
|
||||||
return $this->reflection->getExtension();
|
return $this->reflection->getExtension();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getExtensionName()
|
public function getExtensionName()
|
||||||
{
|
{
|
||||||
return $this->reflection->getExtensionName();
|
return $this->reflection->getExtensionName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getFileName()
|
public function getFileName()
|
||||||
{
|
{
|
||||||
return $this->reflection->getFileName();
|
return $this->reflection->getFileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->reflection->getName();
|
return $this->reflection->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getNamespaceName()
|
public function getNamespaceName()
|
||||||
{
|
{
|
||||||
return $this->reflection->getNamespaceName();
|
return $this->reflection->getNamespaceName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getNumberOfParameters()
|
public function getNumberOfParameters()
|
||||||
{
|
{
|
||||||
return $this->reflection->getNumberOfParameters();
|
return $this->reflection->getNumberOfParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getNumberOfRequiredParameters()
|
public function getNumberOfRequiredParameters()
|
||||||
{
|
{
|
||||||
return $this->reflection->getNumberOfRequiredParameters();
|
return $this->reflection->getNumberOfRequiredParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getParameters()
|
public function getParameters()
|
||||||
{
|
{
|
||||||
return $this->reflection->getParameters();
|
return $this->reflection->getParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getReturnType()
|
public function getReturnType()
|
||||||
{
|
{
|
||||||
return $this->reflection->getReturnType();
|
return $this->reflection->getReturnType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getShortName()
|
public function getShortName()
|
||||||
{
|
{
|
||||||
return $this->reflection->getShortName();
|
return $this->reflection->getShortName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getStartLine()
|
public function getStartLine()
|
||||||
{
|
{
|
||||||
return $this->reflection->getStartLine();
|
return $this->reflection->getStartLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function getStaticVariables()
|
public function getStaticVariables()
|
||||||
{
|
{
|
||||||
return $this->reflection->getStaticVariables();
|
return $this->reflection->getStaticVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function hasReturnType()
|
public function hasReturnType()
|
||||||
{
|
{
|
||||||
return $this->reflection->hasReturnType();
|
return $this->reflection->hasReturnType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function returnsReference()
|
public function returnsReference()
|
||||||
{
|
{
|
||||||
return $this->reflection->returnsReference();
|
return $this->reflection->returnsReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function isGenerator()
|
public function isGenerator()
|
||||||
{
|
{
|
||||||
return $this->reflection->isGenerator();
|
return $this->reflection->isGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
|
||||||
public function isVariadic()
|
public function isVariadic()
|
||||||
{
|
{
|
||||||
return $this->reflection->isVariadic();
|
return $this->reflection->isVariadic();
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class CurriedFunction extends PartiallyAppliedFunction
|
|||||||
* @param int|null $threshold
|
* @param int|null $threshold
|
||||||
* @param array $args
|
* @param array $args
|
||||||
*/
|
*/
|
||||||
public function __construct(callable $callable, int $threshold = null, ...$args)
|
public function __construct(callable $callable, ?int $threshold = null, ...$args)
|
||||||
{
|
{
|
||||||
parent::__construct($callable, ...$args);
|
parent::__construct($callable, ...$args);
|
||||||
$this->threshold = $threshold ?: reflect($callable)->getNumberOfRequiredParameters();
|
$this->threshold = $threshold ?: reflect($callable)->getNumberOfRequiredParameters();
|
||||||
@ -36,7 +36,7 @@ class CurriedFunction extends PartiallyAppliedFunction
|
|||||||
return $this->threshold;
|
return $this->threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withThreshold(int $threshold = null)
|
public function withThreshold(?int $threshold = null)
|
||||||
{
|
{
|
||||||
return new static($this, $threshold);
|
return new static($this, $threshold);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ function apply(callable $callable, ...$args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function curry(callable $callable, int $threshold = null, ...$args): CurriedFunction
|
function curry(callable $callable, ?int $threshold = null, ...$args): CurriedFunction
|
||||||
{
|
{
|
||||||
return new CurriedFunction($callable, $threshold, ...$args);
|
return new CurriedFunction($callable, $threshold, ...$args);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,31 +27,54 @@ function predicate($predicate): Predicate
|
|||||||
case $predicate instanceof Predicate:
|
case $predicate instanceof Predicate:
|
||||||
return $predicate;
|
return $predicate;
|
||||||
case is_callable($predicate):
|
case is_callable($predicate):
|
||||||
return new ClosurePredicate(\Closure::fromCallable($predicate));
|
return new ClosurePredicate(closure($predicate));
|
||||||
default:
|
default:
|
||||||
throw new \InvalidArgumentException('$predicate is not valid predicate.');
|
throw new \InvalidArgumentException('$predicate is not valid predicate.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ref($callable)
|
function closure($callable)
|
||||||
{
|
{
|
||||||
if (is_array($callable)) {
|
switch (true) {
|
||||||
|
case $callable instanceof \Closure:
|
||||||
|
return $callable;
|
||||||
|
|
||||||
|
case is_array($callable):
|
||||||
list($object, $method) = $callable;
|
list($object, $method) = $callable;
|
||||||
$reflection = new \ReflectionObject($object);
|
$reflection = new \ReflectionObject($object);
|
||||||
$method = $reflection->getMethod($method);
|
$method = $reflection->getMethod($method);
|
||||||
|
|
||||||
if (!$method->isPublic()) {
|
if (!$method->isPublic()) {
|
||||||
$class = debug_backtrace()[1]['class'] ?? null;
|
$backtrace = debug_backtrace();
|
||||||
|
foreach ($backtrace as $trace) {
|
||||||
|
if (isset($trace['class']) && $trace['class'] === $reflection->name) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ($reflection->name !== $class) {
|
if ((isset($trace['class']) && strpos($trace['class'], "Kadet\\Functional\\") !== 0)
|
||||||
|
|| ($trace['function'] && strpos($trace['function'], "Kadet\\Functional\\") !== 0)) {
|
||||||
throw new NoAccessException(sprintf('Method "%s" can only be accessed from inside of object.', $method->name));
|
throw new NoAccessException(sprintf('Method "%s" can only be accessed from inside of object.', $method->name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $method->getClosure($object);
|
return $method->getClosure($object);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return \Closure::fromCallable($callable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return \Closure::fromCallable($callable);
|
function arify($callable, int $arity)
|
||||||
|
{
|
||||||
|
return function (...$args) use ($callable, $arity) {
|
||||||
|
return $callable(...array_slice($args, 0, $arity));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function ref($callable, ?int $arity = null) {
|
||||||
|
$closure = closure($callable);
|
||||||
|
return $arity !== null ? arify($callable, $arity) : $closure;
|
||||||
}
|
}
|
||||||
|
|
||||||
function not($predicate)
|
function not($predicate)
|
||||||
@ -101,6 +124,10 @@ function repeat($times, callable $callback)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function identity($x) {
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param callable $callable
|
* @param callable $callable
|
||||||
*
|
*
|
||||||
|
|||||||
118
tests/ObjectTransformsTest.php
Normal file
118
tests/ObjectTransformsTest.php
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright 2019 Kacper Donat
|
||||||
|
*
|
||||||
|
* @author Kacper "Kadet" Donat <kacper@kadet.net>
|
||||||
|
*
|
||||||
|
* Full license available in separate LICENSE file
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PropertiesObject {
|
||||||
|
private $getter;
|
||||||
|
private $magic = [];
|
||||||
|
public $field = 'value';
|
||||||
|
|
||||||
|
public function __construct($field, $getter, array $magic = [])
|
||||||
|
{
|
||||||
|
$this->field = $field;
|
||||||
|
$this->getter = $getter;
|
||||||
|
$this->magic = $magic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getValue()
|
||||||
|
{
|
||||||
|
return $this->getter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($name)
|
||||||
|
{
|
||||||
|
return $this->magic[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return __CLASS__;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ObjectTransformsTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
use RandomDataTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider randomDataProvider
|
||||||
|
*/
|
||||||
|
public function testFieldTransform($data = null)
|
||||||
|
{
|
||||||
|
$object = new PropertiesObject($data, null, []);
|
||||||
|
$transform = \Kadet\Functional\Transforms\field('field');
|
||||||
|
|
||||||
|
$this->assertSame($transform($object), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider randomDataProvider
|
||||||
|
*/
|
||||||
|
public function testFieldTransformMagic($data = null)
|
||||||
|
{
|
||||||
|
$object = new PropertiesObject(false, false, ['magic' => $data]);
|
||||||
|
$transform = \Kadet\Functional\Transforms\property('magic');
|
||||||
|
|
||||||
|
$this->assertSame($transform($object), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider randomDataProvider
|
||||||
|
*/
|
||||||
|
public function testPropertyTransformGetter($data = null)
|
||||||
|
{
|
||||||
|
$object = new PropertiesObject(false, $data, []);
|
||||||
|
$transform = \Kadet\Functional\Transforms\property('value');
|
||||||
|
|
||||||
|
$this->assertSame($transform($object), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider randomDataProvider
|
||||||
|
*/
|
||||||
|
public function testGetterTransform($data = null)
|
||||||
|
{
|
||||||
|
$object = new PropertiesObject(false, $data, []);
|
||||||
|
$transform = \Kadet\Functional\Transforms\getter('value');
|
||||||
|
|
||||||
|
$this->assertSame($transform($object), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider randomDataProvider
|
||||||
|
*/
|
||||||
|
public function testPropertyTransformField($data = null)
|
||||||
|
{
|
||||||
|
$object = new PropertiesObject($data, false, []);
|
||||||
|
$transform = \Kadet\Functional\Transforms\property('field');
|
||||||
|
|
||||||
|
$this->assertSame($transform($object), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider randomDataProvider
|
||||||
|
*/
|
||||||
|
public function testPropertyTransformMagic($data = null)
|
||||||
|
{
|
||||||
|
$object = new PropertiesObject(false, false, ['magic' => $data]);
|
||||||
|
$transform = \Kadet\Functional\Transforms\property('magic');
|
||||||
|
|
||||||
|
$this->assertSame($transform($object), $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider randomDataProvider
|
||||||
|
*/
|
||||||
|
public function testMethodTransform($data = null)
|
||||||
|
{
|
||||||
|
$object = new PropertiesObject(false, false);
|
||||||
|
$transform = \Kadet\Functional\Transforms\method('__toString');
|
||||||
|
|
||||||
|
$this->assertSame($transform($object), PropertiesObject::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use function Kadet\Functional\apply;
|
use function Kadet\Functional\apply;
|
||||||
|
use function Kadet\Functional\arify;
|
||||||
use function Kadet\Functional\ref;
|
use function Kadet\Functional\ref;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,8 +30,15 @@ class TestObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RandomTest extends \PHPUnit\Framework\TestCase
|
class ReferencingTest extends \PHPUnit\Framework\TestCase
|
||||||
{
|
{
|
||||||
|
public function testReferenceClosure()
|
||||||
|
{
|
||||||
|
$f = function () { };
|
||||||
|
|
||||||
|
$this->assertSame($f, ref($f));
|
||||||
|
}
|
||||||
|
|
||||||
public function testApplicationOfArrayNotation()
|
public function testApplicationOfArrayNotation()
|
||||||
{
|
{
|
||||||
$object = new TestObject();
|
$object = new TestObject();
|
||||||
@ -54,4 +62,32 @@ class RandomTest extends \PHPUnit\Framework\TestCase
|
|||||||
|
|
||||||
ref([$object, 'priv']);
|
ref([$object, 'priv']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSetFunctionArity()
|
||||||
|
{
|
||||||
|
$f = function (...$args) {
|
||||||
|
return count($args);
|
||||||
|
};
|
||||||
|
|
||||||
|
$f = arify($f, 2);
|
||||||
|
|
||||||
|
$this->assertSame(1, $f(1));
|
||||||
|
$this->assertSame(2, $f(1, 2));
|
||||||
|
$this->assertSame(2, $f(1, 2, 3));
|
||||||
|
$this->assertSame(2, $f(1, 2, 3, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testReferencingWithSpecificArity()
|
||||||
|
{
|
||||||
|
$f = function (...$args) {
|
||||||
|
return count($args);
|
||||||
|
};
|
||||||
|
|
||||||
|
$f = ref($f, 2);
|
||||||
|
|
||||||
|
$this->assertSame(1, $f(1));
|
||||||
|
$this->assertSame(2, $f(1, 2));
|
||||||
|
$this->assertSame(2, $f(1, 2, 3));
|
||||||
|
$this->assertSame(2, $f(1, 2, 3, 4));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user