-
-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #44 from norzechowicz/text-matcher
Added text matcher
- Loading branch information
Showing
11 changed files
with
298 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?php | ||
|
||
namespace Coduo\PHPMatcher\Exception; | ||
|
||
class UnknownTypeException extends Exception | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php | ||
|
||
namespace Coduo\PHPMatcher\Matcher\Pattern; | ||
|
||
use Coduo\PHPMatcher\Exception\UnknownTypeException; | ||
|
||
class RegexConverter | ||
{ | ||
public function toRegex(TypePattern $type) | ||
{ | ||
switch ($type->getType()) { | ||
case 'string': | ||
case 'wildcard': | ||
case '*': | ||
return "(.+)"; | ||
case 'number': | ||
return "(\\-?[0-9]*[\\.|\\,]?[0-9]*)"; | ||
case 'integer': | ||
return "(\\-?[0-9]*)"; | ||
case 'double': | ||
return "(\\-?[0-9]*[\\.|\\,][0-9]*)"; | ||
default: | ||
throw new UnknownTypeException(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
<?php | ||
|
||
namespace Coduo\PHPMatcher\Matcher; | ||
|
||
use Coduo\PHPMatcher\Matcher\Pattern\TypePattern; | ||
use Coduo\PHPMatcher\Parser; | ||
use Coduo\PHPMatcher\Matcher\Pattern\RegexConverter; | ||
use Coduo\ToString\String; | ||
|
||
class TextMatcher extends Matcher | ||
{ | ||
const PATTERN_REGEXP = "/@[a-zA-Z\\.]+@(\\.[a-zA-Z0-9_]+\\([a-zA-Z0-9{},:@\\.\"'\\(\\)]*\\))*/"; | ||
|
||
const PATTERN_REGEXP_PLACEHOLDER_TEMPLATE = "__PLACEHOLDER%d__"; | ||
|
||
/** | ||
* @var Parser | ||
*/ | ||
private $parser; | ||
|
||
/** | ||
* @var ValueMatcher | ||
*/ | ||
private $matcher; | ||
|
||
/** | ||
* @param ValueMatcher $matcher | ||
* @param Parser $parser | ||
*/ | ||
public function __construct(ValueMatcher $matcher, Parser $parser) | ||
{ | ||
$this->parser = $parser; | ||
$this->matcher = $matcher; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function match($value, $pattern) | ||
{ | ||
if (!is_string($value)) { | ||
$this->error = sprintf("%s \"%s\" is not a valid string.", gettype($value), new String($value)); | ||
return false; | ||
} | ||
|
||
$patternRegex = $pattern; | ||
$patternsReplacedWithRegex = $this->replaceTypePatternsWithPlaceholders($patternRegex); | ||
$patternRegex = $this->prepareRegex($patternRegex); | ||
$patternRegex = $this->replacePlaceholderWithPatternRegexes($patternRegex, $patternsReplacedWithRegex); | ||
|
||
if (!preg_match($patternRegex, $value, $matchedValues)) { | ||
$this->error = sprintf("\"%s\" does not match \"%s\" pattern", $value, $pattern); | ||
return false; | ||
} | ||
|
||
array_shift($matchedValues); // remove matched string | ||
|
||
if (count($patternsReplacedWithRegex) !== count($matchedValues)) { | ||
$this->error = "Unexpected TextMatcher error."; | ||
return false; | ||
} | ||
|
||
foreach ($patternsReplacedWithRegex as $index => $typePattern) { | ||
if (!$typePattern->matchExpanders($matchedValues[$index])) { | ||
$this->error = $typePattern->getError(); | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function canMatch($pattern) | ||
{ | ||
if (!is_string($pattern)) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Reaplce each type pattern (@[email protected]("lorem")) with placeholder, in order | ||
* to use preg_quote without destroying pattern & expanders. | ||
* | ||
* before replacement: "/users/@[email protected](200)/active" | ||
* after replacement: "/users/__PLACEHOLDER0__/active" | ||
* | ||
* @param string $patternRegex | ||
* @return TypePattern[]|array | ||
*/ | ||
private function replaceTypePatternsWithPlaceholders(&$patternRegex) | ||
{ | ||
$patternsReplacedWithRegex = array(); | ||
preg_match_all(self::PATTERN_REGEXP, $patternRegex, $matches); | ||
|
||
foreach ($matches[0] as $index => $typePatternString) { | ||
$typePattern = $this->parser->parse($typePatternString); | ||
$patternsReplacedWithRegex[] = $typePattern; | ||
$patternRegex = str_replace( | ||
$typePatternString, | ||
sprintf(self::PATTERN_REGEXP_PLACEHOLDER_TEMPLATE, $index), | ||
$patternRegex | ||
); | ||
} | ||
|
||
return $patternsReplacedWithRegex; | ||
} | ||
|
||
|
||
/** | ||
* Replace placeholders with type pattern regular expressions | ||
* before replacement: "/users/__PLACEHOLDER0__/active" | ||
* after replacement: "/^\/users\/(\-?[0-9]*)\/active$/" | ||
* | ||
* @param $patternRegex | ||
* @return string | ||
* @throws \Coduo\PHPMatcher\Exception\UnknownTypeException | ||
*/ | ||
private function replacePlaceholderWithPatternRegexes($patternRegex, array $patternsReplacedWithRegex) | ||
{ | ||
$regexConverter = new RegexConverter(); | ||
foreach ($patternsReplacedWithRegex as $index => $typePattern) { | ||
$patternRegex = str_replace( | ||
sprintf(self::PATTERN_REGEXP_PLACEHOLDER_TEMPLATE, $index), | ||
$regexConverter->toRegex($typePattern), | ||
$patternRegex | ||
); | ||
} | ||
|
||
return $patternRegex; | ||
} | ||
|
||
/** | ||
* Prepare regular expression | ||
* | ||
* @param string $patternRegex | ||
* @return string | ||
*/ | ||
private function prepareRegex($patternRegex) | ||
{ | ||
return "/^" . preg_quote($patternRegex, '/') . "$/"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
tests/Coduo/PHPMatcher/Matcher/Pattern/RegexConverterTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
namespace Coduo\PHPMatcher\Tests\Matcher\Pattern; | ||
|
||
use Coduo\PHPMatcher\Matcher\Pattern\TypePattern; | ||
use Coduo\PHPMatcher\Matcher\Pattern\RegexConverter; | ||
|
||
class RegexConverterTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
/** | ||
* @var RegexConverter | ||
*/ | ||
private $converter; | ||
|
||
public function setUp() | ||
{ | ||
$this->converter = new RegexConverter(); | ||
} | ||
|
||
/** | ||
* @expectedException \Coduo\PHPMatcher\Exception\UnknownTypeException | ||
*/ | ||
public function test_convert_unknown_type() | ||
{ | ||
$this->converter->toRegex(new TypePattern("not_a_type")); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
namespace Coduo\PHPMatcher\Tests\Matcher; | ||
|
||
use Coduo\PHPMatcher\Lexer; | ||
use Coduo\PHPMatcher\Matcher; | ||
use Coduo\PHPMatcher\Parser; | ||
|
||
class TextMatcherTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
/** | ||
* @var Matcher\TextMatcher | ||
*/ | ||
private $matcher; | ||
|
||
public function setUp() | ||
{ | ||
$parser = new Parser(new Lexer(), new Parser\ExpanderInitializer()); | ||
$scalarMatchers = new Matcher\ChainMatcher(array( | ||
new Matcher\CallbackMatcher(), | ||
new Matcher\ExpressionMatcher(), | ||
new Matcher\NullMatcher(), | ||
new Matcher\StringMatcher($parser), | ||
new Matcher\IntegerMatcher($parser), | ||
new Matcher\BooleanMatcher(), | ||
new Matcher\DoubleMatcher($parser), | ||
new Matcher\NumberMatcher(), | ||
new Matcher\ScalarMatcher(), | ||
new Matcher\WildcardMatcher(), | ||
)); | ||
$this->matcher = new Matcher\TextMatcher( | ||
new Matcher\ChainMatcher(array( | ||
$scalarMatchers, | ||
new Matcher\ArrayMatcher($scalarMatchers, $parser) | ||
)), | ||
$parser | ||
); | ||
} | ||
|
||
/** | ||
* @dataProvider matchingData | ||
*/ | ||
public function test_positive_matches($value, $pattern, $expectedResult) | ||
{ | ||
$this->assertEquals($expectedResult, $this->matcher->match($value, $pattern)); | ||
} | ||
|
||
public function matchingData() | ||
{ | ||
return array( | ||
array( | ||
"lorem ipsum lol lorem 24 dolorem", | ||
"lorem ipsum @[email protected](\"lo\") lorem @number@ dolorem", | ||
true | ||
), | ||
array( | ||
"lorem ipsum 24 dolorem", | ||
"lorem ipsum @integer@", | ||
false | ||
), | ||
array( | ||
"/users/12345/active", | ||
"/users/@[email protected](0)/active", | ||
true | ||
) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,8 @@ public function setUp() | |
$scalarMatchers, | ||
$arrayMatcher, | ||
new Matcher\JsonMatcher($arrayMatcher), | ||
new Matcher\XmlMatcher($arrayMatcher) | ||
new Matcher\XmlMatcher($arrayMatcher), | ||
new Matcher\TextMatcher($scalarMatchers, $parser) | ||
))); | ||
} | ||
|
||
|
@@ -194,6 +195,14 @@ public function test_matcher_with_xml() | |
$this->assertTrue(match($xml, $xmlPattern)); | ||
} | ||
|
||
public function test_text_matcher() | ||
{ | ||
$value = "lorem ipsum 1234 random text"; | ||
$pattern = "@[email protected]('lo') ipsum @[email protected](10) random text"; | ||
$this->assertTrue($this->matcher->match($value, $pattern)); | ||
$this->assertTrue(match($value, $pattern)); | ||
} | ||
|
||
public function test_matcher_with_captures() | ||
{ | ||
$this->assertTrue($this->matcher->match( | ||
|