diff --git a/.travis.yml b/.travis.yml index d4afa1f..003337d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,16 @@ language: php before_script: + - composer self-update - composer install --dev --prefer-dist -script: phpunit; php vendor/bin/behat --format progress +script: php vendor/bin/phpunit; php vendor/bin/behat --format progress php: - 5.4 - 5.5 + - 5.6 + - 7.0 + +matrix: + fast_finish: true + allow_failures: + - php: hhvm + - php: 7 diff --git a/README.md b/README.md index c73cee4..1b3a4d5 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,14 @@ It outputs a diff to the screen and you can apply it to your code by piping it t php refactor.phar ... | patch -p1 -### VIM Bindings +### Editor Plugins -There is now a VIM plugin for using PHP refactorings within VIM. This plugin -is maintained as a seperate project which can be found at https://github.com/vim-php/vim-php-refactoring +There are third-party plugins available for using PHP refactorings within +different text editors. These separately maintained projects can be found at +the links below: + +* vim : https://github.com/vim-php/vim-php-refactoring +* emacs : https://github.com/keelerm84/php-refactor-mode.el ## Why? diff --git a/composer.json b/composer.json index 457484a..e605c7a 100644 --- a/composer.json +++ b/composer.json @@ -11,17 +11,18 @@ "nikic/php-parser": "@stable", "beberlei/assert": "@stable", "andrewsville/php-token-reflection": "@stable", - "symfony/finder": "@stable", - "symfony/console": "@stable", - "tomphp/patch-builder": "dev-master" + "symfony/finder": "~2.4@stable", + "symfony/console": "~2.4@stable", + "tomphp/patch-builder": "~0.1" }, "require-dev": { "php": ">=5.4", - "behat/behat": "@stable", + "behat/behat": "~2.5@stable", "mikey179/vfsStream": "@stable", "phake/phake": "@stable", - "symfony/process": "@stable" + "symfony/process": "@stable", + "phpunit/phpunit": "~4.6@stable" }, "autoload": { @@ -32,7 +33,5 @@ } }, - "bin": ["src/bin/refactor"], - - "minimum-stability": "dev" + "bin": ["src/bin/refactor"] } diff --git a/composer.lock b/composer.lock index d103bec..6bc4cf4 100644 --- a/composer.lock +++ b/composer.lock @@ -1,26 +1,28 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" ], - "hash": "f47cf8659d10539ccd59f2eb46ad00cb", + "hash": "ec675be63f343e2656ad4fba790a9a74", "packages": [ { "name": "andrewsville/php-token-reflection", - "version": "1.3.1", + "version": "1.4.0", "source": { "type": "git", - "url": "git://github.com/Andrewsville/PHP-Token-Reflection.git", - "reference": "1.3.1" + "url": "https://github.com/Andrewsville/PHP-Token-Reflection.git", + "reference": "e6d0ac2baf66cdf154be34c3d2a2aa1bd4b426ee" }, "dist": { "type": "zip", - "url": "https://github.com/Andrewsville/PHP-Token-Reflection/zipball/1.3.1", - "reference": "1.3.1", + "url": "https://api.github.com/repos/Andrewsville/PHP-Token-Reflection/zipball/e6d0ac2baf66cdf154be34c3d2a2aa1bd4b426ee", + "reference": "e6d0ac2baf66cdf154be34c3d2a2aa1bd4b426ee", "shasum": "" }, "require": { - "php": ">=5.3" + "ext-tokenizer": "*", + "php": ">=5.3.0" }, "type": "library", "autoload": { @@ -35,7 +37,7 @@ "authors": [ { "name": "Ondřej Nešpor", - "homepage": "https://github.com/Andrewsville" + "homepage": "https://github.com/andrewsville" }, { "name": "Jaroslav Hanslík", @@ -49,30 +51,38 @@ "reflection", "tokenizer" ], - "time": "2012-08-25 14:26:44" + "time": "2014-08-06 16:37:08" }, { "name": "beberlei/assert", - "version": "v1.6", + "version": "v2.3", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "6c0069d271323e441c47d2ff26cb18cf3b7cc695" + "reference": "160eba4d1fbe692e42b3cf8a20b92ab23e3a8759" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/6c0069d271323e441c47d2ff26cb18cf3b7cc695", - "reference": "6c0069d271323e441c47d2ff26cb18cf3b7cc695", + "url": "https://api.github.com/repos/beberlei/assert/zipball/160eba4d1fbe692e42b3cf8a20b92ab23e3a8759", + "reference": "160eba4d1fbe692e42b3cf8a20b92ab23e3a8759", "shasum": "" }, "require": { "ext-mbstring": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, "autoload": { "psr-0": { "Assert": "lib/" - } + }, + "files": [ + "lib/Assert/functions.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -90,35 +100,36 @@ "assertion", "validation" ], - "time": "2013-11-05 12:28:46" + "time": "2014-12-18 19:12:40" }, { "name": "nikic/php-parser", - "version": "v0.9.4", + "version": "v1.2.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1e5e280ae88a27effa2ae4aa2bd088494ed8594f" + "reference": "08f97eb4efa029e2fafb6d8c98b71731bf0cf621" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1e5e280ae88a27effa2ae4aa2bd088494ed8594f", - "reference": "1e5e280ae88a27effa2ae4aa2bd088494ed8594f", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/08f97eb4efa029e2fafb6d8c98b71731bf0cf621", + "reference": "08f97eb4efa029e2fafb6d8c98b71731bf0cf621", "shasum": "" }, "require": { - "php": ">=5.2" + "ext-tokenizer": "*", + "php": ">=5.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.9-dev" + "dev-master": "1.2-dev" } }, "autoload": { - "psr-0": { - "PHPParser": "lib/" - } + "files": [ + "lib/bootstrap.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -134,7 +145,7 @@ "parser", "php" ], - "time": "2013-08-25 17:11:40" + "time": "2015-04-03 14:33:59" }, { "name": "phpspec/php-diff", @@ -171,32 +182,37 @@ }, { "name": "symfony/console", - "version": "v2.4.0", + "version": "v2.6.6", "target-dir": "Symfony/Component/Console", "source": { "type": "git", "url": "https://github.com/symfony/Console.git", - "reference": "3c1496ae96d24ccc6c340fcc25f71d7a1ab4c12c" + "reference": "5b91dc4ed5eb08553f57f6df04c4730a73992667" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Console/zipball/3c1496ae96d24ccc6c340fcc25f71d7a1ab4c12c", - "reference": "3c1496ae96d24ccc6c340fcc25f71d7a1ab4c12c", + "url": "https://api.github.com/repos/symfony/Console/zipball/5b91dc4ed5eb08553f57f6df04c4730a73992667", + "reference": "5b91dc4ed5eb08553f57f6df04c4730a73992667", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { - "symfony/event-dispatcher": "~2.1" + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/phpunit-bridge": "~2.7", + "symfony/process": "~2.1" }, "suggest": { - "symfony/event-dispatcher": "" + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -209,41 +225,44 @@ "MIT" ], "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, { "name": "Symfony Community", "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" } ], "description": "Symfony Console Component", "homepage": "http://symfony.com/", - "time": "2013-11-27 09:10:40" + "time": "2015-03-30 15:54:10" }, { "name": "symfony/finder", - "version": "v2.4.0", + "version": "v2.6.6", "target-dir": "Symfony/Component/Finder", "source": { "type": "git", "url": "https://github.com/symfony/Finder.git", - "reference": "72356bf0646b11af1bae666c28a639bd8ede459f" + "reference": "5dbe2e73a580618f5b4880fda93406eed25de251" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Finder/zipball/72356bf0646b11af1bae666c28a639bd8ede459f", - "reference": "72356bf0646b11af1bae666c28a639bd8ede459f", + "url": "https://api.github.com/repos/symfony/Finder/zipball/5dbe2e73a580618f5b4880fda93406eed25de251", + "reference": "5dbe2e73a580618f5b4880fda93406eed25de251", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -256,31 +275,31 @@ "MIT" ], "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, { "name": "Symfony Community", "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" } ], "description": "Symfony Finder Component", "homepage": "http://symfony.com/", - "time": "2013-11-26 16:40:27" + "time": "2015-03-30 15:54:10" }, { "name": "tomphp/patch-builder", - "version": "dev-master", + "version": "v0.1.0", "source": { "type": "git", - "url": "https://github.com/tomphp/PatchBuilder.git", - "reference": "8a0d77b74e3e4487d46ce49d1832c06df272d907" + "url": "https://github.com/tomphp/patch-builder.git", + "reference": "4419eaad23016c7db1deffc6cce3f539096c11ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tomphp/PatchBuilder/zipball/8a0d77b74e3e4487d46ce49d1832c06df272d907", - "reference": "8a0d77b74e3e4487d46ce49d1832c06df272d907", + "url": "https://api.github.com/repos/tomphp/patch-builder/zipball/4419eaad23016c7db1deffc6cce3f539096c11ce", + "reference": "4419eaad23016c7db1deffc6cce3f539096c11ce", "shasum": "" }, "require": { @@ -288,6 +307,7 @@ "phpspec/php-diff": "1.0.2" }, "require-dev": { + "henrikbjorn/phpspec-code-coverage": "dev-master", "phpmd/phpmd": "1.4.0", "phpspec/phpspec": "2.0.*@dev", "satooshi/php-coveralls": "dev-master", @@ -301,22 +321,22 @@ }, "notification-url": "https://packagist.org/downloads/", "description": "PHP Library for manipulating files to produce a patch.", - "time": "2013-12-30 11:51:41" + "time": "2014-01-10 16:47:41" } ], "packages-dev": [ { "name": "behat/behat", - "version": "v2.5.1", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/Behat/Behat.git", - "reference": "b688e3c4bd65ef867d2ec0a0cf8e621c166e259b" + "reference": "ba257dd19d47b6e196c4e43995a2d2db4dd95991" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Behat/Behat/zipball/b688e3c4bd65ef867d2ec0a0cf8e621c166e259b", - "reference": "b688e3c4bd65ef867d2ec0a0cf8e621c166e259b", + "url": "https://api.github.com/repos/Behat/Behat/zipball/ba257dd19d47b6e196c4e43995a2d2db4dd95991", + "reference": "ba257dd19d47b6e196c4e43995a2d2db4dd95991", "shasum": "" }, "require": { @@ -365,11 +385,11 @@ "Behat", "Symfony2" ], - "time": "2013-11-24 10:17:18" + "time": "2015-01-23 22:18:15" }, { "name": "behat/gherkin", - "version": "2.3.x-dev", + "version": "v2.3.5", "source": { "type": "git", "url": "https://github.com/Behat/Gherkin.git", @@ -428,24 +448,86 @@ ], "time": "2013-10-15 11:22:17" }, + { + "name": "doctrine/instantiator", + "version": "1.0.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f976e5de371104877ebc89bd8fecb0019ed9c119", + "reference": "f976e5de371104877ebc89bd8fecb0019ed9c119", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "2.0.*@ALPHA" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Instantiator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2014-10-13 12:58:55" + }, { "name": "mikey179/vfsStream", - "version": "v1.2.0", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/mikey179/vfsStream.git", - "reference": "v1.2.0" + "reference": "4dc0d2f622412f561f5b242b19b98068bbbc883a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/v1.2.0", - "reference": "v1.2.0", + "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/4dc0d2f622412f561f5b242b19b98068bbbc883a", + "reference": "4dc0d2f622412f561f5b242b19b98068bbbc883a", "shasum": "" }, "require": { "php": ">=5.3.0" }, + "require-dev": { + "phpunit/phpunit": "~4.5" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, "autoload": { "psr-0": { "org\\bovigo\\vfs\\": "src/main/php" @@ -453,40 +535,60 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Frank Kleine", + "homepage": "http://frankkleine.de/", + "role": "Developer" + } ], + "description": "Virtual file system to mock the real file system in unit tests.", "homepage": "http://vfs.bovigo.org/", - "time": "2013-04-01 10:41:02" + "time": "2015-03-29 11:19:49" }, { "name": "phake/phake", - "version": "v1.0.3", + "version": "v2.0.2", "source": { "type": "git", - "url": "git://github.com/mlively/Phake.git", - "reference": "v1.0.3" + "url": "https://github.com/mlively/Phake.git", + "reference": "15d688aa23e6d5db433accb75feea6c0a1cdd1f1" }, "dist": { "type": "zip", - "url": "https://github.com/mlively/Phake/zipball/v1.0.3", - "reference": "v1.0.3", + "url": "https://api.github.com/repos/mlively/Phake/zipball/15d688aa23e6d5db433accb75feea6c0a1cdd1f1", + "reference": "15d688aa23e6d5db433accb75feea6c0a1cdd1f1", "shasum": "" }, "require": { - "php": ">=5.2.0" + "php": ">=5.3.3" + }, + "require-dev": { + "doctrine/common": "2.3.*", + "ext-soap": "*", + "hamcrest/hamcrest-php": "1.1.*", + "phpunit/phpunit": "3.7.*" + }, + "suggest": { + "doctrine/common": "Allows mock annotations to use import statements for classes.", + "hamcrest/hamcrest-php": "Use Hamcrest matchers." }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, "autoload": { - "classmap": [ - "src" - ] + "psr-0": { + "Phake": "src/" + } }, "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "src" - ], "license": [ - "BSD" + "BSD-3-Clause" ], "authors": [ { @@ -500,36 +602,43 @@ "mock", "testing" ], - "time": "2012-05-14 08:06:51" + "time": "2015-03-21 18:05:30" }, { - "name": "symfony/config", - "version": "dev-master", - "target-dir": "Symfony/Component/Config", + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/symfony/Config.git", - "reference": "d14e3e3ff200bf148e7e616c82383a59ed5ded40" + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Config/zipball/d14e3e3ff200bf148e7e616c82383a59ed5ded40", - "reference": "d14e3e3ff200bf148e7e616c82383a59ed5ded40", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/filesystem": "~2.3" + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-0": { - "Symfony\\Component\\Config\\": "" + "phpDocumentor": [ + "src/" + ] } }, "notification-url": "https://packagist.org/downloads/", @@ -538,55 +647,43 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" } ], - "description": "Symfony Config Component", - "homepage": "http://symfony.com/", - "time": "2013-12-26 07:59:17" + "time": "2015-02-03 12:10:50" }, { - "name": "symfony/dependency-injection", - "version": "dev-master", - "target-dir": "Symfony/Component/DependencyInjection", + "name": "phpspec/prophecy", + "version": "1.4.0", "source": { "type": "git", - "url": "https://github.com/symfony/DependencyInjection.git", - "reference": "d9d479a6bef711fe8e2c8cce71eadd3f839c7fa6" + "url": "https://github.com/phpspec/prophecy.git", + "reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/d9d479a6bef711fe8e2c8cce71eadd3f839c7fa6", - "reference": "d9d479a6bef711fe8e2c8cce71eadd3f839c7fa6", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5", + "reference": "8724cd239f8ef4c046f55a3b18b4d91cc7f3e4c5", "shasum": "" }, "require": { - "php": ">=5.3.3" + "doctrine/instantiator": "^1.0.2", + "phpdocumentor/reflection-docblock": "~2.0", + "sebastian/comparator": "~1.1" }, "require-dev": { - "symfony/config": "~2.2", - "symfony/expression-language": "~2.4", - "symfony/yaml": "~2.0" - }, - "suggest": { - "symfony/config": "", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" + "phpspec/phpspec": "~2.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { "psr-0": { - "Symfony\\Component\\DependencyInjection\\": "" + "Prophecy\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -595,87 +692,101 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com/" }, { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" } ], - "description": "Symfony DependencyInjection Component", - "homepage": "http://symfony.com/", - "time": "2013-12-28 08:12:58" + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2015-03-27 19:31:25" }, { - "name": "symfony/event-dispatcher", - "version": "dev-master", - "target-dir": "Symfony/Component/EventDispatcher", + "name": "phpunit/php-code-coverage", + "version": "2.0.16", "source": { "type": "git", - "url": "https://github.com/symfony/EventDispatcher.git", - "reference": "6a86e7e768e64c85f9d2b76fa895e47d8b3162b3" + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/6a86e7e768e64c85f9d2b76fa895e47d8b3162b3", - "reference": "6a86e7e768e64c85f9d2b76fa895e47d8b3162b3", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/934fd03eb6840508231a7f73eb8940cf32c3b66c", + "reference": "934fd03eb6840508231a7f73eb8940cf32c3b66c", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "~1.0", + "sebastian/version": "~1.0" }, "require-dev": { - "psr/log": "~1.0", - "symfony/dependency-injection": "~2.0", - "symfony/stopwatch": "~2.2" + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" }, "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-0": { - "Symfony\\Component\\EventDispatcher\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "Symfony EventDispatcher Component", - "homepage": "http://symfony.com/", - "time": "2013-12-28 21:40:48" + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-04-11 04:35:00" }, { - "name": "symfony/filesystem", - "version": "dev-master", - "target-dir": "Symfony/Component/Filesystem", + "name": "phpunit/php-file-iterator", + "version": "1.4.0", "source": { "type": "git", - "url": "https://github.com/symfony/Filesystem.git", - "reference": "f316a10af34320e04bb649a611de370635385a63" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Filesystem/zipball/f316a10af34320e04bb649a611de370635385a63", - "reference": "f316a10af34320e04bb649a611de370635385a63", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a923bb15680d0089e2316f7a4af8f437046e96bb", + "reference": "a923bb15680d0089e2316f7a4af8f437046e96bb", "shasum": "" }, "require": { @@ -684,201 +795,1066 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { - "psr-0": { - "Symfony\\Component\\Filesystem\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "Symfony Filesystem Component", - "homepage": "http://symfony.com/", - "time": "2013-12-28 08:12:58" + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-04-02 05:19:05" }, { - "name": "symfony/process", - "version": "v2.4.0", - "target-dir": "Symfony/Component/Process", + "name": "phpunit/php-text-template", + "version": "1.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/Process.git", - "reference": "87738ff42e2467730ed74d941866e95513844b70" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Process/zipball/87738ff42e2467730ed74d941866e95513844b70", - "reference": "87738ff42e2467730ed74d941866e95513844b70", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", "shasum": "" }, "require": { "php": ">=5.3.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.4-dev" - } - }, "autoload": { - "psr-0": { - "Symfony\\Component\\Process\\": "" - } + "classmap": [ + "Text/" + ] }, "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "Symfony Process Component", - "homepage": "http://symfony.com/", - "time": "2013-11-26 16:40:27" + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" }, { - "name": "symfony/translation", - "version": "dev-master", - "target-dir": "Symfony/Component/Translation", + "name": "phpunit/php-timer", + "version": "1.0.5", "source": { "type": "git", - "url": "https://github.com/symfony/Translation.git", - "reference": "6015e52ba96affd6c8b05d71682fc156d8efa17f" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Translation/zipball/6015e52ba96affd6c8b05d71682fc156d8efa17f", - "reference": "6015e52ba96affd6c8b05d71682fc156d8efa17f", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", "shasum": "" }, "require": { "php": ">=5.3.3" }, - "require-dev": { - "symfony/config": "~2.0", - "symfony/yaml": "~2.2" - }, - "suggest": { - "symfony/config": "", - "symfony/yaml": "" - }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, "autoload": { - "psr-0": { - "Symfony\\Component\\Translation\\": "" - } + "classmap": [ + "PHP/" + ] }, "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" } ], - "description": "Symfony Translation Component", - "homepage": "http://symfony.com/", - "time": "2013-12-28 21:40:48" + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2013-08-02 07:42:54" }, { - "name": "symfony/yaml", - "version": "dev-master", - "target-dir": "Symfony/Component/Yaml", + "name": "phpunit/php-token-stream", + "version": "1.4.1", "source": { "type": "git", - "url": "https://github.com/symfony/Yaml.git", - "reference": "c2e065720708d6db30dfba1278b8f53c45dd9fe0" + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "eab81d02569310739373308137284e0158424330" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/c2e065720708d6db30dfba1278b8f53c45dd9fe0", - "reference": "c2e065720708d6db30dfba1278b8f53c45dd9fe0", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/eab81d02569310739373308137284e0158424330", + "reference": "eab81d02569310739373308137284e0158424330", "shasum": "" }, "require": { + "ext-tokenizer": "*", "php": ">=5.3.3" }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "1.4-dev" } }, "autoload": { - "psr-0": { - "Symfony\\Component\\Yaml\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-04-08 04:46:07" + }, + { + "name": "phpunit/phpunit", + "version": "4.6.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "163232991e652e6efed2f8470326fffa61e848e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/163232991e652e6efed2f8470326fffa61e848e2", + "reference": "163232991e652e6efed2f8470326fffa61e848e2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "~1.3,>=1.3.1", + "phpunit/php-code-coverage": "~2.0,>=2.0.11", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "~1.0", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.2", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.6.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2015-04-11 05:23:21" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "74ffb87f527f24616f72460e54b595f508dccb5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/74ffb87f527f24616f72460e54b595f508dccb5c", + "reference": "74ffb87f527f24616f72460e54b595f508dccb5c", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "~1.0,>=1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-04-02 05:36:41" + }, + { + "name": "sebastian/comparator", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dd8869519a225f7f2b9eb663e225298fade819e", + "reference": "1dd8869519a225f7f2b9eb663e225298fade819e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-01-29 16:28:08" + }, + { + "name": "sebastian/diff", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/863df9687835c62aa423a22412d26fa2ebde3fd3", + "reference": "863df9687835c62aa423a22412d26fa2ebde3fd3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "http://www.github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-02-22 15:13:53" + }, + { + "name": "sebastian/environment", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5a8c7d31914337b69923db26c4221b81ff5a196e", + "reference": "5a8c7d31914337b69923db26c4221b81ff5a196e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2015-01-01 10:01:08" + }, + { + "name": "sebastian/exporter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "84839970d05254c73cde183a721c7af13aede943" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/84839970d05254c73cde183a721c7af13aede943", + "reference": "84839970d05254c73cde183a721c7af13aede943", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-01-27 07:23:06" + }, + { + "name": "sebastian/global-state", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "reference": "c7428acdb62ece0a45e6306f1ae85e1c05b09c01", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2014-10-06 09:23:50" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/3989662bbb30a29d20d9faa04a846af79b276252", + "reference": "3989662bbb30a29d20d9faa04a846af79b276252", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-01-24 09:48:32" + }, + { + "name": "sebastian/version", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/ab931d46cd0d3204a91e1b9a40c4bc13032b58e4", + "reference": "ab931d46cd0d3204a91e1b9a40c4bc13032b58e4", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-02-24 06:35:25" + }, + { + "name": "symfony/config", + "version": "v2.6.6", + "target-dir": "Symfony/Component/Config", + "source": { + "type": "git", + "url": "https://github.com/symfony/Config.git", + "reference": "d91be01336605db8da21b79bc771e46a7276d1bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Config/zipball/d91be01336605db8da21b79bc771e46a7276d1bc", + "reference": "d91be01336605db8da21b79bc771e46a7276d1bc", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "symfony/filesystem": "~2.3" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Config\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Config Component", + "homepage": "http://symfony.com/", + "time": "2015-03-30 15:54:10" + }, + { + "name": "symfony/dependency-injection", + "version": "v2.6.6", + "target-dir": "Symfony/Component/DependencyInjection", + "source": { + "type": "git", + "url": "https://github.com/symfony/DependencyInjection.git", + "reference": "8e9007012226b4bd41f8afed855c452cf5edc3a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/8e9007012226b4bd41f8afed855c452cf5edc3a6", + "reference": "8e9007012226b4bd41f8afed855c452cf5edc3a6", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "conflict": { + "symfony/expression-language": "<2.6" + }, + "require-dev": { + "symfony/config": "~2.2", + "symfony/expression-language": "~2.6", + "symfony/phpunit-bridge": "~2.7", + "symfony/yaml": "~2.1" + }, + "suggest": { + "symfony/config": "", + "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\DependencyInjection\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony DependencyInjection Component", + "homepage": "http://symfony.com/", + "time": "2015-03-30 15:54:10" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.6.6", + "target-dir": "Symfony/Component/EventDispatcher", + "source": { + "type": "git", + "url": "https://github.com/symfony/EventDispatcher.git", + "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/70f7c8478739ad21e3deef0d977b38c77f1fb284", + "reference": "70f7c8478739ad21e3deef0d977b38c77f1fb284", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.0,>=2.0.5", + "symfony/dependency-injection": "~2.6", + "symfony/expression-language": "~2.6", + "symfony/phpunit-bridge": "~2.7", + "symfony/stopwatch": "~2.3" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "http://symfony.com/", + "time": "2015-03-13 17:37:22" + }, + { + "name": "symfony/filesystem", + "version": "v2.6.6", + "target-dir": "Symfony/Component/Filesystem", + "source": { + "type": "git", + "url": "https://github.com/symfony/Filesystem.git", + "reference": "4983964b3693e4f13449cb3800c64a9112c301b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/4983964b3693e4f13449cb3800c64a9112c301b4", + "reference": "4983964b3693e4f13449cb3800c64a9112c301b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Filesystem\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "http://symfony.com/", + "time": "2015-03-22 16:55:57" + }, + { + "name": "symfony/process", + "version": "v2.6.6", + "target-dir": "Symfony/Component/Process", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process.git", + "reference": "a8bebaec1a9dc6cde53e0250e32917579b0be552" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Process/zipball/a8bebaec1a9dc6cde53e0250e32917579b0be552", + "reference": "a8bebaec1a9dc6cde53e0250e32917579b0be552", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Process\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Process Component", + "homepage": "http://symfony.com/", + "time": "2015-03-30 15:54:10" + }, + { + "name": "symfony/translation", + "version": "v2.6.6", + "target-dir": "Symfony/Component/Translation", + "source": { + "type": "git", + "url": "https://github.com/symfony/Translation.git", + "reference": "bd939f05cdaca128f4ddbae1b447d6f0203b60af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Translation/zipball/bd939f05cdaca128f4ddbae1b447d6f0203b60af", + "reference": "bd939f05cdaca128f4ddbae1b447d6f0203b60af", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.3,>=2.3.12", + "symfony/intl": "~2.3", + "symfony/phpunit-bridge": "~2.7", + "symfony/yaml": "~2.2" + }, + "suggest": { + "psr/log": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Translation Component", + "homepage": "http://symfony.com/", + "time": "2015-03-30 15:54:10" + }, + { + "name": "symfony/yaml", + "version": "v2.6.6", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "174f009ed36379a801109955fc5a71a49fe62dd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/174f009ed36379a801109955fc5a71a49fe62dd4", + "reference": "174f009ed36379a801109955fc5a71a49fe62dd4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { "name": "Symfony Community", "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" } ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com/", - "time": "2013-12-28 08:12:58" + "time": "2015-03-30 15:54:10" } ], - "aliases": [ - - ], - "minimum-stability": "dev", + "aliases": [], + "minimum-stability": "stable", "stability-flags": { "nikic/php-parser": 0, "beberlei/assert": 0, "andrewsville/php-token-reflection": 0, "symfony/finder": 0, "symfony/console": 0, - "tomphp/patch-builder": 20, "behat/behat": 0, "mikey179/vfsstream": 0, "phake/phake": 0, - "symfony/process": 0 + "symfony/process": 0, + "phpunit/phpunit": 0 }, - "platform": [ - - ], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], "platform-dev": { "php": ">=5.4" } diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php index 8a91af4..4c49fc0 100644 --- a/features/bootstrap/FeatureContext.php +++ b/features/bootstrap/FeatureContext.php @@ -13,8 +13,7 @@ use QafooLabs\Refactoring\Adapters\Symfony\CliApplication; -require_once 'PHPUnit/Autoload.php'; -require_once 'PHPUnit/Framework/Assert/Functions.php'; +use PHPUnit_Framework_Assert as PHPUnit; /** * Features context. @@ -101,7 +100,7 @@ public function thePhpFileShouldBeRefactored($file, PyStringNode $expectedPatch) $output = array_map('trim', explode("\n", rtrim($this->output))); $formattedExpectedPatch = $this->formatExpectedPatch((string)$expectedPatch); - assertEquals( + PHPUnit::assertEquals( $formattedExpectedPatch, $output, "Expected File:\n" . (string)$expectedPatch . "\n\n" . @@ -112,12 +111,12 @@ public function thePhpFileShouldBeRefactored($file, PyStringNode $expectedPatch) /** * converts / paths in expectedPatch text to \ paths - * + * * leaves the a/ b/ slashes untouched * returns an array of lines * @return array */ - protected function formatExpectedPatch($patch) + protected function formatExpectedPatch($patch) { if ('\\' === DIRECTORY_SEPARATOR) { $formatLine = function ($line) { diff --git a/features/extract_method.feature b/features/extract_method.feature index 7bd5a87..9bfae6e 100644 --- a/features/extract_method.feature +++ b/features/extract_method.feature @@ -265,3 +265,43 @@ Feature: Extract Method } } """ + + Scenario: Extract method from inside a block + Given a PHP File named "src/ExtractMethodFromBlock.php" with: + """ + hello(); + } + } + + + + private function hello() + + { + + echo "Hello World"; + + } + } + + """ diff --git a/features/optimize_use.feature b/features/optimize_use.feature index e9ef4a3..5194043 100644 --- a/features/optimize_use.feature +++ b/features/optimize_use.feature @@ -50,4 +50,37 @@ Feature: Optimize use return $service; } """ + Scenario: Organize use for file without namespace and other uses + Given a PHP File named "src/Foo.php" with: + """ + builder = $builder; } + public function getLines(LineRange $range) + { + return $this->builder->getOriginalLines($range->getStart(), $range->getEnd()); + } + public function replace(LineRange $range, array $newLines) { $this->builder->replaceLines($range->getStart(), $range->getEnd(), $newLines); diff --git a/src/main/QafooLabs/Refactoring/Adapters/PatchBuilder/PatchBuilder.php b/src/main/QafooLabs/Refactoring/Adapters/PatchBuilder/PatchBuilder.php index 9054083..4da855e 100644 --- a/src/main/QafooLabs/Refactoring/Adapters/PatchBuilder/PatchBuilder.php +++ b/src/main/QafooLabs/Refactoring/Adapters/PatchBuilder/PatchBuilder.php @@ -50,6 +50,15 @@ public function __construct($contents, $path = null) $this->path = $path; } + public function getOriginalLines($start, $end) + { + return array_slice( + $this->buffer->getOriginalContents(), + $start - 1, + $end - $start + 1 + ); + } + /** * Change Token in given line from old to new. * @@ -64,7 +73,7 @@ public function changeToken($originalLine, $oldToken, $newToken) $newLine = $this->buffer->getLine($this->createLineNumber($originalLine)); $newLine = preg_replace( - '!(^|[^a-z0-9])(' . preg_quote($oldToken) . ')([^a-z0-9]|$)!i', + '!(^|[^a-z0-9])(' . preg_quote($oldToken) . ')([^a-z0-9]|$)!', '\1' . $newToken . '\3', $newLine ); @@ -75,7 +84,6 @@ public function changeToken($originalLine, $oldToken, $newToken) ); } - /** * Append new lines to an original line of the file. * diff --git a/src/main/QafooLabs/Refactoring/Adapters/TokenReflection/StaticCodeAnalysis.php b/src/main/QafooLabs/Refactoring/Adapters/TokenReflection/StaticCodeAnalysis.php index f43583a..c766693 100644 --- a/src/main/QafooLabs/Refactoring/Adapters/TokenReflection/StaticCodeAnalysis.php +++ b/src/main/QafooLabs/Refactoring/Adapters/TokenReflection/StaticCodeAnalysis.php @@ -22,6 +22,7 @@ use TokenReflection\Broker; use TokenReflection\Broker\Backend\Memory; +use TokenReflection\ReflectionNamespace; class StaticCodeAnalysis extends CodeAnalysis { @@ -102,11 +103,12 @@ public function findClasses(File $file) $file = $this->broker->processString($file->getCode(), $file->getRelativePath(), true); foreach ($file->getNamespaces() as $namespace) { + $noNamespace = ReflectionNamespace::NO_NAMESPACE_NAME === $namespace->getName(); foreach ($namespace->getClasses() as $class) { $classes[] = new PhpClass( PhpName::createDeclarationName($class->getName()), $class->getStartLine(), - $namespace->getStartLine() + $noNamespace ? 0 : $namespace->getStartLine() ); } } diff --git a/src/main/QafooLabs/Refactoring/Application/ConvertLocalToInstanceVariable.php b/src/main/QafooLabs/Refactoring/Application/ConvertLocalToInstanceVariable.php index 2246cd7..5c7e925 100644 --- a/src/main/QafooLabs/Refactoring/Application/ConvertLocalToInstanceVariable.php +++ b/src/main/QafooLabs/Refactoring/Application/ConvertLocalToInstanceVariable.php @@ -13,56 +13,50 @@ use QafooLabs\Refactoring\Domain\Services\VariableScanner; use QafooLabs\Refactoring\Domain\Services\CodeAnalysis; use QafooLabs\Refactoring\Domain\Services\Editor; +use QafooLabs\Refactoring\Domain\Model\EditingAction\AddProperty; +use QafooLabs\Refactoring\Domain\Model\EditingAction\LocalVariableToInstance; -class ConvertLocalToInstanceVariable +class ConvertLocalToInstanceVariable extends SingleFileRefactoring { /** - * @var \QafooLabs\Refactoring\Domain\Services\VariableScanner + * @var Variable */ - private $variableScanner; + private $convertVariable; /** - * @var \QafooLabs\Refactoring\Domain\Services\CodeAnalysis + * @param int $line */ - private $codeAnalysis; + public function refactor(File $file, $line, Variable $convertVariable) + { + $this->file = $file; + $this->line = $line; + $this->convertVariable = $convertVariable; - /** - * @var \QafooLabs\Refactoring\Domain\Services\Editor - */ - private $editor; + $this->assertIsInsideMethod(); - public function __construct(VariableScanner $variableScanner, CodeAnalysis $codeAnalysis, Editor $editor) - { - $this->variableScanner = $variableScanner; - $this->codeAnalysis = $codeAnalysis; - $this->editor = $editor; + $this->startEditingSession(); + $this->addProperty(); + $this->convertVariablesToInstanceVariables(); + $this->completeEditingSession(); } - public function refactor(File $file, $line, Variable $convertVariable) + private function addProperty() { - if ( ! $this->codeAnalysis->isInsideMethod($file, LineRange::fromSingleLine($line))) { - throw RefactoringException::rangeIsNotInsideMethod(LineRange::fromSingleLine($line)); - } + $line = $this->codeAnalysis->getLineOfLastPropertyDefinedInScope($this->file, $this->line); - $instanceVariable = $convertVariable->convertToInstance(); - $lastPropertyLine = $this->codeAnalysis->getLineOfLastPropertyDefinedInScope($file, $line); - - $selectedMethodLineRange = $this->codeAnalysis->findMethodRange($file, LineRange::fromSingleLine($line)); - $definedVariables = $this->variableScanner->scanForVariables( - $file, $selectedMethodLineRange + $this->session->addEdit( + new AddProperty($line, $this->convertVariable->getName()) ); + } - if ( ! $definedVariables->contains($convertVariable)) { - throw RefactoringException::variableNotInRange($convertVariable, $selectedMethodLineRange); - } - - $buffer = $this->editor->openBuffer($file); + private function convertVariablesToInstanceVariables() + { + $definedVariables = $this->getDefinedVariables(); - $session = new EditingSession($buffer); - $session->addProperty($lastPropertyLine, $convertVariable->getName()); - $session->replaceString($definedVariables, $convertVariable, $instanceVariable); + if ( ! $definedVariables->contains($this->convertVariable)) { + throw RefactoringException::variableNotInRange($this->convertVariable, $selectedMethodLineRange); + } - $this->editor->save(); + $this->session->addEdit(new LocalVariableToInstance($definedVariables, $this->convertVariable)); } } - diff --git a/src/main/QafooLabs/Refactoring/Application/ExtractMethod.php b/src/main/QafooLabs/Refactoring/Application/ExtractMethod.php index 079bced..121138b 100644 --- a/src/main/QafooLabs/Refactoring/Application/ExtractMethod.php +++ b/src/main/QafooLabs/Refactoring/Application/ExtractMethod.php @@ -11,60 +11,91 @@ use QafooLabs\Refactoring\Domain\Services\VariableScanner; use QafooLabs\Refactoring\Domain\Services\CodeAnalysis; use QafooLabs\Refactoring\Domain\Services\Editor; +use QafooLabs\Refactoring\Domain\Model\LineCollection; +use QafooLabs\Refactoring\Domain\Model\EditingAction\AddMethod; +use QafooLabs\Refactoring\Domain\Model\EditingAction\ReplaceWithMethodCall; /** * Extract Method Refactoring */ -class ExtractMethod +class ExtractMethod extends SingleFileRefactoring { /** - * @var \QafooLabs\Refactoring\Domain\Services\VariableScanner + * @var LineRange */ - private $variableScanner; + private $extractRange; /** - * @var \QafooLabs\Refactoring\Domain\Services\CodeAnalysis + * @var MethodSignature */ - private $codeAnalysis; + private $newMethod; /** - * @var \QafooLabs\Refactoring\Domain\Services\Editor + * @param string $newMethodName */ - private $editor; - - public function __construct(VariableScanner $variableScanner, CodeAnalysis $codeAnalysis, Editor $editor) + public function refactor(File $file, LineRange $extractRange, $newMethodName) { - $this->variableScanner = $variableScanner; - $this->codeAnalysis = $codeAnalysis; - $this->editor = $editor; + $this->file = $file; + $this->extractRange = $extractRange; + + $this->assertIsInsideMethod(); + + $this->createNewMethodSignature($newMethodName); + + $this->startEditingSession(); + $this->replaceCodeWithMethodCall(); + $this->addNewMethod(); + $this->completeEditingSession(); } - public function refactor(File $file, LineRange $extractRange, $newMethodName) + protected function assertIsInsideMethod() { - if ( ! $this->codeAnalysis->isInsideMethod($file, $extractRange)) { - throw RefactoringException::rangeIsNotInsideMethod($extractRange); + if ( ! $this->codeAnalysis->isInsideMethod($this->file, $this->extractRange)) { + throw RefactoringException::rangeIsNotInsideMethod($this->extractRange); } + } - $isStatic = $this->codeAnalysis->isMethodStatic($file, $extractRange); - $methodRange = $this->codeAnalysis->findMethodRange($file, $extractRange); - $selectedCode = $extractRange->sliceCode($file->getCode()); - - $extractVariables = $this->variableScanner->scanForVariables($file, $extractRange); - $methodVariables = $this->variableScanner->scanForVariables($file, $methodRange); + private function createNewMethodSignature($newMethodName) + { + $extractVariables = $this->variableScanner->scanForVariables($this->file, $this->extractRange); + $methodVariables = $this->variableScanner->scanForVariables($this->file, $this->findMethodRange()); - $buffer = $this->editor->openBuffer($file); + $isStatic = $this->codeAnalysis->isMethodStatic($this->file, $this->extractRange); - $newMethod = new MethodSignature( + $this->newMethod = new MethodSignature( $newMethodName, $isStatic ? MethodSignature::IS_STATIC : 0, $methodVariables->variablesFromSelectionUsedBefore($extractVariables), $methodVariables->variablesFromSelectionUsedAfter($extractVariables) ); + } - $session = new EditingSession($buffer); - $session->replaceRangeWithMethodCall($extractRange, $newMethod); - $session->addMethod($methodRange->getEnd(), $newMethod, $selectedCode); + private function addNewMethod() + { + $this->session->addEdit(new AddMethod( + $this->findMethodRange()->getEnd(), + $this->newMethod, + $this->getSelectedCode() + )); + } + + private function replaceCodeWithMethodCall() + { + $this->session->addEdit(new ReplaceWithMethodCall( + $this->extractRange, + $this->newMethod + )); + } - $this->editor->save(); + private function findMethodRange() + { + return $this->codeAnalysis->findMethodRange($this->file, $this->extractRange); + } + + private function getSelectedCode() + { + return LineCollection::createFromArray( + $this->extractRange->sliceCode($this->file->getCode()) + ); } } diff --git a/src/main/QafooLabs/Refactoring/Application/OptimizeUse.php b/src/main/QafooLabs/Refactoring/Application/OptimizeUse.php index ec950ff..ce9d8de 100644 --- a/src/main/QafooLabs/Refactoring/Application/OptimizeUse.php +++ b/src/main/QafooLabs/Refactoring/Application/OptimizeUse.php @@ -37,6 +37,7 @@ public function refactor(File $file) $occurances = $this->phpNameScanner->findNames($file); $class = $classes[0]; + $appendNewLine = 0 === $class->namespaceDeclarationLine(); $lastUseStatementLine = $class->namespaceDeclarationLine() + 2; $usedNames = array(); $fqcns = array(); @@ -44,7 +45,7 @@ public function refactor(File $file) foreach ($occurances as $occurance) { $name = $occurance->name(); - if ($name->type() === PhpName::TYPE_NAMESPACE) { + if ($name->type() === PhpName::TYPE_NAMESPACE || $name->type() === PhpName::TYPE_CLASS) { continue; } @@ -67,7 +68,13 @@ public function refactor(File $file) $buffer->replaceString($occurance->declarationLine(), '\\'.$name->fullyQualifiedName(), $name->shortname()); if (!in_array($name->fullyQualifiedName(), $usedNames)) { - $buffer->append($lastUseStatementLine, array(sprintf('use %s;', $name->fullyQualifiedName()))); + $lines = array(sprintf('use %s;', $name->fullyQualifiedName())); + if ($appendNewLine) { + $appendNewLine = FALSE; + $lines[] = ''; + } + + $buffer->append($lastUseStatementLine, $lines); $lastUseStatementLine++; } } diff --git a/src/main/QafooLabs/Refactoring/Application/RenameLocalVariable.php b/src/main/QafooLabs/Refactoring/Application/RenameLocalVariable.php index a19171d..4cd51ef 100644 --- a/src/main/QafooLabs/Refactoring/Application/RenameLocalVariable.php +++ b/src/main/QafooLabs/Refactoring/Application/RenameLocalVariable.php @@ -12,63 +12,58 @@ use QafooLabs\Refactoring\Domain\Services\VariableScanner; use QafooLabs\Refactoring\Domain\Services\CodeAnalysis; use QafooLabs\Refactoring\Domain\Services\Editor; +use QafooLabs\Refactoring\Domain\Model\EditingAction\RenameVariable; /** * Rename Local Variable Refactoring */ -class RenameLocalVariable +class RenameLocalVariable extends SingleFileRefactoring { /** - * @var \QafooLabs\Refactoring\Domain\Services\VariableScanner + * @var Variable */ - private $variableScanner; + private $oldName; /** - * @var \QafooLabs\Refactoring\Domain\Services\CodeAnalysis + * @var Variable */ - private $codeAnalysis; + private $newName; /** - * @var \QafooLabs\Refactoring\Domain\Services\Editor + * @param int $line */ - private $editor; - - public function __construct(VariableScanner $variableScanner, CodeAnalysis $codeAnalysis, Editor $editor) - { - $this->variableScanner = $variableScanner; - $this->codeAnalysis = $codeAnalysis; - $this->editor = $editor; - } - public function refactor(File $file, $line, Variable $oldName, Variable $newName) { - if ( ! $this->codeAnalysis->isInsideMethod($file, LineRange::fromSingleLine($line))) { - throw RefactoringException::rangeIsNotInsideMethod(LineRange::fromSingleLine($line)); - } + $this->file = $file; + $this->line = $line; + $this->newName = $newName; + $this->oldName = $oldName; - if ( ! $oldName->isLocal()) { - throw RefactoringException::variableNotLocal($oldName); - } + $this->assertIsInsideMethod(); - if ( ! $newName->isLocal()) { - throw RefactoringException::variableNotLocal($newName); - } + $this->assertVariableIsLocal($this->oldName); + $this->assertVariableIsLocal($this->newName); - $selectedMethodLineRange = $this->codeAnalysis->findMethodRange($file, LineRange::fromSingleLine($line)); - $definedVariables = $this->variableScanner->scanForVariables( - $file, $selectedMethodLineRange - ); + $this->startEditingSession(); + $this->renameLocalVariable(); + $this->completeEditingSession(); + } - if ( ! $definedVariables->contains($oldName)) { - throw RefactoringException::variableNotInRange($oldName, $selectedMethodLineRange); + private function assertVariableIsLocal(Variable $variable) + { + if ( ! $variable->isLocal()) { + throw RefactoringException::variableNotLocal($variable); } + } - $buffer = $this->editor->openBuffer($file); + private function renameLocalVariable() + { + $definedVariables = $this->getDefinedVariables(); - $session = new EditingSession($buffer); - $session->replaceString($definedVariables, $oldName, $newName); + if ( ! $definedVariables->contains($this->oldName)) { + throw RefactoringException::variableNotInRange($this->oldName, $selectedMethodLineRange); + } - $this->editor->save(); + $this->session->addEdit(new RenameVariable($definedVariables, $this->oldName, $this->newName)); } } - diff --git a/src/main/QafooLabs/Refactoring/Application/SingleFileRefactoring.php b/src/main/QafooLabs/Refactoring/Application/SingleFileRefactoring.php new file mode 100644 index 0000000..2af397a --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Application/SingleFileRefactoring.php @@ -0,0 +1,86 @@ +variableScanner = $variableScanner; + $this->codeAnalysis = $codeAnalysis; + $this->editor = $editor; + } + + protected function assertIsInsideMethod() + { + if ( ! $this->codeAnalysis->isInsideMethod($this->file, LineRange::fromSingleLine($this->line))) { + throw RefactoringException::rangeIsNotInsideMethod(LineRange::fromSingleLine($this->line)); + } + } + + protected function startEditingSession() + { + $buffer = $this->editor->openBuffer($this->file); + + $this->session = new EditingSession($buffer); + } + + protected function completeEditingSession() + { + $this->session->performEdits(); + + $this->editor->save(); + } + + protected function getDefinedVariables() + { + $selectedMethodLineRange = $this->codeAnalysis->findMethodRange($this->file, LineRange::fromSingleLine($this->line)); + + $definedVariables = $this->variableScanner->scanForVariables( + $this->file, $selectedMethodLineRange + ); + + return $definedVariables; + } +} diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction.php b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction.php new file mode 100644 index 0000000..513a855 --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction.php @@ -0,0 +1,8 @@ +lineNumber = $lineNumber; + $this->newMethod = $newMethod; + $this->selectedCode = $selectedCode; + } + + public function performEdit(EditorBuffer $buffer) + { + $this->newCode = new IndentingLineCollection(); + + $this->newCode->addIndentation(); + + $this->addMethodOpening(); + $this->addMethodBody(); + $this->addReturnStatement(); + $this->addMethodClosing(); + + $buffer->append($this->lineNumber, $this->getNewCodeAsStringArray()); + } + + private function addMethodOpening() + { + $this->newCode->appendBlankLine(); + + $this->newCode->appendString($this->getNewMethodSignatureString()); + $this->newCode->appendString('{'); + + $this->newCode->addIndentation(); + } + + /** + * @return string + */ + private function getNewMethodSignatureString() + { + return sprintf( + 'private %sfunction %s(%s)', + ($this->newMethod->isStatic() ? 'static ' : ''), + $this->newMethod->getName(), + $this->createVariableList($this->newMethod->arguments()) + ); + } + + /** + * @param string[] $variables + * + * @return string + */ + private function createVariableList(array $variables) + { + return implode(', ', array_map(function ($variableName) { + return '$' . $variableName; + }, $variables)); + } + + private function addMethodBody() + { + $this->newCode->appendLines($this->getUnindentedSelectedCode()); + } + + private function getUnindentedSelectedCode() + { + $detector = new IndentationDetector($this->selectedCode); + + $lines = array_map(function ($line) use ($detector) { + return substr($line, $detector->getMinIndentation()); + }, iterator_to_array(new ToStringIterator($this->selectedCode->getIterator()))); + + return LineCollection::createFromArray($lines); + } + + private function addReturnStatement() + { + $returnVars = $this->newMethod->returnVariables(); + + $numVariables = count($returnVars); + + if ($numVariables === 0) { + return; + } + + $returnVariable = '$' . reset($returnVars); + + if ($numVariables > 1) { + $returnVariable = 'array(' . $this->createVariableList($returnVars) . ')'; + } + + $this->newCode->appendBlankLine(); + $this->newCode->appendString('return ' . $returnVariable . ';'); + } + + private function addMethodClosing() + { + $this->newCode->removeIndentation(); + $this->newCode->appendString('}'); + } + + + /** + * @return string[] + */ + private function getNewCodeAsStringArray() + { + $toString = new ToStringIterator($this->newCode->getIterator()); + + return iterator_to_array($toString); + } +} diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/AddProperty.php b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/AddProperty.php new file mode 100644 index 0000000..fde3cad --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/AddProperty.php @@ -0,0 +1,37 @@ +line = $line; + $this->propertyName = $propertyName; + } + + public function performEdit(EditorBuffer $buffer) + { + $buffer->append($this->line, array( + ' private $' . $this->propertyName . ';', + '' + )); + } +} diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/LocalVariableToInstance.php b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/LocalVariableToInstance.php new file mode 100644 index 0000000..036bcf1 --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/LocalVariableToInstance.php @@ -0,0 +1,38 @@ +definedVars = $definedVars; + $this->variable = $variable; + } + + public function performEdit(EditorBuffer $buffer) + { + $renamer = new RenameVariable( + $this->definedVars, + $this->variable, + $this->variable->convertToInstance() + ); + + $renamer->performEdit($buffer); + } +} diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/RenameVariable.php b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/RenameVariable.php new file mode 100644 index 0000000..69a4ab1 --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/RenameVariable.php @@ -0,0 +1,62 @@ +definedVars = $definedVars; + $this->oldName = $oldName; + $this->newName = $newName; + } + + public function performEdit(EditorBuffer $buffer) + { + foreach ($this->getLinesVariableIsUsedOn() as $line) { + $buffer->replaceString( + $line, + $this->oldName->getToken(), + $this->newName->getToken() + ); + } + } + + /** + * @return int[] + */ + private function getLinesVariableIsUsedOn() + { + $variables = $this->definedVars->all(); + $variableName = $this->oldName->getName(); + + $lines = array(); + + if (isset($variables[$variableName])) { + $lines = $variables[$variableName]; + } + + return $lines; + } +} + diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/ReplaceWithMethodCall.php b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/ReplaceWithMethodCall.php new file mode 100644 index 0000000..0d10625 --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/EditingAction/ReplaceWithMethodCall.php @@ -0,0 +1,92 @@ +range = $range; + $this->newMethod = $newMethod; + } + + public function performEdit(EditorBuffer $buffer) + { + $extractedCode = $buffer->getLines($this->range); + + $buffer->replace($this->range, array($this->getIndent($extractedCode) . $this->getMethodCall())); + } + + /** + * @param string[] $lines + * + * @return string + */ + private function getIndent(array $lines) + { + $detector = new IndentationDetector( + LineCollection::createFromArray($lines) + ); + + return str_repeat(' ', $detector->getFirstLineIndentation()); + } + + private function getMethodCall() + { + return sprintf( + '%s%s%s(%s);', + $this->getReturnVariables(), + ($this->newMethod->isStatic() ? 'self::' : '$this->'), + $this->newMethod->getName(), + $this->createVariableList($this->newMethod->arguments()) + ); + } + + private function getReturnVariables() + { + $returnVars = $this->newMethod->returnVariables(); + + $numVariables = count($returnVars); + + if ($numVariables === 0) { + return; + } + + $returnVariable = '$' . reset($returnVars); + + if ($numVariables > 1) { + $returnVariable = 'list(' . $this->createVariableList($returnVars) . ')'; + } + + return $returnVariable . ' = '; + } + + /** + * @param string[] $variables + * + * @return string + */ + private function createVariableList(array $variables) + { + return implode(', ', array_map(function ($variableName) { + return '$' . $variableName; + }, $variables)); + } +} diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/EditingSession.php b/src/main/QafooLabs/Refactoring/Domain/Model/EditingSession.php index b3c37c5..1cc60f5 100644 --- a/src/main/QafooLabs/Refactoring/Domain/Model/EditingSession.php +++ b/src/main/QafooLabs/Refactoring/Domain/Model/EditingSession.php @@ -21,126 +21,25 @@ class EditingSession */ private $buffer; + /** + * @var EditingAction[] + */ + private $actions = array(); + public function __construct(EditorBuffer $buffer) { $this->buffer = $buffer; } - public function replaceString(DefinedVariables $definedVariables, Variable $oldName, Variable $newName) - { - $this->replaceStringInArray($definedVariables->all(), $oldName, $newName); - } - - private function replaceStringInArray(array $variables, Variable $oldName, Variable $newName) - { - if (isset($variables[$oldName->getName()])) { - foreach ($variables[$oldName->getName()] as $line) { - $this->buffer->replaceString($line, $oldName->getToken(), $newName->getToken()); - } - } - } - - public function replaceRangeWithMethodCall(LineRange $range, MethodSignature $newMethod) - { - $argumentLine = $this->implodeVariables($newMethod->arguments()); - - $code = $newMethod->isStatic() ? 'self::%s(%s);' : '$this->%s(%s);'; - $call = sprintf($code, $newMethod->getName(), $argumentLine); - - if (count($newMethod->returnVariables()) == 1) { - $call = '$' . $newMethod->returnVariables()[0] . ' = ' . $call; - } else if (count($newMethod->returnVariables()) > 1) { - $call = 'list(' . $this->implodeVariables($newMethod->returnVariables()) . ') = ' . $call; - } - - $this->buffer->replace($range, array($this->whitespace(8) . $call)); - } - - public function addMethod($line, MethodSignature $newMethod, $selectedCode) - { - if (count($newMethod->returnVariables()) == 1) { - $selectedCode[] = ''; - $selectedCode[] = $this->whitespace(8) . 'return $' . $newMethod->returnVariables()[0] . ';'; - } else if (count($newMethod->returnVariables()) > 1) { - $selectedCode[] = ''; - $selectedCode[] = $this->whitespace(8) . 'return array(' . $this->implodeVariables($newMethod->returnVariables()) . ');'; - } - - $methodCode = array_merge( - array( - '', - $this->whitespace(4) . $this->renderMethodSignature($newMethod), - $this->whitespace(4) . '{' - ), - $this->realign($selectedCode, 8), - array($this->whitespace(4) . '}') - ); - - $this->buffer->append($line, $methodCode); - } - - private function alignedAtWhitespaces(array $lines) + public function addEdit(EditingAction $action) { - return array_reduce($lines, function ($minWhitespace, $line) { - if ($this->isEmptyLine($line)) { - return $minWhitespace; - } - - return min($minWhitespace, $this->leftWhitespacesOf($line)); - }, 100); + $this->actions[] = $action; } - private function realign(array $lines, $atWhitespaces) + public function performEdits() { - $minWhitespaces = $this->alignedAtWhitespaces($lines); - $whitespaceCorrection = $atWhitespaces - $minWhitespaces; - - if ($whitespaceCorrection === 0) { - return $lines; + foreach ($this->actions as $action) { + $action->performEdit($this->buffer); } - - return array_map(function ($line) use($whitespaceCorrection) { - if ($whitespaceCorrection > 0) { - return $this->whitespace($whitespaceCorrection) . $line; - } - - return substr($line, $whitespaceCorrection - 2); // Why -2? - }, $lines); - } - - private function isEmptyLine($line) - { - return trim($line) === ""; - } - - private function leftWhitespacesOf($line) - { - return strlen($line) - strlen(ltrim($line)); - } - - private function renderMethodSignature(MethodSignature $method) - { - $paramLine = $this->implodeVariables($method->arguments()); - - return sprintf('private%sfunction %s(%s)', $method->isStatic() ? ' static ' : ' ', $method->getName(), $paramLine); - } - - private function implodeVariables($variableNames) - { - return implode(', ', array_map(function ($variableName) { - return '$' . $variableName; - }, $variableNames)); - } - - public function addProperty($line, $propertyName) - { - $this->buffer->append($line, array( - $this->whitespace(4) . 'private $' . $propertyName . ';', '' - )); - } - - private function whitespace($number) - { - return str_repeat(' ', $number); } } diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/EditorBuffer.php b/src/main/QafooLabs/Refactoring/Domain/Model/EditorBuffer.php index edf2dd6..e11d78e 100644 --- a/src/main/QafooLabs/Refactoring/Domain/Model/EditorBuffer.php +++ b/src/main/QafooLabs/Refactoring/Domain/Model/EditorBuffer.php @@ -19,6 +19,15 @@ */ interface EditorBuffer { + /** + * Return the given range of lines from the buffer. + * + * @param LineRange $range + * + * @return string[] + */ + public function getLines(LineRange $range); + /** * Replace LineRange with new lines. * diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/IndentationDetector.php b/src/main/QafooLabs/Refactoring/Domain/Model/IndentationDetector.php new file mode 100644 index 0000000..7a8d5cc --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/IndentationDetector.php @@ -0,0 +1,56 @@ +lines = $lines; + } + + /** + * @return int + */ + public function getMinIndentation() + { + return array_reduce( + iterator_to_array($this->lines), + function ($minIndentation, $line) { + $indentation = $line->getIndentation(); + + if ($line->isEmpty()) { + return $minIndentation; + } + + if ($minIndentation === null) { + return $indentation; + } + + return min($minIndentation, $indentation); + } + ); + } + + /** + * @return int + */ + public function getFirstLineIndentation() + { + $indentation = null; + + foreach ($this->lines as $line) { + if (!$line->isEmpty()) { + $indentation = $line->getIndentation(); + break; + } + } + + return $indentation; + } +} diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/IndentingLineCollection.php b/src/main/QafooLabs/Refactoring/Domain/Model/IndentingLineCollection.php new file mode 100644 index 0000000..0c7c286 --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/IndentingLineCollection.php @@ -0,0 +1,36 @@ +indentation++; + } + + public function removeIndentation() + { + $this->indentation--; + } + + public function append(Line $line) + { + parent::append(new Line($this->createIndentationString() . (string) $line)); + } + + /** + * @return string + */ + private function createIndentationString() + { + return str_repeat(' ', $this->indentation * self::INDENTATION_SIZE); + } +} diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/Line.php b/src/main/QafooLabs/Refactoring/Domain/Model/Line.php new file mode 100644 index 0000000..46d476b --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/Line.php @@ -0,0 +1,43 @@ +line = (string) $line; + } + + /** + * @return string + */ + public function __toString() + { + return $this->line; + } + + /** + * @return bool + */ + public function isEmpty() + { + return trim($this->line) === ''; + } + + /** + * @return int + */ + public function getIndentation() + { + return strlen($this->line) - strlen(ltrim($this->line)); + } +} diff --git a/src/main/QafooLabs/Refactoring/Domain/Model/LineCollection.php b/src/main/QafooLabs/Refactoring/Domain/Model/LineCollection.php new file mode 100644 index 0000000..5022d5a --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Domain/Model/LineCollection.php @@ -0,0 +1,82 @@ +lines = $lines; + } + + public function getIterator() + { + return new ArrayIterator($this->lines); + } + + /** + * @return Line[] + */ + public function getLines() + { + return $this->lines; + } + + public function append(Line $line) + { + $this->lines[] = $line; + } + + /** + * @param string $line + */ + public function appendString($line) + { + $this->append(new Line($line)); + } + + public function appendLines(LineCollection $lines) + { + foreach ($lines as $line) { + $this->append($line); + } + } + + public function appendBlankLine() + { + $this->lines[] = new Line(''); + } + + /** + * @param string[] $lines + * + * @return LineCollection + */ + public static function createFromArray(array $lines) + { + return new self(array_map(function ($line) { + return new Line($line); + }, $lines)); + } + + /** + * @param string $code + * + * @return LineCollection + */ + public static function createFromString($code) + { + return self::createFromArray(explode("\n", $code)); + } +} diff --git a/src/main/QafooLabs/Refactoring/Utils/ToStringIterator.php b/src/main/QafooLabs/Refactoring/Utils/ToStringIterator.php new file mode 100644 index 0000000..7d8cf8a --- /dev/null +++ b/src/main/QafooLabs/Refactoring/Utils/ToStringIterator.php @@ -0,0 +1,52 @@ +iterator = $it; + } + + /** + * @return string + */ + public function current() + { + return (string) $this->iterator->current(); + } + + /** + * @return scalar + */ + public function key() + { + return $this->iterator->key(); + } + + public function next() + { + $this->iterator->next(); + } + + public function rewind() + { + $this->iterator->rewind(); + } + + /** + * @return bool + */ + public function valid() + { + return $this->iterator->valid(); + } +} diff --git a/src/test/QafooLabs/Refactoring/Adapters/PatchBuilder/PatchBuilderTest.php b/src/test/QafooLabs/Refactoring/Adapters/PatchBuilder/PatchBuilderTest.php index d66034b..7586997 100644 --- a/src/test/QafooLabs/Refactoring/Adapters/PatchBuilder/PatchBuilderTest.php +++ b/src/test/QafooLabs/Refactoring/Adapters/PatchBuilder/PatchBuilderTest.php @@ -41,6 +41,23 @@ public function testChangeTokenOnLineAlone() line6 line7 +DIFF; + + $this->assertEquals($expected, $this->builder->generateUnifiedDiff()); + } + + public function testChangeIsCaseSensitive() + { + $this->builder = new PatchBuilder('$bar = new Bar();'); + $this->builder->changeToken(1, 'Bar', 'Foo'); + + $expected = <<assertEquals($expected, $this->builder->generateUnifiedDiff()); } @@ -200,4 +217,12 @@ public function testReplaceLines() DIFF; $this->assertEquals($expected, $this->builder->generateUnifiedDiff()); } + + public function testGetOriginalLines() + { + $this->assertEquals( + array('line4', 'line5', 'line6'), + $this->builder->getOriginalLines(4, 6) + ); + } } diff --git a/src/test/QafooLabs/Refactoring/Adapters/TokenReflection/StaticCodeAnalysisTest.php b/src/test/QafooLabs/Refactoring/Adapters/TokenReflection/StaticCodeAnalysisTest.php new file mode 100644 index 0000000..b24394e --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Adapters/TokenReflection/StaticCodeAnalysisTest.php @@ -0,0 +1,28 @@ +findClasses($file); + $class = $classes[0]; + + $this->assertEquals(0, $class->namespaceDeclarationLine(), 'namespace declaration line for file without namespace'); + } +} diff --git a/src/test/QafooLabs/Refactoring/Application/RenameLocalVariableTest.php.orig b/src/test/QafooLabs/Refactoring/Application/RenameLocalVariableTest.php.orig deleted file mode 100644 index 0a67bd6..0000000 --- a/src/test/QafooLabs/Refactoring/Application/RenameLocalVariableTest.php.orig +++ /dev/null @@ -1,51 +0,0 @@ -scanForVariables(\Phake::anyParameters())->thenReturn( - new DefinedVariables(array('helloWorld' => array(6))) - ); - \Phake::when($editor)->openBuffer(\Phake::anyParameters())->thenReturn($buffer); - - $refactoring = new RenameLocalVariable($scanner, $codeAnalysis, $editor); - - $patch = $refactoring->refactor(new File("foo.php", <<<'PHP' -replaceString(6, '$helloWorld', '$var'); - } - - public function testRenameNonLocalVariable_ThrowsException() - { - } - - public function testRenameIntoNonLocalVariable_ThrowsException() - { - } -} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/AddMethodTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/AddMethodTest.php new file mode 100644 index 0000000..06cdca2 --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/AddMethodTest.php @@ -0,0 +1,229 @@ +buffer = $this->getMock('QafooLabs\Refactoring\Domain\Model\EditorBuffer'); + } + + public function testItIsAnEditingAction() + { + $this->assertInstanceOf( + 'QafooLabs\Refactoring\Domain\Model\EditingAction', + new AddMethod(0, new MethodSignature('test'), new LineCollection()) + ); + } + + public function testBufferAppendIsPerformedAtTheGivenLineNumber() + { + $lineNumber = 27; + + $this->buffer + ->expects($this->once()) + ->method('append') + ->with($this->equalTo($lineNumber), $this->anything()); + + $action = new AddMethod($lineNumber, new MethodSignature('test'), new LineCollection()); + + $action->performEdit($this->buffer); + } + + public function testAppendsMethod() + { + $action = new AddMethod(0, new MethodSignature('testMethod'), new LineCollection()); + + $this->assertGeneratedCodeMatches(array( + '', + ' private function testMethod()', + ' {', + ' }' + ), $action); + } + + public function testReturnStatementForSingleVariable() + { + $action = new AddMethod( + 0, + $this->createMethodSignatureWithReturnVars(array('returnVar')), + new LineCollection() + ); + + $this->assertGeneratedCodeMatches(array( + '', + ' private function testMethod()', + ' {', + '', + ' return $returnVar;', + ' }' + ), $action); + } + + public function testReturnStatementForSingleVariableHasCorrectName() + { + $action = new AddMethod( + 0, + $this->createMethodSignatureWithReturnVars(array('specialVar')), + new LineCollection() + ); + + $this->assertGeneratedCodeMatches(array( + '', + ' private function testMethod()', + ' {', + '', + ' return $specialVar;', + ' }' + ), $action); + } + + public function testReturnStatementForMultipleVariables() + { + $action = new AddMethod( + 0, + $this->createMethodSignatureWithReturnVars(array('ret1', 'ret2')), + new LineCollection() + ); + + $this->assertGeneratedCodeMatches(array( + '', + ' private function testMethod()', + ' {', + '', + ' return array($ret1, $ret2);', + ' }' + ), $action); + } + + public function testMethodNameIsUsed() + { + $action = new AddMethod( + 0, + new MethodSignature('realMethodName'), + new LineCollection() + ); + + $this->assertGeneratedCodeMatches(array( + '', + ' private function realMethodName()', + ' {', + ' }' + ), $action); + } + + public function testStaticMethodsAreDefinedCorrectly() + { + $action = new AddMethod( + 0, + new MethodSignature( + 'realMethodName', + MethodSignature::IS_PRIVATE | MethodSignature::IS_STATIC + ), + new LineCollection() + ); + + $this->assertGeneratedCodeMatches(array( + '', + ' private static function realMethodName()', + ' {', + ' }' + ), $action); + } + + public function testMethodArgumentsAreDefinedCorrectly() + { + $action = new AddMethod( + 0, + new MethodSignature( + 'testMethod', + MethodSignature::IS_PRIVATE, + array('param1', 'param2') + ), + new LineCollection() + ); + + $this->assertGeneratedCodeMatches(array( + '', + ' private function testMethod($param1, $param2)', + ' {', + ' }' + ), $action); + } + + public function testSelectedCodeIsAdded() + { + $action = new AddMethod( + 0, + $this->createMethodSignatureWithReturnVars(array()), + LineCollection::createFromArray(array( + 'echo "Hello World!";' + )) + ); + + $this->assertGeneratedCodeMatches(array( + '', + ' private function testMethod()', + ' {', + ' echo "Hello World!";', + ' }' + ), $action); + } + + public function testSelectedCodeIsAddedWithCorrectIndetations() + { + $action = new AddMethod( + 0, + $this->createMethodSignatureWithReturnVars(array()), + LineCollection::createFromArray(array( + ' if ($something) {', + ' echo "Hello World!";', + ' }' + )) + ); + + $this->assertGeneratedCodeMatches(array( + '', + ' private function testMethod()', + ' {', + ' if ($something) {', + ' echo "Hello World!";', + ' }', + ' }' + ), $action); + } + + private function assertGeneratedCodeMatches(array $expected, AddMethod $action) + { + $this->makeBufferAppendExpectCode($expected); + + $action->performEdit($this->buffer); + } + + private function createMethodSignatureWithReturnVars(array $returnVars) + { + return new MethodSignature( + 'testMethod', + MethodSignature::IS_PRIVATE, + array(), + $returnVars + ); + } + + private function makeBufferAppendExpectCode(array $codeLines) + { + $this->buffer + ->expects($this->once()) + ->method('append') + ->with($this->anything(), $this->equalTo($codeLines)); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/AddPropertyTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/AddPropertyTest.php new file mode 100644 index 0000000..77cc92e --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/AddPropertyTest.php @@ -0,0 +1,50 @@ +buffer = $this->getMock('QafooLabs\Refactoring\Domain\Model\EditorBuffer'); + } + + public function testItIsAnEditingAction() + { + $this->assertInstanceOf( + 'QafooLabs\Refactoring\Domain\Model\EditingAction', + new AddProperty(5, 'testProperty') + ); + } + + public function testPropertyIsAppenedAtGivenLine() + { + $line = 27; + + $action = new AddProperty($line, ''); + + $this->buffer + ->expects($this->once()) + ->method('append') + ->with($line, $this->anything()); + + $action->performEdit($this->buffer); + } + + public function testPropertyCodeIsCorrect() + { + $action = new AddProperty(5, 'testProperty'); + + $this->buffer + ->expects($this->once()) + ->method('append') + ->with($this->anything(), $this->equalTo(array( + ' private $testProperty;', + '' + ))); + + $action->performEdit($this->buffer); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/LocalVariableToInstanceTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/LocalVariableToInstanceTest.php new file mode 100644 index 0000000..2afa4f7 --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/LocalVariableToInstanceTest.php @@ -0,0 +1,114 @@ +buffer = $this->getMock('QafooLabs\Refactoring\Domain\Model\EditorBuffer'); + } + + public function testItIsAnEditingAction() + { + $this->assertInstanceOf( + 'QafooLabs\Refactoring\Domain\Model\EditingAction', + new LocalVariableToInstance( + new DefinedVariables(array(), array()), + new Variable('testVar') + ) + ); + } + + public function testItReplacesVariableWithInstanceVariableVersion() + { + $variable = new Variable('varName'); + + $action = new LocalVariableToInstance( + new DefinedVariables(array('varName' => array(1)), array()), + $variable + ); + + $this->buffer + ->expects($this->once()) + ->method('replaceString') + ->with($this->anything(), $this->equalTo('$varName'), $this->equalTo('$this->varName')); + + $action->performEdit($this->buffer); + } + + public function testItReplacesOnLineForReadOnlyVariable() + { + $definedVars = new DefinedVariables(array('theVar' => array(12)), array()); + $variable = new Variable('theVar'); + + $action = new LocalVariableToInstance($definedVars, $variable); + + $this->buffer + ->expects($this->once()) + ->method('replaceString') + ->with($this->equalTo(12), $this->anything(), $this->anything()); + + $action->performEdit($this->buffer); + } + + public function testItReplacesOn2LinesForReadOnlyVariable() + { + $definedVars = new DefinedVariables(array('theVar' => array(12, 15)), array()); + $variable = new Variable('theVar'); + + $action = new LocalVariableToInstance($definedVars, $variable); + + $this->buffer + ->expects($this->at(0)) + ->method('replaceString') + ->with($this->equalTo(12), $this->anything(), $this->anything()); + + $this->buffer + ->expects($this->at(1)) + ->method('replaceString') + ->with($this->equalTo(15), $this->anything(), $this->anything()); + + $action->performEdit($this->buffer); + } + + public function testItReplacesOnLineForChangedVariable() + { + $definedVars = new DefinedVariables(array(), array('theVar' => array(12))); + $variable = new Variable('theVar'); + + $action = new LocalVariableToInstance($definedVars, $variable); + + $this->buffer + ->expects($this->once()) + ->method('replaceString') + ->with($this->equalTo(12), $this->anything(), $this->anything()); + + $action->performEdit($this->buffer); + } + + public function testItReplacesOn2LinesForChangedVariable() + { + $definedVars = new DefinedVariables(array(), array('theVar' => array(12, 15))); + $variable = new Variable('theVar'); + + $action = new LocalVariableToInstance($definedVars, $variable); + + $this->buffer + ->expects($this->at(0)) + ->method('replaceString') + ->with($this->equalTo(12), $this->anything(), $this->anything()); + + $this->buffer + ->expects($this->at(1)) + ->method('replaceString') + ->with($this->equalTo(15), $this->anything(), $this->anything()); + + $action->performEdit($this->buffer); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/RenameVariableTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/RenameVariableTest.php new file mode 100644 index 0000000..bc5bc13 --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/RenameVariableTest.php @@ -0,0 +1,117 @@ +buffer = $this->getMock('QafooLabs\Refactoring\Domain\Model\EditorBuffer'); + } + + public function testItIsAnEditingAction() + { + $this->assertInstanceOf( + 'QafooLabs\Refactoring\Domain\Model\EditingAction', + new RenameVariable( + new DefinedVariables(array(), array()), + new Variable('testVar'), + new Variable('newVar') + ) + ); + } + + public function testItReplacesVariableWithInstanceVariableVersion() + { + $oldName = new Variable('varName'); + $newName = new Variable('newName'); + + $action = new RenameVariable( + new DefinedVariables(array('varName' => array(1)), array()), + $oldName, + $newName + ); + + $this->buffer + ->expects($this->once()) + ->method('replaceString') + ->with($this->anything(), $this->equalTo('$varName'), $this->equalTo('$newName')); + + $action->performEdit($this->buffer); + } + + public function testItReplacesOnLineForReadOnlyVariable() + { + $definedVars = new DefinedVariables(array('theVar' => array(12)), array()); + $variable = new Variable('theVar'); + + $action = new RenameVariable($definedVars, $variable, $variable); + + $this->buffer + ->expects($this->once()) + ->method('replaceString') + ->with($this->equalTo(12), $this->anything(), $this->anything()); + + $action->performEdit($this->buffer); + } + + public function testItReplacesOn2LinesForReadOnlyVariable() + { + $definedVars = new DefinedVariables(array('theVar' => array(12, 15)), array()); + $variable = new Variable('theVar'); + + $action = new RenameVariable($definedVars, $variable, $variable); + + $this->buffer + ->expects($this->at(0)) + ->method('replaceString') + ->with($this->equalTo(12), $this->anything(), $this->anything()); + + $this->buffer + ->expects($this->at(1)) + ->method('replaceString') + ->with($this->equalTo(15), $this->anything(), $this->anything()); + + $action->performEdit($this->buffer); + } + + public function testItReplacesOnLineForChangedVariable() + { + $definedVars = new DefinedVariables(array(), array('theVar' => array(12))); + $variable = new Variable('theVar'); + + $action = new RenameVariable($definedVars, $variable, $variable); + + $this->buffer + ->expects($this->once()) + ->method('replaceString') + ->with($this->equalTo(12), $this->anything(), $this->anything()); + + $action->performEdit($this->buffer); + } + + public function testItReplacesOn2LinesForChangedVariable() + { + $definedVars = new DefinedVariables(array(), array('theVar' => array(12, 15))); + $variable = new Variable('theVar'); + + $action = new RenameVariable($definedVars, $variable, $variable); + + $this->buffer + ->expects($this->at(0)) + ->method('replaceString') + ->with($this->equalTo(12), $this->anything(), $this->anything()); + + $this->buffer + ->expects($this->at(1)) + ->method('replaceString') + ->with($this->equalTo(15), $this->anything(), $this->anything()); + + $action->performEdit($this->buffer); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/ReplaceWithMethodCallTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/ReplaceWithMethodCallTest.php new file mode 100644 index 0000000..f4e208e --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/EditingAction/ReplaceWithMethodCallTest.php @@ -0,0 +1,186 @@ +buffer = $this->getMock('QafooLabs\Refactoring\Domain\Model\EditorBuffer'); + } + + public function testItIsAnEditingAction() + { + $this->assertInstanceOf( + 'QafooLabs\Refactoring\Domain\Model\EditingAction', + new ReplaceWithMethodCall( + LineRange::fromLines(1, 2), + new MethodSignature('testMethod') + ) + ); + } + + public function testBufferReplacesAtGivenRange() + { + $range = LineRange::fromLines(1, 2); + + $action = new ReplaceWithMethodCall( + $range, + new MethodSignature('testMethod') + ); + + $this->buffer + ->expects($this->once()) + ->method('replace') + ->with($this->equalTo($range), $this->anything()); + + $this->setCodeBeingReplaced(); + + $action->performEdit($this->buffer); + } + + public function testMethodCallIsCorrectForSimpleMethod() + { + $action = new ReplaceWithMethodCall( + LineRange::fromLines(1, 2), + new MethodSignature('testMethod') + ); + + $this->setCodeBeingReplaced(); + + $this->assertGeneratedMethodCallMatches('$this->testMethod();', $action); + } + + public function testMethodCallUsesGivenMethodName() + { + $action = new ReplaceWithMethodCall( + LineRange::fromLines(1, 2), + new MethodSignature('realMethod') + ); + + $this->setCodeBeingReplaced(); + + $this->assertGeneratedMethodCallMatches('$this->realMethod();', $action); + } + + public function testStaticMethodCall() + { + $action = new ReplaceWithMethodCall( + LineRange::fromLines(1, 2), + new MethodSignature('testMethod', MethodSignature::IS_STATIC) + ); + + $this->setCodeBeingReplaced(); + + $this->assertGeneratedMethodCallMatches('self::testMethod();', $action); + } + + public function testMethodCallWithSingleReturnVariable() + { + $action = new ReplaceWithMethodCall( + LineRange::fromLines(1, 2), + new MethodSignature('testMethod', 0, array(), array('result')) + ); + + $this->setCodeBeingReplaced(); + + $this->assertGeneratedMethodCallMatches('$result = $this->testMethod();', $action); + } + + public function testMethodCallWithMultipleReturnVariables() + { + $action = new ReplaceWithMethodCall( + LineRange::fromLines(1, 2), + new MethodSignature('testMethod', 0, array(), array('result1', 'result2')) + ); + + $this->setCodeBeingReplaced(); + + $this->assertGeneratedMethodCallMatches( + 'list($result1, $result2) = $this->testMethod();', + $action + ); + } + + public function testMethodCallWithArguments() + { + $action = new ReplaceWithMethodCall( + LineRange::fromLines(1, 2), + new MethodSignature('testMethod', 0, array('arg1', 'arg2')) + ); + + $this->setCodeBeingReplaced(); + + $this->assertGeneratedMethodCallMatches( + '$this->testMethod($arg1, $arg2);', + $action + ); + } + + public function testExtractedRangeIsReadFromTheBuffer() + { + $range = LineRange::fromLines(1, 2); + + $this->buffer + ->expects($this->once()) + ->method('getLines') + ->with($this->equalTo($range)) + ->will($this->returnValue(array())); + + $action = new ReplaceWithMethodCall( + $range, + new MethodSignature('testMethod') + ); + + $action->performEdit($this->buffer); + } + + public function testExtractRangeIndentsMethodCallForFirstLineWithExtraIndent() + { + $lines = array( + ' echo "Something";', + ); + + $this->buffer + ->expects($this->once()) + ->method('getLines') + ->will($this->returnValue($lines)); + + $action = new ReplaceWithMethodCall( + LineRange::fromLines(1, 2), + new MethodSignature('testMethod') + ); + + $this->assertGeneratedMethodCallMatches( + '$this->testMethod();', + $action, + 12 + ); + } + + private function setCodeBeingReplaced( + array $lines = array(' echo "Replace me";') + ) { + $this->buffer + ->expects($this->any()) + ->method('getLines') + ->will($this->returnValue($lines)); + } + + private function assertGeneratedMethodCallMatches($expected, $action, $indentSize = 8) + { + $expected = str_repeat(' ', $indentSize) . $expected; + + $this->buffer + ->expects($this->once()) + ->method('replace') + ->with($this->anything(), $this->equalTo(array($expected))); + + $action->performEdit($this->buffer); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/EditingSessionTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/EditingSessionTest.php new file mode 100644 index 0000000..8e5d10f --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/EditingSessionTest.php @@ -0,0 +1,47 @@ +buffer = $this->getMock('QafooLabs\Refactoring\Domain\Model\EditorBuffer'); + + $this->session = new EditingSession($this->buffer); + } + + public function testEditActionsArePerformed() + { + $action1 = $this->getMock('QafooLabs\Refactoring\Domain\Model\EditingAction'); + $action2 = $this->getMock('QafooLabs\Refactoring\Domain\Model\EditingAction'); + + $action1->expects($this->once()) + ->method('performEdit') + ->with($this->equalTo($this->buffer)); + + $action2->expects($this->once()) + ->method('performEdit') + ->with($this->equalTo($this->buffer)); + + $this->session->addEdit($action1); + $this->session->addEdit($action2); + + $this->session->performEdits(); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/IndentationDetectorTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/IndentationDetectorTest.php new file mode 100644 index 0000000..70c4443 --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/IndentationDetectorTest.php @@ -0,0 +1,68 @@ +createDetector(array(' echo "test";')); + + $this->assertEquals(4, $detector->getMinIndentation()); + } + + public function testGetMinIndentationForFirstLine() + { + $detector = $this->createDetector(array( + ' echo "Line 1";', + ' echo "Line 2";', + )); + + $this->assertEquals(2, $detector->getMinIndentation()); + } + + public function testGetMinIntentationForLaterLine() + { + $detector = $this->createDetector(array( + ' echo "Line 1";', + ' echo "Line 2";', + )); + + $this->assertEquals(2, $detector->getMinIndentation()); + } + + public function testGetMinIndentationWithBlankLines() + { + $detector = $this->createDetector(array( + '', + ' echo "test";', + )); + + $this->assertEquals(4, $detector->getMinIndentation()); + } + + public function testGetFirstLineIndentation() + { + $detector = $this->createDetector(array( + ' echo "line 1";', + ' echo "line 2";', + )); + + $this->assertEquals(4, $detector->getFirstLineIndentation()); + } + + public function testGetFirstLineIndentationWithBlankLines() + { + $detector = $this->createDetector(array( + '', + ' echo "test";', + )); + + $this->assertEquals(2, $detector->getFirstLineIndentation()); + } + + private function createDetector(array $lines) + { + return new IndentationDetector(LineCollection::createFromArray($lines)); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/IndentingLineCollectionTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/IndentingLineCollectionTest.php new file mode 100644 index 0000000..b8b8723 --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/IndentingLineCollectionTest.php @@ -0,0 +1,109 @@ +lines = new IndentingLineCollection(); + } + + public function testIsALineCollection() + { + $this->assertInstanceOf( + 'QafooLabs\Refactoring\Domain\Model\LineCollection', + $this->lines + ); + } + + public function testAppendAddsIndentation() + { + $this->lines->addIndentation(); + + $this->lines->append(new Line('echo "test";')); + + $this->assertLinesMatch(array( + ' echo "test";' + )); + } + + public function testAppendAddsMulitpleIndentation() + { + $this->lines->append(new Line('echo "line1";')); + $this->lines->addIndentation(); + $this->lines->append(new Line('echo "line2";')); + $this->lines->addIndentation(); + $this->lines->append(new Line('echo "line3";')); + + $this->assertLinesMatch(array( + 'echo "line1";', + ' echo "line2";', + ' echo "line3";' + )); + } + + public function testAppendRemovesIndentation() + { + $this->lines->append(new Line('echo "line1";')); + $this->lines->addIndentation(); + $this->lines->append(new Line('echo "line2";')); + $this->lines->removeIndentation(); + $this->lines->append(new Line('echo "line3";')); + + $this->assertLinesMatch(array( + 'echo "line1";', + ' echo "line2";', + 'echo "line3";' + )); + } + + public function testAppendStringObeysIndentation() + { + $this->lines->appendString('echo "line1";'); + $this->lines->addIndentation(); + $this->lines->appendString('echo "line2";'); + $this->lines->removeIndentation(); + $this->lines->appendString('echo "line3";'); + + $this->assertLinesMatch(array( + 'echo "line1";', + ' echo "line2";', + 'echo "line3";' + )); + } + + public function testAppendLinesObeysIndentation() + { + $this->lines->addIndentation(); + + $this->lines->appendLines(LineCollection::createFromArray(array( + 'echo "line1";', + 'echo "line2";' + ))); + + $this->assertLinesMatch(array( + ' echo "line1";', + ' echo "line2";', + )); + } + + public function testAddBlankLineContainsNoIndentation() + { + $this->lines->appendBlankLine(); + + $this->assertLinesMatch(array('')); + } + + private function assertLinesMatch(array $expected) + { + $this->assertEquals( + $expected, + iterator_to_array(new ToStringIterator($this->lines->getIterator())) + ); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/LineCollectionTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/LineCollectionTest.php new file mode 100644 index 0000000..f96f59f --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/LineCollectionTest.php @@ -0,0 +1,114 @@ +assertSame($lineObjects, $lines->getLines()); + } + + public function testAppendAddsALine() + { + $line1 = new Line('line 1'); + $line2 = new Line('line 2'); + + $lines = new LineCollection(array($line1)); + + $lines->append($line2); + + $this->assertSame(array($line1, $line2), $lines->getLines()); + } + + public function testAppendStringAddsALine() + { + $line1 = 'line 1'; + $line2 = 'line 2'; + + $lines = new LineCollection(array(new Line($line1))); + + $lines->appendString($line2); + + $this->assertEquals( + array(new Line($line1), new Line($line2)), + $lines->getLines() + ); + } + + public function testCreateFromArray() + { + $lines = LineCollection::createFromArray(array( + 'line1', + 'line2', + )); + + $this->assertEquals( + array(new Line('line1'), new Line('line2')), + $lines->getLines() + ); + } + + public function testCreateFromString() + { + $lines = LineCollection::createFromString( + "line1\nline2" + ); + + $this->assertEquals( + array(new Line('line1'), new Line('line2')), + $lines->getLines() + ); + } + + public function testIsIterable() + { + $lineObjects = array( + new Line('line 1'), + new Line('line 2') + ); + + $lines = new LineCollection($lineObjects); + + $this->assertEquals($lineObjects, iterator_to_array($lines)); + } + + public function testAppendLinesAddsGivenLines() + { + $lines = LineCollection::createFromArray(array( + 'line1', + 'line2', + )); + + $lines->appendLines(LineCollection::createFromArray(array( + 'line3', + 'line4', + ))); + + $this->assertEquals( + array('line1', 'line2', 'line3', 'line4'), + iterator_to_array(new ToStringIterator($lines->getIterator())) + ); + } + + public function testAppendlankLine() + { + $lines = new LineCollection(); + + $lines->appendBlankLine(); + + $this->assertEquals( + array(''), + iterator_to_array(new ToStringIterator($lines->getIterator())) + ); + } +} diff --git a/src/test/QafooLabs/Refactoring/Domain/Model/LineTest.php b/src/test/QafooLabs/Refactoring/Domain/Model/LineTest.php new file mode 100644 index 0000000..36d991b --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Domain/Model/LineTest.php @@ -0,0 +1,43 @@ +assertEquals($content, (string) $line); + } + + public function testIsEmptyForEmptyLine() + { + $line = new Line(''); + + $this->assertTrue($line->isEmpty()); + } + + public function testIsEmptyForLineWithContent() + { + $line = new Line('$a = 5;'); + + $this->assertFalse($line->isEmpty()); + } + + public function testGetIndentationFor2Spaces() + { + $line = new Line(' echo "Test";'); + + $this->assertEquals(2, $line->getIndentation()); + } + + public function testGetIndentationFor4Spaces() + { + $line = new Line(' echo "Test";'); + + $this->assertEquals(4, $line->getIndentation()); + } +} diff --git a/src/test/QafooLabs/Refactoring/Utils/ToStringIteratorTest.php b/src/test/QafooLabs/Refactoring/Utils/ToStringIteratorTest.php new file mode 100644 index 0000000..d9f543f --- /dev/null +++ b/src/test/QafooLabs/Refactoring/Utils/ToStringIteratorTest.php @@ -0,0 +1,49 @@ +assertEquals( + array('value1', 'value2'), + iterator_to_array($it) + ); + } +} + +class StringableClass +{ + private $value; + + public function __construct($value) + { + $this->value = $value; + } + + public function __toString() + { + return (string) $this->value; + } +}