Commit 66b34b7a authored by Sebastian Kehr's avatar Sebastian Kehr 🚣🏼
Browse files

introduced stop flags (refs #12817)

parent bfebef65
......@@ -14,7 +14,7 @@
}
},
"autoload-dev": {
"psr-4": { "finc\\Rules\\": "test/" }
"psr-4": { "finc\\Rules\\": "tests/" }
},
"require-dev": {
"phpunit/phpunit": "^5"
......
......@@ -41,6 +41,7 @@ use Symfony\Component\ExpressionLanguage\ExpressionLanguage as Engine;
*/
class Evaluator
{
const STOP_FLAG = 'STOP';
/**
* @var Engine The engine to use for rule evaluation.
*/
......@@ -51,21 +52,31 @@ class Evaluator
*/
protected $rules;
/**
* @var string[] List of context variable names wich will stop further rule
* evaluation when set to some truthy value.
*/
protected $stopFlags;
/**
* Constructor.
*
* @param array $rules List of rules to be evaluated.
* @param array $rules List of rules to be evaluated.
* @param string[] $stopFlag
*/
public function __construct(array $rules = [])
public function __construct(array $rules, array $stopFlags = [])
{
$this->engine = new Engine;
$this->rules = $rules;
$this->stopFlags = $stopFlags;
uksort($this->rules, function ($firstIdx, $secondIdx) {
uksort(
$this->rules, function ($firstIdx, $secondIdx) {
$firstPrio = intval($this->rules[$firstIdx][0]);
$secondPrio = intval($this->rules[$secondIdx][0]);
return $secondPrio - $firstPrio ?: $secondIdx - $firstIdx;
});
}
);
}
/**
......@@ -75,6 +86,8 @@ class Evaluator
*/
public function __invoke(array $context = [])
{
$stopFlags = array_fill_keys($this->stopFlags, false);
$context = array_merge($stopFlags, $context);
return $this->evaluate($context, ...$this->rules);
}
......@@ -96,6 +109,10 @@ class Evaluator
return $context;
}
foreach ($this->stopFlags as $stopFlag) {
if ($context[$stopFlag]) return $context;
}
list(, $head, $body) = $rule;
$context[$head] = $this->engine->evaluate($body, $context);
return $this->evaluate($context, ...$rules);
......
......@@ -43,15 +43,33 @@ class EvaluatorTest extends TestCase
{
protected $rules
= [
[50, 'e', 'd * d'],
['100', 'd', 'a.f("xyz") * 2 - 2']
// 5th rule
[80, 't', '[1]'],
// 4th rule
[85, 'e', 'e + e'],
// 3rd rule
[90, 's', '[]'],
// 2nd rule
[95, 'e', '1'],
// 1st rule
['100', 'd', 'a.f("xyz") * 2 - 2'],
// last rule due to lowest priority
[75, 'e', 'd * d'],
];
public function test()
public function testSimple()
{
$evaluator = new Evaluator($this->rules);
$initialContext = ['a' => new ContextObject, 'b' => 3];
$resultContext = $evaluator($initialContext);
$this->assertArraySubset(['d' => 4, 'e' => 16], $resultContext);
}
public function testStop()
{
$evaluator = new Evaluator($this->rules, ['s', 't']);
$initialContext = ['a' => new ContextObject, 'b' => 3];
$resultContext = $evaluator($initialContext);
$this->assertArraySubset(['d' => 4, 'e' => 2], $resultContext);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment