commit 40f8bfeab8ff89c537a8b1ff1567234054da0535 Author: Kacper Donat Date: Wed Feb 28 21:37:37 2018 +0100 proof of concept diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4dfe93e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Created by .ignore support plugin (hsz.mobi) +/.idea/ + +# PHP +/vendor/ +/node_modules/ + +test.*.php \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..5f34b0f --- /dev/null +++ b/composer.json @@ -0,0 +1,26 @@ +{ + "name": "kadet/predicate", + "description": "Functional library for PHP", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Kacper Donat", + "email": "kadet1090@gmail.com" + } + ], + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "autoload": { + "psr-4": { + "Kadet\\Functional\\": "./src/" + }, + "files": [ + "./src/functions.php" + ] + } +} diff --git a/src/Predicate.php b/src/Predicate.php new file mode 100644 index 0000000..0247394 --- /dev/null +++ b/src/Predicate.php @@ -0,0 +1,21 @@ + + * + * Full license available in separate LICENSE file + */ + +namespace Kadet\Functional; + + +interface Predicate +{ + public function __invoke(...$args): bool; + + public function not(): Predicate; + + public function and(...$predicate): Predicate; + public function or(...$predicate): Predicate; +} \ No newline at end of file diff --git a/src/Predicate/AbstractPredicate.php b/src/Predicate/AbstractPredicate.php new file mode 100644 index 0000000..bccab4f --- /dev/null +++ b/src/Predicate/AbstractPredicate.php @@ -0,0 +1,34 @@ + + * + * Full license available in separate LICENSE file + */ + +namespace Kadet\Functional\Predicate; + + +use Kadet\Functional\Predicate; +use function Kadet\Functional\predicate; + +abstract class AbstractPredicate implements Predicate +{ + public function not(): Predicate + { + return new NegatedPredicate($this); + } + + public function and(...$predicate): Predicate + { + array_unshift($predicate, $this); + return new AllOfPredicate(...array_map(predicate::class, $predicate)); + } + + public function or(...$predicate): Predicate + { + array_unshift($predicate, $this); + return new AnyOfPredicate(...array_map(predicate::class, $predicate)); + } +} \ No newline at end of file diff --git a/src/Predicate/AllOfPredicate.php b/src/Predicate/AllOfPredicate.php new file mode 100644 index 0000000..7097cfc --- /dev/null +++ b/src/Predicate/AllOfPredicate.php @@ -0,0 +1,44 @@ + + * + * Full license available in separate LICENSE file + */ + +namespace Kadet\Functional\Predicate; + + +use Kadet\Functional\Predicate; + +class AllOfPredicate extends AbstractPredicate +{ + /** + * Array of predicates to check if all are satisfied. + * @var \Kadet\Functional\Predicate[] + */ + private $predicates = []; + + public function __construct(Predicate ...$predicates) + { + $this->predicates = $predicates; + } + + public function and(...$predicate): Predicate + { + $predicate = array_merge($this->predicates, $predicate); + return parent::and($predicate); + } + + public function __invoke(...$args): bool + { + foreach ($this->predicates as $predicate) { + if (!$predicate(...$args)) { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/src/Predicate/AnyOfPredicate.php b/src/Predicate/AnyOfPredicate.php new file mode 100644 index 0000000..19f3cb7 --- /dev/null +++ b/src/Predicate/AnyOfPredicate.php @@ -0,0 +1,45 @@ + + * + * Full license available in separate LICENSE file + */ + +namespace Kadet\Functional\Predicate; + + +use Kadet\Functional\Predicate; + +class AnyOfPredicate extends AbstractPredicate +{ + /** + * Array of predicates to check if all are satisfied. + * @var \Kadet\Functional\Predicate[] + */ + private $predicates = []; + + public function __construct(Predicate ...$predicates) + { + $this->predicates = $predicates; + } + + public function or(...$predicate): Predicate + { + $predicate = array_merge($this->predicates, $predicate); + return parent::or($predicate); + } + + + public function __invoke(...$args): bool + { + foreach ($this->predicates as $predicate) { + if ($predicate(...$args)) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/src/Predicate/ClosurePredicate.php b/src/Predicate/ClosurePredicate.php new file mode 100644 index 0000000..985aa6a --- /dev/null +++ b/src/Predicate/ClosurePredicate.php @@ -0,0 +1,34 @@ + + * + * Full license available in separate LICENSE file + */ + +namespace Kadet\Functional\Predicate; + + +class ClosurePredicate extends AbstractPredicate +{ + /** + * @var \Closure + */ + private $closure; + + /** + * ClosurePredicate constructor. + * + * @param \Closure $closure + */ + public function __construct(\Closure $closure) + { + $this->closure = $closure; + } + + public function __invoke(...$args): bool + { + return ($this->closure)(...$args); + } +} \ No newline at end of file diff --git a/src/Predicate/NegatedPredicate.php b/src/Predicate/NegatedPredicate.php new file mode 100644 index 0000000..cbcc2e0 --- /dev/null +++ b/src/Predicate/NegatedPredicate.php @@ -0,0 +1,38 @@ + + * + * Full license available in separate LICENSE file + */ + +namespace Kadet\Functional\Predicate; + + +use Kadet\Functional\Predicate; + +class NegatedPredicate extends AbstractPredicate +{ + /** + * Predicate to be negated. + * @var \Kadet\Functional\Predicate + */ + private $negated; + + public function __construct(Predicate $predicate) + { + $this->negated = $predicate; + } + + public function not(): Predicate + { + // negation of negations is plain value + return $this->negated; + } + + public function __invoke(...$args): bool + { + return !($this->negated)(...$args); + } +} \ No newline at end of file diff --git a/src/functions.php b/src/functions.php new file mode 100644 index 0000000..d906ae7 --- /dev/null +++ b/src/functions.php @@ -0,0 +1,26 @@ +