Skip to content

Commit 206217e

Browse files
committed
Merge pull request #31 from norzechowicz/aggregate-expanders
Aggregate expanders
2 parents 459f4a8 + dec1895 commit 206217e

File tree

17 files changed

+281
-65
lines changed

17 files changed

+281
-65
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ $match = $matcher->match("lorem ipsum dolor", "@string@")
5656
* ``lowerThan($boundry)``
5757
* ``greaterThan($boundry)``
5858
* ``inArray($value)``
59+
* ``oneOf(...$expanders)`` - example usage ``"@[email protected](contains('foo'), contains('bar'), contains('baz'))"``
5960

6061
##Example usage
6162

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Coduo\PHPMatcher\Exception;
4+
5+
class InvalidArgumentException extends Exception
6+
{
7+
}

src/Coduo/PHPMatcher/Factory/SimpleFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,6 @@ protected function buildScalarMatchers()
5959
*/
6060
protected function buildParser()
6161
{
62-
return new Parser(new Lexer());
62+
return new Parser(new Lexer(), new Parser\ExpanderInitializer());
6363
}
6464
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
namespace Coduo\PHPMatcher\Matcher\Pattern\Expander;
4+
5+
use Coduo\PHPMatcher\Matcher\Pattern\PatternExpander;
6+
use Coduo\ToString\String;
7+
8+
class OneOf implements PatternExpander
9+
{
10+
/**
11+
* @var PatternExpander[]
12+
*/
13+
protected $expanders;
14+
15+
protected $error;
16+
17+
public function __construct()
18+
{
19+
if (func_num_args() < 2) {
20+
throw new \InvalidArgumentException("OneOf expander require at least two expanders.");
21+
}
22+
foreach (func_get_args() as $argument) {
23+
if (!$argument instanceof PatternExpander) {
24+
throw new \InvalidArgumentException("OneOf expander require each argument to be a valid PatternExpander.");
25+
}
26+
27+
$this->expanders[] = $argument;
28+
}
29+
}
30+
31+
/**
32+
* @param $value
33+
* @return boolean
34+
*/
35+
public function match($value)
36+
{
37+
foreach ($this->expanders as $expander) {
38+
if ($expander->match($value)) {
39+
return true;
40+
}
41+
}
42+
43+
$this->error = sprintf("Any expander available in OneOf expander does not match \"%s\".", new String($value));
44+
return false;
45+
}
46+
47+
/**
48+
* @return string|null
49+
*/
50+
public function getError()
51+
{
52+
return $this->error;
53+
}
54+
}

src/Coduo/PHPMatcher/Parser.php

Lines changed: 10 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44

55
use Coduo\PHPMatcher\AST;
66
use Coduo\PHPMatcher\Exception\Exception;
7-
use Coduo\PHPMatcher\Exception\InvalidExpanderTypeException;
87
use Coduo\PHPMatcher\Exception\PatternException;
9-
use Coduo\PHPMatcher\Exception\UnknownExpanderClassException;
108
use Coduo\PHPMatcher\Exception\UnknownExpanderException;
119
use Coduo\PHPMatcher\Matcher\Pattern;
10+
use Coduo\PHPMatcher\Parser\ExpanderInitializer;
1211

