moved decorate implementation to dedicated intercept and pipe calls

This commit is contained in:
Fabio Ivona
2021-10-09 10:22:24 +02:00
parent 8835502074
commit 55376d32e5
5 changed files with 54 additions and 23 deletions

View File

@ -6,6 +6,7 @@ namespace Pest\Concerns;
use BadMethodCallException; use BadMethodCallException;
use Closure; use Closure;
use Pest\Expectation;
/** /**
* @internal * @internal
@ -18,7 +19,7 @@ trait Extendable
private static $extends = []; private static $extends = [];
/** @var array<string, array<Closure>> */ /** @var array<string, array<Closure>> */
private static $decorators = []; private static $pipes = [];
/** /**
* Register a custom extend. * Register a custom extend.
@ -28,9 +29,36 @@ trait Extendable
static::$extends[$name] = $extend; static::$extends[$name] = $extend;
} }
public static function decorate(string $name, Closure $decorator): void public static function pipe(string $name, Closure $pipe): void
{ {
static::$decorators[$name][] = $decorator; self::$pipes[$name][] = $pipe;
}
/**
* @param string|Closure $filter
*/
public static function intercept(string $name, $filter, Closure $handler): void
{
if (is_string($filter)) {
$filter = function ($value) use ($filter): bool {
return $value instanceof $filter;
};
}
//@phpstan-ignore-next-line
self::pipe($name, function (...$arguments) use ($handler, $filter) {
$next = array_pop($arguments);
//@phpstan-ignore-next-line
if ($filter($this->value)) {
//@phpstan-ignore-next-line
$handler->bindTo($this, get_class($this))(...$arguments);
return;
}
$next(...$arguments);
});
} }
/** /**
@ -42,24 +70,24 @@ trait Extendable
} }
/** /**
* Checks if decorator are registered. * Checks if pipes are registered for a given expectation.
*/ */
public static function hasDecorators(string $name): bool public static function hasPipes(string $name): bool
{ {
return array_key_exists($name, static::$decorators); return array_key_exists($name, static::$pipes);
} }
/** /**
* @return array<int, Closure> * @return array<int, Closure>
*/ */
public function decorators(string $name, object $context, string $scope): array public function pipes(string $name, object $context, string $scope): array
{ {
if (!self::hasDecorators($name)) { if (!self::hasPipes($name)) {
return []; return [];
} }
$decorators = []; $decorators = [];
foreach (self::$decorators[$name] as $decorator) { foreach (self::$pipes[$name] as $decorator) {
$decorators[] = $decorator->bindTo($context, $scope); $decorators[] = $decorator->bindTo($context, $scope);
} }

View File

@ -261,7 +261,7 @@ final class Expectation
} }
Pipeline::send(...$parameters) Pipeline::send(...$parameters)
->through($this->decorators($method, $this, Expectation::class)) ->through($this->pipes($method, $this, Expectation::class))
->finally(function ($parameters) use ($method): void { ->finally(function ($parameters) use ($method): void {
$this->callExpectation($method, $parameters); $this->callExpectation($method, $parameters);
}); });

View File

@ -31,8 +31,16 @@ final class Extendable
$this->extendableClass::extend($name, $extend); $this->extendableClass::extend($name, $extend);
} }
public function decorate(string $name, Closure $extend): void public function pipe(string $name, Closure $pipe): void
{ {
$this->extendableClass::decorate($name, $extend); $this->extendableClass::pipe($name, $pipe);
}
/**
* @param string|Closure $filter
*/
public function intercept(string $name, $filter, Closure $handler): void
{
$this->extendableClass::intercept($name, $filter, $handler);
} }
} }

View File

@ -55,7 +55,9 @@ final class Pipeline
{ {
return function ($stack, $pipe): Closure { return function ($stack, $pipe): Closure {
return function (...$passable) use ($stack, $pipe) { return function (...$passable) use ($stack, $pipe) {
return $pipe($stack, ...$passable); $passable[] = $stack;
return $pipe(...$passable);
}; };
}; };
} }

View File

@ -23,7 +23,7 @@ class Character
} }
} }
expect()->decorate('toBe', function ($next, $expected) { expect()->pipe('toBe', function ($expected, $next) {
if ($this->value instanceof Character) { if ($this->value instanceof Character) {
assertInstanceOf(Character::class, $expected); assertInstanceOf(Character::class, $expected);
assertEquals($this->value->value, $expected->value); assertEquals($this->value->value, $expected->value);
@ -34,15 +34,8 @@ expect()->decorate('toBe', function ($next, $expected) {
$next($expected); $next($expected);
}); });
expect()->decorate('toBe', function ($next, $expected) { expect()->intercept('toBe', Number::class, function ($expected) {
if ($this->value instanceof Number) { assertEquals($this->value->value, $expected->value);
assertInstanceOf(Number::class, $expected);
assertEquals($this->value->value, $expected->value);
return;
}
$next($expected);
}); });
test('pass', function () { test('pass', function () {