[
  {
    "path": ".composer-auth.json",
    "content": "{\n    \"github-oauth\": {\n        \"github.com\": \"PLEASE DO NOT USE THIS TOKEN IN YOUR OWN PROJECTS/FORKS\",\n        \"github.com\": \"This token is reserved for testing the webmozart/* repositories\",\n        \"github.com\": \"a9debbffdd953ee9b3b82dbc3b807cde2086bb86\"\n    }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "/vendor/\ncomposer.lock\n"
  },
  {
    "path": ".styleci.yml",
    "content": "preset: symfony\n\nenabled:\n    - ordered_use\n\ndisabled:\n    - empty_return\n    - phpdoc_annotation_without_dot # This is still buggy: https://github.com/symfony/symfony/pull/19198\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: php\n\nsudo: false\n\nbranches:\n  only:\n    - master\n\ncache:\n  directories:\n    - $HOME/.composer/cache/files\n\nmatrix:\n  include:\n    - php: 5.3\n    - php: 5.4\n    - php: 5.5\n    - php: 5.6\n    - php: hhvm\n    - php: nightly\n    - php: 7.0\n      env: COVERAGE=yes\n    - php: 7.0\n      env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable'\n  allow_failures:\n    - php: hhvm\n    - php: nightly\n  fast_finish: true\n\nbefore_install:\n  - if [[ $TRAVIS_PHP_VERSION != hhvm && $COVERAGE != yes ]]; then phpenv config-rm xdebug.ini; fi;\n  - if [[ $TRAVIS_REPO_SLUG = webmozart/expression ]]; then cp .composer-auth.json ~/.composer/auth.json; fi;\n  - composer self-update\n\ninstall: composer update $COMPOSER_FLAGS --prefer-dist --no-interaction\n\nscript: if [[ $COVERAGE = yes ]]; then vendor/bin/phpunit --verbose --coverage-clover=coverage.clover; else vendor/bin/phpunit --verbose; fi\n\nafter_script: if [[ $COVERAGE = yes ]]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Changelog\n=========\n\n* 1.0.0 (2015-12-17)\n\n * added `Expr::filter()` to filter collections\n * removed `final` keyword of expression classes to facilitate building\n   domain expressions\n * renamed `Conjunction` to `AndX`\n * renamed `Disjunction` to `OrX`\n * added `Expr::andX()` and `Expr::orX()`\n\n* 1.0.0-beta5 (2015-10-02)\n\n * added `method()` selector\n * added `property()` selector\n * removed optional `$key` arguments. Use the `key()`/`method()`/`property()`\n   selectors instead\n * added `isInstanceOf()`\n * removed class `NotEmpty` and used `Not` with `IsEmpty` instead\n * renamed `Webmozart\\Expression\\Comparison` namespace to `Webmozart\\Expression\\Constraint`\n * fixed type juggling in `equivalentTo()`\n\n* 1.0.0-beta4 (2015-08-24)\n\n * fixed return types in `Expr::true()` and `Expr::false()`\n * fixed minimum versions in composer.json\n\n* 1.0.0-beta3 (2015-05-28)\n\n * optimized `Valid::andX()` and `Valid::orX()`\n * optimized `Invalid::andX()` and `Invalid::orX()`\n * removed `true()` and `false()`. Use `same()` instead\n * renamed `valid()` to `true()` and `invalid()` to `false()`\n * added `contains()`\n * added brackets around string output of nested conjunctions/disjunctions\n\n* 1.0.0-beta2 (2015-04-13)\n\n * added `Selector`\n * removed `key*()` methods\n * renamed argument `$field` to `$key`, moved it to end of the method arguments\n   and made it optional for all test methods\n * removed argument `$field` from `key()`\n * removed argument `$strict` from `true()`, `false()` and `oneOf()`\n * added `atLeast()` selector\n * added `exactly()` selector\n * added `all()` selector\n * added `atMost()` selector\n * added `count()` selector\n * renamed `oneOf()` to `in()`\n * added `valid()`\n * added `invalid()`\n * optimized `andValid()`, `andInvalid()`, `orValid()` and `orInvalid()`\n\n* 1.0.0-beta (2015-03-19)\n\n * first beta release\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 Bernhard Schussek\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "Webmozart Expression\n====================\n\n[![Build Status](https://travis-ci.org/webmozart/expression.svg?branch=master)](https://travis-ci.org/webmozart/expression)\n[![Build status](https://ci.appveyor.com/api/projects/status/6dstc380h5pr5rk3/branch/master?svg=true)](https://ci.appveyor.com/project/webmozart/expression/branch/master)\n[![Latest Stable Version](https://poser.pugx.org/webmozart/expression/v/stable.svg)](https://packagist.org/packages/webmozart/expression)\n[![Total Downloads](https://poser.pugx.org/webmozart/expression/downloads.svg)](https://packagist.org/packages/webmozart/expression)\n[![Dependency Status](https://www.versioneye.com/php/webmozart:expression/1.0.0/badge.svg)](https://www.versioneye.com/php/webmozart:expression/1.0.0)\n\nLatest release: [1.0.0](https://packagist.org/packages/webmozart/expression#1.0.0)\n\nPHP >= 5.3.9\n\nThis library implements the [Specification Pattern] for PHP. You can use it to\neasily filter results of your domain services by evaluating logical expressions.\n\nConversely to [rulerz], this library focuses on providing a usable and efficient\nPHP API first. An expression language that converts string expressions into\n`Expression` instances can be built on top, but is not included in the current\nrelease.\n\nVisitors can be implemented that convert `Expression` objects into Doctrine\nqueries and similar objects.\n\nInstallation\n------------\n\nUse [Composer] to install the package:\n\n```\n$ composer require webmozart/expression\n```\n\nBasic Usage\n-----------\n\nUse the [`Expression`] interface in finder methods of your service classes:\n\n```php\nuse Webmozart\\Expression\\Expression;\n\ninterface PersonRepository\n{\n    public function findPersons(Expression $expr);\n}\n```\n\nWhen querying persons from the repository, you can create new expressions with\nthe [`Expr`] factory class:\n\n```php\n$expr = Expr::method('getFirstName', Expr::startsWith('Tho'))\n    ->andMethod('getAge', Expr::greaterThan(35));\n    \n$persons = $repository->findPersons($expr);\n```\n\nThe repository implementation can use the `evaluate()` method to match \nindividual persons against the criteria:\n\n```php\nclass PersonRepositoryImpl implements PersonRepository\n{\n    private $persons = [];\n    \n    public function findPersons(Expression $expr)\n    {\n        return Expr::filter($this->persons, $expr);\n    }\n}\n```\n\n[Visitors](#expression-transformation) can be built to convert expressions into\nother types of specifications, such as Doctrine query builders.\n\nDomain Expressions\n------------------\n\nExtend existing expressions to build domain-specific expressions:\n\n```php\nclass IsPremium extends Method\n{\n    public function __construct()\n    {\n        parent::__construct('isPremium', [], Expr::same(true));\n    }\n}\n\nclass HasPreviousBookings extends Method\n{\n    public function __construct()\n    {\n        parent::__construct(\n            'getBookings', \n            [], \n            Expr::count(Expr::greaterThan(0))\n        );\n    }\n}\n\n// Check if a customer is premium\nif ((new IsPremium())->evaluate($customer)) {\n    // ...\n}\n\n// Get premium customers with bookings\n$customers = $repo->findCustomers(Expr::andX([\n    new IsPremium(),\n    new HasPreviousBookings(),\n]));\n```\n\nThe following sections describe the core expressions in detail.\n\nExpressions\n-----------\n\nThe [`Expr`] class is able to create the following expressions:\n\nMethod                      | Description\n--------------------------- | --------------------------------------------------------\n`null()`                    | Check that a value is `null`\n`notNull()`                 | Check that a value is not `null`\n`isEmpty()`                 | Check that a value is empty (using `empty()`)\n`notEmpty()`                | Check that a value is not empty (using `empty()`)\n`isInstanceOf($className)`  | Check that a value is instance of a class (using `instanceof`)\n`equals($value)`            | Check that a value equals another value (using `==`)\n`notEquals($value)`         | Check that a value does not equal another value (using `!=`)\n`same($value)`              | Check that a value is identical to another value (using `===`)\n`notSame($value)`           | Check that a value does not equal another value (using `!==`)\n`greaterThan($value)`       | Check that a value is greater than another value\n`greaterThanEqual($value)`  | Check that a value is greater than or equal to another value\n`lessThan($value)`          | Check that a value is less than another value\n`lessThanEqual($value)`     | Check that a value is less than or equal to another value\n`startsWith($prefix)`       | Check that a value starts with a given string\n`endsWith($suffix)`         | Check that a value ends with a given string\n`contains($string)`         | Check that a value contains a given string\n`matches($regExp)`          | Check that a value matches a regular expression\n`in($values)`               | Check that a value occurs in a list of values\n`keyExists($key)`           | Check that a key exists in a value\n`keyNotExists($key)`        | Check that a key does not exist in a value\n`true()`                    | Always `true` (tautology)\n`false()`                   | Always `false` (contradiction)\n\nSelectors\n---------\n\nWith composite values like arrays or objects, you often want to match only a\npart of that value (like an array key or the result of a getter) against an\nexpression. You can select the evaluated parts with a *selector*.\n\nWhen you evaluate arrays, use the `key()` selector to match the value of an\narray key:\n\n```php\n$expr = Expr::key('age', Expr::greaterThan(10));\n\n$expr->evaluate(['age' => 12]);\n// => true\n```\n\nEach selector method accepts the expression as last argument that should be\nevaluated for the selected value.\n\nWhen evaluating objects, use `property()` and `method()` to evaluate the values\nof properties and the results of method calls:\n\n```php\n$expr = Expr::property('age', Expr::greaterThan(10));\n\n$expr->evaluate(new Person(12));\n// => true\n\n$expr = Expr::method('getAge', Expr::greaterThan(10));\n\n$expr->evaluate(new Person(12));\n// => true\n```\n\nThe `method()` selector also accepts arguments that will be passed to the \nmethod. Pass the arguments before the evaluated expression:\n\n```php\n$expr = Expr::method('getParameter', 'age', Expr::greaterThan(10));\n\n$expr->evaluate(new Person(12));\n// => true\n```\n\nYou can nest selectors to evaluate expressions for nested objects or arrays:\n\n```php\n$expr = Expr::method('getBirthDate', Expr::method('format', 'Y', Expr::lessThan(2000)));\n\n$expr->evaluate(new Person(12));\n// => false\n```\n\nThe following table lists all available selectors:\n\nMethod                   | Description\n------------------------ | -------------------------------------------------------------------------------\n`key($key, $expr)`       | Evaluate an expression for a key of an array\n`method($name, $expr)`   | Evaluate an expression for the result of a method call\n`property($name, $expr)` | Evaluate an expression for the value of a property\n`count($expr)`           | Evaluate an expression for the count of a collection\n\nThe `count()` selector accepts arrays and `Countable` objects.\n\nQuantors\n--------\n\nQuantors are applied to collections and test whether an expression matches for a\ncertain number of elements. A famous one is the all-quantor:\n\n```php\n$expr = Expr::all(Expr::method('getAge', Expr::greaterThan(10)));\n\n$expr->evaluate([new Person(12), new Person(11)]);\n// => true\n```\n\nQuantors accept both arrays and `Traversable` instances. The following table \nlists all available quantors:\n\nMethod                   | Description\n------------------------ | -------------------------------------------------------------------------------\n`all($expr)`             | Check that an expression matches for all entries of a collection\n`atLeast($count, $expr)` | Check that an expression matches for at least `$count` entries of a collection\n`atMost($count, $expr)`  | Check that an expression matches for at most `$count` entries of a collection\n`exactly($count, $expr)` | Check that an expression matches for exactly `$count` entries of a collection\n\nLogical Operators\n-----------------\n\nYou can negate an expression with `not()`:\n\n```php\n$expr = Expr::not(Expr::method('getFirstName', Expr::startsWith('Tho')));\n```\n\nYou can connect multiple expressions with \"and\" using the `and*()` methods:\n\n```php\n$expr = Expr::method('getFirstName', Expr::startsWith('Tho'))\n    ->andMethod('getAge', Expr::greaterThan(35));\n```\n\nThe same is possible for the \"or\" operator:\n\n```php\n$expr = Expr::method('getFirstName', Expr::startsWith('Tho'))\n    ->orMethod('getAge', Expr::greaterThan(35));\n```\n\nYou can use and/or inside selectors:\n\n```php\n$expr = Expr::method('getAge', Expr::greaterThan(35)->orLessThan(20));\n```\n\nIf you want to mix and match \"and\" and \"or\" operators, use `andX()` and `orX()`\nto add embedded expressions:\n\n```php\n$expr = Expr::method('getFirstName', Expr::startsWith('Tho'))\n    ->andX(\n        Expr::method('getAge', Expr::lessThan(14))\n            ->orMethod('isReduced', Expr::same(true))\n    );\n```\n\nTesting\n-------\n\nTo make sure that PHPUnit compares [`Expression`] objects correctly, you should \nregister the [`ExpressionComparator`] with PHPUnit in your PHPUnit bootstrap file:\n\n```php\n// tests/bootstrap.php\nuse SebastianBergmann\\Comparator\\Factory;\nuse Webmozart\\Expression\\PhpUnit\\ExpressionComparator;\n\nrequire_once __DIR__.'/../vendor/autoload.php';\n\nFactory::getInstance()->register(new ExpressionComparator());\n```\n\nMake sure the file is registered correctly in `phpunit.xml.dist`:\n\n```xml\n<!-- phpunit.xml.dist -->\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit bootstrap=\"tests/bootstrap.php\" colors=\"true\">\n    <!-- ... -->\n</phpunit>\n```\n\nThe [`ExpressionComparator`] makes sure that PHPUnit compares different \n[`Expression`] instances by *logical equivalence* instead of by object equality. \nFor example, the following [`Expression`] are logically equivalent, but not equal \nas objects:\n \n```php\n// Logically equivalent\n$c1 = Expr::notNull()->andSame(35);\n$c2 = Expr::same(35)->andNotNull();\n\n$c1 == $c2;\n// => false\n\n$c1->equivalentTo($c2);\n// => true\n\n// Also logically equivalent\n$c1 = Expr::same(35);\n$c2 = Expr::oneOf([35]);\n\n$c1 == $c2;\n// => false\n\n$c1->equivalentTo($c2);\n// => true\n```\n\nExpression Transformation\n-------------------------\n\nIn some cases, you will want to transform expressions to some other\nrepresentation. A prime example is the transformation of an expression to a\n[Doctrine] query.\n\nYou can implement a custom [`ExpressionVisitor`] to do the transformation. The \nvisitor's methods `enterExpression()` and `leaveExpression()` are called for \nevery node of the expression tree:\n\n```php\nuse Webmozart\\Expression\\Traversal\\ExpressionVisitor;\n\nclass QueryBuilderVisitor implements ExpressionVisitor\n{\n    private $qb;\n    \n    public function __construct(QueryBuilder $qb)\n    {\n        $this->qb = $qb;\n    }\n    \n    public function enterExpression(Expression $expr)\n    {\n        // configure the $qb...\n    }\n    \n    public function leaveExpression(Expression $expr)\n    {\n        // configure the $qb...\n    }\n}\n```\n\nUse an [`ExpressionTraverser`] to traverse an expression with your visitor:\n\n```php\npublic function expressionToQueryBuilder(Expression $expr)\n{\n    $qb = new QueryBuilder();\n    \n    $traverser = new ExpressionTraverser();\n    $traverser->addVisitor(new QueryBuilderVisitor($qb));\n    $traverser->traverse($expr);\n    \n    return $qb;\n}\n```\n\nAuthors\n-------\n\n* [Bernhard Schussek] a.k.a. [@webmozart]\n* [The Community Contributors]\n\nContribute\n----------\n\nContributions to the package are always welcome!\n\n* Report any bugs or issues you find on the [issue tracker].\n* You can grab the source code at the package's [Git repository].\n\nSupport\n-------\n\nIf you are having problems, send a mail to bschussek@gmail.com or shout out to\n[@webmozart] on Twitter.\n\nLicense\n-------\n\nAll contents of this package are licensed under the [MIT license].\n\n[Composer]: https://getcomposer.org\n[Doctrine]: http://www.doctrine-project.org/\n[Bernhard Schussek]: http://webmozarts.com\n[The Community Contributors]: https://github.com/webmozart/expression/graphs/contributors\n[issue tracker]: https://github.com/webmozart/expression\n[Git repository]: https://github.com/webmozart/expression\n[@webmozart]: https://twitter.com/webmozart\n[MIT license]: LICENSE\n[`Expression`]: src/Expression.php\n[`Expr`]: src/Expr.php\n[`ExpressionComparator`]: src/PhpUnit/ExpressionComparator.php\n[`ExpressionTraverser`]: src/Traversal/ExpressionTraverser.php\n[`ExpressionVisitor`]: src/Traversal/ExpressionVisitor.php\n[Specification Pattern]: http://www.martinfowler.com/apsupp/spec.pdf\n[rulerz]: https://github.com/K-Phoen/rulerz\n"
  },
  {
    "path": "appveyor.yml",
    "content": "build: false\nplatform: x86\nclone_folder: c:\\projects\\webmozart\\expression\n\nbranches:\n  only:\n    - master\n\ncache:\n  - c:\\php -> appveyor.yml\n\ninit:\n  - SET PATH=c:\\php;%PATH%\n  - SET COMPOSER_NO_INTERACTION=1\n  - SET PHP=1\n\ninstall:\n  - IF EXIST c:\\php (SET PHP=0) ELSE (mkdir c:\\php)\n  - cd c:\\php\n  - IF %PHP%==1 appveyor DownloadFile http://windows.php.net/downloads/releases/archives/php-7.0.0-nts-Win32-VC14-x86.zip\n  - IF %PHP%==1 7z x php-7.0.0-nts-Win32-VC14-x86.zip -y >nul\n  - IF %PHP%==1 del /Q *.zip\n  - IF %PHP%==1 echo @php %%~dp0composer.phar %%* > composer.bat\n  - IF %PHP%==1 copy /Y php.ini-development php.ini\n  - IF %PHP%==1 echo max_execution_time=1200 >> php.ini\n  - IF %PHP%==1 echo date.timezone=\"UTC\" >> php.ini\n  - IF %PHP%==1 echo extension_dir=ext >> php.ini\n  - IF %PHP%==1 echo extension=php_curl.dll >> php.ini\n  - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini\n  - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini\n  - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini\n  - appveyor DownloadFile https://getcomposer.org/composer.phar\n  - cd c:\\projects\\webmozart\\expression\n  - mkdir %APPDATA%\\Composer\n  - IF %APPVEYOR_REPO_NAME%==webmozart/expression copy /Y .composer-auth.json %APPDATA%\\Composer\\auth.json\n  - composer update --prefer-dist --no-progress --ansi\n\ntest_script:\n  - cd c:\\projects\\webmozart\\expression\n  - vendor\\bin\\phpunit.bat --verbose\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"webmozart/expression\",\n    \"description\": \"Implementation of the Specification pattern and logical expressions for PHP.\",\n    \"keywords\": [\"specification\", \"criteria\", \"formula\", \"expression\", \"filter\", \"logic\"],\n    \"license\": \"MIT\",\n    \"authors\": [\n        {\n            \"name\": \"Bernhard Schussek\",\n            \"email\": \"bschussek@gmail.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^5.3.9|^7.0\"\n    },\n    \"require-dev\": {\n        \"phpunit/phpunit\": \"^4.6\",\n        \"sebastian/version\": \"^1.0.1\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Webmozart\\\\Expression\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Webmozart\\\\Expression\\\\Tests\\\\\": \"tests/\"\n        }\n    },\n    \"extra\": {\n        \"branch-alias\": {\n            \"dev-master\": \"1.0-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit bootstrap=\"vendor/autoload.php\" colors=\"true\">\n    <testsuites>\n        <testsuite name=\"Webmozart Expression Test Suite\">\n            <directory suffix=\"Test.php\">./tests/</directory>\n        </testsuite>\n    </testsuites>\n\n    <!-- Whitelist for code coverage -->\n    <filter>\n        <whitelist>\n            <directory suffix=\".php\">./src/</directory>\n        </whitelist>\n    </filter>\n</phpunit>\n"
  },
  {
    "path": "src/Constraint/Contains.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value contains another value.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n * @author Stephan Wentz <stephan@wentz.it>\n */\nclass Contains extends Literal\n{\n    /**\n     * @var string\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = (string) $comparedValue;\n    }\n\n    /**\n     * Returns the accepted suffix.\n     *\n     * @return string The accepted suffix.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return false !== strpos($value, $this->comparedValue);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue === $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'contains('.StringUtil::formatValue($this->comparedValue).')';\n    }\n}\n"
  },
  {
    "path": "src/Constraint/EndsWith.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value has a given suffix.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass EndsWith extends Literal\n{\n    /**\n     * @var string\n     */\n    private $acceptedSuffix;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string $acceptedSuffix The accepted suffix.\n     */\n    public function __construct($acceptedSuffix)\n    {\n        $this->acceptedSuffix = (string) $acceptedSuffix;\n    }\n\n    /**\n     * Returns the accepted suffix.\n     *\n     * @return string The accepted suffix.\n     */\n    public function getAcceptedSuffix()\n    {\n        return $this->acceptedSuffix;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $this->acceptedSuffix === substr($value, -strlen($this->acceptedSuffix));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->acceptedSuffix === $other->acceptedSuffix;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'endsWith('.StringUtil::formatValue($this->acceptedSuffix).')';\n    }\n}\n"
  },
  {
    "path": "src/Constraint/Equals.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value equals another value.\n *\n * The comparison is done using PHP's \"==\" equality operator.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Equals extends Literal\n{\n    /**\n     * @var string\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param mixed $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = $comparedValue;\n    }\n\n    /**\n     * Returns the compared value.\n     *\n     * @return mixed The compared value.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $this->comparedValue == $value;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if ($other instanceof In && !$other->isStrict()) {\n            return array($this->comparedValue) == $other->getAcceptedValues();\n        }\n\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue == $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return '=='.StringUtil::formatValue($this->comparedValue);\n    }\n}\n"
  },
  {
    "path": "src/Constraint/GreaterThan.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value is greater than a given value.\n *\n * The comparison is done using PHP's \">\" comparison operator.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass GreaterThan extends Literal\n{\n    /**\n     * @var mixed\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param mixed $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = $comparedValue;\n    }\n\n    /**\n     * Returns the compared value.\n     *\n     * @return mixed The compared value.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $value > $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue == $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return '>'.StringUtil::formatValue($this->comparedValue);\n    }\n}\n"
  },
  {
    "path": "src/Constraint/GreaterThanEqual.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value is greater than or equal to a given value.\n *\n * The comparison is done using PHP's \">=\" comparison operator.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass GreaterThanEqual extends Literal\n{\n    /**\n     * @var mixed\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param mixed $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = $comparedValue;\n    }\n\n    /**\n     * Returns the compared value.\n     *\n     * @return mixed The compared value.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $value >= $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue == $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return '>='.StringUtil::formatValue($this->comparedValue);\n    }\n}\n"
  },
  {
    "path": "src/Constraint/In.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value is one of a list of values.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass In extends Literal\n{\n    /**\n     * @var array\n     */\n    private $acceptedValues;\n\n    /**\n     * @var bool\n     */\n    private $strict;\n\n    /**\n     * Creates the expression.\n     *\n     * @param array $acceptedValues The accepted values.\n     * @param bool  $strict         Whether to do strict comparison.\n     */\n    public function __construct(array $acceptedValues, $strict = true)\n    {\n        $this->acceptedValues = $acceptedValues;\n        $this->strict = $strict;\n    }\n\n    /**\n     * Returns the accepted values.\n     *\n     * @return array The accepted values.\n     */\n    public function getAcceptedValues()\n    {\n        return $this->acceptedValues;\n    }\n\n    /**\n     * Returns whether the value is compared strictly.\n     *\n     * @return bool Returns `true` if using strict comparison (`===`) and\n     *              `false` if using weak comparison (`==`).\n     */\n    public function isStrict()\n    {\n        return $this->strict;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return in_array($value, $this->acceptedValues, $this->strict);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (1 === count($this->acceptedValues)) {\n            // In is logically equivalent to Same if strict and only one value\n            if ($this->strict && $other instanceof Same) {\n                return reset($this->acceptedValues) === $other->getComparedValue();\n            }\n\n            // In is logically equivalent to Equals if not strict and only one value\n            if (!$this->strict && $other instanceof Equals) {\n                return reset($this->acceptedValues) == $other->getComparedValue();\n            }\n        }\n\n        // Since this class is final, we can check with instanceof\n        if (!$other instanceof $this) {\n            return false;\n        }\n\n        if ($this->strict !== $other->strict) {\n            return false;\n        }\n\n        if (!$this->strict) {\n            return $this->acceptedValues == $other->acceptedValues;\n        }\n\n        $acceptedValuesLeft = $this->acceptedValues;\n        $acceptedValuesRight = $other->acceptedValues;\n\n        // Ignore order\n        sort($acceptedValuesLeft);\n        sort($acceptedValuesRight);\n\n        return $acceptedValuesLeft === $acceptedValuesRight;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        $values = array_map(function ($value) {\n            return StringUtil::formatValue($value);\n        }, $this->acceptedValues);\n\n        return 'in('.implode(', ', $values).')';\n    }\n}\n"
  },
  {
    "path": "src/Constraint/IsEmpty.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\n\n/**\n * Checks that a value is empty.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass IsEmpty extends Literal\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return empty($value);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'empty()';\n    }\n}\n"
  },
  {
    "path": "src/Constraint/IsInstanceOf.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\n\n/**\n * Checks that a value is an instance of a given class name.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass IsInstanceOf extends Literal\n{\n    /**\n     * @var array\n     */\n    private $className;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string $className The accepted class name.\n     */\n    public function __construct($className)\n    {\n        $this->className = $className;\n    }\n\n    /**\n     * Returns the accepted class name.\n     *\n     * @return array The accepted class name.\n     */\n    public function getClassName()\n    {\n        return $this->className;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $value instanceof $this->className;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        if (!$other instanceof $this) {\n            return false;\n        }\n\n        return $this->className === $other->className;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'instanceOf('.$this->className.')';\n    }\n}\n"
  },
  {
    "path": "src/Constraint/KeyExists.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that an array key exists.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass KeyExists extends Literal\n{\n    /**\n     * @var string\n     */\n    private $key;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string $key The array key.\n     */\n    public function __construct($key)\n    {\n        $this->key = (string) $key;\n    }\n\n    /**\n     * Returns the array key.\n     *\n     * @return string The array key.\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_array($value)) {\n            return false;\n        }\n\n        return array_key_exists($this->key, $value);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->key === $other->key;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'keyExists('.StringUtil::formatValue($this->key).')';\n    }\n}\n"
  },
  {
    "path": "src/Constraint/KeyNotExists.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that an array key does not exist.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass KeyNotExists extends Literal\n{\n    /**\n     * @var string\n     */\n    private $key;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string $key The array key.\n     */\n    public function __construct($key)\n    {\n        $this->key = (string) $key;\n    }\n\n    /**\n     * Returns the array key.\n     *\n     * @return string The array key.\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_array($value)) {\n            return false;\n        }\n\n        return !array_key_exists($this->key, $value);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->key === $other->key;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'keyNotExists('.StringUtil::formatValue($this->key).')';\n    }\n}\n"
  },
  {
    "path": "src/Constraint/LessThan.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value is less than a given value.\n *\n * The comparison is done using PHP's \"<\" comparison operator.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass LessThan extends Literal\n{\n    /**\n     * @var mixed\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param mixed $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = $comparedValue;\n    }\n\n    /**\n     * Returns the compared value.\n     *\n     * @return mixed The compared value.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $value < $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue == $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return '<'.StringUtil::formatValue($this->comparedValue);\n    }\n}\n"
  },
  {
    "path": "src/Constraint/LessThanEqual.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value is less than or equal to a given value.\n *\n * The comparison is done using PHP's \"<=\" comparison operator.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass LessThanEqual extends Literal\n{\n    /**\n     * @var mixed\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param mixed $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = $comparedValue;\n    }\n\n    /**\n     * Returns the compared value.\n     *\n     * @return mixed The compared value.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $value <= $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue == $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return '<='.StringUtil::formatValue($this->comparedValue);\n    }\n}\n"
  },
  {
    "path": "src/Constraint/Matches.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value matches a given regular expression.\n *\n * The comparison is done using PHP's `preg_match()` function.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Matches extends Literal\n{\n    /**\n     * @var string\n     */\n    private $regExp;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string $regExp The regular expression.\n     */\n    public function __construct($regExp)\n    {\n        $this->regExp = $regExp;\n    }\n\n    /**\n     * Returns the regular expression.\n     *\n     * @return mixed The regular expression.\n     */\n    public function getRegularExpression()\n    {\n        return $this->regExp;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return (bool) preg_match($this->regExp, $value);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->regExp === $other->regExp;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'matches('.StringUtil::formatValue($this->regExp).')';\n    }\n}\n"
  },
  {
    "path": "src/Constraint/NotEquals.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value does not equal another value.\n *\n * The comparison is done using PHP's \"!=\" equality operator.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass NotEquals extends Literal\n{\n    /**\n     * @var mixed\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param mixed $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = $comparedValue;\n    }\n\n    /**\n     * Returns the compared value.\n     *\n     * @return mixed The compared value.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $this->comparedValue != $value;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue == $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return '!='.StringUtil::formatValue($this->comparedValue);\n    }\n}\n"
  },
  {
    "path": "src/Constraint/NotSame.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value is not identical to another value.\n *\n * The comparison is done using PHP's \"!==\" equality operator.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass NotSame extends Literal\n{\n    /**\n     * @var mixed\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param mixed $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = $comparedValue;\n    }\n\n    /**\n     * Returns the compared value.\n     *\n     * @return mixed The compared value.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $this->comparedValue !== $value;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue === $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return '!=='.StringUtil::formatValue($this->comparedValue);\n    }\n}\n"
  },
  {
    "path": "src/Constraint/Same.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value is identical to another value.\n *\n * The comparison is done using PHP's \"===\" equality operator.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Same extends Literal\n{\n    /**\n     * @var mixed\n     */\n    private $comparedValue;\n\n    /**\n     * Creates the expression.\n     *\n     * @param mixed $comparedValue The compared value.\n     */\n    public function __construct($comparedValue)\n    {\n        $this->comparedValue = $comparedValue;\n    }\n\n    /**\n     * Returns the compared value.\n     *\n     * @return mixed The compared value.\n     */\n    public function getComparedValue()\n    {\n        return $this->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $this->comparedValue === $value;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if ($other instanceof In && $other->isStrict()) {\n            return array($this->comparedValue) === $other->getAcceptedValues();\n        }\n\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->comparedValue === $other->comparedValue;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return '==='.StringUtil::formatValue($this->comparedValue);\n    }\n}\n"
  },
  {
    "path": "src/Constraint/StartsWith.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Constraint;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks that a value has a given prefix.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass StartsWith extends Literal\n{\n    /**\n     * @var string\n     */\n    private $acceptedPrefix;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string $acceptedPrefix The accepted prefix.\n     */\n    public function __construct($acceptedPrefix)\n    {\n        $this->acceptedPrefix = (string) $acceptedPrefix;\n    }\n\n    /**\n     * Returns the accepted prefix.\n     *\n     * @return string The accepted prefix.\n     */\n    public function getAcceptedPrefix()\n    {\n        return $this->acceptedPrefix;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return 0 === strpos($value, $this->acceptedPrefix);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->acceptedPrefix === $other->acceptedPrefix;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'startsWith('.StringUtil::formatValue($this->acceptedPrefix).')';\n    }\n}\n"
  },
  {
    "path": "src/Expr.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression;\n\nuse ArrayAccess;\nuse InvalidArgumentException;\nuse Traversable;\nuse Webmozart\\Expression\\Constraint\\Contains;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\Equals;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Constraint\\GreaterThanEqual;\nuse Webmozart\\Expression\\Constraint\\In;\nuse Webmozart\\Expression\\Constraint\\IsEmpty;\nuse Webmozart\\Expression\\Constraint\\IsInstanceOf;\nuse Webmozart\\Expression\\Constraint\\KeyExists;\nuse Webmozart\\Expression\\Constraint\\KeyNotExists;\nuse Webmozart\\Expression\\Constraint\\LessThan;\nuse Webmozart\\Expression\\Constraint\\LessThanEqual;\nuse Webmozart\\Expression\\Constraint\\Matches;\nuse Webmozart\\Expression\\Constraint\\NotEquals;\nuse Webmozart\\Expression\\Constraint\\NotSame;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Constraint\\StartsWith;\nuse Webmozart\\Expression\\Logic\\AlwaysFalse;\nuse Webmozart\\Expression\\Logic\\AlwaysTrue;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\Not;\nuse Webmozart\\Expression\\Logic\\OrX;\nuse Webmozart\\Expression\\Selector\\All;\nuse Webmozart\\Expression\\Selector\\AtLeast;\nuse Webmozart\\Expression\\Selector\\AtMost;\nuse Webmozart\\Expression\\Selector\\Count;\nuse Webmozart\\Expression\\Selector\\Exactly;\nuse Webmozart\\Expression\\Selector\\Key;\nuse Webmozart\\Expression\\Selector\\Method;\nuse Webmozart\\Expression\\Selector\\Property;\n\n/**\n * Factory for {@link Expression} instances.\n *\n * Use this class to build expressions:ons:\n *\n * ```php\n * $expr = Expr::greaterThan(20)->orLessThan(10);\n * ```\n *\n * You can evaluate the expression with another value {@link Expression::evaluate()}:\n *\n * ```php\n * if ($expr->evaluate($value)) {\n *     // do something...\n * }\n * ```\n *\n * You can also evaluate expressions by arrays by passing the array keys as\n * second argument:\n *\n * ```php\n * $expr = Expr::greaterThan(20, 'age')\n *     ->andStartsWith('Thomas', 'name');\n *\n * $values = array(\n *     'age' => 35,\n *     'name' => 'Thomas Edison',\n * );\n *\n * if ($expr->evaluate($values)) {\n *     // do something...\n * }\n * ```\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Expr\n{\n    /**\n     * Filter a collection for entries matching the expression.\n     *\n     * @param array|ArrayAccess|Traversable $collection An array or an object\n     *                                                  implementing Traversable\n     *                                                  and ArrayAccess.\n     * @param Expression                    $expr       The expression to\n     *                                                  evaluate for each entry.\n     *\n     * @return array|ArrayAccess|Traversable The filtered collection.\n     */\n    public static function filter($collection, Expression $expr)\n    {\n        if (is_array($collection)) {\n            return array_filter($collection, array($expr, 'evaluate'));\n        }\n\n        if (!($collection instanceof Traversable && $collection instanceof ArrayAccess)) {\n            throw new InvalidArgumentException(sprintf(\n                'Expected an array or an instance of Traversable and ArrayAccess. Got: %s',\n                is_object($collection) ? get_class($collection) : gettype($collection)\n            ));\n        }\n\n        $clone = clone $collection;\n\n        foreach ($collection as $key => $value) {\n            if (!$expr->evaluate($value)) {\n                unset($clone[$key]);\n            }\n        }\n\n        return $clone;\n    }\n\n    /**\n     * Returns the expression.\n     *\n     * Facilitates usage of expressions on PHP < 7.\n     *\n     * @param Expression $expr An expression.\n     *\n     * @return Expression The expression.\n     */\n    public static function expr(Expression $expr)\n    {\n        return $expr;\n    }\n\n    /**\n     * Negate an expression.\n     *\n     * @param Expression $expr The negated expression.\n     *\n     * @return Not The created negation.\n     */\n    public static function not(Expression $expr)\n    {\n        return new Not($expr);\n    }\n\n    /**\n     * Create a conjunction.\n     *\n     * @param Expression[] $conjuncts The conjuncts.\n     *\n     * @return AndX The created conjunction.\n     */\n    public static function andX(array $conjuncts)\n    {\n        return new AndX($conjuncts);\n    }\n\n    /**\n     * Create a disjunction.\n     *\n     * @param Expression[] $disjuncts The disjuncts.\n     *\n     * @return OrX The created disjunction.\n     */\n    public static function orX(array $disjuncts)\n    {\n        return new OrX($disjuncts);\n    }\n\n    /**\n     * Always true (tautology).\n     *\n     * @return AlwaysTrue The created expression.\n     */\n    public static function true()\n    {\n        return new AlwaysTrue();\n    }\n\n    /**\n     * Always false (contradiction).\n     *\n     * @return AlwaysFalse The created expression.\n     */\n    public static function false()\n    {\n        return new AlwaysFalse();\n    }\n\n    /**\n     * Check that the value of an array key matches an expression.\n     *\n     * @param string|int $key  The array key.\n     * @param Expression $expr The evaluated expression.\n     *\n     * @return Key The created expression.\n     */\n    public static function key($key, Expression $expr)\n    {\n        return new Key($key, $expr);\n    }\n\n    /**\n     * Check that the result of a method call matches an expression.\n     *\n     * @param string     $methodName The name of the method to call.\n     * @param mixed      $args...    The method arguments.\n     * @param Expression $expr       The evaluated expression.\n     *\n     * @return Method The created expression.\n     */\n    public static function method($methodName, $args)\n    {\n        $args = func_get_args();\n        $methodName = array_shift($args);\n        $expr = array_pop($args);\n\n        return new Method($methodName, $args, $expr);\n    }\n\n    /**\n     * Check that the value of a property matches an expression.\n     *\n     * @param string     $propertyName The name of the property.\n     * @param Expression $expr         The evaluated expression.\n     *\n     * @return Method The created expression.\n     */\n    public static function property($propertyName, Expression $expr)\n    {\n        return new Property($propertyName, $expr);\n    }\n\n    /**\n     * Check that at least N entries of a traversable value match an expression.\n     *\n     * @param int        $count The minimum number of entries that need to match.\n     * @param Expression $expr  The evaluated expression.\n     *\n     * @return AtLeast The created expression.\n     */\n    public static function atLeast($count, Expression $expr)\n    {\n        return new AtLeast($count, $expr);\n    }\n\n    /**\n     * Check that at most N entries of a traversable value match an expression.\n     *\n     * @param int        $count The maximum number of entries that need to match.\n     * @param Expression $expr  The evaluated expression.\n     *\n     * @return AtMost The created expression.\n     */\n    public static function atMost($count, Expression $expr)\n    {\n        return new AtMost($count, $expr);\n    }\n\n    /**\n     * Check that exactly N entries of a traversable value match an expression.\n     *\n     * @param int        $count The number of entries that need to match.\n     * @param Expression $expr  The evaluated expression.\n     *\n     * @return Exactly The created expression.\n     */\n    public static function exactly($count, Expression $expr)\n    {\n        return new Exactly($count, $expr);\n    }\n\n    /**\n     * Check that all entries of a traversable value match an expression.\n     *\n     * @param Expression $expr The evaluated expression.\n     *\n     * @return All The created expression.\n     */\n    public static function all(Expression $expr)\n    {\n        return new All($expr);\n    }\n\n    /**\n     * Check that the count of a collection matches an expression.\n     *\n     * @param Expression $expr The evaluated expression.\n     *\n     * @return Count The created expression.\n     */\n    public static function count(Expression $expr)\n    {\n        return new Count($expr);\n    }\n\n    /**\n     * Check that a value is null.\n     *\n     * @return Same The created expression.\n     */\n    public static function null()\n    {\n        return new Same(null);\n    }\n\n    /**\n     * Check that a value is not null.\n     *\n     * @return NotSame The created expression.\n     */\n    public static function notNull()\n    {\n        return new NotSame(null);\n    }\n\n    /**\n     * Check that a value is empty.\n     *\n     * @return IsEmpty The created expression.\n     */\n    public static function isEmpty()\n    {\n        return new IsEmpty();\n    }\n\n    /**\n     * Check that a value is not empty.\n     *\n     * @return Not The created expression.\n     */\n    public static function notEmpty()\n    {\n        return new Not(new IsEmpty());\n    }\n\n    /**\n     * Check that a value is an instance of a given class.\n     *\n     * @param string $className The class name.\n     *\n     * @return IsEmpty The created expression.\n     */\n    public static function isInstanceOf($className)\n    {\n        return new IsInstanceOf($className);\n    }\n\n    /**\n     * Check that a value equals another value.\n     *\n     * @param mixed $value The compared value.\n     *\n     * @return Equals The created expression.\n     */\n    public static function equals($value)\n    {\n        return new Equals($value);\n    }\n\n    /**\n     * Check that a value does not equal another value.\n     *\n     * @param mixed $value The compared value.\n     *\n     * @return NotEquals The created expression.\n     */\n    public static function notEquals($value)\n    {\n        return new NotEquals($value);\n    }\n\n    /**\n     * Check that a value is identical to another value.\n     *\n     * @param mixed $value The compared value.\n     *\n     * @return Same The created expression.\n     */\n    public static function same($value)\n    {\n        return new Same($value);\n    }\n\n    /**\n     * Check that a value is not identical to another value.\n     *\n     * @param mixed $value The compared value.\n     *\n     * @return NotSame The created expression.\n     */\n    public static function notSame($value)\n    {\n        return new NotSame($value);\n    }\n\n    /**\n     * Check that a value is greater than another value.\n     *\n     * @param mixed $value The compared value.\n     *\n     * @return GreaterThan The created expression.\n     */\n    public static function greaterThan($value)\n    {\n        return new GreaterThan($value);\n    }\n\n    /**\n     * Check that a value is greater than or equal to another value.\n     *\n     * @param mixed $value The compared value.\n     *\n     * @return GreaterThanEqual The created expression.\n     */\n    public static function greaterThanEqual($value)\n    {\n        return new GreaterThanEqual($value);\n    }\n\n    /**\n     * Check that a value is less than another value.\n     *\n     * @param mixed $value The compared value.\n     *\n     * @return LessThan The created expression.\n     */\n    public static function lessThan($value)\n    {\n        return new LessThan($value);\n    }\n\n    /**\n     * Check that a value is less than or equal to another value.\n     *\n     * @param mixed $value The compared value.\n     *\n     * @return LessThanEqual The created expression.\n     */\n    public static function lessThanEqual($value)\n    {\n        return new LessThanEqual($value);\n    }\n\n    /**\n     * Check that a value occurs in a list of values.\n     *\n     * @param array $values The compared values.\n     *\n     * @return In The created expression.\n     */\n    public static function in(array $values)\n    {\n        return new In($values);\n    }\n\n    /**\n     * Check that a value matches a regular expression.\n     *\n     * @param string $regExp The regular expression.\n     *\n     * @return Matches The created expression.\n     */\n    public static function matches($regExp)\n    {\n        return new Matches($regExp);\n    }\n\n    /**\n     * Check that a value starts with a given string.\n     *\n     * @param string $prefix The prefix string.\n     *\n     * @return StartsWith The created expression.\n     */\n    public static function startsWith($prefix)\n    {\n        return new StartsWith($prefix);\n    }\n\n    /**\n     * Check that a value ends with a given string.\n     *\n     * @param string $suffix The suffix string.\n     *\n     * @return EndsWith The created expression.\n     */\n    public static function endsWith($suffix)\n    {\n        return new EndsWith($suffix);\n    }\n\n    /**\n     * Check that a value contains a given string.\n     *\n     * @param string $string The sub-string.\n     *\n     * @return Contains The created expression.\n     */\n    public static function contains($string)\n    {\n        return new Contains($string);\n    }\n\n    /**\n     * Check that a value key exists.\n     *\n     * @param string $keyName The key name.\n     *\n     * @return KeyExists The created expression.\n     */\n    public static function keyExists($keyName)\n    {\n        return new KeyExists($keyName);\n    }\n\n    /**\n     * Check that a value key does not exist.\n     *\n     * @param string $keyName The key name.\n     *\n     * @return KeyNotExists The created expression.\n     */\n    public static function keyNotExists($keyName)\n    {\n        return new KeyNotExists($keyName);\n    }\n\n    /**\n     * This class cannot be instantiated.\n     */\n    private function __construct()\n    {\n    }\n}\n"
  },
  {
    "path": "src/Expression.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression;\n\n/**\n * A logical expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\ninterface Expression\n{\n    /**\n     * Evaluates the expression with the given value.\n     *\n     * @param mixed $value A value.\n     *\n     * @return bool Returns `true` if the value satisfies the expression and\n     *              `false` otherwise.\n     */\n    public function evaluate($value);\n\n    /**\n     * Returns whether this expression is logically equivalent to another expression.\n     *\n     * @param Expression $other Some expression.\n     *\n     * @return bool Returns `true` if the expressions are logically equivalent\n     *              and `false` otherwise.\n     */\n    public function equivalentTo(Expression $other);\n\n    /**\n     * Returns a string representation of the expression.\n     *\n     * @return string The expression as string.\n     */\n    public function toString();\n}\n"
  },
  {
    "path": "src/Logic/AlwaysFalse.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Logic;\n\nuse Webmozart\\Expression\\Expression;\n\n/**\n * Always false (contradiction).\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AlwaysFalse extends Literal\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'false';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function andX(Expression $expr)\n    {\n        return $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function orX(Expression $expr)\n    {\n        return $expr;\n    }\n}\n"
  },
  {
    "path": "src/Logic/AlwaysTrue.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Logic;\n\nuse Webmozart\\Expression\\Expression;\n\n/**\n * Always true (tautology).\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AlwaysTrue extends Literal\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'true';\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function andX(Expression $expr)\n    {\n        return $expr;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function orX(Expression $expr)\n    {\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/Logic/AndX.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Logic;\n\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Expression;\n\n/**\n * A disjunction of expressions.\n *\n * A disjunction is a set of {@link Expression} instances connected by logical\n * \"and\" operators.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AndX implements Expression\n{\n    /**\n     * @var Expression[]\n     */\n    private $conjuncts = array();\n\n    /**\n     * Creates a conjunction of the given expressions.\n     *\n     * @param Expression[] $conjuncts The conjuncts.\n     */\n    public function __construct(array $conjuncts = array())\n    {\n        foreach ($conjuncts as $conjunct) {\n            if ($conjunct instanceof self) {\n                foreach ($conjunct->conjuncts as $expr) {\n                    // $conjunct is guaranteed not to contain Conjunctions\n                    $this->conjuncts[] = $expr;\n                }\n            } else {\n                $this->conjuncts[] = $conjunct;\n            }\n        }\n    }\n\n    /**\n     * Returns the conjuncts of the conjunction.\n     *\n     * @return Expression[] The conjuncts.\n     */\n    public function getConjuncts()\n    {\n        return $this->conjuncts;\n    }\n\n    public function andX(Expression $expr)\n    {\n        if ($expr instanceof AlwaysTrue) {\n            return $this;\n        } elseif ($expr instanceof AlwaysFalse) {\n            return $expr;\n        }\n\n        foreach ($this->conjuncts as $conjunct) {\n            if ($conjunct->equivalentTo($expr)) {\n                return $this;\n            }\n        }\n\n        $conjuncts = $this->conjuncts;\n\n        if ($expr instanceof self) {\n            $conjuncts = array_merge($conjuncts, $expr->conjuncts);\n        } else {\n            $conjuncts[] = $expr;\n        }\n\n        return new self($conjuncts);\n    }\n\n    public function andNot(Expression $expr)\n    {\n        return $this->andX(Expr::not($expr));\n    }\n\n    public function andTrue()\n    {\n        return $this;\n    }\n\n    public function andFalse()\n    {\n        return Expr::false();\n    }\n\n    public function andKey($keyName, Expression $expr)\n    {\n        return $this->andX(Expr::key($keyName, $expr));\n    }\n\n    public function andMethod($methodName, $args)\n    {\n        return $this->andX(call_user_func_array(array('Webmozart\\Expression\\Expr', 'method'), func_get_args()));\n    }\n\n    public function andProperty($propertyName, Expression $expr)\n    {\n        return $this->andX(Expr::property($propertyName, $expr));\n    }\n\n    public function andAtLeast($count, Expression $expr)\n    {\n        return $this->andX(Expr::atLeast($count, $expr));\n    }\n\n    public function andAtMost($count, Expression $expr)\n    {\n        return $this->andX(Expr::atMost($count, $expr));\n    }\n\n    public function andExactly($count, Expression $expr)\n    {\n        return $this->andX(Expr::exactly($count, $expr));\n    }\n\n    public function andAll(Expression $expr)\n    {\n        return $this->andX(Expr::all($expr));\n    }\n\n    public function andCount(Expression $expr)\n    {\n        return $this->andX(Expr::count($expr));\n    }\n\n    public function andNull()\n    {\n        return $this->andX(Expr::null());\n    }\n\n    public function andNotNull()\n    {\n        return $this->andX(Expr::notNull());\n    }\n\n    public function andEmpty()\n    {\n        return $this->andX(Expr::isEmpty());\n    }\n\n    public function andNotEmpty()\n    {\n        return $this->andX(Expr::notEmpty());\n    }\n\n    public function andInstanceOf($className)\n    {\n        return $this->andX(Expr::isInstanceOf($className));\n    }\n\n    public function andEquals($value)\n    {\n        return $this->andX(Expr::equals($value));\n    }\n\n    public function andNotEquals($value)\n    {\n        return $this->andX(Expr::notEquals($value));\n    }\n\n    public function andSame($value)\n    {\n        return $this->andX(Expr::same($value));\n    }\n\n    public function andNotSame($value)\n    {\n        return $this->andX(Expr::notSame($value));\n    }\n\n    public function andGreaterThan($value)\n    {\n        return $this->andX(Expr::greaterThan($value));\n    }\n\n    public function andGreaterThanEqual($value)\n    {\n        return $this->andX(Expr::greaterThanEqual($value));\n    }\n\n    public function andLessThan($value)\n    {\n        return $this->andX(Expr::lessThan($value));\n    }\n\n    public function andLessThanEqual($value)\n    {\n        return $this->andX(Expr::lessThanEqual($value));\n    }\n\n    public function andIn(array $values)\n    {\n        return $this->andX(Expr::in($values));\n    }\n\n    public function andMatches($regExp)\n    {\n        return $this->andX(Expr::matches($regExp));\n    }\n\n    public function andStartsWith($prefix)\n    {\n        return $this->andX(Expr::startsWith($prefix));\n    }\n\n    public function andEndsWith($suffix)\n    {\n        return $this->andX(Expr::endsWith($suffix));\n    }\n\n    public function andContains($string)\n    {\n        return $this->andX(Expr::contains($string));\n    }\n\n    public function andKeyExists($keyName)\n    {\n        return $this->andX(Expr::keyExists($keyName));\n    }\n\n    public function andKeyNotExists($keyName)\n    {\n        return $this->andX(Expr::keyNotExists($keyName));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($values)\n    {\n        foreach ($this->conjuncts as $expr) {\n            if (!$expr->evaluate($values)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (get_class($this) !== get_class($other)) {\n            return false;\n        }\n\n        /* @var static $other */\n        $leftConjuncts = $this->conjuncts;\n        $rightConjuncts = $other->conjuncts;\n\n        foreach ($leftConjuncts as $leftConjunct) {\n            foreach ($rightConjuncts as $j => $rightConjunct) {\n                if ($leftConjunct->equivalentTo($rightConjunct)) {\n                    unset($rightConjuncts[$j]);\n                    continue 2;\n                }\n            }\n\n            // $leftConjunct was not found in $rightConjuncts\n            return false;\n        }\n\n        // All $leftConjuncts were found. Check if any $rightConjuncts are left\n        return 0 === count($rightConjuncts);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return implode(' && ', array_map(function (Expression $conjunct) {\n            return $conjunct instanceof OrX ? '('.$conjunct->toString().')' : $conjunct->toString();\n        }, $this->conjuncts));\n    }\n\n    public function __toString()\n    {\n        return $this->toString();\n    }\n}\n"
  },
  {
    "path": "src/Logic/Literal.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Logic;\n\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Expression;\n\n/**\n * A logical literal.\n *\n * In pure logics, a literal is any part of a formula that does not contain\n * \"and\" or \"or\" operators. In this package, the definition of a literal is\n * widened to any logical expression that is *not* a conjunction/disjunction.\n *\n * Examples:\n *\n *  * not endsWith(\".css\")\n *  * greaterThan(0)\n *  * not (greaterThan(0) and lessThan(120))\n *\n * The following examples are *not* literals:\n *\n *  * greaterThan(0) and lessThan(120)\n *  * in([\"A\", \"B\", \"C]) or null()\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nabstract class Literal implements Expression\n{\n    public function andX(Expression $expr)\n    {\n        if ($expr instanceof AlwaysTrue) {\n            return $this;\n        } elseif ($expr instanceof AlwaysFalse) {\n            return $expr;\n        }\n\n        if ($this->equivalentTo($expr)) {\n            return $this;\n        }\n\n        return new AndX(array($this, $expr));\n    }\n\n    public function andNot(Expression $expr)\n    {\n        return $this->andX(Expr::not($expr));\n    }\n\n    public function andTrue()\n    {\n        return $this;\n    }\n\n    public function andFalse()\n    {\n        return Expr::false();\n    }\n\n    public function andKey($keyName, Expression $expr)\n    {\n        return $this->andX(Expr::key($keyName, $expr));\n    }\n\n    public function andMethod($methodName, $args)\n    {\n        return $this->andX(call_user_func_array(array('Webmozart\\Expression\\Expr', 'method'), func_get_args()));\n    }\n\n    public function andProperty($propertyName, Expression $expr)\n    {\n        return $this->andX(Expr::property($propertyName, $expr));\n    }\n\n    public function andAtLeast($count, Expression $expr)\n    {\n        return $this->andX(Expr::atLeast($count, $expr));\n    }\n\n    public function andAtMost($count, Expression $expr)\n    {\n        return $this->andX(Expr::atMost($count, $expr));\n    }\n\n    public function andExactly($count, Expression $expr)\n    {\n        return $this->andX(Expr::exactly($count, $expr));\n    }\n\n    public function andAll(Expression $expr)\n    {\n        return $this->andX(Expr::all($expr));\n    }\n\n    public function andCount(Expression $expr)\n    {\n        return $this->andX(Expr::count($expr));\n    }\n\n    public function andNull()\n    {\n        return $this->andX(Expr::null());\n    }\n\n    public function andNotNull()\n    {\n        return $this->andX(Expr::notNull());\n    }\n\n    public function andEmpty()\n    {\n        return $this->andX(Expr::isEmpty());\n    }\n\n    public function andNotEmpty()\n    {\n        return $this->andX(Expr::notEmpty());\n    }\n\n    public function andInstanceOf($className)\n    {\n        return $this->andX(Expr::isInstanceOf($className));\n    }\n\n    public function andEquals($value)\n    {\n        return $this->andX(Expr::equals($value));\n    }\n\n    public function andNotEquals($value)\n    {\n        return $this->andX(Expr::notEquals($value));\n    }\n\n    public function andSame($value)\n    {\n        return $this->andX(Expr::same($value));\n    }\n\n    public function andNotSame($value)\n    {\n        return $this->andX(Expr::notSame($value));\n    }\n\n    public function andGreaterThan($value)\n    {\n        return $this->andX(Expr::greaterThan($value));\n    }\n\n    public function andGreaterThanEqual($value)\n    {\n        return $this->andX(Expr::greaterThanEqual($value));\n    }\n\n    public function andLessThan($value)\n    {\n        return $this->andX(Expr::lessThan($value));\n    }\n\n    public function andLessThanEqual($value)\n    {\n        return $this->andX(Expr::lessThanEqual($value));\n    }\n\n    public function andIn(array $values)\n    {\n        return $this->andX(Expr::in($values));\n    }\n\n    public function andMatches($regExp)\n    {\n        return $this->andX(Expr::matches($regExp));\n    }\n\n    public function andStartsWith($prefix)\n    {\n        return $this->andX(Expr::startsWith($prefix));\n    }\n\n    public function andEndsWith($suffix)\n    {\n        return $this->andX(Expr::endsWith($suffix));\n    }\n\n    public function andContains($string)\n    {\n        return $this->andX(Expr::contains($string));\n    }\n\n    public function andKeyExists($keyName)\n    {\n        return $this->andX(Expr::keyExists($keyName));\n    }\n\n    public function andKeyNotExists($keyName)\n    {\n        return $this->andX(Expr::keyNotExists($keyName));\n    }\n\n    public function orX(Expression $expr)\n    {\n        if ($expr instanceof AlwaysFalse) {\n            return $this;\n        } elseif ($expr instanceof AlwaysTrue) {\n            return $expr;\n        }\n\n        if ($this->equivalentTo($expr)) {\n            return $this;\n        }\n\n        return new OrX(array($this, $expr));\n    }\n\n    public function orNot(Expression $expr)\n    {\n        return $this->orX(Expr::not($expr));\n    }\n\n    public function orTrue()\n    {\n        return Expr::true();\n    }\n\n    public function orFalse()\n    {\n        return $this;\n    }\n\n    public function orKey($keyName, Expression $expr)\n    {\n        return $this->orX(Expr::key($keyName, $expr));\n    }\n\n    public function orMethod($methodName, $args)\n    {\n        return $this->orX(call_user_func_array(array('Webmozart\\Expression\\Expr', 'method'), func_get_args()));\n    }\n\n    public function orProperty($propertyName, Expression $expr)\n    {\n        return $this->orX(Expr::property($propertyName, $expr));\n    }\n\n    public function orAtLeast($count, Expression $expr)\n    {\n        return $this->orX(Expr::atLeast($count, $expr));\n    }\n\n    public function orAtMost($count, Expression $expr)\n    {\n        return $this->orX(Expr::atMost($count, $expr));\n    }\n\n    public function orExactly($count, Expression $expr)\n    {\n        return $this->orX(Expr::exactly($count, $expr));\n    }\n\n    public function orAll(Expression $expr)\n    {\n        return $this->orX(Expr::all($expr));\n    }\n\n    public function orCount(Expression $expr)\n    {\n        return $this->orX(Expr::count($expr));\n    }\n\n    public function orNull()\n    {\n        return $this->orX(Expr::null());\n    }\n\n    public function orNotNull()\n    {\n        return $this->orX(Expr::notNull());\n    }\n\n    public function orEmpty()\n    {\n        return $this->orX(Expr::isEmpty());\n    }\n\n    public function orNotEmpty()\n    {\n        return $this->orX(Expr::notEmpty());\n    }\n\n    public function orInstanceOf($className)\n    {\n        return $this->orX(Expr::isInstanceOf($className));\n    }\n\n    public function orEquals($value)\n    {\n        return $this->orX(Expr::equals($value));\n    }\n\n    public function orNotEquals($value)\n    {\n        return $this->orX(Expr::notEquals($value));\n    }\n\n    public function orSame($value)\n    {\n        return $this->orX(Expr::same($value));\n    }\n\n    public function orNotSame($value)\n    {\n        return $this->orX(Expr::notSame($value));\n    }\n\n    public function orGreaterThan($value)\n    {\n        return $this->orX(Expr::greaterThan($value));\n    }\n\n    public function orGreaterThanEqual($value)\n    {\n        return $this->orX(Expr::greaterThanEqual($value));\n    }\n\n    public function orLessThan($value)\n    {\n        return $this->orX(Expr::lessThan($value));\n    }\n\n    public function orLessThanEqual($value)\n    {\n        return $this->orX(Expr::lessThanEqual($value));\n    }\n\n    public function orIn(array $values)\n    {\n        return $this->orX(Expr::in($values));\n    }\n\n    public function orMatches($regExp)\n    {\n        return $this->orX(Expr::matches($regExp));\n    }\n\n    public function orStartsWith($prefix)\n    {\n        return $this->orX(Expr::startsWith($prefix));\n    }\n\n    public function orEndsWith($suffix)\n    {\n        return $this->orX(Expr::endsWith($suffix));\n    }\n\n    public function orContains($string)\n    {\n        return $this->orX(Expr::contains($string));\n    }\n\n    public function orKeyExists($keyName)\n    {\n        return $this->orX(Expr::keyExists($keyName));\n    }\n\n    public function orKeyNotExists($keyName)\n    {\n        return $this->orX(Expr::keyNotExists($keyName));\n    }\n\n    public function __toString()\n    {\n        return $this->toString();\n    }\n}\n"
  },
  {
    "path": "src/Logic/Not.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Logic;\n\nuse Webmozart\\Expression\\Expression;\n\n/**\n * Negates another expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Not extends Literal\n{\n    /**\n     * @var Expression\n     */\n    private $expr;\n\n    /**\n     * Creates the negation.\n     *\n     * @param Expression $expr The negated expression.\n     */\n    public function __construct(Expression $expr)\n    {\n        $this->expr = $expr;\n    }\n\n    /**\n     * Returns the negated expression.\n     *\n     * @return Expression The negated expression.\n     */\n    public function getNegatedExpression()\n    {\n        return $this->expr;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return !$this->expr->evaluate($value);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        // Since this class is final, we can check with instanceof\n        return $other instanceof $this && $this->expr->equivalentTo($other->expr);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        $exprString = $this->expr->toString();\n\n        if (isset($exprString[0]) && '(' === $exprString[0]) {\n            return 'not'.$exprString;\n        }\n\n        return 'not('.$exprString.')';\n    }\n}\n"
  },
  {
    "path": "src/Logic/OrX.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Logic;\n\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Expression;\n\n/**\n * A disjunction of expressions.\n *\n * A disjunction is a set of {@link Expression} instances connected by logical\n * \"or\" operators.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass OrX implements Expression\n{\n    /**\n     * @var Expression[]\n     */\n    private $disjuncts = array();\n\n    /**\n     * Creates a disjunction of the given expressions.\n     *\n     * @param Expression[] $disjuncts The disjuncts.\n     */\n    public function __construct(array $disjuncts = array())\n    {\n        foreach ($disjuncts as $disjunct) {\n            if ($disjunct instanceof self) {\n                foreach ($disjunct->disjuncts as $expr) {\n                    // $disjunct is guaranteed not to contain Disjunctions\n                    $this->disjuncts[] = $expr;\n                }\n            } else {\n                $this->disjuncts[] = $disjunct;\n            }\n        }\n    }\n\n    /**\n     * Returns the disjuncts of the disjunction.\n     *\n     * @return Expression[] The disjuncts.\n     */\n    public function getDisjuncts()\n    {\n        return $this->disjuncts;\n    }\n\n    public function orX(Expression $expr)\n    {\n        if ($expr instanceof AlwaysFalse) {\n            return $this;\n        } elseif ($expr instanceof AlwaysTrue) {\n            return $expr;\n        }\n\n        foreach ($this->disjuncts as $disjunct) {\n            if ($disjunct->equivalentTo($expr)) {\n                return $this;\n            }\n        }\n\n        $disjuncts = $this->disjuncts;\n\n        if ($expr instanceof self) {\n            $disjuncts = array_merge($disjuncts, $expr->disjuncts);\n        } else {\n            $disjuncts[] = $expr;\n        }\n\n        return new self($disjuncts);\n    }\n\n    public function orNot(Expression $expr)\n    {\n        return $this->orX(Expr::not($expr));\n    }\n\n    public function orTrue()\n    {\n        return Expr::true();\n    }\n\n    public function orFalse()\n    {\n        return $this;\n    }\n\n    public function orKey($keyName, Expression $expr)\n    {\n        return $this->orX(Expr::key($keyName, $expr));\n    }\n\n    public function orMethod($methodName, $args)\n    {\n        return $this->orX(call_user_func_array(array('Webmozart\\Expression\\Expr', 'method'), func_get_args()));\n    }\n\n    public function orProperty($propertyName, Expression $expr)\n    {\n        return $this->orX(Expr::property($propertyName, $expr));\n    }\n\n    public function orAtLeast($count, Expression $expr)\n    {\n        return $this->orX(Expr::atLeast($count, $expr));\n    }\n\n    public function orAtMost($count, Expression $expr)\n    {\n        return $this->orX(Expr::atMost($count, $expr));\n    }\n\n    public function orExactly($count, Expression $expr)\n    {\n        return $this->orX(Expr::exactly($count, $expr));\n    }\n\n    public function orCount(Expression $expr)\n    {\n        return $this->orX(Expr::count($expr));\n    }\n\n    public function orAll(Expression $expr)\n    {\n        return $this->orX(Expr::all($expr));\n    }\n\n    public function orNull()\n    {\n        return $this->orX(Expr::null());\n    }\n\n    public function orNotNull()\n    {\n        return $this->orX(Expr::notNull());\n    }\n\n    public function orEmpty()\n    {\n        return $this->orX(Expr::isEmpty());\n    }\n\n    public function orNotEmpty()\n    {\n        return $this->orX(Expr::notEmpty());\n    }\n\n    public function orInstanceOf($className)\n    {\n        return $this->orX(Expr::isInstanceOf($className));\n    }\n\n    public function orEquals($value)\n    {\n        return $this->orX(Expr::equals($value));\n    }\n\n    public function orNotEquals($value)\n    {\n        return $this->orX(Expr::notEquals($value));\n    }\n\n    public function orSame($value)\n    {\n        return $this->orX(Expr::same($value));\n    }\n\n    public function orNotSame($value)\n    {\n        return $this->orX(Expr::notSame($value));\n    }\n\n    public function orGreaterThan($value)\n    {\n        return $this->orX(Expr::greaterThan($value));\n    }\n\n    public function orGreaterThanEqual($value)\n    {\n        return $this->orX(Expr::greaterThanEqual($value));\n    }\n\n    public function orLessThan($value)\n    {\n        return $this->orX(Expr::lessThan($value));\n    }\n\n    public function orLessThanEqual($value)\n    {\n        return $this->orX(Expr::lessThanEqual($value));\n    }\n\n    public function orIn(array $values)\n    {\n        return $this->orX(Expr::in($values));\n    }\n\n    public function orMatches($regExp)\n    {\n        return $this->orX(Expr::matches($regExp));\n    }\n\n    public function orStartsWith($prefix)\n    {\n        return $this->orX(Expr::startsWith($prefix));\n    }\n\n    public function orEndsWith($suffix)\n    {\n        return $this->orX(Expr::endsWith($suffix));\n    }\n\n    public function orContains($string)\n    {\n        return $this->orX(Expr::contains($string));\n    }\n\n    public function orKeyExists($keyName)\n    {\n        return $this->orX(Expr::keyExists($keyName));\n    }\n\n    public function orKeyNotExists($keyName)\n    {\n        return $this->orX(Expr::keyNotExists($keyName));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($values)\n    {\n        foreach ($this->disjuncts as $expr) {\n            if ($expr->evaluate($values)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (get_class($this) !== get_class($other)) {\n            return false;\n        }\n\n        /* @var static $other */\n        $leftDisjuncts = $this->disjuncts;\n        $rightDisjuncts = $other->disjuncts;\n\n        foreach ($leftDisjuncts as $leftDisjunct) {\n            foreach ($rightDisjuncts as $j => $rightDisjunct) {\n                if ($leftDisjunct->equivalentTo($rightDisjunct)) {\n                    unset($rightDisjuncts[$j]);\n                    continue 2;\n                }\n            }\n\n            // $leftDisjunct was not found in $rightDisjuncts\n            return false;\n        }\n\n        // All $leftDisjuncts were found. Check if any $rightDisjuncts are left\n        return 0 === count($rightDisjuncts);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return implode(' || ', array_map(function (Expression $disjunct) {\n            return $disjunct instanceof AndX ? '('.$disjunct->toString().')' : $disjunct->toString();\n        }, $this->disjuncts));\n    }\n\n    public function __toString()\n    {\n        return $this->toString();\n    }\n}\n"
  },
  {
    "path": "src/PhpUnit/ExpressionComparator.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\PhpUnit;\n\nuse SebastianBergmann\\Comparator\\Comparator;\nuse SebastianBergmann\\Comparator\\ComparisonFailure;\nuse Webmozart\\Expression\\Expression;\n\n/**\n * Compares {@link Expression} objects for equality.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass ExpressionComparator extends Comparator\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function accepts($expected, $actual)\n    {\n        return $expected instanceof Expression && $actual instanceof Expression;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = array())\n    {\n        if (get_class($actual) !== get_class($expected)) {\n            throw new ComparisonFailure(\n                $expected,\n                $actual,\n                $this->exporter->export($expected),\n                $this->exporter->export($actual),\n                false,\n                sprintf(\n                    '%s is not instance of expected class \"%s\".',\n                    $this->exporter->export($actual),\n                    get_class($expected)\n                )\n            );\n        }\n\n        /** @var Expression $actual */\n        if (!$actual->equivalentTo($expected)) {\n            throw new ComparisonFailure(\n                $expected,\n                $actual,\n                $expected->toString(),\n                $actual->toString(),\n                false,\n                'Failed asserting that two expressions are equal.'\n            );\n        }\n    }\n}\n"
  },
  {
    "path": "src/Selector/All.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Traversable;\n\n/**\n * Checks that all iterator entries match an expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass All extends Selector\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_array($value) && !$value instanceof Traversable) {\n            return false;\n        }\n\n        foreach ($value as $entry) {\n            if (!$this->expr->evaluate($entry)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'all('.$this->expr->toString().')';\n    }\n}\n"
  },
  {
    "path": "src/Selector/AtLeast.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Traversable;\nuse Webmozart\\Expression\\Expression;\n\n/**\n * Checks that at least N iterator entries match an expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AtLeast extends Selector\n{\n    /**\n     * @var int\n     */\n    private $count;\n\n    /**\n     * Creates the expression.\n     *\n     * @param int        $count The minimum number of entries that must match\n     *                          the expression.\n     * @param Expression $expr  The expression to evaluate with each entry.\n     */\n    public function __construct($count, Expression $expr)\n    {\n        parent::__construct($expr);\n\n        $this->count = (int) $count;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_array($value) && !$value instanceof Traversable) {\n            return false;\n        }\n\n        $found = 0;\n\n        foreach ($value as $entry) {\n            if ($this->expr->evaluate($entry)) {\n                ++$found;\n\n                if ($found >= $this->count) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (!parent::equivalentTo($other)) {\n            return false;\n        }\n\n        /* @var static $other */\n        return $this->count === $other->count;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'atLeast('.$this->count.', '.$this->expr->toString().')';\n    }\n}\n"
  },
  {
    "path": "src/Selector/AtMost.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Traversable;\nuse Webmozart\\Expression\\Expression;\n\n/**\n * Checks that at most N iterator entries match an expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AtMost extends Selector\n{\n    /**\n     * @var int\n     */\n    private $count;\n\n    /**\n     * Creates the expression.\n     *\n     * @param int        $count The maximum number of entries that must match\n     *                          the expression.\n     * @param Expression $expr  The expression to evaluate with each entry.\n     */\n    public function __construct($count, Expression $expr)\n    {\n        parent::__construct($expr);\n\n        $this->count = (int) $count;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_array($value) && !$value instanceof Traversable) {\n            return false;\n        }\n\n        $found = 0;\n\n        foreach ($value as $entry) {\n            if ($this->expr->evaluate($entry)) {\n                ++$found;\n\n                if ($found > $this->count) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (!parent::equivalentTo($other)) {\n            return false;\n        }\n\n        /* @var static $other */\n        return $this->count === $other->count;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'atMost('.$this->count.', '.$this->expr->toString().')';\n    }\n}\n"
  },
  {
    "path": "src/Selector/Count.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Countable;\n\n/**\n * Checks that the count of a collection matches an expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Count extends Selector\n{\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_array($value) && !$value instanceof Countable) {\n            return false;\n        }\n\n        return $this->expr->evaluate(count($value));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'count('.$this->expr->toString().')';\n    }\n}\n"
  },
  {
    "path": "src/Selector/Exactly.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Traversable;\nuse Webmozart\\Expression\\Expression;\n\n/**\n * Checks that exactly N iterator entries match an expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Exactly extends Selector\n{\n    /**\n     * @var int\n     */\n    private $count;\n\n    /**\n     * Creates the expression.\n     *\n     * @param int        $count The number of entries that must match the\n     *                          expression.\n     * @param Expression $expr  The expression to evaluate with each entry.\n     */\n    public function __construct($count, Expression $expr)\n    {\n        parent::__construct($expr);\n\n        $this->count = (int) $count;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_array($value) && !$value instanceof Traversable) {\n            return false;\n        }\n\n        $found = 0;\n\n        foreach ($value as $entry) {\n            if ($this->expr->evaluate($entry)) {\n                ++$found;\n\n                if ($found > $this->count) {\n                    return false;\n                }\n            }\n        }\n\n        return $found === $this->count;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (!parent::equivalentTo($other)) {\n            return false;\n        }\n\n        /* @var static $other */\n        return $this->count === $other->count;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        return 'exactly('.$this->count.', '.$this->expr->toString().')';\n    }\n}\n"
  },
  {
    "path": "src/Selector/Key.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\OrX;\n\n/**\n * Checks whether an array key matches an expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Key extends Selector\n{\n    /**\n     * @var string\n     */\n    private $key;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string|int $key  The array key.\n     * @param Expression $expr The expression to evaluate for the key.\n     */\n    public function __construct($key, Expression $expr)\n    {\n        parent::__construct($expr);\n\n        $this->key = (string) $key;\n    }\n\n    /**\n     * Returns the array key.\n     *\n     * @return string|int The array key.\n     */\n    public function getKey()\n    {\n        return $this->key;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_array($value)) {\n            return false;\n        }\n\n        if (!array_key_exists($this->key, $value)) {\n            return false;\n        }\n\n        return $this->expr->evaluate($value[$this->key]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (!parent::equivalentTo($other)) {\n            return false;\n        }\n\n        /* @var static $other */\n        return $this->key === $other->key;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        $exprString = $this->expr->toString();\n\n        if ($this->expr instanceof AndX || $this->expr instanceof OrX) {\n            return $this->key.'{'.$exprString.'}';\n        }\n\n        // Append \"functions\" with \".\"\n        if (isset($exprString[0]) && ctype_alpha($exprString[0])) {\n            return $this->key.'.'.$exprString;\n        }\n\n        return $this->key.$exprString;\n    }\n}\n"
  },
  {
    "path": "src/Selector/Method.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\OrX;\nuse Webmozart\\Expression\\Util\\StringUtil;\n\n/**\n * Checks whether the result of a method call matches an expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Method extends Selector\n{\n    /**\n     * @var string\n     */\n    private $methodName;\n\n    /**\n     * @var array\n     */\n    private $arguments;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string     $methodName The name of the method to call.\n     * @param array      $arguments  The arguments to pass to the method.\n     * @param Expression $expr       The expression to evaluate for the result.\n     */\n    public function __construct($methodName, array $arguments, Expression $expr)\n    {\n        parent::__construct($expr);\n\n        $this->methodName = $methodName;\n        $this->arguments = $arguments;\n    }\n\n    /**\n     * Returns the method name.\n     *\n     * @return string The method name.\n     */\n    public function getMethodName()\n    {\n        return $this->methodName;\n    }\n\n    /**\n     * Returns the method arguments.\n     *\n     * @return array The method arguments.\n     */\n    public function getArguments()\n    {\n        return $this->arguments;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_object($value)) {\n            return false;\n        }\n\n        if (!method_exists($value, $this->methodName)) {\n            return false;\n        }\n\n        return $this->expr->evaluate(call_user_func_array(array($value, $this->methodName), $this->arguments));\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (!parent::equivalentTo($other)) {\n            return false;\n        }\n\n        /* @var static $other */\n        return $this->methodName === $other->methodName && $this->arguments === $other->arguments;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        $exprString = $this->expr->toString();\n        $argsString = implode(', ', StringUtil::formatValues($this->arguments));\n\n        if ($this->expr instanceof AndX || $this->expr instanceof OrX) {\n            return $this->methodName.'('.$argsString.'){'.$exprString.'}';\n        }\n\n        // Append \"functions\" with \".\"\n        if (isset($exprString[0]) && ctype_alpha($exprString[0])) {\n            return $this->methodName.'('.$argsString.').'.$exprString;\n        }\n\n        return $this->methodName.'('.$argsString.')'.$exprString;\n    }\n}\n"
  },
  {
    "path": "src/Selector/Property.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\OrX;\n\n/**\n * Checks whether the value of a property matches an expression.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass Property extends Selector\n{\n    /**\n     * @var string\n     */\n    private $propertyName;\n\n    /**\n     * Creates the expression.\n     *\n     * @param string     $propertyName The name of the property.\n     * @param Expression $expr         The expression to evaluate for the result.\n     */\n    public function __construct($propertyName, Expression $expr)\n    {\n        parent::__construct($expr);\n\n        $this->propertyName = $propertyName;\n    }\n\n    /**\n     * Returns the property name.\n     *\n     * @return string The property name.\n     */\n    public function getPropertyName()\n    {\n        return $this->propertyName;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        if (!is_object($value)) {\n            return false;\n        }\n\n        $propertyName = $this->propertyName;\n\n        if (!property_exists($value, $propertyName)) {\n            return false;\n        }\n\n        return $this->expr->evaluate($value->$propertyName);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (!parent::equivalentTo($other)) {\n            return false;\n        }\n\n        /* @var static $other */\n        return $this->propertyName === $other->propertyName;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n        $exprString = $this->expr->toString();\n\n        if ($this->expr instanceof AndX || $this->expr instanceof OrX) {\n            return $this->propertyName.'{'.$exprString.'}';\n        }\n\n        // Append \"functions\" with \".\"\n        if (isset($exprString[0]) && ctype_alpha($exprString[0])) {\n            return $this->propertyName.'.'.$exprString;\n        }\n\n        return $this->propertyName.$exprString;\n    }\n}\n"
  },
  {
    "path": "src/Selector/Selector.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Selector;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\n\n/**\n * A logical selector.\n *\n * Evaluates an expression for elements of a structured value.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nabstract class Selector extends Literal\n{\n    /**\n     * @var Expression\n     */\n    protected $expr;\n\n    /**\n     * Checks whether a value selected from the evaluated value matches an\n     * expression.\n     *\n     * @param Expression $expr The expression to evaluate for the selected value.\n     */\n    public function __construct(Expression $expr)\n    {\n        $this->expr = $expr;\n    }\n\n    /**\n     * Returns the expression that is evaluated for the selected value.\n     *\n     * @return Expression The inner expression.\n     */\n    public function getExpression()\n    {\n        return $this->expr;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function equivalentTo(Expression $other)\n    {\n        if (get_class($this) !== get_class($other)) {\n            return false;\n        }\n\n        /* @var Selector $other */\n        return $this->expr->equivalentTo($other->expr);\n    }\n}\n"
  },
  {
    "path": "src/Traversal/ExpressionTraverser.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Traversal;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\Not;\nuse Webmozart\\Expression\\Logic\\OrX;\nuse Webmozart\\Expression\\Selector\\Key;\n\n/**\n * Traverses {@link Expression} instances.\n *\n * You can attach {@link ExpressionVisitor} instances to the traverse which\n * will be invoked for every node of the expression tree.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass ExpressionTraverser\n{\n    /**\n     * @var ExpressionVisitor[]\n     */\n    private $visitors = array();\n\n    /**\n     * Adds a visitor to the traverser.\n     *\n     * The visitors are invoked in the order in which they are added.\n     *\n     * @param ExpressionVisitor $visitor The visitor to add.\n     */\n    public function addVisitor(ExpressionVisitor $visitor)\n    {\n        $this->visitors[] = $visitor;\n    }\n\n    /**\n     * Removes a visitor from the traverser.\n     *\n     * If the visitor was added multiple times, all instances are removed.\n     *\n     * @param ExpressionVisitor $visitor The visitor to remove.\n     */\n    public function removeVisitor(ExpressionVisitor $visitor)\n    {\n        while (false !== ($key = array_search($visitor, $this->visitors, true))) {\n            unset($this->visitors[$key]);\n        }\n\n        $this->visitors = array_values($this->visitors);\n    }\n\n    /**\n     * Returns the visitors of the traverser.\n     *\n     * @return ExpressionVisitor[] The visitors.\n     */\n    public function getVisitors()\n    {\n        return $this->visitors;\n    }\n\n    /**\n     * Traverses an expression.\n     *\n     * @param Expression $expr The expression to traverse.\n     *\n     * @return Expression The modified expression. May be `null` if the\n     *                    expression was removed entirely.\n     */\n    public function traverse(Expression $expr)\n    {\n        // Do one full traversal per visitor. If any of the visitors removes\n        // the expression entirely, subsequent visitors are not invoked.\n        foreach ($this->visitors as $visitor) {\n            $expr = $this->traverseForVisitor($expr, $visitor);\n\n            if (!$expr) {\n                return null;\n            }\n        }\n\n        return $expr;\n    }\n\n    private function traverseForVisitor(Expression $expr, ExpressionVisitor $visitor)\n    {\n        $expr = $visitor->enterExpression($expr);\n\n        if ($expr instanceof Key) {\n            $expr = $this->traverseKey($expr);\n        } elseif ($expr instanceof Not) {\n            $expr = $this->traverseNot($expr);\n        } elseif ($expr instanceof AndX) {\n            $expr = $this->traverseConjunction($expr);\n        } elseif ($expr instanceof OrX) {\n            $expr = $this->traverseDisjunction($expr);\n        }\n\n        if ($expr) {\n            $expr = $visitor->leaveExpression($expr);\n        }\n\n        return $expr;\n    }\n\n    private function traverseKey(Key $expr)\n    {\n        $innerExpr1 = $expr->getExpression();\n        $innerExpr2 = $this->traverse($innerExpr1);\n\n        if ($innerExpr1 === $innerExpr2) {\n            return $expr;\n        }\n\n        return $innerExpr2 ? new Key($expr->getKey(), $innerExpr2) : null;\n    }\n\n    private function traverseNot(Not $expr)\n    {\n        $negatedExpr1 = $expr->getNegatedExpression();\n        $negatedExpr2 = $this->traverse($negatedExpr1);\n\n        if ($negatedExpr1 === $negatedExpr2) {\n            return $expr;\n        }\n\n        return $negatedExpr2 ? new Not($negatedExpr2) : null;\n    }\n\n    private function traverseConjunction(AndX $expr)\n    {\n        $conjuncts1 = $expr->getConjuncts();\n        $conjuncts2 = array();\n\n        foreach ($conjuncts1 as $conjunct) {\n            if ($conjunct = $this->traverse($conjunct)) {\n                $conjuncts2[] = $conjunct;\n            }\n        }\n\n        if ($conjuncts1 === $conjuncts2) {\n            return $expr;\n        }\n\n        return $conjuncts2 ? new AndX($conjuncts2) : null;\n    }\n\n    private function traverseDisjunction(OrX $expr)\n    {\n        $disjuncts1 = $expr->getDisjuncts();\n        $disjuncts2 = array();\n\n        foreach ($disjuncts1 as $disjunct) {\n            if ($disjunct = $this->traverse($disjunct)) {\n                $disjuncts2[] = $disjunct;\n            }\n        }\n\n        if ($disjuncts1 === $disjuncts2) {\n            return $expr;\n        }\n\n        return $disjuncts2 ? new OrX($disjuncts2) : null;\n    }\n}\n"
  },
  {
    "path": "src/Traversal/ExpressionVisitor.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Traversal;\n\nuse Webmozart\\Expression\\Expression;\n\n/**\n * Visits the nodes of an {@link Expression} tree.\n *\n * The visitor needs to be attached to a {@link ExpressionTraverser}. The\n * traverser invokes the visitor for every node of the expression tree.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\ninterface ExpressionVisitor\n{\n    /**\n     * Called when the traverser enters an expression.\n     *\n     * @param Expression $expr The expression.\n     *\n     * @return Expression The modified expression.\n     */\n    public function enterExpression(Expression $expr);\n\n    /**\n     * Called when the traverser leaves an expression.\n     *\n     * @param Expression $expr The expression.\n     *\n     * @return Expression|null The modified expression or `null` if the\n     *                         expression should be removed from the tree.\n     */\n    public function leaveExpression(Expression $expr);\n}\n"
  },
  {
    "path": "src/Util/StringUtil.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Util;\n\n/**\n * Contains string utility methods.\n *\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass StringUtil\n{\n    /**\n     * Formats a value as string.\n     *\n     * @param mixed $value The value.\n     *\n     * @return string The value as string.\n     */\n    public static function formatValue($value)\n    {\n        if (null === $value) {\n            return 'null';\n        }\n\n        if (true === $value) {\n            return 'true';\n        }\n\n        if (false === $value) {\n            return 'false';\n        }\n\n        if (is_string($value)) {\n            return '\"'.$value.'\"';\n        }\n\n        if (is_object($value)) {\n            return 'object';\n        }\n\n        if (is_array($value)) {\n            return 'array';\n        }\n\n        return (string) $value;\n    }\n\n    /**\n     * Formats a list of values as strings.\n     *\n     * @param array $values The values.\n     *\n     * @return array The values as strings.\n     */\n    public static function formatValues(array $values)\n    {\n        foreach ($values as $key => $value) {\n            $values[$key] = self::formatValue($value);\n        }\n\n        return $values;\n    }\n\n    /**\n     * May not be instantiated.\n     */\n    private function __construct()\n    {\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/ContainsTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Contains;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n * @author Stephan Wentz <stephan@wentz.it>\n */\nclass ContainsTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new Contains('test');\n\n        $this->assertTrue($expr->evaluate('testString'));\n        $this->assertTrue($expr->evaluate('anothertest'));\n        $this->assertTrue($expr->evaluate('testtest'));\n        $this->assertTrue($expr->evaluate('test'));\n        $this->assertFalse($expr->evaluate('xest'));\n        $this->assertFalse($expr->evaluate('est'));\n        $this->assertFalse($expr->evaluate('tesx'));\n    }\n\n    public function testToString()\n    {\n        $expr = new Contains('testString');\n\n        $this->assertSame('contains(\"testString\")', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/EndsWithTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass EndsWithTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new EndsWith('.css');\n\n        $this->assertTrue($expr->evaluate('style.css'));\n        $this->assertFalse($expr->evaluate('style.css.dist'));\n    }\n\n    public function testToString()\n    {\n        $expr = new EndsWith('.css');\n\n        $this->assertSame('endsWith(\".css\")', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/EqualsTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Equals;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass EqualsTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new Equals('10');\n\n        $this->assertTrue($expr->evaluate('10'));\n        $this->assertTrue($expr->evaluate(10));\n        $this->assertTrue($expr->evaluate(10.0));\n        $this->assertFalse($expr->evaluate('100'));\n        $this->assertFalse($expr->evaluate(11));\n    }\n\n    public function testToString()\n    {\n        $expr = new Equals('10');\n\n        $this->assertSame('==\"10\"', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/GreaterThanEqualTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information => please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\GreaterThanEqual;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass GreaterThanEqualTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new GreaterThanEqual(10);\n\n        $this->assertTrue($expr->evaluate(11));\n        $this->assertTrue($expr->evaluate(11.0));\n        $this->assertTrue($expr->evaluate('11'));\n        $this->assertTrue($expr->evaluate(10));\n        $this->assertFalse($expr->evaluate(9));\n    }\n\n    public function testToString()\n    {\n        $expr = new GreaterThanEqual(10);\n\n        $this->assertSame('>=10', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/GreaterThanTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information => please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass GreaterThanTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new GreaterThan(10);\n\n        $this->assertTrue($expr->evaluate(11));\n        $this->assertTrue($expr->evaluate(11.0));\n        $this->assertTrue($expr->evaluate('11'));\n        $this->assertFalse($expr->evaluate(10));\n        $this->assertFalse($expr->evaluate(9));\n    }\n\n    public function testToString()\n    {\n        $expr = new GreaterThan(10);\n\n        $this->assertSame('>10', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/InTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\In;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass InTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluateStrict()\n    {\n        $expr = new In(array('1', '2', '3'));\n\n        $this->assertTrue($expr->evaluate('1'));\n        $this->assertFalse($expr->evaluate(1));\n        $this->assertFalse($expr->evaluate(1.0));\n        $this->assertFalse($expr->evaluate(0));\n        $this->assertFalse($expr->evaluate(10));\n        $this->assertFalse($expr->evaluate(null));\n    }\n\n    public function testEvaluateNonStrict()\n    {\n        $expr = new In(array('1', '2', '3'), false);\n\n        $this->assertTrue($expr->evaluate('1'));\n        $this->assertTrue($expr->evaluate(1));\n        $this->assertTrue($expr->evaluate(1.0));\n        $this->assertFalse($expr->evaluate(0));\n        $this->assertFalse($expr->evaluate(10));\n        $this->assertFalse($expr->evaluate(null));\n    }\n\n    public function testToString()\n    {\n        $expr = new In(array('1', '2', '3'), false);\n\n        $this->assertSame('in(\"1\", \"2\", \"3\")', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/IsEmptyTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\IsEmpty;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass IsEmptyTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new IsEmpty();\n\n        $this->assertTrue($expr->evaluate(null));\n        $this->assertTrue($expr->evaluate(0));\n        $this->assertTrue($expr->evaluate(''));\n        $this->assertTrue($expr->evaluate(false));\n        $this->assertFalse($expr->evaluate(true));\n        $this->assertFalse($expr->evaluate('abcd'));\n    }\n\n    public function testToString()\n    {\n        $expr = new IsEmpty();\n\n        $this->assertSame('empty()', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/IsInstanceOfTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse DirectoryIterator;\nuse PHPUnit_Framework_TestCase;\nuse SplFileInfo;\nuse Webmozart\\Expression\\Constraint\\IsInstanceOf;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass IsInstanceOfTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new IsInstanceOf('SplFileInfo');\n\n        $this->assertTrue($expr->evaluate(new SplFileInfo(__DIR__)));\n        $this->assertTrue($expr->evaluate(new DirectoryIterator(__DIR__)));\n        $this->assertFalse($expr->evaluate((object) array()));\n        $this->assertFalse($expr->evaluate(array()));\n        $this->assertFalse($expr->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr = new IsInstanceOf('SplFileInfo');\n\n        $this->assertSame('instanceOf(SplFileInfo)', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/KeyExistsTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\KeyExists;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass KeyExistsTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new KeyExists('key');\n\n        $this->assertTrue($expr->evaluate(array('key' => 11)));\n        $this->assertFalse($expr->evaluate(array()));\n        $this->assertFalse($expr->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr = new KeyExists('key');\n\n        $this->assertSame('keyExists(\"key\")', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/KeyNotExistsTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\KeyNotExists;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass KeyNotExistsTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new KeyNotExists('key');\n\n        $this->assertTrue($expr->evaluate(array()));\n        $this->assertFalse($expr->evaluate(array('key' => 11)));\n        $this->assertFalse($expr->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr = new KeyNotExists('key');\n\n        $this->assertSame('keyNotExists(\"key\")', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/LessThanEqualTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information => please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\LessThanEqual;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass LessThanEqualTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new LessThanEqual(10);\n\n        $this->assertTrue($expr->evaluate(9));\n        $this->assertTrue($expr->evaluate(9.0));\n        $this->assertTrue($expr->evaluate('9'));\n        $this->assertTrue($expr->evaluate(10));\n        $this->assertFalse($expr->evaluate(11));\n    }\n\n    public function testToString()\n    {\n        $expr = new LessThanEqual(10);\n\n        $this->assertSame('<=10', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/LessThanTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information => please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\LessThan;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass LessThanTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new LessThan(10);\n\n        $this->assertTrue($expr->evaluate(9));\n        $this->assertTrue($expr->evaluate(9.0));\n        $this->assertTrue($expr->evaluate('9'));\n        $this->assertFalse($expr->evaluate(10));\n        $this->assertFalse($expr->evaluate(11));\n    }\n\n    public function testToString()\n    {\n        $expr = new LessThan(10);\n\n        $this->assertSame('<10', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/MatchesTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Matches;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass MatchesTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new Matches('~^\\d{4}$~');\n\n        $this->assertTrue($expr->evaluate('1010'));\n        $this->assertTrue($expr->evaluate(1010));\n        $this->assertFalse($expr->evaluate('abcd'));\n        $this->assertFalse($expr->evaluate('10101'));\n    }\n\n    public function testToString()\n    {\n        $expr = new Matches('~^\\d{4}$~');\n\n        $this->assertSame('matches(\"~^\\d{4}$~\")', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/NotEqualsTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\NotEquals;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass NotEqualsTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new NotEquals('10');\n\n        $this->assertTrue($expr->evaluate('100'));\n        $this->assertTrue($expr->evaluate(11));\n        $this->assertFalse($expr->evaluate('10'));\n        $this->assertFalse($expr->evaluate(10));\n        $this->assertFalse($expr->evaluate(10.0));\n    }\n\n    public function testToString()\n    {\n        $expr = new NotEquals('10');\n\n        $this->assertSame('!=\"10\"', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/NotSameTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\NotSame;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass NotSameTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new NotSame('10');\n\n        $this->assertTrue($expr->evaluate('100'));\n        $this->assertTrue($expr->evaluate(11));\n        $this->assertTrue($expr->evaluate(10));\n        $this->assertTrue($expr->evaluate(10.0));\n        $this->assertFalse($expr->evaluate('10'));\n    }\n\n    public function testToString()\n    {\n        $expr = new NotSame('10');\n\n        $this->assertSame('!==\"10\"', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/SameTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Same;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass SameTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new Same('10');\n\n        $this->assertTrue($expr->evaluate('10'));\n        $this->assertFalse($expr->evaluate('100'));\n        $this->assertFalse($expr->evaluate(11));\n        $this->assertFalse($expr->evaluate(10));\n        $this->assertFalse($expr->evaluate(10.0));\n    }\n\n    public function testToString()\n    {\n        $expr = new Same('10');\n\n        $this->assertSame('===\"10\"', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Comparison/StartsWithTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Comparison;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\StartsWith;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass StartsWithTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new StartsWith('Thomas');\n\n        $this->assertTrue($expr->evaluate('Thomas Edison'));\n        $this->assertFalse($expr->evaluate('Mr. Thomas Edison'));\n    }\n\n    public function testToString()\n    {\n        $expr = new StartsWith('Thomas');\n\n        $this->assertSame('startsWith(\"Thomas\")', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/DomainExpressionsTest.php",
    "content": "<?php\n\n/*\n * This file is part of the vendor/project package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Tests\\Fixtures\\Customer;\nuse Webmozart\\Expression\\Tests\\Fixtures\\HasPreviousBookings;\nuse Webmozart\\Expression\\Tests\\Fixtures\\IsPremium;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass DomainExpressionsTest extends PHPUnit_Framework_TestCase\n{\n    public function testDomainExpressions()\n    {\n        $c1 = new Customer();\n        $c1->setPremium(true);\n        $c2 = new Customer();\n        $c2->setBookings(array('booking1', 'booking2'));\n        $c3 = new Customer();\n        $c3->setPremium(true);\n        $c3->setBookings(array('booking1'));\n\n        $customers = array($c1, $c2, $c3);\n\n        $this->assertEquals(array($c1, 2 => $c3), Expr::filter($customers, new IsPremium()));\n        $this->assertEquals(array(1 => $c2, 2 => $c3), Expr::filter($customers, new HasPreviousBookings()));\n        $this->assertEquals(array(2 => $c3), Expr::filter($customers, Expr::andX(array(\n            new HasPreviousBookings(),\n            new IsPremium(),\n        ))));\n    }\n}\n"
  },
  {
    "path": "tests/EquivalenceTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Contains;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\Equals;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Constraint\\GreaterThanEqual;\nuse Webmozart\\Expression\\Constraint\\In;\nuse Webmozart\\Expression\\Constraint\\IsEmpty;\nuse Webmozart\\Expression\\Constraint\\IsInstanceOf;\nuse Webmozart\\Expression\\Constraint\\KeyExists;\nuse Webmozart\\Expression\\Constraint\\KeyNotExists;\nuse Webmozart\\Expression\\Constraint\\LessThan;\nuse Webmozart\\Expression\\Constraint\\LessThanEqual;\nuse Webmozart\\Expression\\Constraint\\Matches;\nuse Webmozart\\Expression\\Constraint\\NotEquals;\nuse Webmozart\\Expression\\Constraint\\NotSame;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Constraint\\StartsWith;\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\AlwaysFalse;\nuse Webmozart\\Expression\\Logic\\AlwaysTrue;\nuse Webmozart\\Expression\\Logic\\Not;\nuse Webmozart\\Expression\\Selector\\All;\nuse Webmozart\\Expression\\Selector\\AtLeast;\nuse Webmozart\\Expression\\Selector\\AtMost;\nuse Webmozart\\Expression\\Selector\\Count;\nuse Webmozart\\Expression\\Selector\\Exactly;\nuse Webmozart\\Expression\\Selector\\Key;\nuse Webmozart\\Expression\\Selector\\Method;\nuse Webmozart\\Expression\\Selector\\Property;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass EquivalenceTest extends PHPUnit_Framework_TestCase\n{\n    public function getEquivalentCriteria()\n    {\n        return array(\n            array(new Same('10'), new Same('10')),\n            array(new Same('10'), new In(array('10'), true)),\n\n            array(new NotSame('10'), new NotSame('10')),\n\n            array(new Equals('10'), new Equals('10')),\n            array(new Equals('10'), new Equals(10)),\n            array(new Equals('10'), new In(array('10'), false)),\n            array(new Equals('10'), new In(array(10), false)),\n\n            array(new NotEquals('10'), new NotEquals('10')),\n            array(new NotEquals('10'), new NotEquals(10)),\n\n            array(new GreaterThan('10'), new GreaterThan('10')),\n            array(new GreaterThan('10'), new GreaterThan(10)),\n\n            array(new GreaterThanEqual('10'), new GreaterThanEqual('10')),\n            array(new GreaterThanEqual('10'), new GreaterThanEqual(10)),\n\n            array(new LessThan('10'), new LessThan('10')),\n            array(new LessThan('10'), new LessThan(10)),\n\n            array(new LessThanEqual('10'), new LessThanEqual('10')),\n            array(new LessThanEqual('10'), new LessThanEqual(10)),\n\n            array(new IsEmpty(), new IsEmpty()),\n\n            array(new IsInstanceOf('SplFileInfo'), new IsInstanceOf('SplFileInfo')),\n\n            array(new KeyExists('10'), new KeyExists('10')),\n            array(new KeyExists('10'), new KeyExists(10)),\n\n            array(new KeyNotExists('10'), new KeyNotExists('10')),\n            array(new KeyNotExists('10'), new KeyNotExists(10)),\n\n            array(new Matches('foo.*'), new Matches('foo.*')),\n\n            array(new In(array('10'), false), new In(array('10'), false)),\n            array(new In(array('10'), false), new In(array(10), false)),\n            array(new In(array('10'), true), new In(array('10'), true)),\n\n            array(new StartsWith('10'), new StartsWith('10')),\n            array(new StartsWith('10'), new StartsWith(10)),\n\n            array(new EndsWith('10'), new EndsWith('10')),\n            array(new EndsWith('10'), new EndsWith(10)),\n\n            array(new Contains('10'), new Contains('10')),\n            array(new Contains('10'), new Contains(10)),\n\n            array(new Not(new Same('10')), new Not(new Same('10'))),\n\n            array(new Key('key', new Same('10')), new Key('key', new Same('10'))),\n            array(new Key('42', new Same('10')), new Key(42, new Same('10'))),\n\n            array(new Property('prop', new Same('10')), new Property('prop', new Same('10'))),\n\n            array(new Method('getFoo', array(), new Same('10')), new Method('getFoo', array(), new Same('10'))),\n            array(new Method('getFoo', array(42), new Same('10')), new Method('getFoo', array(42), new Same('10'))),\n\n            array(new AtLeast(1, new Same('10')), new AtLeast(1, new Same('10'))),\n\n            array(new AtMost(1, new Same('10')), new AtMost(1, new Same('10'))),\n\n            array(new Exactly(1, new Same('10')), new Exactly(1, new Same('10'))),\n\n            array(new All(new Same('10')), new All(new Same('10'))),\n\n            array(new Count(new Same(10)), new Count(new Same(10))),\n\n            array(new AlwaysTrue(), new AlwaysTrue()),\n\n            array(new AlwaysFalse(), new AlwaysFalse()),\n        );\n    }\n\n    /**\n     * @dataProvider getEquivalentCriteria\n     */\n    public function testEquivalence(Expression $left, Expression $right)\n    {\n        $this->assertTrue($left->equivalentTo($right));\n        $this->assertTrue($right->equivalentTo($left));\n    }\n\n    public function getNonEquivalentCriteria()\n    {\n        return array(\n            array(new Same('10'), new Same('11')),\n            array(new Same('10'), new Same(10)),\n            array(new Same('10'), new Equals('10')),\n\n            array(new Same('10'), new In(array(10), true)),\n            array(new Same('10'), new In(array('10'), false)),\n            array(new Same('10'), new In(array(), true)),\n            array(new Same('10'), new In(array('10', '11'), true)),\n\n            array(new NotSame('10'), new NotSame('11')),\n            array(new NotSame('10'), new NotSame(10)),\n            array(new NotSame('10'), new NotEquals('10')),\n\n            array(new Equals('10'), new Equals('11')),\n            array(new Equals('10'), new In(array('10'), true)),\n            array(new Equals('10'), new In(array(), false)),\n            array(new Equals('10'), new In(array('10', '11'), false)),\n\n            array(new GreaterThan('10'), new GreaterThan('11')),\n            array(new GreaterThan('10'), new LessThan('10')),\n\n            array(new GreaterThanEqual('10'), new GreaterThanEqual('11')),\n            array(new GreaterThanEqual('10'), new LessThan('10')),\n\n            array(new LessThan('10'), new LessThan('11')),\n            array(new LessThan('10'), new GreaterThan('10')),\n\n            array(new LessThanEqual('10'), new LessThanEqual('11')),\n            array(new LessThanEqual('10'), new GreaterThan('10')),\n\n            array(new IsInstanceOf('SplFileInfo'), new IsInstanceOf('DateTime')),\n\n            array(new KeyExists('10'), new KeyExists('11')),\n            array(new KeyExists('foo'), new KeyExists(0)),\n            array(new KeyExists('10'), new Equals('10')),\n\n            array(new KeyNotExists('10'), new KeyNotExists('11')),\n            array(new KeyNotExists('foo'), new KeyNotExists(0)),\n            array(new KeyNotExists('10'), new Equals('10')),\n\n            array(new Matches('10'), new Matches(10)),\n            array(new Matches('10'), new Equals('10')),\n\n            array(new In(array('10'), true), new In(array('11'), true)),\n            array(new In(array('10'), true), new In(array(10), true)),\n            array(new In(array('10'), true), new In(array('11'), false)),\n            array(new In(array('10'), true), new IsEmpty()),\n\n            array(new StartsWith('10'), new StartsWith('11')),\n            array(new StartsWith('foo'), new StartsWith(0)),\n            array(new StartsWith('10'), new Equals('10')),\n\n            array(new EndsWith('10'), new EndsWith('11')),\n            array(new EndsWith('foo'), new EndsWith(0)),\n            array(new EndsWith('10'), new Equals('10')),\n\n            array(new Contains('10'), new Contains('11')),\n            array(new Contains('foo'), new Contains(0)),\n            array(new Contains('10'), new Equals('10')),\n\n            array(new Not(new Same('10')), new Not(new Same(10))),\n            array(new Not(new Same('10')), new Same(10)),\n\n            array(new Key('foo', new Same('10')), new Key('bar', new Same('10'))),\n            array(new Key('foo', new Same('10')), new Key(0, new Same('10'))),\n            array(new Key('foo', new Same('10')), new Key('foo', new Same(10))),\n            array(new Key('foo', new Same('10')), new Same('10')),\n\n            array(new Property('foo', new Same('10')), new Property('bar', new Same('10'))),\n            array(new Property('foo', new Same('10')), new Property('foo', new Same(10))),\n            array(new Property('foo', new Same('10')), new Same('10')),\n\n            array(new Method('getFoo', array(42), new Same('10')), new Method('getFoo', array('42'), new Same('10'))),\n            array(new Method('getFoo', array(42), new Same('10')), new Method('getFoo', array(42, true), new Same('10'))),\n            array(new Method('getFoo', array(), new Same('10')), new Method('getBar', array(), new Same('10'))),\n            array(new Method('getFoo', array(), new Same('10')), new Method('getFoo', array(), new Same(10))),\n            array(new Method('getFoo', array(), new Same('10')), new Same('10')),\n\n            array(new AtLeast(1, new Same('10')), new AtLeast(2, new Same('10'))),\n            array(new AtLeast(1, new Same('10')), new AtLeast(1, new Same(10))),\n            array(new AtLeast(1, new Same('10')), new Same('10')),\n\n            array(new AtMost(1, new Same('10')), new AtMost(2, new Same('10'))),\n            array(new AtMost(1, new Same('10')), new AtMost(1, new Same(10))),\n            array(new AtMost(1, new Same('10')), new Same('10')),\n\n            array(new Exactly(1, new Same('10')), new Exactly(2, new Same('10'))),\n            array(new Exactly(1, new Same('10')), new Exactly(1, new Same(10))),\n            array(new Exactly(1, new Same('10')), new Same('10')),\n\n            array(new All(new Same('10')), new All(new Same(10))),\n            array(new All(new Same('10')), new Same('10')),\n\n            array(new Count(new Same('10')), new Count(new Same(10))),\n            array(new Count(new Same('10')), new Same('10')),\n\n            array(new AlwaysTrue(), new Same(10)),\n\n            array(new AlwaysFalse(), new Same(10)),\n        );\n    }\n\n    /**\n     * @dataProvider getNonEquivalentCriteria\n     */\n    public function testNonEquivalence(Expression $left, Expression $right)\n    {\n        $this->assertFalse($left->equivalentTo($right));\n        $this->assertFalse($right->equivalentTo($left));\n    }\n}\n"
  },
  {
    "path": "tests/ExprTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests;\n\nuse ArrayObject;\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Contains;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\Equals;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Constraint\\GreaterThanEqual;\nuse Webmozart\\Expression\\Constraint\\In;\nuse Webmozart\\Expression\\Constraint\\IsEmpty;\nuse Webmozart\\Expression\\Constraint\\IsInstanceOf;\nuse Webmozart\\Expression\\Constraint\\KeyExists;\nuse Webmozart\\Expression\\Constraint\\KeyNotExists;\nuse Webmozart\\Expression\\Constraint\\LessThan;\nuse Webmozart\\Expression\\Constraint\\LessThanEqual;\nuse Webmozart\\Expression\\Constraint\\Matches;\nuse Webmozart\\Expression\\Constraint\\NotEquals;\nuse Webmozart\\Expression\\Constraint\\NotSame;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Constraint\\StartsWith;\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Logic\\AlwaysFalse;\nuse Webmozart\\Expression\\Logic\\AlwaysTrue;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\Not;\nuse Webmozart\\Expression\\Logic\\OrX;\nuse Webmozart\\Expression\\Selector\\All;\nuse Webmozart\\Expression\\Selector\\AtLeast;\nuse Webmozart\\Expression\\Selector\\AtMost;\nuse Webmozart\\Expression\\Selector\\Count;\nuse Webmozart\\Expression\\Selector\\Exactly;\nuse Webmozart\\Expression\\Selector\\Key;\nuse Webmozart\\Expression\\Selector\\Method;\nuse Webmozart\\Expression\\Selector\\Property;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass ExprTest extends PHPUnit_Framework_TestCase\n{\n    public static function getComparisons()\n    {\n        return array(\n            array(\n                'keyExists',\n                array('key'),\n                new KeyExists('key'),\n            ),\n            array(\n                'keyNotExists',\n                array('key'),\n                new KeyNotExists('key'),\n            ),\n            array(\n                'null',\n                array(),\n                new Same(null),\n            ),\n            array(\n                'notNull',\n                array(),\n                new NotSame(null),\n            ),\n            array(\n                'isEmpty',\n                array(),\n                new IsEmpty(),\n            ),\n            array(\n                'isInstanceOf',\n                array('DateTime'),\n                new IsInstanceOf('DateTime'),\n            ),\n            array(\n                'notEmpty',\n                array(),\n                new Not(new IsEmpty()),\n            ),\n            array(\n                'equals',\n                array(10),\n                new Equals(10),\n            ),\n            array(\n                'notEquals',\n                array(10),\n                new NotEquals(10),\n            ),\n            array(\n                'same',\n                array(10),\n                new Same(10),\n            ),\n            array(\n                'notSame',\n                array(10),\n                new NotSame(10),\n            ),\n            array(\n                'greaterThan',\n                array(10),\n                new GreaterThan(10),\n            ),\n            array(\n                'greaterThanEqual',\n                array(10),\n                new GreaterThanEqual(10),\n            ),\n            array(\n                'lessThan',\n                array(10),\n                new LessThan(10),\n            ),\n            array(\n                'lessThanEqual',\n                array(10),\n                new LessThanEqual(10),\n            ),\n            array(\n                'matches',\n                array('~^\\d{4}$~'),\n                new Matches('~^\\d{4}$~'),\n            ),\n            array(\n                'startsWith',\n                array('Thomas'),\n                new StartsWith('Thomas'),\n            ),\n            array(\n                'endsWith',\n                array('.css'),\n                new EndsWith('.css'),\n            ),\n            array(\n                'contains',\n                array('css'),\n                new Contains('css'),\n            ),\n            array(\n                'in',\n                array(array('1', '2', '3')),\n                new In(array('1', '2', '3')),\n            ),\n        );\n    }\n\n    public static function getMethodTests()\n    {\n        $expr = new Same('10');\n\n        return array_merge(array(\n            array(\n                'not',\n                array($expr),\n                new Not($expr),\n            ),\n            array(\n                'key',\n                array('key', $expr),\n                new Key('key', $expr),\n            ),\n            array(\n                'method',\n                array('getFoo', $expr),\n                new Method('getFoo', array(), $expr),\n            ),\n            array(\n                'method',\n                array('getFoo', 42, 'bar', $expr),\n                new Method('getFoo', array(42, 'bar'), $expr),\n            ),\n            array(\n                'property',\n                array('prop', $expr),\n                new Property('prop', $expr),\n            ),\n            array(\n                'atLeast',\n                array(2, $expr),\n                new AtLeast(2, $expr),\n            ),\n            array(\n                'atMost',\n                array(2, $expr),\n                new AtMost(2, $expr),\n            ),\n            array(\n                'exactly',\n                array(2, $expr),\n                new Exactly(2, $expr),\n            ),\n            array(\n                'all',\n                array($expr),\n                new All($expr),\n            ),\n            array(\n                'count',\n                array($expr),\n                new Count($expr),\n            ),\n            array(\n                'true',\n                array(),\n                new AlwaysTrue(),\n            ),\n            array(\n                'false',\n                array(),\n                new AlwaysFalse(),\n            ),\n        ), self::getComparisons());\n    }\n\n    /**\n     * @dataProvider getMethodTests\n     */\n    public function testCreate($method, $args, $expected)\n    {\n        $this->assertEquals($expected, call_user_func_array(array('Webmozart\\Expression\\Expr', $method), $args));\n    }\n\n    public function testExpr()\n    {\n        $expr = new Same(true);\n\n        $this->assertSame($expr, Expr::expr($expr));\n    }\n\n    public function testAndX()\n    {\n        $andX = new AndX(array(new GreaterThan(5), new LessThan(10)));\n\n        $this->assertEquals($andX, Expr::andX(array(Expr::greaterThan(5), Expr::lessThan(10))));\n    }\n\n    public function testOrX()\n    {\n        $andX = new OrX(array(new LessThan(5), new GreaterThan(10)));\n\n        $this->assertEquals($andX, Expr::orX(array(Expr::lessThan(5), Expr::greaterThan(10))));\n    }\n\n    public function testFilterArray()\n    {\n        $input = range(1, 10);\n        $output = array_filter($input, function ($i) {\n            return $i > 4;\n        });\n\n        $this->assertSame($output, Expr::filter($input, Expr::greaterThan(4)));\n    }\n\n    public function testFilterCollection()\n    {\n        $input = new ArrayObject(range(1, 10));\n        $output = new ArrayObject(array_filter(range(1, 10), function ($i) {\n            return $i > 4;\n        }));\n\n        $this->assertEquals($output, Expr::filter($input, Expr::greaterThan(4)));\n    }\n}\n"
  },
  {
    "path": "tests/Fixtures/Customer.php",
    "content": "<?php\n\n/*\n * This file is part of the vendor/project package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Fixtures;\n\nclass Customer\n{\n    private $premium = false;\n\n    private $bookings = array();\n\n    public function setPremium($premium)\n    {\n        $this->premium = (bool) $premium;\n    }\n\n    public function isPremium()\n    {\n        return $this->premium;\n    }\n\n    public function setBookings(array $bookings)\n    {\n        $this->bookings = $bookings;\n    }\n\n    public function getBookings()\n    {\n        return $this->bookings;\n    }\n}\n"
  },
  {
    "path": "tests/Fixtures/HasPreviousBookings.php",
    "content": "<?php\n\n/*\n * This file is part of the vendor/project package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Fixtures;\n\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Selector\\Method;\n\nclass HasPreviousBookings extends Method\n{\n    public function __construct()\n    {\n        parent::__construct('getBookings', array(), Expr::count(Expr::greaterThan(0)));\n    }\n}\n"
  },
  {
    "path": "tests/Fixtures/IsPremium.php",
    "content": "<?php\n\n/*\n * This file is part of the vendor/project package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Fixtures;\n\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Selector\\Method;\n\nclass IsPremium extends Method\n{\n    public function __construct()\n    {\n        parent::__construct('isPremium', array(), Expr::same(true));\n    }\n}\n"
  },
  {
    "path": "tests/Logic/AlwaysFalseTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Logic;\n\nuse PHPUnit_Framework_TestCase;\nuse stdClass;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Logic\\AlwaysFalse;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AlwaysFalseTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new AlwaysFalse();\n\n        $this->assertFalse($expr->evaluate(123));\n        $this->assertFalse($expr->evaluate(true));\n        $this->assertFalse($expr->evaluate(new stdClass()));\n    }\n\n    public function testToString()\n    {\n        $expr = new AlwaysFalse();\n\n        $this->assertSame('false', $expr->toString());\n    }\n\n    public function testAndReturnsFalse()\n    {\n        $expr = new AlwaysFalse();\n        $same = new Same('10');\n\n        $this->assertSame($expr, $expr->andX($same));\n    }\n\n    public function testOrReturnsConjunct()\n    {\n        $expr = new AlwaysFalse();\n        $same = new Same('10');\n\n        $this->assertSame($same, $expr->orX($same));\n    }\n}\n"
  },
  {
    "path": "tests/Logic/AlwaysTrueTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Logic;\n\nuse PHPUnit_Framework_TestCase;\nuse stdClass;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Logic\\AlwaysTrue;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AlwaysTrueTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new AlwaysTrue();\n\n        $this->assertTrue($expr->evaluate(123));\n        $this->assertTrue($expr->evaluate(true));\n        $this->assertTrue($expr->evaluate(new stdClass()));\n    }\n\n    public function testToString()\n    {\n        $expr = new AlwaysTrue();\n\n        $this->assertSame('true', $expr->toString());\n    }\n\n    public function testAndReturnsConjunct()\n    {\n        $expr = new AlwaysTrue();\n        $same = new Same('10');\n\n        $this->assertSame($same, $expr->andX($same));\n    }\n\n    public function testOrReturnsTrue()\n    {\n        $expr = new AlwaysTrue();\n        $same = new Same('10');\n\n        $this->assertSame($expr, $expr->orX($same));\n    }\n}\n"
  },
  {
    "path": "tests/Logic/ConjunctionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Logic;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Contains;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\OrX;\nuse Webmozart\\Expression\\Selector\\Key;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass ConjunctionTest extends PHPUnit_Framework_TestCase\n{\n    public function testCreate()\n    {\n        $conjunction = new AndX(array(\n            $notNull = new Same('10'),\n            $greaterThan = new GreaterThan('age', 0),\n        ));\n\n        $this->assertSame(array($notNull, $greaterThan), $conjunction->getConjuncts());\n    }\n\n    public function testCreateInlinesConjunction()\n    {\n        $conjunction = new AndX(array(\n            $notNull = new Same('10'),\n            new AndX(array($greaterThan = new GreaterThan('age', 0))),\n        ));\n\n        $this->assertSame(array($notNull, $greaterThan), $conjunction->getConjuncts());\n    }\n\n    public function testAndX()\n    {\n        $conjunction1 = new AndX(array($notNull = new Same('10')));\n\n        // Expressions are value objects, hence we must not alter the original\n        // conjunction\n        $conjunction2 = $conjunction1->andX($greaterThan = new GreaterThan('age', 0));\n\n        $this->assertSame(array($notNull), $conjunction1->getConjuncts());\n        $this->assertSame(array($notNull, $greaterThan), $conjunction2->getConjuncts());\n    }\n\n    public function testAndXIgnoresDuplicates()\n    {\n        $conjunction1 = new AndX(array($notNull = new Same('10')));\n        $conjunction2 = $conjunction1->andX(new Same('10'));\n\n        $this->assertSame($conjunction1, $conjunction2);\n    }\n\n    public function testAndXInlinesConjunctions()\n    {\n        $conjunction1 = new AndX(array($notNull = new Same('10')));\n        $conjunction2 = new AndX(array($greaterThan = new GreaterThan('name')));\n\n        $conjunction3 = $conjunction1->andX($conjunction2);\n\n        $this->assertSame(array($notNull), $conjunction1->getConjuncts());\n        $this->assertSame(array($greaterThan), $conjunction2->getConjuncts());\n        $this->assertSame(array($notNull, $greaterThan), $conjunction3->getConjuncts());\n    }\n\n    public function testAndTrueIgnored()\n    {\n        $conjunction1 = new AndX(array($notNull = new Same('10')));\n        $conjunction2 = $conjunction1->andTrue();\n\n        $this->assertSame($conjunction1, $conjunction2);\n    }\n\n    public function testAndXIgnoresTrue()\n    {\n        $conjunction1 = new AndX(array($notNull = new Same('10')));\n        $conjunction2 = $conjunction1->andX(Expr::true());\n\n        $this->assertSame($conjunction1, $conjunction2);\n    }\n\n    public function testAndFalseReturnsFalse()\n    {\n        $conjunction1 = new AndX(array($notNull = new Same('10')));\n        $conjunction2 = $conjunction1->andFalse();\n\n        $this->assertInstanceOf('Webmozart\\Expression\\Logic\\AlwaysFalse', $conjunction2);\n    }\n\n    public function testAndXReturnsFalse()\n    {\n        $conjunction1 = new AndX(array($notNull = new Same('10')));\n        $conjunction2 = $conjunction1->andX($false = Expr::false());\n\n        $this->assertSame($false, $conjunction2);\n    }\n\n    /**\n     * @dataProvider \\Webmozart\\Expression\\Tests\\ExprTest::getMethodTests\n     */\n    public function testAnd($method, $args, $expected)\n    {\n        // tested separately\n        if ('true' === $method || 'false' === $method) {\n            return;\n        }\n\n        if ('is' === substr($method, 0, 2)) {\n            $method = substr($method, 2);\n        }\n\n        $method = 'and'.ucfirst($method);\n        $conjunction1 = new AndX();\n\n        $conjunction2 = call_user_func_array(array($conjunction1, $method), $args);\n\n        $this->assertEquals(array(), $conjunction1->getConjuncts());\n        $this->assertEquals(array($expected), $conjunction2->getConjuncts());\n    }\n\n    public function testEvaluate()\n    {\n        $conjunction = new AndX(array(\n            new Key('name', new Same('Thomas')),\n            new Key('age', new GreaterThan(0)),\n        ));\n\n        $this->assertTrue($conjunction->evaluate(array('name' => 'Thomas', 'age' => 35)));\n        $this->assertFalse($conjunction->evaluate(array('name' => null, 'age' => 35)));\n        $this->assertFalse($conjunction->evaluate(array('name' => 'Thomas', 'age' => 0)));\n        $this->assertFalse($conjunction->evaluate(array('name' => null, 'age' => 0)));\n    }\n\n    public function testEquivalentTo()\n    {\n        $conjunction1 = new AndX(array(\n            new Key('name', new Same('10')),\n            new Key('age', new GreaterThan(0)),\n        ));\n\n        // conjunctions match independent of the order of the conjuncts\n        $conjunction2 = new AndX(array(\n            new Key('age', new GreaterThan(0)),\n            new Key('name', new Same('10')),\n        ));\n\n        $conjunction3 = new AndX(array(\n            new Key('age', new GreaterThan(0)),\n        ));\n\n        $this->assertTrue($conjunction1->equivalentTo($conjunction2));\n        $this->assertTrue($conjunction2->equivalentTo($conjunction1));\n        $this->assertFalse($conjunction2->equivalentTo($conjunction3));\n        $this->assertFalse($conjunction3->equivalentTo($conjunction2));\n        $this->assertFalse($conjunction1->equivalentTo($conjunction3));\n        $this->assertFalse($conjunction3->equivalentTo($conjunction1));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new AndX();\n        $expr2 = new AndX(array(new GreaterThan(10), new EndsWith('.css')));\n        $expr3 = new AndX(array(new GreaterThan(10), new OrX(array(new Contains('foo'), new EndsWith('.css')))));\n\n        $this->assertSame('', $expr1->toString());\n        $this->assertSame('>10 && endsWith(\".css\")', $expr2->toString());\n        $this->assertSame('>10 && (contains(\"foo\") || endsWith(\".css\"))', $expr3->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Logic/DisjunctionTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Logic;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Contains;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Logic\\AlwaysFalse;\nuse Webmozart\\Expression\\Logic\\AlwaysTrue;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\OrX;\nuse Webmozart\\Expression\\Selector\\Key;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass DisjunctionTest extends PHPUnit_Framework_TestCase\n{\n    public function testCreate()\n    {\n        $disjunction = new OrX(array(\n            $notNull = new Same('10'),\n            $greaterThan = new GreaterThan('age', 0),\n        ));\n\n        $this->assertSame(array($notNull, $greaterThan), $disjunction->getDisjuncts());\n    }\n\n    public function testCreateInlinesDisjunctions()\n    {\n        $disjunction = new OrX(array(\n            $notNull = new Same('10'),\n            new OrX(array($greaterThan = new GreaterThan('age', 0))),\n        ));\n\n        $this->assertSame(array($notNull, $greaterThan), $disjunction->getDisjuncts());\n    }\n\n    public function testOrX()\n    {\n        $disjunction1 = new OrX(array($notNull = new Same('10')));\n\n        // Expressions are value objects, hence we must not alter the original\n        // conjunction\n        $disjunction2 = $disjunction1->orX($greaterThan = new GreaterThan('age', 0));\n\n        $this->assertSame(array($notNull), $disjunction1->getDisjuncts());\n        $this->assertSame(array($notNull, $greaterThan), $disjunction2->getDisjuncts());\n    }\n\n    public function testOrXIgnoresDuplicates()\n    {\n        $disjunction1 = new OrX(array($notNull = new Same('10')));\n        $disjunction2 = $disjunction1->orX(new Same('10'));\n\n        $this->assertSame($disjunction1, $disjunction2);\n    }\n\n    public function testOrXInlinesDisjunctions()\n    {\n        $disjunction1 = new OrX(array($notNull = new Same('10')));\n        $disjunction2 = new OrX(array($greaterThan = new GreaterThan('age', 0)));\n\n        // Expressions are value objects, hence we must not alter the original\n        // conjunction\n        $disjunction3 = $disjunction1->orX($disjunction2);\n\n        $this->assertSame(array($notNull), $disjunction1->getDisjuncts());\n        $this->assertSame(array($greaterThan), $disjunction2->getDisjuncts());\n        $this->assertSame(array($notNull, $greaterThan), $disjunction3->getDisjuncts());\n    }\n\n    public function testOrFalseIgnored()\n    {\n        $disjunction1 = new OrX(array($notNull = new Same('10')));\n        $disjunction2 = $disjunction1->orFalse();\n\n        $this->assertSame($disjunction1, $disjunction2);\n    }\n\n    public function testOrXIgnoresFalse()\n    {\n        $disjunction1 = new OrX(array($notNull = new Same('10')));\n        $disjunction2 = $disjunction1->orX(new AlwaysFalse());\n\n        $this->assertSame($disjunction1, $disjunction2);\n    }\n\n    public function testOrTrueReturnsTrue()\n    {\n        $disjunction1 = new OrX(array($notNull = new Same('10')));\n        $disjunction2 = $disjunction1->orTrue();\n\n        $this->assertInstanceOf('Webmozart\\Expression\\Logic\\AlwaysTrue', $disjunction2);\n    }\n\n    public function testOrXReturnsTrue()\n    {\n        $disjunction1 = new OrX(array($notNull = new Same('10')));\n        $disjunction2 = $disjunction1->orX($true = new AlwaysTrue());\n\n        $this->assertSame($true, $disjunction2);\n    }\n\n    /**\n     * @dataProvider \\Webmozart\\Expression\\Tests\\ExprTest::getMethodTests\n     */\n    public function testOr($method, $args, $expected)\n    {\n        // tested separately\n        if ('true' === $method || 'false' === $method) {\n            return;\n        }\n\n        if ('is' === substr($method, 0, 2)) {\n            $method = substr($method, 2);\n        }\n\n        $method = 'or'.ucfirst($method);\n        $disjunction1 = new OrX();\n\n        $disjunction2 = call_user_func_array(array($disjunction1, $method), $args);\n\n        $this->assertEquals(array(), $disjunction1->getDisjuncts());\n        $this->assertEquals(array($expected), $disjunction2->getDisjuncts());\n    }\n\n    public function testEvaluate()\n    {\n        $disjunction = new OrX(array(\n            new Key('name', new Same('Thomas')),\n            new Key('age', new GreaterThan(0)),\n        ));\n\n        $this->assertTrue($disjunction->evaluate(array('name' => 'Thomas', 'age' => 35)));\n        $this->assertTrue($disjunction->evaluate(array('name' => null, 'age' => 35)));\n        $this->assertTrue($disjunction->evaluate(array('name' => 'Thomas', 'age' => 0)));\n        $this->assertFalse($disjunction->evaluate(array('name' => null, 'age' => 0)));\n    }\n\n    public function testEquivalentTo()\n    {\n        $disjunction1 = new OrX(array(\n            new Key('name', new Same('10')),\n            new Key('age', new GreaterThan(0)),\n        ));\n\n        // disjunctions match independent of the order of the conjuncts\n        $disjunction2 = new OrX(array(\n            new Key('age', new GreaterThan(0)),\n            new Key('name', new Same('10')),\n        ));\n\n        $disjunction3 = new OrX(array(\n            new Key('age', new GreaterThan(0)),\n        ));\n\n        $this->assertTrue($disjunction1->equivalentTo($disjunction2));\n        $this->assertTrue($disjunction2->equivalentTo($disjunction1));\n        $this->assertFalse($disjunction2->equivalentTo($disjunction3));\n        $this->assertFalse($disjunction3->equivalentTo($disjunction2));\n        $this->assertFalse($disjunction1->equivalentTo($disjunction3));\n        $this->assertFalse($disjunction3->equivalentTo($disjunction1));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new OrX();\n        $expr2 = new OrX(array(new GreaterThan(10), new EndsWith('.css')));\n        $expr3 = new OrX(array(new GreaterThan(10), new AndX(array(new Contains('foo'), new EndsWith('.css')))));\n\n        $this->assertSame('', $expr1->toString());\n        $this->assertSame('>10 || endsWith(\".css\")', $expr2->toString());\n        $this->assertSame('>10 || (contains(\"foo\") && endsWith(\".css\"))', $expr3->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Logic/Fixtures/TestLiteral.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Logic\\Fixtures;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Logic\\Literal;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass TestLiteral extends Literal\n{\n    private $value;\n\n    public function __construct($value = null)\n    {\n        $this->value = $value;\n    }\n\n    public function evaluate($value)\n    {\n    }\n\n    public function equivalentTo(Expression $other)\n    {\n        return $other instanceof $this && $this->value === $other->value;\n    }\n\n    public function toString()\n    {\n    }\n}\n"
  },
  {
    "path": "tests/Logic/LiteralTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Logic;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Expr;\nuse Webmozart\\Expression\\Logic\\AlwaysFalse;\nuse Webmozart\\Expression\\Logic\\AlwaysTrue;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\OrX;\nuse Webmozart\\Expression\\Tests\\Logic\\Fixtures\\TestLiteral;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass LiteralTest extends PHPUnit_Framework_TestCase\n{\n    public function testAndX()\n    {\n        $literal = new TestLiteral();\n        $expr = new Same('10');\n\n        $this->assertEquals(new AndX(array($literal, $expr)), $literal->andX($expr));\n    }\n\n    public function testAndXIgnoresDuplicates()\n    {\n        $literal = new TestLiteral('value');\n\n        $this->assertEquals($literal, $literal->andX(new TestLiteral('value')));\n    }\n\n    public function testAndTrueIgnored()\n    {\n        $literal = new TestLiteral('value');\n        $conjunction = $literal->andTrue();\n\n        $this->assertSame($literal, $conjunction);\n    }\n\n    public function testAndXIgnoresTrue()\n    {\n        $literal = new TestLiteral('value');\n        $conjunction = $literal->andX(Expr::true());\n\n        $this->assertSame($literal, $conjunction);\n    }\n\n    public function testAndFalseReturnsFalse()\n    {\n        $literal = new TestLiteral('value');\n        $conjunction = $literal->andFalse();\n\n        $this->assertInstanceOf('Webmozart\\Expression\\Logic\\AlwaysFalse', $conjunction);\n    }\n\n    public function testAndXReturnsFalse()\n    {\n        $literal = new TestLiteral('value');\n        $conjunction = $literal->andX($false = Expr::false());\n\n        $this->assertSame($false, $conjunction);\n    }\n\n    /**\n     * @dataProvider \\Webmozart\\Expression\\Tests\\ExprTest::getMethodTests\n     */\n    public function testAnd($method, $args, $expected)\n    {\n        // tested separately\n        if ('true' === $method || 'false' === $method) {\n            return;\n        }\n\n        if ('is' === substr($method, 0, 2)) {\n            $method = substr($method, 2);\n        }\n\n        $method = 'and'.ucfirst($method);\n        $literal = new TestLiteral();\n\n        $result = call_user_func_array(array($literal, $method), $args);\n\n        $this->assertEquals(new AndX(array($literal, $expected)), $result);\n    }\n\n    public function testOrX()\n    {\n        $literal = new TestLiteral();\n        $expr = new Same('10');\n\n        $this->assertEquals(new OrX(array($literal, $expr)), $literal->orX($expr));\n    }\n\n    public function testOrXIgnoresDuplicates()\n    {\n        $literal = new TestLiteral('value');\n\n        $this->assertEquals($literal, $literal->orX(new TestLiteral('value')));\n    }\n\n    public function testOrFalseIgnored()\n    {\n        $literal = new TestLiteral('value');\n        $disjunction = $literal->orFalse();\n\n        $this->assertSame($literal, $disjunction);\n    }\n\n    public function testOrXIgnoresFalse()\n    {\n        $literal = new TestLiteral('value');\n        $disjunction = $literal->orX(new AlwaysFalse());\n\n        $this->assertSame($literal, $disjunction);\n    }\n\n    public function testOrTrueReturnsTrue()\n    {\n        $literal = new TestLiteral('value');\n        $disjunction = $literal->orTrue();\n\n        $this->assertInstanceOf('Webmozart\\Expression\\Logic\\AlwaysTrue', $disjunction);\n    }\n\n    public function testOrXReturnsTrue()\n    {\n        $literal = new TestLiteral('value');\n        $disjunction = $literal->orX($true = new AlwaysTrue());\n\n        $this->assertSame($true, $disjunction);\n    }\n\n    /**\n     * @dataProvider \\Webmozart\\Expression\\Tests\\ExprTest::getMethodTests\n     */\n    public function testOr($method, $args, $expected)\n    {\n        // tested separately\n        if ('true' === $method || 'false' === $method) {\n            return;\n        }\n\n        if ('is' === substr($method, 0, 2)) {\n            $method = substr($method, 2);\n        }\n\n        $method = 'or'.ucfirst($method);\n        $literal = new TestLiteral();\n\n        $result = call_user_func_array(array($literal, $method), $args);\n\n        $this->assertEquals(new OrX(array($literal, $expected)), $result);\n    }\n}\n"
  },
  {
    "path": "tests/Logic/NotTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Logic;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Constraint\\LessThan;\nuse Webmozart\\Expression\\Constraint\\StartsWith;\nuse Webmozart\\Expression\\Logic\\Not;\nuse Webmozart\\Expression\\Logic\\OrX;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass NotTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new Not(new StartsWith('Thomas'));\n\n        $this->assertTrue($expr->evaluate('Mr. Thomas Edison'));\n        $this->assertFalse($expr->evaluate('Thomas Edison'));\n    }\n\n    public function testEquivalentTo()\n    {\n        $expr1 = new Not(new OrX(array(new LessThan(0), new GreaterThan(10))));\n        $expr2 = new Not(new OrX(array(new GreaterThan(10), new LessThan(0))));\n        $expr3 = new Not(new OrX(array(new GreaterThan(10))));\n\n        $this->assertTrue($expr1->equivalentTo($expr2));\n        $this->assertFalse($expr2->equivalentTo($expr3));\n        $this->assertFalse($expr1->equivalentTo($expr3));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new Not(new StartsWith('Thomas'));\n        $expr2 = new Not(new OrX(array(new GreaterThan(10), new LessThan(0))));\n\n        $this->assertSame('not(startsWith(\"Thomas\"))', $expr1->toString());\n        $this->assertSame('not(>10 || <0)', $expr2->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Selector/AllTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse ArrayIterator;\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Selector\\All;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AllTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $all = new All(new GreaterThan(10));\n\n        $this->assertTrue($all->evaluate(array(11, 12, 13)));\n        $this->assertTrue($all->evaluate(array(11, 12)));\n        $this->assertFalse($all->evaluate(array(10, 11, 12)));\n        $this->assertFalse($all->evaluate(array(9, 10, 11, 12)));\n        $this->assertTrue($all->evaluate(new ArrayIterator(array(11, 12, 13))));\n        $this->assertTrue($all->evaluate(new ArrayIterator(array(11, 12))));\n        $this->assertFalse($all->evaluate(new ArrayIterator(array(10, 11, 12))));\n        $this->assertFalse($all->evaluate(new ArrayIterator(array(9, 10, 11, 12))));\n\n        $this->assertTrue($all->evaluate(array()));\n        $this->assertFalse($all->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new All(new GreaterThan(10));\n        $expr2 = new All(new EndsWith('.css'));\n        $expr3 = new All(new AndX(array(\n            new GreaterThan(10),\n            new EndsWith('.css'),\n        )));\n\n        $this->assertSame('all(>10)', $expr1->toString());\n        $this->assertSame('all(endsWith(\".css\"))', $expr2->toString());\n        $this->assertSame('all(>10 && endsWith(\".css\"))', $expr3->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Selector/AtLeastTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse ArrayIterator;\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Selector\\AtLeast;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AtLeastTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $atLeast1 = new AtLeast(1, new GreaterThan(10));\n        $atLeast2 = new AtLeast(2, new GreaterThan(10));\n\n        $this->assertTrue($atLeast1->evaluate(array(9, 10, 11, 12)));\n        $this->assertTrue($atLeast1->evaluate(array(9, 10, 11)));\n        $this->assertFalse($atLeast1->evaluate(array(9, 10)));\n        $this->assertTrue($atLeast1->evaluate(new ArrayIterator(array(9, 10, 11, 12))));\n        $this->assertTrue($atLeast1->evaluate(new ArrayIterator(array(9, 10, 11))));\n        $this->assertFalse($atLeast1->evaluate(new ArrayIterator(array(9, 10))));\n\n        $this->assertTrue($atLeast2->evaluate(array(9, 10, 11, 12)));\n        $this->assertFalse($atLeast2->evaluate(array(9, 10, 11)));\n        $this->assertFalse($atLeast2->evaluate(array(9, 10)));\n        $this->assertTrue($atLeast2->evaluate(new ArrayIterator(array(9, 10, 11, 12))));\n        $this->assertFalse($atLeast2->evaluate(new ArrayIterator(array(9, 10, 11))));\n        $this->assertFalse($atLeast2->evaluate(new ArrayIterator(array(9, 10))));\n\n        $this->assertFalse($atLeast1->evaluate(array()));\n        $this->assertFalse($atLeast1->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new AtLeast(1, new GreaterThan(10));\n        $expr2 = new AtLeast(2, new EndsWith('.css'));\n        $expr3 = new AtLeast(3, new AndX(array(\n            new GreaterThan(10),\n            new EndsWith('.css'),\n        )));\n\n        $this->assertSame('atLeast(1, >10)', $expr1->toString());\n        $this->assertSame('atLeast(2, endsWith(\".css\"))', $expr2->toString());\n        $this->assertSame('atLeast(3, >10 && endsWith(\".css\"))', $expr3->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Selector/AtMostTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse ArrayIterator;\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Selector\\AtMost;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass AtMostTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $atMost1 = new AtMost(1, new GreaterThan(10));\n        $atMost2 = new AtMost(2, new GreaterThan(10));\n\n        $this->assertFalse($atMost1->evaluate(array(9, 10, 11, 12)));\n        $this->assertTrue($atMost1->evaluate(array(9, 10, 11)));\n        $this->assertTrue($atMost1->evaluate(array(9, 10)));\n        $this->assertFalse($atMost1->evaluate(new ArrayIterator(array(9, 10, 11, 12))));\n        $this->assertTrue($atMost1->evaluate(new ArrayIterator(array(9, 10, 11))));\n        $this->assertTrue($atMost1->evaluate(new ArrayIterator(array(9, 10))));\n\n        $this->assertFalse($atMost2->evaluate(array(9, 10, 11, 12, 13)));\n        $this->assertTrue($atMost2->evaluate(array(9, 10, 11, 12)));\n        $this->assertTrue($atMost2->evaluate(array(9, 10, 11)));\n        $this->assertTrue($atMost2->evaluate(array(9, 10)));\n        $this->assertFalse($atMost2->evaluate(new ArrayIterator(array(9, 10, 11, 12, 13))));\n        $this->assertTrue($atMost2->evaluate(new ArrayIterator(array(9, 10, 11, 12))));\n        $this->assertTrue($atMost2->evaluate(new ArrayIterator(array(9, 10, 11))));\n        $this->assertTrue($atMost2->evaluate(new ArrayIterator(array(9, 10))));\n\n        $this->assertTrue($atMost1->evaluate(array()));\n        $this->assertFalse($atMost1->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new AtMost(1, new GreaterThan(10));\n        $expr2 = new AtMost(2, new EndsWith('.css'));\n        $expr3 = new AtMost(3, new AndX(array(\n            new GreaterThan(10),\n            new EndsWith('.css'),\n        )));\n\n        $this->assertSame('atMost(1, >10)', $expr1->toString());\n        $this->assertSame('atMost(2, endsWith(\".css\"))', $expr2->toString());\n        $this->assertSame('atMost(3, >10 && endsWith(\".css\"))', $expr3->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Selector/CountTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse ArrayIterator;\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Selector\\Count;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass CountTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $all = new Count(new GreaterThan(1));\n\n        $this->assertTrue($all->evaluate(array(1, 2, 3)));\n        $this->assertTrue($all->evaluate(array(1, 2)));\n        $this->assertFalse($all->evaluate(array(1)));\n        $this->assertTrue($all->evaluate(new ArrayIterator(array(1, 2, 3))));\n        $this->assertTrue($all->evaluate(new ArrayIterator(array(1, 2))));\n        $this->assertFalse($all->evaluate(new ArrayIterator(array(1))));\n\n        $this->assertFalse($all->evaluate(array()));\n        $this->assertFalse($all->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr = new Count(new GreaterThan(10));\n\n        $this->assertSame('count(>10)', $expr->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Selector/ExactlyTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse ArrayIterator;\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Selector\\Exactly;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass ExactlyTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $exactly1 = new Exactly(1, new GreaterThan(10));\n        $exactly2 = new Exactly(2, new GreaterThan(10));\n\n        $this->assertFalse($exactly1->evaluate(array(9, 10, 11, 12)));\n        $this->assertTrue($exactly1->evaluate(array(9, 10, 11)));\n        $this->assertFalse($exactly1->evaluate(array(9, 10)));\n        $this->assertFalse($exactly1->evaluate(new ArrayIterator(array(9, 10, 11, 12))));\n        $this->assertTrue($exactly1->evaluate(new ArrayIterator(array(9, 10, 11))));\n        $this->assertFalse($exactly1->evaluate(new ArrayIterator(array(9, 10))));\n\n        $this->assertTrue($exactly2->evaluate(array(9, 10, 11, 12)));\n        $this->assertFalse($exactly2->evaluate(array(9, 10, 11)));\n        $this->assertFalse($exactly2->evaluate(array(9, 10)));\n        $this->assertTrue($exactly2->evaluate(new ArrayIterator(array(9, 10, 11, 12))));\n        $this->assertFalse($exactly2->evaluate(new ArrayIterator(array(9, 10, 11))));\n        $this->assertFalse($exactly2->evaluate(new ArrayIterator(array(9, 10))));\n\n        $this->assertFalse($exactly1->evaluate(array()));\n        $this->assertFalse($exactly1->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new Exactly(1, new GreaterThan(10));\n        $expr2 = new Exactly(2, new EndsWith('.css'));\n        $expr3 = new Exactly(3, new AndX(array(\n            new GreaterThan(10),\n            new EndsWith('.css'),\n        )));\n\n        $this->assertSame('exactly(1, >10)', $expr1->toString());\n        $this->assertSame('exactly(2, endsWith(\".css\"))', $expr2->toString());\n        $this->assertSame('exactly(3, >10 && endsWith(\".css\"))', $expr3->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Selector/Fixtures/TestSelector.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector\\Fixtures;\n\nuse Webmozart\\Expression\\Expression;\nuse Webmozart\\Expression\\Selector\\Selector;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass TestSelector extends Selector\n{\n    /**\n     * @var string|int\n     */\n    private $key;\n\n    public function __construct($key, Expression $expr)\n    {\n        parent::__construct($expr);\n\n        $this->key = $key;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function evaluate($value)\n    {\n        return $this->expr->evaluate($value[$this->key]);\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function toString()\n    {\n    }\n}\n"
  },
  {
    "path": "tests/Selector/KeyTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Selector\\Key;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass KeyTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new Key('key', new GreaterThan(10));\n\n        $this->assertTrue($expr->evaluate(array('key' => 11)));\n        $this->assertFalse($expr->evaluate(array('key' => 9)));\n        $this->assertFalse($expr->evaluate(array()));\n        $this->assertFalse($expr->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new Key('name', new GreaterThan(10));\n        $expr2 = new Key('name', new EndsWith('.css'));\n        $expr3 = new Key('name', new AndX(array(\n            new GreaterThan(10),\n            new EndsWith('.css'),\n        )));\n\n        $this->assertSame('name>10', $expr1->toString());\n        $this->assertSame('name.endsWith(\".css\")', $expr2->toString());\n        $this->assertSame('name{>10 && endsWith(\".css\")}', $expr3->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Selector/MethodTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse PHPUnit_Framework_TestCase;\nuse stdClass;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Selector\\Method;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass MethodTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new Method('getFoo', array(), new GreaterThan(10));\n\n        $this->assertTrue($expr->evaluate(new MethodTest_TestClass(11)));\n        $this->assertFalse($expr->evaluate(new MethodTest_TestClass(9)));\n        $this->assertFalse($expr->evaluate('foobar'));\n        $this->assertFalse($expr->evaluate(new stdClass()));\n    }\n\n    public function testEvaluateWithArguments()\n    {\n        $expr = new Method('getBar', array(2), new GreaterThan(10));\n\n        $this->assertTrue($expr->evaluate(new MethodTest_TestClass(9)));\n        $this->assertFalse($expr->evaluate(new MethodTest_TestClass(7)));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new Method('getName', array(42, true), new GreaterThan(10));\n        $expr2 = new Method('getName', array('foo'), new EndsWith('.css'));\n        $expr3 = new Method('getName', array(new stdClass()), new AndX(array(\n            new GreaterThan(10),\n            new EndsWith('.css'),\n        )));\n\n        $this->assertSame('getName(42, true)>10', $expr1->toString());\n        $this->assertSame('getName(\"foo\").endsWith(\".css\")', $expr2->toString());\n        $this->assertSame('getName(object){>10 && endsWith(\".css\")}', $expr3->toString());\n    }\n}\n\nclass MethodTest_TestClass\n{\n    private $foo;\n\n    public function __construct($foo)\n    {\n        $this->foo = $foo;\n    }\n\n    public function getFoo()\n    {\n        return $this->foo;\n    }\n\n    public function getBar($x)\n    {\n        return $this->foo + $x;\n    }\n}\n"
  },
  {
    "path": "tests/Selector/PropertyTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\EndsWith;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Selector\\Property;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass PropertyTest extends PHPUnit_Framework_TestCase\n{\n    public function testEvaluate()\n    {\n        $expr = new Property('prop', new GreaterThan(10));\n\n        $this->assertTrue($expr->evaluate((object) array('prop' => 11)));\n        $this->assertFalse($expr->evaluate((object) array('prop' => 9)));\n        $this->assertFalse($expr->evaluate((object) array()));\n        $this->assertFalse($expr->evaluate(array()));\n        $this->assertFalse($expr->evaluate('foobar'));\n    }\n\n    public function testToString()\n    {\n        $expr1 = new Property('prop', new GreaterThan(10));\n        $expr2 = new Property('prop', new EndsWith('.css'));\n        $expr3 = new Property('prop', new AndX(array(\n            new GreaterThan(10),\n            new EndsWith('.css'),\n        )));\n\n        $this->assertSame('prop>10', $expr1->toString());\n        $this->assertSame('prop.endsWith(\".css\")', $expr2->toString());\n        $this->assertSame('prop{>10 && endsWith(\".css\")}', $expr3->toString());\n    }\n}\n"
  },
  {
    "path": "tests/Selector/SelectorTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Selector;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Tests\\Selector\\Fixtures\\TestSelector;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass SelectorTest extends PHPUnit_Framework_TestCase\n{\n    public function testGetExpression()\n    {\n        $selector = new TestSelector('key', $expr = new Same('10'));\n\n        $this->assertSame($expr, $selector->getExpression());\n    }\n\n    public function testEquivalentTo()\n    {\n        // \"key\" is ignored in the dummy implementation\n        $selector1 = new TestSelector('key', new Same('10'));\n        $selector2 = new TestSelector('key', new Same('10'));\n        $selector3 = new TestSelector('key', new Same(10));\n\n        $this->assertTrue($selector1->equivalentTo($selector2));\n        $this->assertTrue($selector2->equivalentTo($selector1));\n        $this->assertFalse($selector1->equivalentTo($selector3));\n        $this->assertFalse($selector3->equivalentTo($selector1));\n        $this->assertFalse($selector2->equivalentTo($selector3));\n        $this->assertFalse($selector3->equivalentTo($selector2));\n\n        $this->assertFalse($selector1->equivalentTo(new Same('10')));\n    }\n}\n"
  },
  {
    "path": "tests/Traversal/ExpressionTraverserTest.php",
    "content": "<?php\n\n/*\n * This file is part of the webmozart/expression package.\n *\n * (c) Bernhard Schussek <bschussek@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nnamespace Webmozart\\Expression\\Tests\\Traversal;\n\nuse PHPUnit_Framework_TestCase;\nuse Webmozart\\Expression\\Constraint\\GreaterThan;\nuse Webmozart\\Expression\\Constraint\\Same;\nuse Webmozart\\Expression\\Logic\\AndX;\nuse Webmozart\\Expression\\Logic\\Not;\nuse Webmozart\\Expression\\Logic\\OrX;\nuse Webmozart\\Expression\\Selector\\Key;\nuse Webmozart\\Expression\\Traversal\\ExpressionTraverser;\n\n/**\n * @since  1.0\n *\n * @author Bernhard Schussek <bschussek@gmail.com>\n */\nclass ExpressionTraverserTest extends PHPUnit_Framework_TestCase\n{\n    /**\n     * @var ExpressionTraverser\n     */\n    private $traverser;\n\n    protected function setUp()\n    {\n        $this->traverser = new ExpressionTraverser();\n    }\n\n    public function testAddVisitor()\n    {\n        $visitor1 = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor2 = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n\n        $this->traverser->addVisitor($visitor1);\n        $this->traverser->addVisitor($visitor2);\n        $this->traverser->addVisitor($visitor1);\n\n        $this->assertSame(array($visitor1, $visitor2, $visitor1), $this->traverser->getVisitors());\n    }\n\n    public function testRemoveVisitor()\n    {\n        $visitor1 = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor2 = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n\n        $this->traverser->addVisitor($visitor1);\n        $this->traverser->addVisitor($visitor2);\n        $this->traverser->addVisitor($visitor1);\n        $this->traverser->removeVisitor($visitor1);\n\n        $this->assertSame(array($visitor2), $this->traverser->getVisitors());\n    }\n\n    public function testTraverse()\n    {\n        $expr = new GreaterThan(10);\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n        $visitor->expects($this->at(1))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr, $this->traverser->traverse($expr));\n    }\n\n    public function testModifyExprInEnterExpression()\n    {\n        $expr1 = new GreaterThan(10);\n        $expr2 = new GreaterThan(5);\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr2);\n        $visitor->expects($this->at(1))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testModifyExprInLeaveExpression()\n    {\n        $expr1 = new GreaterThan(10);\n        $expr2 = new GreaterThan(5);\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testRemoveExpr()\n    {\n        $expr = new GreaterThan(10);\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n        $visitor->expects($this->at(1))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn(null);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertNull($this->traverser->traverse($expr));\n    }\n\n    public function testTraverseMultipleVisitors()\n    {\n        $expr1 = new GreaterThan(10);\n        $expr2 = new GreaterThan(5);\n\n        $visitor1 = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor1->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor1->expects($this->at(1))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr2);\n\n        $visitor2 = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor2->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr2))\n            ->willReturn($expr2);\n        $visitor2->expects($this->at(1))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor1);\n        $this->traverser->addVisitor($visitor2);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testTraverseSkipsSubsequentVisitorsIfExpressionRemoved()\n    {\n        $expr = new GreaterThan(10);\n\n        $visitor1 = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor1->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n        $visitor1->expects($this->at(1))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn(null);\n\n        $visitor2 = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor2->expects($this->never())\n            ->method('enterExpression');\n        $visitor2->expects($this->never())\n            ->method('leaveExpression');\n\n        $this->traverser->addVisitor($visitor1);\n        $this->traverser->addVisitor($visitor2);\n\n        $this->assertNull($this->traverser->traverse($expr));\n    }\n\n    public function testTraverseNot()\n    {\n        $expr = new Not($gt = new GreaterThan(10));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt))\n            ->willReturn($gt);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt))\n            ->willReturn($gt);\n        $visitor->expects($this->at(3))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr, $this->traverser->traverse($expr));\n    }\n\n    public function testModifyNotChildInEnterExpression()\n    {\n        $expr1 = new Not($gt1 = new GreaterThan(10));\n        $expr2 = new Not($gt2 = new GreaterThan(5));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt2))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(3))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testModifyNotChildInLeaveExpression()\n    {\n        $expr1 = new Not($gt1 = new GreaterThan(10));\n        $expr2 = new Not($gt2 = new GreaterThan(5));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(3))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testRemoveNotChild()\n    {\n        $expr1 = new Not($gt1 = new GreaterThan(10));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn(null);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertNull($this->traverser->traverse($expr1));\n    }\n\n    public function testTraverseKey()\n    {\n        $expr = new Key('key', $gt = new GreaterThan(10));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt))\n            ->willReturn($gt);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt))\n            ->willReturn($gt);\n        $visitor->expects($this->at(3))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr, $this->traverser->traverse($expr));\n    }\n\n    public function testModifyKeyChildInEnterExpression()\n    {\n        $expr1 = new Key('key', $gt1 = new GreaterThan(10));\n        $expr2 = new Key('key', $gt2 = new GreaterThan(5));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt2))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(3))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testModifyKeyChildInLeaveExpression()\n    {\n        $expr1 = new Key('key', $gt1 = new GreaterThan(10));\n        $expr2 = new Key('key', $gt2 = new GreaterThan(5));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(3))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testRemoveKeyChild()\n    {\n        $expr1 = new Key('key', $gt1 = new GreaterThan(10));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn(null);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertNull($this->traverser->traverse($expr1));\n    }\n\n    public function testTraverseConjunction()\n    {\n        $expr = new AndX(array(\n            $gt = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt))\n            ->willReturn($gt);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt))\n            ->willReturn($gt);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(5))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr, $this->traverser->traverse($expr));\n    }\n\n    public function testModifyConjunctInEnterExpression()\n    {\n        $expr1 = new AndX(array(\n            $gt1 = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n        $expr2 = new AndX(array(\n            $gt2 = new GreaterThan(5),\n            $same,\n        ));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt2))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(5))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testModifyConjunctInLeaveExpression()\n    {\n        $expr1 = new AndX(array(\n            $gt1 = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n        $expr2 = new AndX(array(\n            $gt2 = new GreaterThan(5),\n            $same,\n        ));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(5))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testRemoveConjunct()\n    {\n        $expr1 = new AndX(array(\n            $gt1 = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n        $expr2 = new AndX(array($same));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn(null);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(5))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testRemoveAllConjuncts()\n    {\n        $expr1 = new AndX(array(\n            $gt1 = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn(null);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn(null);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertNull($this->traverser->traverse($expr1));\n    }\n\n    public function testTraverseDisjunction()\n    {\n        $expr = new OrX(array(\n            $gt = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt))\n            ->willReturn($gt);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt))\n            ->willReturn($gt);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(5))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($expr))\n            ->willReturn($expr);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr, $this->traverser->traverse($expr));\n    }\n\n    public function testModifyDisjunctInEnterExpression()\n    {\n        $expr1 = new OrX(array(\n            $gt1 = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n        $expr2 = new OrX(array(\n            $gt2 = new GreaterThan(5),\n            $same,\n        ));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt2))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(5))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testModifyDisjunctInLeaveExpression()\n    {\n        $expr1 = new OrX(array(\n            $gt1 = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n        $expr2 = new OrX(array(\n            $gt2 = new GreaterThan(5),\n            $same,\n        ));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt2);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(5))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testRemoveDisjunct()\n    {\n        $expr1 = new OrX(array(\n            $gt1 = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n        $expr2 = new OrX(array($same));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn(null);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(5))\n            ->method('leaveExpression')\n            ->with($this->equalTo($expr2))\n            ->willReturn($expr2);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertSame($expr2, $this->traverser->traverse($expr1));\n    }\n\n    public function testRemoveAllDisjuncts()\n    {\n        $expr1 = new OrX(array(\n            $gt1 = new GreaterThan(10),\n            $same = new Same('5'),\n        ));\n\n        $visitor = $this->getMock('Webmozart\\Expression\\Traversal\\ExpressionVisitor');\n        $visitor->expects($this->at(0))\n            ->method('enterExpression')\n            ->with($this->identicalTo($expr1))\n            ->willReturn($expr1);\n        $visitor->expects($this->at(1))\n            ->method('enterExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn($gt1);\n        $visitor->expects($this->at(2))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($gt1))\n            ->willReturn(null);\n        $visitor->expects($this->at(3))\n            ->method('enterExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn($same);\n        $visitor->expects($this->at(4))\n            ->method('leaveExpression')\n            ->with($this->identicalTo($same))\n            ->willReturn(null);\n\n        $this->traverser->addVisitor($visitor);\n\n        $this->assertNull($this->traverser->traverse($expr1));\n    }\n}\n"
  }
]