1312
class Parser
1413
{
@@ -20,24 +19,17 @@ class Parser
2019
private $lexer;
2120

2221
/**
23-
* @var array
22+
* @var ExpanderInitializer
2423
*/
25-
private $expanderDefinitions = array(
26-
"startsWith" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\StartsWith",
27-
"endsWith" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\EndsWith",
28-
"notEmpty" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\NotEmpty",
29-
"lowerThan" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\LowerThan",
30-
"greaterThan" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\GreaterThan",
31-
"inArray" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\InArray",
32-
"contains" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\Contains"
33-
);
24+
private $expanderInitializer;
3425

3526
/**
3627
* @param Lexer $lexer
3728
*/
38-
public function __construct(Lexer $lexer)
29+
public function __construct(Lexer $lexer, ExpanderInitializer $expanderInitializer)
3930
{
4031
$this->lexer = $lexer;
32+
$this->expanderInitializer = $expanderInitializer;
4133
}
4234

4335
/**
@@ -64,11 +56,7 @@ public function parse($pattern)
6456
$AST = $this->getAST($pattern);
6557
$pattern = new Pattern\TypePattern((string) $AST->getType());
6658
foreach ($AST->getExpanders() as $expander) {
67-
if (!array_key_exists($expander->getName(), $this->expanderDefinitions)) {
68-
throw new UnknownExpanderException(sprintf("Unknown expander \"%s\"", $expander->getName()));
69-
}
70-
71-
$pattern->addExpander($this->initializeExpander($expander));
59+
$pattern->addExpander($this->expanderInitializer->initialize($expander));
7260
}
7361

7462
return $pattern;
@@ -84,20 +72,6 @@ public function getAST($pattern)
8472
return $this->getPattern();
8573
}
8674

87-
/**
88-
* @param $expanderName
89-
* @param $expanderFQCN Fully-Qualified Class Name that implements PatternExpander interface
90-
* @throws UnknownExpanderClassException
91-
*/
92-
public function addExpanderDefinition($expanderName, $expanderFQCN)
93-
{
94-
if (!class_exists($expanderFQCN)) {
95-
throw new UnknownExpanderClassException(sprintf("Class \"%s\" does not exists.", $expanderFQCN));
96-
}
97-
98-
$this->expanderDefinitions[$expanderName] = $expanderFQCN;
99-
}
100-
10175
/**
10276
* Create AST root
10377
*
@@ -222,6 +196,10 @@ private function getNextArgumentValue()
222196
return $this->getArrayArgument();
223197
}
224198

199+
if ($this->lexer->isNextToken(Lexer::T_EXPANDER_NAME)) {
200+
return $this->getNextExpanderNode();
201+
}
202+
225203
if (!$this->lexer->isNextTokenAny($validArgumentTypes)) {
226204
$this->unexpectedSyntaxError($this->lexer->lookahead, "string, number, boolean or null argument");
227205
}
@@ -341,23 +319,4 @@ private function endOfPattern()
341319
{
342320
return is_null($this->lexer->lookahead);
343321
}
344-
345-
/**
346-
* @param AST\Expander $expander
347-
* @throws InvalidExpanderTypeException
348-
* @return Pattern\PatternExpander
349-
*/
350-
private function initializeExpander(AST\Expander $expander)
351-
{
352-
$reflection = new \ReflectionClass($this->expanderDefinitions[$expander->getName()]);
353-
$expander = !$expander->hasArguments()
354-
? $reflection->newInstance()
355-
: $reflection->newInstanceArgs($expander->getArguments());
356-
357-
if (!$expander instanceof Pattern\PatternExpander) {
358-
throw new InvalidExpanderTypeException();
359-
}
360-
361-
return $expander;
362-
}
363322
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
namespace Coduo\PHPMatcher\Parser;
4+
5+
use Coduo\PHPMatcher\AST\Expander;
6+
use Coduo\PHPMatcher\Exception\InvalidArgumentException;
7+
use Coduo\PHPMatcher\Exception\InvalidExpanderTypeException;
8+
use Coduo\PHPMatcher\Exception\UnknownExpanderClassException;
9+
use Coduo\PHPMatcher\Exception\UnknownExpanderException;
10+
use Coduo\PHPMatcher\Matcher\Pattern\PatternExpander;
11+
12+
class ExpanderInitializer
13+
{
14+
/**
15+
* @var array
16+
*/
17+
private $expanderDefinitions = array(
18+
"startsWith" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\StartsWith",
19+
"endsWith" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\EndsWith",
20+
"notEmpty" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\NotEmpty",
21+
"lowerThan" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\LowerThan",
22+
"greaterThan" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\GreaterThan",
23+
"inArray" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\InArray",
24+
"contains" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\Contains",
25+
26+
"oneOf" => "Coduo\\PHPMatcher\\Matcher\\Pattern\\Expander\\OneOf"
27+
);
28+
29+
/**
30+
* @param string $expanderName
31+
* @param string $expanderFQCN Fully-Qualified Class Name that implements PatternExpander interface
32+
* @throws UnknownExpanderClassException
33+
*/
34+
public function setExpanderDefinition($expanderName, $expanderFQCN)
35+
{
36+
if (!class_exists($expanderFQCN)) {
37+
throw new UnknownExpanderClassException(sprintf("Class \"%s\" does not exists.", $expanderFQCN));
38+
}
39+
40+
$this->expanderDefinitions[$expanderName] = $expanderFQCN;
41+
}
42+
43+
/**
44+
* @param $expanderName
45+
* @return bool
46+
*/
47+
public function hasExpanderDefinition($expanderName)
48+
{
49+
return array_key_exists($expanderName, $this->expanderDefinitions);
50+
}
51+
52+
/**
53+
* @param $expanderName
54+
* @return string
55+
* @throws InvalidArgumentException
56+
*/
57+
public function getExpanderDefinition($expanderName)
58+
{
59+
if (!$this->hasExpanderDefinition($expanderName)) {
60+
throw new InvalidArgumentException(sprintf("Definition for \"%s\" expander does not exists.", $expanderName));
61+
}
62+
63+
return $this->expanderDefinitions[$expanderName];
64+
}
65+
66+
/**
67+
* @param Expander $expanderNode
68+
* @throws InvalidExpanderTypeException
69+
* @throws UnknownExpanderException
70+
* @return PatternExpander
71+
*/
72+
public function initialize(Expander $expanderNode)
73+
{
74+
if (!array_key_exists($expanderNode->getName(), $this->expanderDefinitions)) {
75+
throw new UnknownExpanderException(sprintf("Unknown expander \"%s\"", $expanderNode->getName()));
76+
}
77+
78+
$reflection = new \ReflectionClass($this->expanderDefinitions[$expanderNode->getName()]);
79+
80+
if ($expanderNode->hasArguments()) {
81+
$arguments = array();
82+
foreach ($expanderNode->getArguments() as $argument) {
83+
$arguments[] = ($argument instanceof Expander)
84+
? $this->initialize($argument)
85+
: $argument;
86+
}
87+
88+
$expander = $reflection->newInstanceArgs($arguments);
89+
} else {
90+
$expander = $reflection->newInstance();
91+
}
92+
93+
if (!$expander instanceof PatternExpander) {
94+
throw new InvalidExpanderTypeException();
95+
}
96+
97+
return $expander;
98+
}
99+
}

tests/Coduo/PHPMatcher/Matcher/ArrayMatcherTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class ArrayMatcherTest extends \PHPUnit_Framework_TestCase
1515

1616
public function setUp()
1717
{
18-
$parser = new Parser(new Lexer());
18+
$parser = new Parser(new Lexer(), new Parser\ExpanderInitializer());
1919
$this->matcher = new Matcher\ArrayMatcher(
2020
new Matcher\ChainMatcher(array(
2121
new Matcher\CallbackMatcher(),
@@ -55,7 +55,7 @@ public function test_negative_match_when_cant_find_matcher_that_can_match_array_
5555
new Matcher\ChainMatcher(array(
5656
new Matcher\WildcardMatcher()
5757
)),
58-
$parser = new Parser(new Lexer())
58+
$parser = new Parser(new Lexer(), new Parser\ExpanderInitializer())
5959
);
6060

6161
$this->assertFalse($matcher->match(array('test' => 1), array('test' => 1)));

tests/Coduo/PHPMatcher/Matcher/DoubleMatcherTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class DoubleMatcherTest extends \PHPUnit_Framework_TestCase
1414

1515
public function setUp()
1616
{
17-
$this->matcher = new DoubleMatcher(new Parser(new Lexer()));
17+
$this->matcher = new DoubleMatcher(new Parser(new Lexer(), new Parser\ExpanderInitializer()));
1818
}
1919

2020
/**

tests/Coduo/PHPMatcher/Matcher/IntegerMatcherTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class IntegerMatcherTest extends \PHPUnit_Framework_TestCase
1414

1515
public function setUp()
1616
{
17-
$this->matcher = new IntegerMatcher(new Parser(new Lexer()));
17+
$this->matcher = new IntegerMatcher(new Parser(new Lexer(), new Parser\ExpanderInitializer()));
1818
}
1919

2020
/**

tests/Coduo/PHPMatcher/Matcher/JsonMatcherTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class JsonMatcherTest extends \PHPUnit_Framework_TestCase
1515

1616
public function setUp()
1717
{
18-
$parser = new Parser(new Lexer());
18+
$parser = new Parser(new Lexer(), new Parser\ExpanderInitializer());
1919
$scalarMatchers = new Matcher\ChainMatcher(array(
2020
new Matcher\CallbackMatcher(),
2121
new Matcher\ExpressionMatcher(),

0 commit comments

Comments
 (0)