Update libraries (#6384)

Remove dev dependencies, causing issues for people
This commit is contained in:
Tony Murray
2017-04-13 10:47:59 +01:00
committed by Neil Lathwood
parent 72ce39cf9b
commit d44d23dba6
1636 changed files with 139 additions and 162726 deletions
+1 -1
View File
@@ -2,6 +2,6 @@
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit272059f49825f0adab6de160cf59ca72::getLoader();
-1
View File
@@ -1 +0,0 @@
../jakub-onderka/php-parallel-lint/parallel-lint
-1
View File
@@ -1 +0,0 @@
../squizlabs/php_codesniffer/scripts/phpcbf
-1
View File
@@ -1 +0,0 @@
../squizlabs/php_codesniffer/scripts/phpcs
-1
View File
@@ -1 +0,0 @@
../phpunit/phpunit/phpunit
-1
View File
@@ -1 +0,0 @@
../fojuth/readmegen/readmegen
+7 -5
View File
@@ -53,8 +53,8 @@ class ClassLoader
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
public function getPrefixes()
{
@@ -322,20 +322,20 @@ class ClassLoader
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if ($file === null) {
if (false === $file) {
// Remember that this class does not exist.
return $this->classMap[$class] = false;
$this->missingClasses[$class] = true;
}
return $file;
@@ -399,6 +399,8 @@ class ClassLoader
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
+1
View File
@@ -388,6 +388,7 @@ return array(
'HTMLPurifier_Zipper' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
'LibreNMS\\Component' => $baseDir . '/LibreNMS/Component.php',
'LibreNMS\\ComposerHelper' => $baseDir . '/LibreNMS/ComposerHelper.php',
'LibreNMS\\Exceptions\\DatabaseConnectException' => $baseDir . '/LibreNMS/Exceptions/DatabaseConnectException.php',
'LibreNMS\\Exceptions\\FileExistsException' => $baseDir . '/LibreNMS/Exceptions/FileExistsException.php',
'LibreNMS\\Exceptions\\HostExistsException' => $baseDir . '/LibreNMS/Exceptions/HostExistsException.php',
'LibreNMS\\Exceptions\\HostIpExistsException' => $baseDir . '/LibreNMS/Exceptions/HostIpExistsException.php',
+1
View File
@@ -508,6 +508,7 @@ class ComposerStaticInit272059f49825f0adab6de160cf59ca72
'HTMLPurifier_Zipper' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
'LibreNMS\\Component' => __DIR__ . '/../..' . '/LibreNMS/Component.php',
'LibreNMS\\ComposerHelper' => __DIR__ . '/../..' . '/LibreNMS/ComposerHelper.php',
'LibreNMS\\Exceptions\\DatabaseConnectException' => __DIR__ . '/../..' . '/LibreNMS/Exceptions/DatabaseConnectException.php',
'LibreNMS\\Exceptions\\FileExistsException' => __DIR__ . '/../..' . '/LibreNMS/Exceptions/FileExistsException.php',
'LibreNMS\\Exceptions\\HostExistsException' => __DIR__ . '/../..' . '/LibreNMS/Exceptions/HostExistsException.php',
'LibreNMS\\Exceptions\\HostIpExistsException' => __DIR__ . '/../..' . '/LibreNMS/Exceptions/HostIpExistsException.php',
+129 -113
View File
@@ -405,68 +405,6 @@
"html"
]
},
{
"name": "phpmailer/phpmailer",
"version": "v5.2.22",
"version_normalized": "5.2.22.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "b18cb98131bd83103ccb26a888fdfe3177b8a663"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/b18cb98131bd83103ccb26a888fdfe3177b8a663",
"reference": "b18cb98131bd83103ccb26a888fdfe3177b8a663",
"shasum": ""
},
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"phpdocumentor/phpdocumentor": "*",
"phpunit/phpunit": "4.7.*"
},
"suggest": {
"league/oauth2-google": "Needed for Google XOAUTH2 authentication"
},
"time": "2017-01-09 09:33:47",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"class.phpmailer.php",
"class.phpmaileroauth.php",
"class.phpmaileroauthgoogle.php",
"class.smtp.php",
"class.pop3.php",
"extras/EasyPeasyICS.php",
"extras/ntlm_sasl_client.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "Jim Jagielski",
"email": "[email protected]"
},
{
"name": "Marcus Bointon",
"email": "[email protected]"
},
{
"name": "Andy Prevost",
"email": "[email protected]"
},
{
"name": "Brent R. Matzelle"
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP"
},
{
"name": "slim/slim",
"version": "2.6.3",
@@ -580,57 +518,6 @@
"rfc2869"
]
},
{
"name": "symfony/yaml",
"version": "v2.8.18",
"version_normalized": "2.8.18.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "2a7bab3c16f6f452c47818fdd08f3b1e49ffcf7d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/2a7bab3c16f6f452c47818fdd08f3b1e49ffcf7d",
"reference": "2a7bab3c16f6f452c47818fdd08f3b1e49ffcf7d",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"time": "2017-03-01 18:13:50",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com"
},
{
"name": "rmccue/requests",
"version": "v1.7.0",
@@ -681,5 +568,134 @@
"iri",
"sockets"
]
},
{
"name": "phpmailer/phpmailer",
"version": "v5.2.23",
"version_normalized": "5.2.23.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "7115df4a6f76281109ebe352900c42403b728bb4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/7115df4a6f76281109ebe352900c42403b728bb4",
"reference": "7115df4a6f76281109ebe352900c42403b728bb4",
"shasum": ""
},
"require": {
"php": ">=5.0.0"
},
"require-dev": {
"doctrine/annotations": "1.2.*",
"jms/serializer": "0.16.*",
"phpdocumentor/phpdocumentor": "2.*",
"phpunit/phpunit": "4.8.*",
"symfony/debug": "2.8.*",
"symfony/filesystem": "2.8.*",
"symfony/translation": "2.8.*",
"symfony/yaml": "2.8.*",
"zendframework/zend-cache": "2.5.1",
"zendframework/zend-config": "2.5.1",
"zendframework/zend-eventmanager": "2.5.1",
"zendframework/zend-filter": "2.5.1",
"zendframework/zend-i18n": "2.5.1",
"zendframework/zend-json": "2.5.1",
"zendframework/zend-math": "2.5.1",
"zendframework/zend-serializer": "2.5.*",
"zendframework/zend-servicemanager": "2.5.*",
"zendframework/zend-stdlib": "2.5.1"
},
"suggest": {
"league/oauth2-google": "Needed for Google XOAUTH2 authentication"
},
"time": "2017-03-15 19:32:56",
"type": "library",
"installation-source": "dist",
"autoload": {
"classmap": [
"class.phpmailer.php",
"class.phpmaileroauth.php",
"class.phpmaileroauthgoogle.php",
"class.smtp.php",
"class.pop3.php",
"extras/EasyPeasyICS.php",
"extras/ntlm_sasl_client.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "Jim Jagielski",
"email": "[email protected]"
},
{
"name": "Marcus Bointon",
"email": "[email protected]"
},
{
"name": "Andy Prevost",
"email": "[email protected]"
},
{
"name": "Brent R. Matzelle"
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP"
},
{
"name": "symfony/yaml",
"version": "v2.8.19",
"version_normalized": "2.8.19.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "286d84891690b0e2515874717e49360d1c98a703"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/286d84891690b0e2515874717e49360d1c98a703",
"reference": "286d84891690b0e2515874717e49360d1c98a703",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"time": "2017-03-20 09:41:44",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "[email protected]"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com"
}
]
-5
View File
@@ -1,5 +0,0 @@
phpunit.xml
composer.lock
build
vendor
coverage.clover
-46
View File
@@ -1,46 +0,0 @@
before_commands:
- "composer install --prefer-source"
tools:
external_code_coverage:
timeout: 600
php_code_coverage:
enabled: true
test_command: ./vendor/bin/phpunit
php_code_sniffer:
enabled: true
config:
standard: PSR2
filter:
paths: ["src/*", "tests/*"]
php_cpd:
enabled: true
excluded_dirs: ["build/*", "tests", "vendor"]
php_cs_fixer:
enabled: true
config:
level: all
filter:
paths: ["src/*", "tests/*"]
php_loc:
enabled: true
excluded_dirs: ["build", "tests", "vendor"]
php_mess_detector:
enabled: true
config:
ruleset: phpmd.xml.dist
design_rules: { eval_expression: false }
filter:
paths: ["src/*"]
php_pdepend:
enabled: true
excluded_dirs: ["build", "tests", "vendor"]
php_analyzer:
enabled: true
filter:
paths: ["src/*", "tests/*"]
php_hhvm:
enabled: true
filter:
paths: ["src/*", "tests/*"]
sensiolabs_security_checker: true
-14
View File
@@ -1,14 +0,0 @@
#!/bin/sh
set -x
if [ "$TRAVIS_PHP_VERSION" = 'hhvm' ] || [ "$TRAVIS_PHP_VERSION" = 'hhvm-nightly' ] ; then
curl -sS https://getcomposer.org/installer > composer-installer.php
hhvm composer-installer.php
hhvm -v ResourceLimit.SocketDefaultTimeout=30 -v Http.SlowQueryThreshold=30000 composer.phar update --prefer-source
elif [ "$TRAVIS_PHP_VERSION" = '5.3.3' ] ; then
composer self-update
composer update --prefer-source --no-dev
composer dump-autoload
else
composer self-update
composer update --prefer-source
fi
-22
View File
@@ -1,22 +0,0 @@
language: php
php:
- 5.3.3
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
before_script:
- ./.travis.install.sh
- if [ $TRAVIS_PHP_VERSION = '5.6' ]; then PHPUNIT_FLAGS="--coverage-clover coverage.clover"; else PHPUNIT_FLAGS=""; fi
script:
- if [ $TRAVIS_PHP_VERSION = '5.3.3' ]; then phpunit; fi
- if [ $TRAVIS_PHP_VERSION != '5.3.3' ]; then ./vendor/bin/phpunit $PHPUNIT_FLAGS; fi
- if [ $TRAVIS_PHP_VERSION != '5.3.3' ]; then ./vendor/bin/phpcs --standard=PSR2 ./src/ ./tests/; fi
- if [[ $TRAVIS_PHP_VERSION != '5.3.3' && $TRAVIS_PHP_VERSION != '5.4.29' && $TRAVIS_PHP_VERSION != '5.5.13' ]]; then php -n ./vendor/bin/athletic -p ./tests/DoctrineTest/InstantiatorPerformance/ -f GroupedFormatter; fi
after_script:
- if [ $TRAVIS_PHP_VERSION = '5.6' ]; then wget https://scrutinizer-ci.com/ocular.phar; php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi
-35
View File
@@ -1,35 +0,0 @@
# Contributing
* Coding standard for the project is [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
* The project will follow strict [object calisthenics](http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php)
* Any contribution must provide tests for additional introduced conditions
* Any un-confirmed issue needs a failing test case before being accepted
* Pull requests must be sent from a new hotfix/feature branch, not from `master`.
## Installation
To install the project and run the tests, you need to clone it first:
```sh
$ git clone git://github.com/doctrine/instantiator.git
```
You will then need to run a composer installation:
```sh
$ cd Instantiator
$ curl -s https://getcomposer.org/installer | php
$ php composer.phar update
```
## Testing
The PHPUnit version to be used is the one installed as a dev- dependency via composer:
```sh
$ ./vendor/bin/phpunit
```
Accepted coverage for new contributions is 80%. Any contribution not satisfying this requirement
won't be merged.
-19
View File
@@ -1,19 +0,0 @@
Copyright (c) 2014 Doctrine Project
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-40
View File
@@ -1,40 +0,0 @@
# Instantiator
This library provides a way of avoiding usage of constructors when instantiating PHP classes.
[![Build Status](https://travis-ci.org/doctrine/instantiator.svg?branch=master)](https://travis-ci.org/doctrine/instantiator)
[![Code Coverage](https://scrutinizer-ci.com/g/doctrine/instantiator/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/doctrine/instantiator/?branch=master)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/doctrine/instantiator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/doctrine/instantiator/?branch=master)
[![Dependency Status](https://www.versioneye.com/package/php--doctrine--instantiator/badge.svg)](https://www.versioneye.com/package/php--doctrine--instantiator)
[![HHVM Status](http://hhvm.h4cc.de/badge/doctrine/instantiator.png)](http://hhvm.h4cc.de/package/doctrine/instantiator)
[![Latest Stable Version](https://poser.pugx.org/doctrine/instantiator/v/stable.png)](https://packagist.org/packages/doctrine/instantiator)
[![Latest Unstable Version](https://poser.pugx.org/doctrine/instantiator/v/unstable.png)](https://packagist.org/packages/doctrine/instantiator)
## Installation
The suggested installation method is via [composer](https://getcomposer.org/):
```sh
php composer.phar require "doctrine/instantiator:~1.0.3"
```
## Usage
The instantiator is able to create new instances of any class without using the constructor or any API of the class
itself:
```php
$instantiator = new \Doctrine\Instantiator\Instantiator();
$instance = $instantiator->instantiate('My\\ClassName\\Here');
```
## Contributing
Please read the [CONTRIBUTING.md](CONTRIBUTING.md) contents if you wish to help out!
## Credits
This library was migrated from [ocramius/instantiator](https://github.com/Ocramius/Instantiator), which
has been donated to the doctrine organization, and which is now deprecated in favour of this package.
-45
View File
@@ -1,45 +0,0 @@
{
"name": "doctrine/instantiator",
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
"type": "library",
"license": "MIT",
"homepage": "https://github.com/doctrine/instantiator",
"keywords": [
"instantiate",
"constructor"
],
"authors": [
{
"name": "Marco Pivetta",
"email": "[email protected]",
"homepage": "http://ocramius.github.com/"
}
],
"require": {
"php": ">=5.3,<8.0-DEV"
},
"require-dev": {
"ext-phar": "*",
"ext-pdo": "*",
"phpunit/phpunit": "~4.0",
"squizlabs/php_codesniffer": "~2.0",
"athletic/athletic": "~0.1.8"
},
"autoload": {
"psr-4": {
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
}
},
"autoload-dev": {
"psr-0": {
"DoctrineTest\\InstantiatorPerformance\\": "tests",
"DoctrineTest\\InstantiatorTest\\": "tests",
"DoctrineTest\\InstantiatorTestAsset\\": "tests"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
}
}
-27
View File
@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ruleset
name="Instantiator rules"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"
>
<rule ref="rulesets/cleancode.xml">
<!-- static access is used for caching purposes -->
<exclude name="StaticAccess"/>
</rule>
<rule ref="rulesets/codesize.xml"/>
<rule ref="rulesets/controversial.xml"/>
<rule ref="rulesets/design.xml"/>
<rule ref="rulesets/naming.xml"/>
<rule ref="rulesets/unusedcode.xml"/>
<rule
name="NPathComplexity"
message="The {0} {1}() has an NPath complexity of {2}. The configured NPath complexity threshold is {3}."
class="PHP_PMD_Rule_Design_NpathComplexity"
>
<properties>
<property name="minimum" description="The npath reporting threshold" value="10"/>
</properties>
</rule>
</ruleset>
-22
View File
@@ -1,22 +0,0 @@
<?xml version="1.0"?>
<phpunit
bootstrap="./vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
verbose="true"
stopOnFailure="false"
processIsolation="false"
backupGlobals="false"
syntaxCheck="true"
>
<testsuite name="Doctrine\Instantiator tests">
<directory>./tests/DoctrineTest/InstantiatorTest</directory>
</testsuite>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>
@@ -1,29 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Instantiator\Exception;
/**
* Base exception marker interface for the instantiator component
*
* @author Marco Pivetta <[email protected]>
*/
interface ExceptionInterface
{
}
@@ -1,62 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Instantiator\Exception;
use InvalidArgumentException as BaseInvalidArgumentException;
use ReflectionClass;
/**
* Exception for invalid arguments provided to the instantiator
*
* @author Marco Pivetta <[email protected]>
*/
class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
{
/**
* @param string $className
*
* @return self
*/
public static function fromNonExistingClass($className)
{
if (interface_exists($className)) {
return new self(sprintf('The provided type "%s" is an interface, and can not be instantiated', $className));
}
if (PHP_VERSION_ID >= 50400 && trait_exists($className)) {
return new self(sprintf('The provided type "%s" is a trait, and can not be instantiated', $className));
}
return new self(sprintf('The provided class "%s" does not exist', $className));
}
/**
* @param ReflectionClass $reflectionClass
*
* @return self
*/
public static function fromAbstractClass(ReflectionClass $reflectionClass)
{
return new self(sprintf(
'The provided class "%s" is abstract, and can not be instantiated',
$reflectionClass->getName()
));
}
}
@@ -1,79 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Instantiator\Exception;
use Exception;
use ReflectionClass;
use UnexpectedValueException as BaseUnexpectedValueException;
/**
* Exception for given parameters causing invalid/unexpected state on instantiation
*
* @author Marco Pivetta <[email protected]>
*/
class UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface
{
/**
* @param ReflectionClass $reflectionClass
* @param Exception $exception
*
* @return self
*/
public static function fromSerializationTriggeredException(ReflectionClass $reflectionClass, Exception $exception)
{
return new self(
sprintf(
'An exception was raised while trying to instantiate an instance of "%s" via un-serialization',
$reflectionClass->getName()
),
0,
$exception
);
}
/**
* @param ReflectionClass $reflectionClass
* @param string $errorString
* @param int $errorCode
* @param string $errorFile
* @param int $errorLine
*
* @return UnexpectedValueException
*/
public static function fromUncleanUnSerialization(
ReflectionClass $reflectionClass,
$errorString,
$errorCode,
$errorFile,
$errorLine
) {
return new self(
sprintf(
'Could not produce an instance of "%s" via un-serialization, since an error was triggered '
. 'in file "%s" at line "%d"',
$reflectionClass->getName(),
$errorFile,
$errorLine
),
0,
new Exception($errorString, $errorCode)
);
}
}
@@ -1,273 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Instantiator;
use Closure;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
use Doctrine\Instantiator\Exception\UnexpectedValueException;
use Exception;
use ReflectionClass;
/**
* {@inheritDoc}
*
* @author Marco Pivetta <[email protected]>
*/
final class Instantiator implements InstantiatorInterface
{
/**
* Markers used internally by PHP to define whether {@see \unserialize} should invoke
* the method {@see \Serializable::unserialize()} when dealing with classes implementing
* the {@see \Serializable} interface.
*/
const SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C';
const SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O';
/**
* @var \Closure[] of {@see \Closure} instances used to instantiate specific classes
*/
private static $cachedInstantiators = array();
/**
* @var object[] of objects that can directly be cloned
*/
private static $cachedCloneables = array();
/**
* {@inheritDoc}
*/
public function instantiate($className)
{
if (isset(self::$cachedCloneables[$className])) {
return clone self::$cachedCloneables[$className];
}
if (isset(self::$cachedInstantiators[$className])) {
$factory = self::$cachedInstantiators[$className];
return $factory();
}
return $this->buildAndCacheFromFactory($className);
}
/**
* Builds the requested object and caches it in static properties for performance
*
* @param string $className
*
* @return object
*/
private function buildAndCacheFromFactory($className)
{
$factory = self::$cachedInstantiators[$className] = $this->buildFactory($className);
$instance = $factory();
if ($this->isSafeToClone(new ReflectionClass($instance))) {
self::$cachedCloneables[$className] = clone $instance;
}
return $instance;
}
/**
* Builds a {@see \Closure} capable of instantiating the given $className without
* invoking its constructor.
*
* @param string $className
*
* @return Closure
*/
private function buildFactory($className)
{
$reflectionClass = $this->getReflectionClass($className);
if ($this->isInstantiableViaReflection($reflectionClass)) {
return function () use ($reflectionClass) {
return $reflectionClass->newInstanceWithoutConstructor();
};
}
$serializedString = sprintf(
'%s:%d:"%s":0:{}',
$this->getSerializationFormat($reflectionClass),
strlen($className),
$className
);
$this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString);
return function () use ($serializedString) {
return unserialize($serializedString);
};
}
/**
* @param string $className
*
* @return ReflectionClass
*
* @throws InvalidArgumentException
*/
private function getReflectionClass($className)
{
if (! class_exists($className)) {
throw InvalidArgumentException::fromNonExistingClass($className);
}
$reflection = new ReflectionClass($className);
if ($reflection->isAbstract()) {
throw InvalidArgumentException::fromAbstractClass($reflection);
}
return $reflection;
}
/**
* @param ReflectionClass $reflectionClass
* @param string $serializedString
*
* @throws UnexpectedValueException
*
* @return void
*/
private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, $serializedString)
{
set_error_handler(function ($code, $message, $file, $line) use ($reflectionClass, & $error) {
$error = UnexpectedValueException::fromUncleanUnSerialization(
$reflectionClass,
$message,
$code,
$file,
$line
);
});
$this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString);
restore_error_handler();
if ($error) {
throw $error;
}
}
/**
* @param ReflectionClass $reflectionClass
* @param string $serializedString
*
* @throws UnexpectedValueException
*
* @return void
*/
private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, $serializedString)
{
try {
unserialize($serializedString);
} catch (Exception $exception) {
restore_error_handler();
throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception);
}
}
/**
* @param ReflectionClass $reflectionClass
*
* @return bool
*/
private function isInstantiableViaReflection(ReflectionClass $reflectionClass)
{
if (\PHP_VERSION_ID >= 50600) {
return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal());
}
return \PHP_VERSION_ID >= 50400 && ! $this->hasInternalAncestors($reflectionClass);
}
/**
* Verifies whether the given class is to be considered internal
*
* @param ReflectionClass $reflectionClass
*
* @return bool
*/
private function hasInternalAncestors(ReflectionClass $reflectionClass)
{
do {
if ($reflectionClass->isInternal()) {
return true;
}
} while ($reflectionClass = $reflectionClass->getParentClass());
return false;
}
/**
* Verifies if the given PHP version implements the `Serializable` interface serialization
* with an incompatible serialization format. If that's the case, use serialization marker
* "C" instead of "O".
*
* @link http://news.php.net/php.internals/74654
*
* @param ReflectionClass $reflectionClass
*
* @return string the serialization format marker, either self::SERIALIZATION_FORMAT_USE_UNSERIALIZER
* or self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER
*/
private function getSerializationFormat(ReflectionClass $reflectionClass)
{
if ($this->isPhpVersionWithBrokenSerializationFormat()
&& $reflectionClass->implementsInterface('Serializable')
) {
return self::SERIALIZATION_FORMAT_USE_UNSERIALIZER;
}
return self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER;
}
/**
* Checks whether the current PHP runtime uses an incompatible serialization format
*
* @return bool
*/
private function isPhpVersionWithBrokenSerializationFormat()
{
return PHP_VERSION_ID === 50429 || PHP_VERSION_ID === 50513;
}
/**
* Checks if a class is cloneable
*
* @param ReflectionClass $reflection
*
* @return bool
*/
private function isSafeToClone(ReflectionClass $reflection)
{
if (method_exists($reflection, 'isCloneable') && ! $reflection->isCloneable()) {
return false;
}
// not cloneable if it implements `__clone`, as we want to avoid calling it
return ! $reflection->hasMethod('__clone');
}
}
@@ -1,37 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Instantiator;
/**
* Instantiator provides utility methods to build objects without invoking their constructors
*
* @author Marco Pivetta <[email protected]>
*/
interface InstantiatorInterface
{
/**
* @param string $className
*
* @return object
*
* @throws \Doctrine\Instantiator\Exception\ExceptionInterface
*/
public function instantiate($className);
}
@@ -1,96 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorPerformance;
use Athletic\AthleticEvent;
use Doctrine\Instantiator\Instantiator;
/**
* Performance tests for {@see \Doctrine\Instantiator\Instantiator}
*
* @author Marco Pivetta <[email protected]>
*/
class InstantiatorPerformanceEvent extends AthleticEvent
{
/**
* @var \Doctrine\Instantiator\Instantiator
*/
private $instantiator;
/**
* {@inheritDoc}
*/
protected function setUp()
{
$this->instantiator = new Instantiator();
$this->instantiator->instantiate(__CLASS__);
$this->instantiator->instantiate('ArrayObject');
$this->instantiator->instantiate('DoctrineTest\\InstantiatorTestAsset\\SimpleSerializableAsset');
$this->instantiator->instantiate('DoctrineTest\\InstantiatorTestAsset\\SerializableArrayObjectAsset');
$this->instantiator->instantiate('DoctrineTest\\InstantiatorTestAsset\\UnCloneableAsset');
}
/**
* @iterations 20000
* @baseline
* @group instantiation
*/
public function testInstantiateSelf()
{
$this->instantiator->instantiate(__CLASS__);
}
/**
* @iterations 20000
* @group instantiation
*/
public function testInstantiateInternalClass()
{
$this->instantiator->instantiate('ArrayObject');
}
/**
* @iterations 20000
* @group instantiation
*/
public function testInstantiateSimpleSerializableAssetClass()
{
$this->instantiator->instantiate('DoctrineTest\\InstantiatorTestAsset\\SimpleSerializableAsset');
}
/**
* @iterations 20000
* @group instantiation
*/
public function testInstantiateSerializableArrayObjectAsset()
{
$this->instantiator->instantiate('DoctrineTest\\InstantiatorTestAsset\\SerializableArrayObjectAsset');
}
/**
* @iterations 20000
* @group instantiation
*/
public function testInstantiateUnCloneableAsset()
{
$this->instantiator->instantiate('DoctrineTest\\InstantiatorTestAsset\\UnCloneableAsset');
}
}
@@ -1,83 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTest\Exception;
use Doctrine\Instantiator\Exception\InvalidArgumentException;
use PHPUnit_Framework_TestCase;
use ReflectionClass;
/**
* Tests for {@see \Doctrine\Instantiator\Exception\InvalidArgumentException}
*
* @author Marco Pivetta <[email protected]>
*
* @covers \Doctrine\Instantiator\Exception\InvalidArgumentException
*/
class InvalidArgumentExceptionTest extends PHPUnit_Framework_TestCase
{
public function testFromNonExistingTypeWithNonExistingClass()
{
$className = __CLASS__ . uniqid();
$exception = InvalidArgumentException::fromNonExistingClass($className);
$this->assertInstanceOf('Doctrine\\Instantiator\\Exception\\InvalidArgumentException', $exception);
$this->assertSame('The provided class "' . $className . '" does not exist', $exception->getMessage());
}
public function testFromNonExistingTypeWithTrait()
{
if (PHP_VERSION_ID < 50400) {
$this->markTestSkipped('Need at least PHP 5.4.0, as this test requires traits support to run');
}
$exception = InvalidArgumentException::fromNonExistingClass(
'DoctrineTest\\InstantiatorTestAsset\\SimpleTraitAsset'
);
$this->assertSame(
'The provided type "DoctrineTest\\InstantiatorTestAsset\\SimpleTraitAsset" is a trait, '
. 'and can not be instantiated',
$exception->getMessage()
);
}
public function testFromNonExistingTypeWithInterface()
{
$exception = InvalidArgumentException::fromNonExistingClass('Doctrine\\Instantiator\\InstantiatorInterface');
$this->assertSame(
'The provided type "Doctrine\\Instantiator\\InstantiatorInterface" is an interface, '
. 'and can not be instantiated',
$exception->getMessage()
);
}
public function testFromAbstractClass()
{
$reflection = new ReflectionClass('DoctrineTest\\InstantiatorTestAsset\\AbstractClassAsset');
$exception = InvalidArgumentException::fromAbstractClass($reflection);
$this->assertSame(
'The provided class "DoctrineTest\\InstantiatorTestAsset\\AbstractClassAsset" is abstract, '
. 'and can not be instantiated',
$exception->getMessage()
);
}
}
@@ -1,69 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTest\Exception;
use Doctrine\Instantiator\Exception\UnexpectedValueException;
use Exception;
use PHPUnit_Framework_TestCase;
use ReflectionClass;
/**
* Tests for {@see \Doctrine\Instantiator\Exception\UnexpectedValueException}
*
* @author Marco Pivetta <[email protected]>
*
* @covers \Doctrine\Instantiator\Exception\UnexpectedValueException
*/
class UnexpectedValueExceptionTest extends PHPUnit_Framework_TestCase
{
public function testFromSerializationTriggeredException()
{
$reflectionClass = new ReflectionClass($this);
$previous = new Exception();
$exception = UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $previous);
$this->assertInstanceOf('Doctrine\\Instantiator\\Exception\\UnexpectedValueException', $exception);
$this->assertSame($previous, $exception->getPrevious());
$this->assertSame(
'An exception was raised while trying to instantiate an instance of "'
. __CLASS__ . '" via un-serialization',
$exception->getMessage()
);
}
public function testFromUncleanUnSerialization()
{
$reflection = new ReflectionClass('DoctrineTest\\InstantiatorTestAsset\\AbstractClassAsset');
$exception = UnexpectedValueException::fromUncleanUnSerialization($reflection, 'foo', 123, 'bar', 456);
$this->assertInstanceOf('Doctrine\\Instantiator\\Exception\\UnexpectedValueException', $exception);
$this->assertSame(
'Could not produce an instance of "DoctrineTest\\InstantiatorTestAsset\\AbstractClassAsset" '
. 'via un-serialization, since an error was triggered in file "bar" at line "456"',
$exception->getMessage()
);
$previous = $exception->getPrevious();
$this->assertInstanceOf('Exception', $previous);
$this->assertSame('foo', $previous->getMessage());
$this->assertSame(123, $previous->getCode());
}
}
@@ -1,219 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTest;
use Doctrine\Instantiator\Exception\UnexpectedValueException;
use Doctrine\Instantiator\Instantiator;
use PHPUnit_Framework_TestCase;
use ReflectionClass;
/**
* Tests for {@see \Doctrine\Instantiator\Instantiator}
*
* @author Marco Pivetta <[email protected]>
*
* @covers \Doctrine\Instantiator\Instantiator
*/
class InstantiatorTest extends PHPUnit_Framework_TestCase
{
/**
* @var Instantiator
*/
private $instantiator;
/**
* {@inheritDoc}
*/
protected function setUp()
{
$this->instantiator = new Instantiator();
}
/**
* @param string $className
*
* @dataProvider getInstantiableClasses
*/
public function testCanInstantiate($className)
{
$this->assertInstanceOf($className, $this->instantiator->instantiate($className));
}
/**
* @param string $className
*
* @dataProvider getInstantiableClasses
*/
public function testInstantiatesSeparateInstances($className)
{
$instance1 = $this->instantiator->instantiate($className);
$instance2 = $this->instantiator->instantiate($className);
$this->assertEquals($instance1, $instance2);
$this->assertNotSame($instance1, $instance2);
}
public function testExceptionOnUnSerializationException()
{
if (defined('HHVM_VERSION')) {
$this->markTestSkipped(
'As of facebook/hhvm#3432, HHVM has no PDORow, and therefore '
. ' no internal final classes that cannot be instantiated'
);
}
$className = 'DoctrineTest\\InstantiatorTestAsset\\UnserializeExceptionArrayObjectAsset';
if (\PHP_VERSION_ID >= 50600) {
$className = 'PDORow';
}
if (\PHP_VERSION_ID === 50429 || \PHP_VERSION_ID === 50513) {
$className = 'DoctrineTest\\InstantiatorTestAsset\\SerializableArrayObjectAsset';
}
$this->setExpectedException('Doctrine\\Instantiator\\Exception\\UnexpectedValueException');
$this->instantiator->instantiate($className);
}
public function testNoticeOnUnSerializationException()
{
if (\PHP_VERSION_ID >= 50600) {
$this->markTestSkipped(
'PHP 5.6 supports `ReflectionClass#newInstanceWithoutConstructor()` for some internal classes'
);
}
try {
$this->instantiator->instantiate('DoctrineTest\\InstantiatorTestAsset\\WakeUpNoticesAsset');
$this->fail('No exception was raised');
} catch (UnexpectedValueException $exception) {
$wakeUpNoticesReflection = new ReflectionClass('DoctrineTest\\InstantiatorTestAsset\\WakeUpNoticesAsset');
$previous = $exception->getPrevious();
$this->assertInstanceOf('Exception', $previous);
// in PHP 5.4.29 and PHP 5.5.13, this case is not a notice, but an exception being thrown
if (! (\PHP_VERSION_ID === 50429 || \PHP_VERSION_ID === 50513)) {
$this->assertSame(
'Could not produce an instance of "DoctrineTest\\InstantiatorTestAsset\WakeUpNoticesAsset" '
. 'via un-serialization, since an error was triggered in file "'
. $wakeUpNoticesReflection->getFileName() . '" at line "36"',
$exception->getMessage()
);
$this->assertSame('Something went bananas while un-serializing this instance', $previous->getMessage());
$this->assertSame(\E_USER_NOTICE, $previous->getCode());
}
}
}
/**
* @param string $invalidClassName
*
* @dataProvider getInvalidClassNames
*/
public function testInstantiationFromNonExistingClass($invalidClassName)
{
$this->setExpectedException('Doctrine\\Instantiator\\Exception\\InvalidArgumentException');
$this->instantiator->instantiate($invalidClassName);
}
public function testInstancesAreNotCloned()
{
$className = 'TemporaryClass' . uniqid();
eval('namespace ' . __NAMESPACE__ . '; class ' . $className . '{}');
$instance = $this->instantiator->instantiate(__NAMESPACE__ . '\\' . $className);
$instance->foo = 'bar';
$instance2 = $this->instantiator->instantiate(__NAMESPACE__ . '\\' . $className);
$this->assertObjectNotHasAttribute('foo', $instance2);
}
/**
* Provides a list of instantiable classes (existing)
*
* @return string[][]
*/
public function getInstantiableClasses()
{
$classes = array(
array('stdClass'),
array(__CLASS__),
array('Doctrine\\Instantiator\\Instantiator'),
array('Exception'),
array('PharException'),
array('DoctrineTest\\InstantiatorTestAsset\\SimpleSerializableAsset'),
array('DoctrineTest\\InstantiatorTestAsset\\ExceptionAsset'),
array('DoctrineTest\\InstantiatorTestAsset\\FinalExceptionAsset'),
array('DoctrineTest\\InstantiatorTestAsset\\PharExceptionAsset'),
array('DoctrineTest\\InstantiatorTestAsset\\UnCloneableAsset'),
array('DoctrineTest\\InstantiatorTestAsset\\XMLReaderAsset'),
);
if (\PHP_VERSION_ID === 50429 || \PHP_VERSION_ID === 50513) {
return $classes;
}
$classes = array_merge(
$classes,
array(
array('PharException'),
array('ArrayObject'),
array('DoctrineTest\\InstantiatorTestAsset\\ArrayObjectAsset'),
array('DoctrineTest\\InstantiatorTestAsset\\SerializableArrayObjectAsset'),
)
);
if (\PHP_VERSION_ID >= 50600) {
$classes[] = array('DoctrineTest\\InstantiatorTestAsset\\WakeUpNoticesAsset');
$classes[] = array('DoctrineTest\\InstantiatorTestAsset\\UnserializeExceptionArrayObjectAsset');
}
return $classes;
}
/**
* Provides a list of instantiable classes (existing)
*
* @return string[][]
*/
public function getInvalidClassNames()
{
$classNames = array(
array(__CLASS__ . uniqid()),
array('Doctrine\\Instantiator\\InstantiatorInterface'),
array('DoctrineTest\\InstantiatorTestAsset\\AbstractClassAsset'),
);
if (\PHP_VERSION_ID >= 50400) {
$classNames[] = array('DoctrineTest\\InstantiatorTestAsset\\SimpleTraitAsset');
}
return $classNames;
}
}
@@ -1,29 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
/**
* A simple asset for an abstract class
*
* @author Marco Pivetta <[email protected]>
*/
abstract class AbstractClassAsset
{
}
@@ -1,41 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use ArrayObject;
use BadMethodCallException;
/**
* Test asset that extends an internal PHP class
*
* @author Marco Pivetta <[email protected]>
*/
class ArrayObjectAsset extends ArrayObject
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
@@ -1,41 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use BadMethodCallException;
use Exception;
/**
* Test asset that extends an internal PHP base exception
*
* @author Marco Pivetta <[email protected]>
*/
class ExceptionAsset extends Exception
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
@@ -1,41 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use BadMethodCallException;
use Exception;
/**
* Test asset that extends an internal PHP base exception
*
* @author Marco Pivetta <[email protected]>
*/
final class FinalExceptionAsset extends Exception
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
@@ -1,41 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use BadMethodCallException;
use Phar;
/**
* Test asset that extends an internal PHP class
*
* @author Marco Pivetta <[email protected]>
*/
class PharAsset extends Phar
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
@@ -1,44 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use BadMethodCallException;
use PharException;
/**
* Test asset that extends an internal PHP class
* This class should be serializable without problems
* and without getting the "Erroneous data format for unserializing"
* error
*
* @author Marco Pivetta <[email protected]>
*/
class PharExceptionAsset extends PharException
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
@@ -1,62 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use ArrayObject;
use BadMethodCallException;
use Serializable;
/**
* Serializable test asset that also extends an internal class
*
* @author Marco Pivetta <[email protected]>
*/
class SerializableArrayObjectAsset extends ArrayObject implements Serializable
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
/**
* {@inheritDoc}
*/
public function serialize()
{
return '';
}
/**
* {@inheritDoc}
*
* Should not be called
*
* @throws BadMethodCallException
*/
public function unserialize($serialized)
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
@@ -1,61 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use BadMethodCallException;
use Serializable;
/**
* Base serializable test asset
*
* @author Marco Pivetta <[email protected]>
*/
class SimpleSerializableAsset implements Serializable
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
/**
* {@inheritDoc}
*/
public function serialize()
{
return '';
}
/**
* {@inheritDoc}
*
* Should not be called
*
* @throws BadMethodCallException
*/
public function unserialize($serialized)
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
@@ -1,29 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
/**
* A simple trait with no attached logic
*
* @author Marco Pivetta <[email protected]>
*/
trait SimpleTraitAsset
{
}
@@ -1,50 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use BadMethodCallException;
/**
* Base un-cloneable asset
*
* @author Marco Pivetta <[email protected]>
*/
class UnCloneableAsset
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
/**
* Magic `__clone` - should not be invoked
*
* @throws BadMethodCallException
*/
public function __clone()
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
@@ -1,39 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use ArrayObject;
use BadMethodCallException;
/**
* A simple asset for an abstract class
*
* @author Marco Pivetta <[email protected]>
*/
class UnserializeExceptionArrayObjectAsset extends ArrayObject
{
/**
* {@inheritDoc}
*/
public function __wakeup()
{
throw new BadMethodCallException();
}
}
@@ -1,38 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use ArrayObject;
/**
* A simple asset for an abstract class
*
* @author Marco Pivetta <[email protected]>
*/
class WakeUpNoticesAsset extends ArrayObject
{
/**
* Wakeup method called after un-serialization
*/
public function __wakeup()
{
trigger_error('Something went bananas while un-serializing this instance');
}
}
@@ -1,41 +0,0 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace DoctrineTest\InstantiatorTestAsset;
use BadMethodCallException;
use XMLReader;
/**
* Test asset that extends an internal PHP class
*
* @author Dave Marshall <[email protected]>
*/
class XMLReaderAsset extends XMLReader
{
/**
* Constructor - should not be called
*
* @throws BadMethodCallException
*/
public function __construct()
{
throw new BadMethodCallException('Not supposed to be called!');
}
}
-6
View File
@@ -1,6 +0,0 @@
/nbproject/private/
vendor/
bin/
nbproject/
composer.lock
.idea/
-20
View File
@@ -1,20 +0,0 @@
language: php
php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
before_script:
- composer self-update
- composer install --prefer-source --no-interaction --dev
script:
- vendor/phpspec/phpspec/bin/phpspec run -f dot
matrix:
allow_failures:
- php: hhvm
fast_finish: true
-22
View File
@@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 fojuth
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-160
View File
@@ -1,160 +0,0 @@
# ReadmeGen
[![Build Status](https://travis-ci.org/fojuth/readmegen.svg)](https://travis-ci.org/fojuth/readmegen)
Generate your project's log using VCS commit messages.
ReadmeGen is a PHP package that scans the VCS's log searching for messages with specific pattern. These messages are extracted, grouped and prepended to the changelog file (e.g. readme.md). The package can be instructed to fetch messages between specific tags (or commits). This way, whenever you're tagging a new release, you can run ReadmeGen to generate the changelog automatically.
**Notice**: The package currently supports only GIT and the *.md output files. You can provide support for othe VCS's or output formats? Help welcome :)
### Installation
#### Global installation (recommended)
```
composer global require fojuth/readmegen:@stable
```
You can read more about global installation in the [composer docs](https://getcomposer.org/doc/03-cli.md#global).
#### Local installation
```
composer require fojuth/readmegen:1.*
```
#### Windows installation
Make sure the Windows `PATH` variable contains the path to the composer bin dir:
```
C:\Users\{USER}\AppData\Roaming\Composer\vendor\bin
```
Restart any shell terminal you want to use for changes to take effect.
### Usage
This package is intended to be used as an executable script, not a library you would include in your project. Assuming you installed ReadmeGen globally, to update your changelog file, simply run:
```
readmegen --from TAG --to TAG --release RELEASE_NUMBER --break BREAKPOINT
```
For example:
```
readmegen --from 1.12.0 --to 1.13.0 --release 1.13.0 --break *Changelog*
```
This tells the script to generate a changelod update named `1.13.0` and that it should scan the log since tag `1.12.0` up to `1.13.0`. No earlier (or latter) commits will be taken into consideration. ReadmeGen will inject the generated log *after* the `*Changelog*` line.
If you want to generate the changelog from a specific tag (or commit checksum) up to the latest commit (`HEAD`) just omit the `--to` argument:
```
readmegen --from a04cf99 --release 1.13.0 --break *Changelog*
```
You can also specify the breakpoint in the `readmegen.yml` config file so the command will be even cleaner:
```
readmegen --from a04cf99 --release 1.13.0
```
### Message format
ReadmeGen will search for messages that start with a specific keyword. These keywords tell the script to which group the commit should be appended. The message groups can be overwritten.
For example - the default configuration supports four types of commits: Features, Bugfixes, Documentation and Refactoring. The commit will be appended to a certain group only if it starts with a specific word. The default config allows two keywords for bugfixes: `bugfix` and `fix`. This means, that for a message to be appended to the Bugfix group it has to start with either `bugfix: blabla` or `Fix: foo bar` (notice the colon `:` sign - it has to be right after the keyword). The keywords are case insensitive.
All commits that do not fit into any of the groups will be ignored (we don't want merges and stuff like that in the changelog).
### Grouping commits
Each commit that fits into a group will be grouped (yeah, that sounds silly). Groups will be printed out in the order they appear in the config file, so if you have `Features` and `Bugfixes`, this is the order they will appear in the changelog:
```
Features
- feature 1
- feature 2
Bugfixes
- fix 1
```
You can override the groups in your custom config file (details below).
### Link patterns
ReadmeGen can link issues to a issue tracker - all numbers starting with `#` will be linked to a website defined in the config under the `issue_tracker_pattern` key. If a commit message has a string `#1234` in it, it will be converted to a link targeting the issue tracker.
### Local config
The default config holds the definitions of commit groups and the issue link pattern. It also specifies which VCS to use and the type of the output file. You can override these settings (project-wide) by creating a `readmegen.yml` file in the root dir of your project. When ReadmeGen will be run it will check if this file exists and merge the settings accordingly.
The default `readmegen.yml` config looks like this:
```
vcs: git
format: md
issue_tracker_pattern: http://some.issue.tracker.com/\1
break: "## Changelog"
output_file_name: "README.md"
message_groups:
Features:
- feature
- feat
Bugfixes:
- fix
- bugfix
Documentation:
- docs
Refactoring:
- refactoring
```
Each of the `message_groups` key is the name of the group that will be put in the changelog. The values inside the group are the keywords the commit must start with (followed by the colon `:` sign) to be appended to that group.
### Release number
ReadmeGen requires a release number (`--release`) to be provided. This will be the title of the generated changelog.
### Breakpoint
By default the changes will go onto the beginning of the changelog file. You can though specify a "breakpoint" beneath which these changes should be appended. Usually, you'll have some "intro" in you changelog, and the changes listed below. You don't want the script to push the changes on top of the file, but below a certain line. You can specify this line in the `readmegen.yml` config file or using the `--break` argument.
For example:
```
readmegen --from 1.12.0 --to 1.13.0 --release 1.3.3 --break *Changelog*
```
The script will append the changes *below* the line that contains the `*Changelog*` phrase. This should be the only phrase in this line. If you use the CLI argument method (`--break`), the breakpoint **must not contain spaces**. Thus you are encouraged to use the config method - you can use spaces there, as shown in the default config.
ReadmeGen will search for the `## Changelog` breakpoint by default. If the breakpoint phrase is not found, the output will go onto the beginning of the changelog file.
### Example commits
Here are some example commit messages that will be grabbed by ReadmeGen (with the default config):
```
feature: Added some cool stuff (#1234)
fix: #4245, regarding client login bug
docs: Updated the transaction section of the docs
feat: Some more cool stuff
```
## Changelog
## 1.1.2
*(2015-07-12)*
#### Features
* Change output file name (thanks to [reva2](https://github.com/reva2))
#### Bugfixes
* Added missing new line character in example usage message (thanks to [reva2](https://github.com/reva2))
---
## 1.1.1
*(2015-01-04)*
#### Features
* Added .travis.yml
---
## 1.1.0
*(2014-12-30)*
#### Features
* Added "break" to the readmegen.yml default config file. It has a default value set and can be overwritten locally.
---
## 1.0.2
*(2014-12-30)*
#### Bugfixes
* The release date is extracted from the --to commit.
---
-30
View File
@@ -1,30 +0,0 @@
{
"name": "fojuth/readmegen",
"description": "Readme file / doc generator. It uses VCS logs as a source of information.",
"keywords": ["readme", "generator", "log parser", "vcs"],
"license": "MIT",
"authors": [
{
"name": "Kamil Fojuth",
"email": "[email protected]"
}
],
"require": {
"symfony/yaml": "~2.1",
"ulrichsg/getopt-php": "2.*"
},
"require-dev": {
"phpspec/phpspec": "dev-master"
},
"config": {
"bin-dir": "bin"
},
"bin": [
"readmegen"
],
"autoload": {
"psr-4": {
"ReadmeGen\\": "src/"
}
}
}
-4
View File
@@ -1,4 +0,0 @@
suites:
readmegen:
namespace: ReadmeGen
psr4_prefix: ReadmeGen
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env php
<?php
$loaded = false;
foreach (array(__DIR__ . '/../../autoload.php', __DIR__ . '/vendor/autoload.php') as $file) {
if (file_exists($file)) {
require $file;
$loaded = true;
break;
}
}
if (!$loaded) {
die(
'You need to set up the project dependencies using the following commands:' . PHP_EOL .
'wget http://getcomposer.org/composer.phar' . PHP_EOL .
'php composer.phar install' . PHP_EOL
);
}
if (2 > count($argv)) {
die("Example usage: php generate.php --from <tag / commit> --release <release number>\n");
}
new \ReadmeGen\Bootstrap($argv);
-16
View File
@@ -1,16 +0,0 @@
vcs: git
format: md
issue_tracker_pattern: http://some.issue.tracker.com/\1
break: "## Changelog"
output_file_name: "README.md"
message_groups:
Features:
- feature
- feat
Bugfixes:
- fix
- bugfix
Documentation:
- docs
Refactoring:
- refactoring
-54
View File
@@ -1,54 +0,0 @@
<?php
namespace spec\ReadmeGen\Config;
use PhpSpec\ObjectBehavior;
class LoaderSpec extends ObjectBehavior
{
protected $dummyConfigFile = 'dummy_config.yaml';
protected $badConfigFile = 'dummy_config_bad.yaml';
function let()
{
file_put_contents($this->dummyConfigFile, "vcs: git\nfoo: bar");
file_put_contents($this->badConfigFile, "badly:\tformed\n\tfile");
}
function letgo()
{
unlink($this->dummyConfigFile);
unlink($this->badConfigFile);
}
function it_should_throw_exception_when_default_config_doesnt_exist()
{
$this->shouldThrow('\InvalidArgumentException')->during('get', array('foobar.yml'));
}
function it_should_throw_exception_when_the_config_file_is_malformed()
{
$this->shouldThrow('\Symfony\Component\Yaml\Exception\ParseException')->during('get', array($this->badConfigFile));
}
function it_loads_the_default_config()
{
$this->get($this->dummyConfigFile)->shouldBeArray();
}
function it_should_have_specific_values_loaded()
{
$this->get($this->dummyConfigFile)->shouldHaveKey('vcs');
}
function getMatchers()
{
return array(
'haveKey' => function($subject, $key) {
return array_key_exists($key, $subject);
},
);
}
}
-37
View File
@@ -1,37 +0,0 @@
<?php
namespace spec\ReadmeGen\Input;
use PhpSpec\ObjectBehavior;
class ParserSpec extends ObjectBehavior
{
function it_should_fetch_options()
{
$this->setInput('someDummyContent --f=foo --to=bar --release=4.5.6');
$result = $this->parse();
$result['from']->shouldReturn('foo');
$result['f']->shouldReturn('foo');
$result['to']->shouldReturn('bar');
$result['t']->shouldReturn('bar');
$result['release']->shouldReturn('4.5.6');
$result['r']->shouldReturn('4.5.6');
}
function it_should_check_for_required_arguments()
{
$this->setInput('someDummyContent --from=1.2');
$this->shouldThrow('\BadMethodCallException')->during('parse');
$this->setInput('someDummyContent --release=1.2');
$this->shouldThrow('\BadMethodCallException')->during('parse');
$this->setInput('someDummyContent --release=1.2 --from=2.3');
$result = $this->parse();
$result['release']->shouldBe('1.2');
$result['from']->shouldBe('2.3');
}
}
-28
View File
@@ -1,28 +0,0 @@
<?php
namespace spec\ReadmeGen\Log;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use ReadmeGen\Output\Format\FormatInterface;
class DecoratorSpec extends ObjectBehavior
{
function let(FormatInterface $formatter)
{
$this->beConstructedWith($formatter);
}
function it_should_set_the_correct_output_class(FormatInterface $formatter)
{
$formatter->setLog(array())->shouldBeCalled();
$formatter->setIssueTrackerUrlPattern('')->shouldBeCalled();
$formatter->decorate()->willReturn('foo');
$this->setLog(array());
$this->setIssueTrackerUrlPattern('');
$this->decorate()->shouldReturn('foo');
}
}
-46
View File
@@ -1,46 +0,0 @@
<?php
namespace spec\ReadmeGen\Log;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class ExtractorSpec extends ObjectBehavior
{
function it_extracts_messages_from_log()
{
$log = array(
'foo',
'feature: bar baz',
'nope',
'feature: dummy feature',
'feat: lol',
'also nope',
'fix: some bugfix',
);
$messageGroups = array(
'Features' => array('feature', 'feat'),
'Bugfixes' => array('bugfix', 'fix'),
'Docs' => array('docs'),
);
$result = array(
'Features' => array(
'bar baz',
'dummy feature',
'lol',
),
'Bugfixes' => array(
'some bugfix',
),
);
$this->setLog($log);
$this->setMessageGroups($messageGroups);
$this->extract()->shouldReturn($result);
}
}
-59
View File
@@ -1,59 +0,0 @@
<?php
namespace spec\ReadmeGen\Output\Format;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class MdSpec extends ObjectBehavior
{
protected $issueTrackerUrl = 'http://some.issue.tracker.com/show/';
protected $issueTrackerPattern = 'http://some.issue.tracker.com/show/\1';
protected $log = array(
'Features' => array(
'bar #123 baz',
'dummy feature',
),
'Bugfixes' => array(
'some bugfix (#890)',
),
);
function let() {
$this->setLog($this->log);
}
function it_should_add_links_to_the_issue_tracker()
{
$result = array(
'Features' => array(
"bar [#123]({$this->issueTrackerUrl}123) baz",
'dummy feature',
),
'Bugfixes' => array(
"some bugfix ([#890]({$this->issueTrackerUrl}890))",
),
);
$this->setIssueTrackerUrlPattern($this->issueTrackerPattern);
$this->decorate()->shouldReturn($result);
}
function it_should_generate_a_write_ready_output() {
$this->setRelease('4.5.6')
->setDate(new \DateTime('2014-12-21'));
$result = array(
"## 4.5.6",
"*(2014-12-21)*",
"\n#### Features",
'* bar #123 baz',
'* dummy feature',
"\n#### Bugfixes",
'* some bugfix (#890)',
"\n---\n",
);
$this->generate()->shouldReturn($result);
}
}
-86
View File
@@ -1,86 +0,0 @@
<?php namespace spec\ReadmeGen\Output;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use ReadmeGen\Output\Format\FormatInterface;
class WriterSpec extends ObjectBehavior
{
protected $fileName = 'foobar.md';
protected $fileNameWithBreakpoint = 'foobar_break.md';
protected $break = '- Changelog';
function let(FormatInterface $formatter)
{
$this->beConstructedWith($formatter);
file_put_contents($this->fileNameWithBreakpoint, "line one\n{$this->break}\nline two\n##{$this->break}\nline three");
}
function letgo()
{
@ unlink($this->fileName);
@ unlink($this->fileNameWithBreakpoint);
}
function it_should_write_log_output_to_a_file(FormatInterface $formatter)
{
$logContent = array(
'Features:',
'- foo',
'- bar',
);
$formatter->generate()->willReturn($logContent);
$formatter->getFileName()->willReturn($this->fileName);
$this->write();
if (false === file_exists($this->fileName)) {
throw new \Exception(sprintf('File %s has not been created.', $this->fileName));
}
$content = file_get_contents($this->fileName);
if (true === empty($content)) {
throw new \Exception(sprintf('File %s is empty.', $this->fileName));
}
if (trim($content) !== join("\n", $logContent)) {
throw new \Exception('File content differs from expectations.');
}
}
function it_should_add_content_after_breakpoint(FormatInterface $formatter)
{
$logContent = array(
'Features:',
'- foo',
'- bar',
);
$resultContent = array(
'line one',
$this->break,
'Features:',
'- foo',
'- bar',
'',
'line two',
'##'.$this->break,
'line three',
);
$formatter->generate()->willReturn($logContent);
$formatter->getFileName()->willReturn($this->fileNameWithBreakpoint);
$this->setBreak($this->break);
$this->write();
$content = file_get_contents($this->fileNameWithBreakpoint);
if (trim($content) !== join("\n", $resultContent)) {
throw new \Exception('File content differs from expectations.');
}
}
}
-163
View File
@@ -1,163 +0,0 @@
<?php
namespace spec\ReadmeGen {
use PhpSpec\ObjectBehavior;
use \ReadmeGen\Config\Loader as ConfigLoader;
use \ReadmeGen\Shell;
use \ReadmeGen\Vcs\Type\Git;
use \ReadmeGen\Log\Extractor;
use \ReadmeGen\Log\Decorator;
use \ReadmeGen\Output\Format\Md;
use \ReadmeGen\Output\Writer;
class ReadmeGenSpec extends ObjectBehavior
{
protected $dummyConfigFile = 'dummy_config.yaml';
protected $dummyConfig = "vcs: dummyvcs\nfoo: bar\nmessage_groups:\n Features:\n - feat\n - feature\n Bugfixes:\n - fix\n - bugfix";
protected $dummyConfigArray = array(
'vcs' => 'dummyvcs',
'foo' => 'bar',
'message_groups' => array(
'Features' => array(
'feat', 'feature'
),
'Bugfixes' => array(
'fix', 'bugfix'
),
),
);
protected $badConfigFile = 'bad_config.yaml';
protected $badConfig = "vcs: nope\nfoo: bar";
protected $gitConfigFile = 'git_config.yaml';
protected $gitConfig = "vcs: git\nmessage_groups:\n Features:\n - feat\n - feature\n Bugfixes:\n - fix\n - bugfix\nformat: md\nissue_tracker_pattern: http://issue.tracker.com/\\1";
protected $outputFile = 'dummy.md';
function let()
{
file_put_contents($this->dummyConfigFile, $this->dummyConfig);
file_put_contents($this->badConfigFile, $this->badConfig);
$this->beConstructedWith(new ConfigLoader, $this->dummyConfigFile, true);
}
function letgo()
{
unlink($this->dummyConfigFile);
unlink($this->badConfigFile);
@ unlink($this->gitConfigFile);
@ unlink($this->outputFile);
}
function it_should_load_default_config()
{
$this->getConfig()->shouldBe($this->dummyConfigArray);
}
function it_loads_the_correct_vcs_parser()
{
$config = $this->getConfig();
$config['vcs']->shouldBe('dummyvcs');
$this->getParser()->shouldHaveType('\ReadmeGen\Vcs\Parser');
$this->getParser()->getVcsParser()->shouldHaveType('\ReadmeGen\Vcs\Type\Dummyvcs');
}
function it_throws_exception_when_trying_to_load_nonexisting_vcs_parser()
{
$this->beConstructedWith(new ConfigLoader, $this->badConfigFile, true);
$this->shouldThrow('\InvalidArgumentException')->during('getParser');
}
function it_runs_the_whole_process(Shell $shell)
{
file_put_contents($this->gitConfigFile, $this->gitConfig);
$shell->run(sprintf('git log --pretty=format:"%%s%s%%b" 1.2.3..4.0.0', Git::MSG_SEPARATOR))->willReturn($this->getLogAsString());
$this->beConstructedWith(new ConfigLoader, $this->gitConfigFile, true);
$this->getParser()->getVcsParser()->shouldHaveType('\ReadmeGen\Vcs\Type\Git');
$this->getParser()->setArguments(array(
'from' => '1.2.3',
'to' => '4.0.0',
));
$this->getParser()->setShellRunner($shell);
$log = $this->getParser()->parse();
$this->setExtractor(new Extractor());
$logGrouped = $this->extractMessages($log)->shouldReturn(array(
'Features' => array(
'bar baz #123',
'dummy feature',
'lol',
),
'Bugfixes' => array(
'some bugfix',
)
));
$formatter = new Md();
$formatter->setFileName($this->outputFile)
->setRelease('4.5.6')
->setDate(new \DateTime(2014-12-12));
$this->setDecorator(new Decorator($formatter));
$this->getDecoratedMessages($logGrouped)->shouldReturn(array(
'Features' => array(
'bar baz [#123](http://issue.tracker.com/123)',
'dummy feature',
'lol',
),
'Bugfixes' => array(
'some bugfix',
)
));
$outputWriter = new Writer($formatter);
$this->setOutputWriter($outputWriter);
$this->writeOutput()->shouldReturn(true);
}
protected function getLogAsString()
{
$log = array(
'foo',
'feature: bar baz #123',
'nope',
'feature: dummy feature',
'feat: lol',
'also nope',
'fix: some bugfix',
);
return join(Git::MSG_SEPARATOR."\n", $log).Git::MSG_SEPARATOR."\n";
}
}
}
/**
* Dummy VCS type class used by ReadmeGen during tests.
*/
namespace ReadmeGen\Vcs\Type {
class Dummyvcs extends \ReadmeGen\Vcs\Type\AbstractType
{
public function parse()
{
return array();
}
public function getToDate(){
}
}
}
-26
View File
@@ -1,26 +0,0 @@
<?php
namespace spec\ReadmeGen\Vcs;
use PhpSpec\ObjectBehavior;
use ReadmeGen\Vcs\Type\TypeInterface;
class ParserSpec extends ObjectBehavior
{
function let(TypeInterface $vcs)
{
$this->beConstructedWith($vcs);
}
function it_should_parse_the_vcs_log_into_an_array(TypeInterface $vcs)
{
$returnData = array(
'foo bar',
'baz',
);
$vcs->parse()->willReturn($returnData);
$this->parse()->shouldBe($returnData);
}
}
-72
View File
@@ -1,72 +0,0 @@
<?php
namespace spec\ReadmeGen\Vcs\Type;
use PhpSpec\ObjectBehavior;
use ReadmeGen\Shell;
use ReadmeGen\Vcs\Type\Git;
class GitSpec extends ObjectBehavior
{
function it_should_parse_a_git_log(Shell $shell)
{
$this->setArguments(array('from' => '1.0'));
$log = sprintf("Foo bar.%s\nDummy message.%s\n\n", Git::MSG_SEPARATOR, Git::MSG_SEPARATOR);
$shell->run($this->getCommand())->willReturn($log);
$this->setShellRunner($shell);
$this->parse()->shouldReturn(array(
'Foo bar.',
'Dummy message.',
));
}
function it_has_input_options_and_arguments()
{
$this->setOptions(array('a'));
$this->setArguments(array('foo' => 'bar'));
$this->hasOption('z')->shouldReturn(false);
$this->hasOption('a')->shouldReturn(true);
$this->hasArgument('wat')->shouldReturn(false);
$this->hasArgument('foo')->shouldReturn(true);
$this->getArgument('foo')->shouldReturn('bar');
}
function it_should_add_options_and_arguments_to_the_command(Shell $shell)
{
$log = sprintf("Foo bar.%s\nDummy message.%s\n\n", Git::MSG_SEPARATOR, Git::MSG_SEPARATOR);
$shell->run(sprintf('git log --pretty=format:"%%s%s%%b"', Git::MSG_SEPARATOR))->willReturn($log);
$this->setShellRunner($shell);
$this->setOptions(array('x', 'y'));
$this->setArguments(array('foo' => 'bar', 'baz' => 'wat', 'from' => '1.0'));
$this->getCommand()->shouldReturn('git log --pretty=format:"%s'.Git::MSG_SEPARATOR.'%b" 1.0..HEAD --x --y');
}
function it_should_properly_include_the_from_and_to_arguments() {
$this->setOptions(array('x', 'y'));
$this->setArguments(array('from' => '3.4.5', 'foo' => 'bar'));
$this->getCommand()->shouldReturn('git log --pretty=format:"%s'.Git::MSG_SEPARATOR.'%b" 3.4.5..HEAD --x --y');
$this->setArguments(array('from' => '3.4.5', 'foo' => 'bar', 'to' => '4.0'));
$this->getCommand()->shouldReturn('git log --pretty=format:"%s'.Git::MSG_SEPARATOR.'%b" 3.4.5..4.0 --x --y');
}
function it_returns_the_date_of_the_commit(Shell $shell) {
$shell->run('git log -1 -s --format=%ci 3f04264')->willReturn('2014-11-28 01:01:58 +0100');
$this->setShellRunner($shell);
$this->setArguments(array('from' => '1.0', 'to' => '3f04264'));
$this->getToDate()->shouldReturn('2014-11-28');
}
}
-130
View File
@@ -1,130 +0,0 @@
<?php namespace ReadmeGen;
use ReadmeGen\Input\Parser;
use ReadmeGen\Config\Loader as ConfigLoader;
use ReadmeGen\Log\Extractor;
use ReadmeGen\Log\Decorator;
use ReadmeGen\Output\Writer;
class Bootstrap
{
protected $generator;
public function __construct(array $input)
{
// Set up the input parser
$inputParser = new Parser();
$inputParser->setInput(join(' ', $input));
// Parse the input
try {
$input = $inputParser->parse();
} catch (\BadMethodCallException $e) {
die($e->getMessage());
}
// Run the whole process
$this->run($input->getOptions());
}
/**
* Generates the output file.
*
* @param array $options
*/
public function run(array $options)
{
$this->generator = new ReadmeGen(new ConfigLoader());
$this->setupParser($options);
// Extract useful log entries
$logGrouped = $this->generator->setExtractor(new Extractor())
->extractMessages($this->getLog());
$config = $this->generator->getConfig();
$formatterClassName = '\ReadmeGen\Output\Format\\' . ucfirst($config['format']);
// Create the output formatter
$formatter = new $formatterClassName;
$formatter
->setRelease($options['release'])
->setFileName($config['output_file_name'])
->setDate($this->getToDate());
// Pass decorated log entries to the generator
$this->generator->setDecorator(new Decorator($formatter))
->getDecoratedMessages($logGrouped);
$writer = new Writer($formatter);
// If present, respect the breakpoint in the existing output file
$break = $this->getBreak($options, $config);
if (false === empty($break)) {
$writer->setBreak($break);
}
// Write the output
$this->generator->setOutputWriter($writer)
->writeOutput();
}
/**
* Returns the parsed log.
*
* @return mixed
*/
public function getLog()
{
return $this->generator->getParser()
->parse();
}
/**
* Returns the date of the latter commit (--to).
*
* @return string
*/
protected function getToDate()
{
$date = $this->generator->getParser()
->getToDate();
return new \DateTime($date);
}
/**
* Sets the parser.
*
* @param array $options
*/
protected function setupParser(array $options)
{
$this->generator->getParser()
->setArguments($options)
->setShellRunner(new Shell);
}
/**
* Returns the breakpoint if set, null otherwise.
*
* @param array $options
* @param array $config
* @return null|string
*/
protected function getBreak(array $options, array $config){
if (true === isset($options['break'])) {
return $options['break'];
}
if (true === isset($config['break'])) {
return $config['break'];
}
return null;
}
}
-46
View File
@@ -1,46 +0,0 @@
<?php namespace ReadmeGen\Config;
use Symfony\Component\Yaml\Yaml;
/**
* YAML config loader.
*/
class Loader
{
/**
* Returns the config as an array.
*
* @param string $path Path to the file.
* @param array $sourceConfig Config array the result should be merged with.
* @return array
* @throws \Symfony\Component\Yaml\Exception\ParseException When a parse error occurs.
*/
public function get($path, array $sourceConfig = null)
{
$config = Yaml::parse($this->getFileContent($path));
if (false === empty($sourceConfig)) {
return array_replace_recursive($sourceConfig, $config);
}
return $config;
}
/**
* Returns the file's contents.
*
* @param string $path Path to file.
* @return string
* @throws \InvalidArgumentException When the file does not exist.
*/
protected function getFileContent($path)
{
if (false === file_exists($path)) {
throw new \InvalidArgumentException(sprintf('File "%s" does not exist.', $path));
}
return file_get_contents($path);
}
}
-74
View File
@@ -1,74 +0,0 @@
<?php namespace ReadmeGen\Input;
use Ulrichsg\Getopt\Getopt;
use Ulrichsg\Getopt\Option;
/**
* Input parser.
*
* Class Parser
* @package ReadmeGen\Input
*/
class Parser
{
/**
* CLI input parser.
*
* @var Getopt
*/
protected $handler;
/**
* Entered command.
*
* @var string
*/
protected $input;
public function __construct()
{
// Register possible input arguments.
$this->handler = new Getopt(array(
new Option('r', 'release', Getopt::REQUIRED_ARGUMENT),
new Option('f', 'from', Getopt::REQUIRED_ARGUMENT),
new Option('t', 'to', Getopt::OPTIONAL_ARGUMENT),
new Option('b', 'break', Getopt::OPTIONAL_ARGUMENT),
));
}
/**
* Set the input.
*
* @param $input string
*/
public function setInput($input)
{
$inputArray = explode(' ', $input);
array_shift($inputArray);
$this->input = join(' ', $inputArray);
}
/**
* Parses the input and returns the Getopt handler.
*
* @return Getopt
*/
public function parse()
{
$this->handler->parse($this->input);
$output = $this->handler->getOptions();
if (false === isset($output['from'])) {
throw new \BadMethodCallException('The --from argument is required.');
}
if (false === isset($output['release'])) {
throw new \BadMethodCallException('The --release argument is required.');
}
return $this->handler;
}
}
-60
View File
@@ -1,60 +0,0 @@
<?php namespace ReadmeGen\Log;
use ReadmeGen\Output\Format\FormatInterface;
/**
* Output decorator.
*
* Class Decorator
* @package ReadmeGen\Log
*/
class Decorator
{
/**
* Formatter instance.
*
* @var FormatInterface
*/
protected $formatter;
public function __construct(FormatInterface $formatter)
{
$this->formatter = $formatter;
}
/**
* Log setter.
*
* @param array $log
* @return $this
*/
public function setLog(array $log)
{
$this->formatter->setLog($log);
return $this;
}
/**
* Issue tracker pattern setter.
*
* @param string $pattern
* @return $this
*/
public function setIssueTrackerUrlPattern($pattern)
{
$this->formatter->setIssueTrackerUrlPattern($pattern);
return $this;
}
/**
* Returns the decorated log.
*
* @return FormatInterface
*/
public function decorate()
{
return $this->formatter->decorate();
}
}
-116
View File
@@ -1,116 +0,0 @@
<?php namespace ReadmeGen\Log;
/**
* Log extractor.
*
* Filters the parsed log and returns grouped messages.
*/
class Extractor {
/**
* The log.
*
* @var array
*/
protected $log = array();
/**
* Message groups.
*
* @var array
*/
protected $messageGroups = array();
/**
* Message groups as a string.
*
* @var string
*/
protected $messageGroupsJoined;
/**
* Grouped messages.
*
* @var array
*/
protected $groups = array();
/**
* Log setter.
*
* @param array $log
* @return $this
*/
public function setLog(array $log)
{
$this->log = $log;
return $this;
}
/**
* Message groups setter.
*
* @param array $messageGroups
* @return $this
*/
public function setMessageGroups(array $messageGroups)
{
$this->messageGroups = $messageGroups;
// Set the joined message groups as well
foreach ($this->messageGroups as $header => $keywords) {
$this->messageGroupsJoined[$header] = join('|', $keywords);
}
return $this;
}
/**
* Groups messages and returns them.
*
* @return array
*/
public function extract() {
foreach ($this->log as $line) {
foreach ($this->messageGroupsJoined as $header => $keywords) {
$pattern = $this->getPattern($keywords);
if (preg_match($pattern, $line)) {
$this->appendToGroup($header, $line, $pattern);
}
}
}
// Remove empty groups
foreach (array_keys($this->messageGroups) as $groupKey) {
if (true === empty($this->groups[$groupKey])) {
unset($this->messageGroups[$groupKey]);
}
}
// The array_merge sorts $messageGroups basing on $groups
return array_merge($this->messageGroups, $this->groups);
}
/**
* Appends a message to a group
*
* @param string $groupHeader
* @param string $text
* @param string $pattern
*/
protected function appendToGroup($groupHeader, $text, $pattern) {
$this->groups[$groupHeader][] = trim(preg_replace($pattern, '', $text));
}
/**
* Returns the regexp pattern used to determine the log entry's group.
*
* @param string $keywords
* @return string
*/
protected function getPattern($keywords) {
return '/^('.$keywords.'):/i';
}
}
@@ -1,66 +0,0 @@
<?php namespace ReadmeGen\Output\Format;
interface FormatInterface {
/**
* Log setter.
*
* @param array $log
* @return mixed
*/
public function setLog(array $log);
/**
* Issue tracker patter setter.
*
* @param $pattern
* @return mixed
*/
public function setIssueTrackerUrlPattern($pattern);
/**
* Decorates the output (e.g. adds linkgs to the issue tracker)
*
* @return self
*/
public function decorate();
/**
* Returns a write-ready log.
*
* @return array
*/
public function generate();
/**
* Returns the output filename.
*
* @return string
*/
public function getFileName();
/**
* Output filename setter.
*
* @param $fileName
* @return mixed
*/
public function setFileName($fileName);
/**
* Release number setter.
*
* @param $release
* @return mixed
*/
public function setRelease($release);
/**
* Creation date setter.
*
* @param \DateTime $date
* @return mixed
*/
public function setDate(\DateTime $date);
}
-175
View File
@@ -1,175 +0,0 @@
<?php namespace ReadmeGen\Output\Format;
use ReadmeGen\Vcs\Type\AbstractType as VCS;
class Md implements FormatInterface
{
/**
* VCS log.
*
* @var array
*/
protected $log;
/**
* Issue tracker link pattern.
*
* @var string
*/
protected $pattern;
/**
* Output filename.
*
* @var string
*/
protected $fileName = 'README.md';
/**
* Release number (included in the output).
*
* @var string
*/
protected $release;
/**
* Date (included in the output).
*
* @var \DateTime
*/
protected $date;
/**
* Log setter.
*
* @param array $log
* @return mixed
*/
public function setLog(array $log = null)
{
$this->log = $log;
return $this;
}
/**
* Issue tracker patter setter.
*
* @param $pattern
* @return mixed
*/
public function setIssueTrackerUrlPattern($pattern)
{
$this->pattern = $pattern;
return $this;
}
/**
* Decorates the output (e.g. adds linkgs to the issue tracker)
*
* @return self
*/
public function decorate()
{
foreach ($this->log as &$entries) {
array_walk($entries, array($this, 'injectLinks'));
}
return $this->log;
}
/**
* Injects issue tracker links into the log.
*
* @param string $entry Log entry.
*/
protected function injectLinks(&$entry)
{
$entry = preg_replace('/#(\d+)/', "[#\\1]({$this->pattern})", $entry);
}
/**
* Returns a write-ready log.
*
* @return array
*/
public function generate()
{
if (true === empty($this->log)) {
return array();
}
$log = array();
// Iterate over grouped entries
foreach ($this->log as $header => &$entries) {
// Add a group header (e.g. Bugfixes)
$log[] = sprintf("\n#### %s", $header);
// Iterate over entries
foreach ($entries as &$line) {
$message = explode(VCS::MSG_SEPARATOR, $line);
$log[] = sprintf("* %s", trim($message[0]));
// Include multi-line entries
if (true === isset($message[1])) {
$log[] = sprintf("\n %s", trim($message[1]));
}
}
}
// Return a write-ready log
return array_merge(array("## {$this->release}", "*({$this->date->format('Y-m-d')})*"), $log, array("\n---\n"));
}
/**
* Returns the output filename.
*
* @return string
*/
public function getFileName()
{
return $this->fileName;
}
/**
* Output filename setter.
*
* @param $fileName
* @return mixed
*/
public function setFileName($fileName)
{
$this->fileName = $fileName;
return $this;
}
/**
* Release number setter.
*
* @param $release
* @return mixed
*/
public function setRelease($release) {
$this->release = $release;
return $this;
}
/**
* Creation date setter.
*
* @param \DateTime $date
* @return mixed
*/
public function setDate(\DateTime $date) {
$this->date = $date;
return $this;
}
}
-89
View File
@@ -1,89 +0,0 @@
<?php namespace ReadmeGen\Output;
use ReadmeGen\Output\Format\FormatInterface;
/**
* Output writer.
*
* Class Writer
* @package ReadmeGen\Output
*/
class Writer
{
/**
* Format specific writer.
*
* @var FormatInterface
*/
protected $formatter;
/**
* Output breakpoint.
*
* @var string
*/
protected $break;
public function __construct(FormatInterface $formatter)
{
$this->formatter = $formatter;
}
/**
* Writes the output to a file.
*
* @return bool
*/
public function write()
{
// Crete the file if it does not exist
$this->makeFile($this->formatter->getFileName());
// Contents of the original file
$fileContent = file_get_contents($this->formatter->getFileName());
// Final log
$log = join("\n", (array) $this->formatter->generate())."\n";
// Include the breakpoint
if (false === empty($this->break) && 1 === preg_match("/^{$this->break}/m", $fileContent)) {
$splitFileContent = preg_split("/^{$this->break}/m", $fileContent);
file_put_contents($this->formatter->getFileName(), $splitFileContent[0].$this->break."\n".$log.$splitFileContent[1]);
return true;
}
file_put_contents($this->formatter->getFileName(), $log.$fileContent);
return true;
}
/**
* Create the file if it does not exist.
*
* @param string $fileName
*/
protected function makeFile($fileName){
if (file_exists($fileName)) {
return;
}
touch($fileName);
}
/**
* Breakpoint setter.
*
* @param null|string $break
* @return $this
*/
public function setBreak($break = null)
{
if (false === empty($break)) {
$this->break = $break;
}
return $this;
}
}
-187
View File
@@ -1,187 +0,0 @@
<?php namespace ReadmeGen;
use ReadmeGen\Config\Loader as ConfigLoader;
use ReadmeGen\Vcs\Parser;
use ReadmeGen\Log\Extractor;
use ReadmeGen\Log\Decorator;
use ReadmeGen\Output\Writer as OutputWriter;
class ReadmeGen
{
/**
* Path to the default config file.
*/
protected $defaultConfigPath = 'readmegen.yml';
/**
* Config loader.
*
* @var ConfigLoader
*/
protected $configLoader;
/**
* Default config.
*
* @var array
*/
protected $defaultConfig = array();
/**
* Final config - default config merged with local config.
*
* @var array
*/
protected $config = array();
/**
* Parser instance.
*
* @var Parser
*/
protected $parser;
/**
* Message extractor.
*
* @var Extractor
*/
protected $extractor;
/**
* Message decorator.
*
* @var \ReadmeGen\Log\Decorator
*/
protected $decorator;
protected $output;
public function __construct(ConfigLoader $configLoader, $defaultConfigPath = null, $ignoreLocalConfig = false)
{
// Root config path
$rootConfigPath = realpath(__DIR__.'/../'.$this->defaultConfigPath);
// Overriding the root config
$configPath = (false === empty($defaultConfigPath) ? $defaultConfigPath : $rootConfigPath);
$this->configLoader = $configLoader;
$this->defaultConfig = $this->configLoader->get($configPath);
$localConfigPath = realpath($this->defaultConfigPath);
// Merging local config
if (file_exists($localConfigPath) && false === $ignoreLocalConfig) {
$this->config = $this->configLoader->get($localConfigPath, $this->defaultConfig);
}
else {
$this->config = $this->defaultConfig;
}
}
/**
* Returns the config.
*
* @return array
*/
public function getConfig()
{
return $this->config;
}
/**
* Returns the parser.
*
* @return Parser
* @throws \InvalidArgumentException When the VCS parser class does not exist.
*/
public function getParser()
{
if (true === empty($this->parser)) {
$typeParserClassName = sprintf('\ReadmeGen\Vcs\Type\%s', ucfirst($this->config['vcs']));
if (false === class_exists($typeParserClassName)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist', $typeParserClassName));
}
$this->parser = new Parser(new $typeParserClassName());
}
return $this->parser;
}
public function setExtractor(Extractor $extractor)
{
$this->extractor = $extractor;
return $this;
}
/**
* Returns messages extracted from the log.
*
* @param array $log
* @return array
*/
public function extractMessages(array $log = null)
{
if (true === empty($log)) {
return array();
}
$this->extractor->setMessageGroups($this->config['message_groups']);
return $this->extractor->setLog($log)
->extract();
}
/**
*
* phpspec failed to properly resolve the aliased version of this interface.
*
* @param \ReadmeGen\Log\Decorator $decorator
* @return $this
*/
public function setDecorator(Decorator $decorator)
{
$this->decorator = $decorator;
return $this;
}
/**
* Returns decorated log messages.
*
* @param array $log
* @return array|Output\Format\FormatInterface
*/
public function getDecoratedMessages(array $log = null)
{
if (true === empty($log)) {
return array();
}
return $this->decorator->setLog($log)
->setIssueTrackerUrlPattern($this->config['issue_tracker_pattern'])
->decorate();
}
public function setOutputWriter(OutputWriter $output)
{
$this->output = $output;
return $this;
}
/**
* Writes the ready output to the file.
*
* @return mixed
*/
public function writeOutput()
{
return $this->output->write();
}
}
-20
View File
@@ -1,20 +0,0 @@
<?php namespace ReadmeGen;
/**
* Shell command runner.
*/
class Shell
{
/**
* Returns the result of the executed command.
*
* @param string $command
* @return string
*/
public function run($command)
{
return shell_exec($command);
}
}
-92
View File
@@ -1,92 +0,0 @@
<?php namespace ReadmeGen\Vcs;
use ReadmeGen\Vcs\Type\TypeInterface;
use ReadmeGen\Shell;
/**
* VCS log parser.
*
* Used to return the VCS log as an array.
*/
class Parser
{
/**
* VCS-specific parser.
*
* @var TypeInterface
*/
protected $vcs;
public function __construct(TypeInterface $vcs)
{
$this->vcs = $vcs;
}
/**
* Returns the parsed log.
*
* @return array
*/
public function parse()
{
return $this->vcs->parse();
}
/**
* Returns the VCS parser.
*
* @return TypeInterface
*/
public function getVcsParser()
{
return $this->vcs;
}
/**
* Shell runner setter.
*
* @param Shell $shell
* @return $this
*/
public function setShellRunner(Shell $shell)
{
$this->vcs->setShellRunner($shell);
return $this;
}
/**
* Sets input options.
*
* @param array $options
* @return $this
*/
public function setOptions(array $options = null)
{
$this->vcs->setOptions($options);
return $this;
}
/**
* Sets input arguments.
*
* @param array $arguments
* @return $this
*/
public function setArguments(array $arguments = null)
{
$this->vcs->setArguments($arguments);
return $this;
}
/**
* Returns the date of the latter (--to) commit, in the format YYYY-MM-DD.
*
* @return string
*/
public function getToDate(){
return $this->vcs->getToDate();
}
}
-126
View File
@@ -1,126 +0,0 @@
<?php namespace ReadmeGen\Vcs\Type;
use ReadmeGen\Shell;
abstract class AbstractType implements TypeInterface
{
const MSG_SEPARATOR = '{{MSG_SEPARATOR}}';
/**
* Shell script runner.
*
* @var Shell
*/
protected $shell;
/**
* Input arguments.
*
* @var array
*/
protected $arguments = array();
/**
* Input arguments.
*
* @var array
*/
protected $options = array();
/**
* Shell command executing class setter.
*
* @param Shell $shell
*/
public function setShellRunner(Shell $shell)
{
$this->shell = $shell;
}
/**
* Runs the shell command and returns the result.
*
* @param $command
* @return string
*/
protected function runCommand($command)
{
return $this->shell->run($command);
}
/**
* Input option setter.
*
* @param array $options
* @return mixed
*/
public function setOptions(array $options = null)
{
$this->options = $options;
}
/**
* Input argument setter.
*
* @param array $arguments
* @return mixed
*/
public function setArguments(array $arguments = null)
{
$this->arguments = $arguments;
}
/**
* Returns true if an option exists.
*
* @param $option
* @return mixed
*/
public function hasOption($option)
{
return in_array($option, $this->options);
}
/**
* Returns all options.
*
* @return mixed
*/
public function getOptions()
{
return $this->options;
}
/**
* Returns true if an argument exists.
*
* @param $argument
* @return mixed
*/
public function hasArgument($argument)
{
return isset($this->arguments[$argument]);
}
/**
* Returns the argument's value.
*
* @param $argument
* @return mixed
*/
public function getArgument($argument)
{
return $this->arguments[$argument];
}
/**
* Return all arguments.
*
* @return mixed
*/
public function getArguments()
{
return $this->arguments;
}
}
-77
View File
@@ -1,77 +0,0 @@
<?php namespace ReadmeGen\Vcs\Type;
class Git extends AbstractType
{
/**
* Parses the log.
*
* @return array
*/
public function parse()
{
return array_filter(array_map('trim', explode(self::MSG_SEPARATOR, $this->getLog())));
}
/**
* Returns the base VCS log command.
*
* @return string
*/
protected function getBaseCommand()
{
return 'git log --pretty=format:"%s{{MSG_SEPARATOR}}%b"';
}
/**
* Returns the compiled VCS log command.
*
* @return string
*/
public function getCommand()
{
$options = $this->getOptions();
$arguments = $this->getArguments();
$to = null;
$from = $arguments['from'];
if (true === isset($arguments['to'])) {
$to = $arguments['to'];
}
array_walk($options, function (&$option) {
$option = '--' . $option;
});
array_walk($arguments, function (&$value, $argument) {
$value = '--' . $argument . '=' . $value;
});
return trim(sprintf('%s %s %s', $this->getBaseCommand(), $this->getRange($from, $to), join(' ', $options)));
}
protected function getLog()
{
return $this->runCommand($this->getCommand());
}
protected function getRange($from, $to = null)
{
$range = $from . '..';
return $range . (($to) ?: 'HEAD');
}
public function getToDate()
{
$arguments = $this->getArguments();
$to = (true === isset($arguments['to'])) ? $arguments['to'] : 'HEAD';
$fullDate = $this->runCommand(sprintf('git log -1 -s --format=%%ci %s', $to));
$date = explode(' ', $fullDate);
return $date[0];
}
}
-83
View File
@@ -1,83 +0,0 @@
<?php namespace ReadmeGen\Vcs\Type;
use ReadmeGen\Shell;
interface TypeInterface
{
/**
* Parses the log.
*
* @return array
*/
public function parse();
/**
* Shell command executing class setter.
*
* @param Shell $shell
*/
public function setShellRunner(Shell $shell);
/**
* Input option setter.
*
* @param array $options
* @return mixed
*/
public function setOptions(array $options = null);
/**
* Input argument setter.
*
* @param array $arguments
* @return mixed
*/
public function setArguments(array $arguments = null);
/**
* Returns true if an option exists.
*
* @param $option
* @return mixed
*/
public function hasOption($option);
/**
* Returns all options.
*
* @return mixed
*/
public function getOptions();
/**
* Returns true if an argument exists.
*
* @param $argument
* @return mixed
*/
public function hasArgument($argument);
/**
* Returns the argument's value.
*
* @param $argument
* @return mixed
*/
public function getArgument($argument);
/**
* Return all arguments.
*
* @return mixed
*/
public function getArguments();
/**
* Returns the date of the latter (--to) commit, in the format YYYY-MM-DD.
*
* @return string
*/
public function getToDate();
}
@@ -1,3 +0,0 @@
build
vendor
composer.lock
-15
View File
@@ -1,15 +0,0 @@
language: php
php:
- 5.3.3
- 5.4
- 5.5
before_script:
- composer self-update
- composer install --no-interaction --prefer-source --dev
script:
- ant phplint
- ant phpcs
- ant phpunit
-93
View File
@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project default="build">
<!-- Set executables according to OS -->
<condition property="phpunit" value="${basedir}/vendor/bin/phpunit.bat" else="${basedir}/vendor/bin/phpunit">
<os family="windows" />
</condition>
<condition property="phpcs" value="${basedir}/vendor/bin/phpcs.bat" else="${basedir}/vendor/bin/phpcs">
<os family="windows" />
</condition>
<condition property="parallel-lint" value="${basedir}/vendor/bin/parallel-lint.bat" else="${basedir}/vendor/bin/parallel-lint">
<os family="windows" />
</condition>
<condition property="var-dump-check" value="${basedir}/vendor/bin/var-dump-check.bat" else="${basedir}/vendor/bin/var-dump-check">
<os family="windows"/>
</condition>
<!-- Use colors in output can be disabled when calling ant with -Duse-colors=false -->
<property name="use-colors" value="true" />
<condition property="colors-arg.color" value="--colors" else="">
<equals arg1="${use-colors}" arg2="true" />
</condition>
<condition property="colors-arg.no-colors" value="" else="--no-colors">
<equals arg1="${use-colors}" arg2="true" />
</condition>
<!-- Targets -->
<target name="prepare" description="Create build directory">
<mkdir dir="${basedir}/build/logs" />
</target>
<target name="phplint" description="Check syntax errors in PHP files">
<exec executable="${parallel-lint}" failonerror="true">
<arg line='--exclude ${basedir}/vendor/' />
<arg line='${colors-arg.no-colors}' />
<arg line='${basedir}' />
</exec>
</target>
<target name="var-dump-check" description="Check PHP files for forgotten variable dumps">
<exec executable="${var-dump-check}" failonerror="true">
<arg line='--exclude ${basedir}/vendor/' />
<arg line='${colors-arg.no-colors}' />
<arg line='${basedir}' />
</exec>
</target>
<target name="phpcs" depends="prepare" description="Check PHP code style">
<delete file="${basedir}/build/logs/checkstyle.xml" quiet="true" />
<exec executable="${phpcs}">
<arg line='--extensions=php' />
<arg line='--standard="${basedir}/vendor/jakub-onderka/php-code-style/ruleset.xml"' />
<arg line='--report-checkstyle="${basedir}/build/logs/checkstyle.xml"' />
<arg line='--report-full' />
<arg line='"${basedir}/src"' />
</exec>
</target>
<target name="phpunit" depends="prepare" description="PHP unit">
<delete file="${basedir}/build/logs/phpunit.xml" quiet="true" />
<exec executable="${phpunit}">
<arg line='--configuration ${basedir}/phpunit.xml' />
<arg line='-d memory_limit=256M' />
<arg line='--log-junit "${basedir}/build/logs/phpunit.xml"' />
<arg line='${colors-arg.color}' />
</exec>
</target>
<target name="phpunit-coverage" depends="prepare" description="PHP unit with code coverage">
<delete file="${basedir}/build/logs/phpunit.xml" quiet="true" />
<delete file="${basedir}/build/logs/clover.xml" quiet="true" />
<delete dir="${basedir}/build/coverage" quiet="true" />
<mkdir dir="${basedir}/build/coverage" />
<exec executable="${phpunit}">
<arg line='--configuration ${basedir}/phpunit.xml' />
<arg line='-d memory_limit=256M' />
<arg line='--log-junit "${basedir}/build/logs/phpunit.xml"' />
<arg line='--coverage-clover "${basedir}/build/logs/clover.xml"' />
<arg line='--coverage-html "${basedir}/build/coverage/"' />
<arg line='${colors-arg.color}' />
</exec>
</target>
<target name="build" depends="phplint,var-dump-check,phpcs,phpunit" />
</project>
-24
View File
@@ -1,24 +0,0 @@
{
"name": "jakub-onderka/php-console-color",
"license": "BSD-2-Clause",
"version": "0.1",
"authors": [
{
"name": "Jakub Onderka",
"email": "[email protected]"
}
],
"autoload": {
"psr-0": {"JakubOnderka\\PhpConsoleColor": "src/"}
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"jakub-onderka/php-parallel-lint": "0.*",
"jakub-onderka/php-var-dump-check": "0.*",
"squizlabs/php_codesniffer": "1.*",
"jakub-onderka/php-code-style": "1.0"
}
}
-38
View File
@@ -1,38 +0,0 @@
<?php
$loader = require_once __DIR__ . '/vendor/autoload.php';
$consoleColor = new JakubOnderka\PhpConsoleColor\ConsoleColor();
echo "Colors are supported: " . ($consoleColor->isSupported() ? 'Yes' : 'No') . "\n";
echo "256 colors are supported: " . ($consoleColor->are256ColorsSupported() ? 'Yes' : 'No') . "\n\n";
if ($consoleColor->isSupported()) {
foreach ($consoleColor->getPossibleStyles() as $style) {
echo $consoleColor->apply($style, $style) . "\n";
}
}
echo "\n";
if ($consoleColor->are256ColorsSupported()) {
echo "Foreground colors:\n";
for ($i = 1; $i <= 255; $i++) {
echo $consoleColor->apply("color_$i", str_pad($i, 6, ' ', STR_PAD_BOTH));
if ($i % 15 === 0) {
echo "\n";
}
}
echo "\nBackground colors:\n";
for ($i = 1; $i <= 255; $i++) {
echo $consoleColor->apply("bg_color_$i", str_pad($i, 6, ' ', STR_PAD_BOTH));
if ($i % 15 === 0) {
echo "\n";
}
}
echo "\n";
}
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php">
<testsuites>
<testsuite>
<directory>tests/*</directory>
</testsuite>
</testsuites>
<!-- Ignore vendor folder for code coverage -->
<filter>
<blacklist>
<directory>vendor</directory>
</blacklist>
</filter>
</phpunit>
@@ -1,280 +0,0 @@
<?php
namespace JakubOnderka\PhpConsoleColor;
class ConsoleColor
{
const FOREGROUND = 38,
BACKGROUND = 48;
const COLOR256_REGEXP = '~^(bg_)?color_([0-9]{1,3})$~';
const RESET_STYLE = 0;
/** @var bool */
private $isSupported;
/** @var bool */
private $forceStyle = false;
/** @var array */
private $styles = array(
'none' => null,
'bold' => '1',
'dark' => '2',
'italic' => '3',
'underline' => '4',
'blink' => '5',
'reverse' => '7',
'concealed' => '8',
'default' => '39',
'black' => '30',
'red' => '31',
'green' => '32',
'yellow' => '33',
'blue' => '34',
'magenta' => '35',
'cyan' => '36',
'light_gray' => '37',
'dark_gray' => '90',
'light_red' => '91',
'light_green' => '92',
'light_yellow' => '93',
'light_blue' => '94',
'light_magenta' => '95',
'light_cyan' => '96',
'white' => '97',
'bg_default' => '49',
'bg_black' => '40',
'bg_red' => '41',
'bg_green' => '42',
'bg_yellow' => '43',
'bg_blue' => '44',
'bg_magenta' => '45',
'bg_cyan' => '46',
'bg_light_gray' => '47',
'bg_dark_gray' => '100',
'bg_light_red' => '101',
'bg_light_green' => '102',
'bg_light_yellow' => '103',
'bg_light_blue' => '104',
'bg_light_magenta' => '105',
'bg_light_cyan' => '106',
'bg_white' => '107',
);
/** @var array */
private $themes = array();
public function __construct()
{
$this->isSupported = $this->isSupported();
}
/**
* @param string|array $style
* @param string $text
* @return string
* @throws InvalidStyleException
* @throws \InvalidArgumentException
*/
public function apply($style, $text)
{
if (!$this->isStyleForced() && !$this->isSupported()) {
return $text;
}
if (is_string($style)) {
$style = array($style);
}
if (!is_array($style)) {
throw new \InvalidArgumentException("Style must be string or array.");
}
$sequences = array();
foreach ($style as $s) {
if (isset($this->themes[$s])) {
$sequences = array_merge($sequences, $this->themeSequence($s));
} else if ($this->isValidStyle($s)) {
$sequences[] = $this->styleSequence($s);
} else {
throw new InvalidStyleException($s);
}
}
$sequences = array_filter($sequences, function ($val) {
return $val !== null;
});
if (empty($sequences)) {
return $text;
}
return $this->escSequence(implode(';', $sequences)) . $text . $this->escSequence(self::RESET_STYLE);
}
/**
* @param bool $forceStyle
*/
public function setForceStyle($forceStyle)
{
$this->forceStyle = (bool) $forceStyle;
}
/**
* @return bool
*/
public function isStyleForced()
{
return $this->forceStyle;
}
/**
* @param array $themes
* @throws InvalidStyleException
* @throws \InvalidArgumentException
*/
public function setThemes(array $themes)
{
$this->themes = array();
foreach ($themes as $name => $styles) {
$this->addTheme($name, $styles);
}
}
/**
* @param string $name
* @param array|string $styles
* @throws \InvalidArgumentException
* @throws InvalidStyleException
*/
public function addTheme($name, $styles)
{
if (is_string($styles)) {
$styles = array($styles);
}
if (!is_array($styles)) {
throw new \InvalidArgumentException("Style must be string or array.");
}
foreach ($styles as $style) {
if (!$this->isValidStyle($style)) {
throw new InvalidStyleException($style);
}
}
$this->themes[$name] = $styles;
}
/**
* @return array
*/
public function getThemes()
{
return $this->themes;
}
/**
* @param string $name
* @return bool
*/
public function hasTheme($name)
{
return isset($this->themes[$name]);
}
/**
* @param string $name
*/
public function removeTheme($name)
{
unset($this->themes[$name]);
}
/**
* @return bool
*/
public function isSupported()
{
if (DIRECTORY_SEPARATOR === '\\') {
return getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON';
}
return function_exists('posix_isatty') && @posix_isatty(STDOUT);
}
/**
* @return bool
*/
public function are256ColorsSupported()
{
return DIRECTORY_SEPARATOR === '/' && strpos(getenv('TERM'), '256color') !== false;
}
/**
* @return array
*/
public function getPossibleStyles()
{
return array_keys($this->styles);
}
/**
* @param string $name
* @return string
* @throws InvalidStyleException
*/
private function themeSequence($name)
{
$sequences = array();
foreach ($this->themes[$name] as $style) {
$sequences[] = $this->styleSequence($style);
}
return $sequences;
}
/**
* @param string $style
* @return string
* @throws InvalidStyleException
*/
private function styleSequence($style)
{
if (array_key_exists($style, $this->styles)) {
return $this->styles[$style];
}
if (!$this->are256ColorsSupported()) {
return null;
}
preg_match(self::COLOR256_REGEXP, $style, $matches);
$type = $matches[1] === 'bg_' ? self::BACKGROUND : self::FOREGROUND;
$value = $matches[2];
return "$type;5;$value";
}
/**
* @param string $style
* @return bool
*/
private function isValidStyle($style)
{
return array_key_exists($style, $this->styles) || preg_match(self::COLOR256_REGEXP, $style);
}
/**
* @param string|int $value
* @return string
*/
private function escSequence($value)
{
return "\033[{$value}m";
}
}
@@ -1,10 +0,0 @@
<?php
namespace JakubOnderka\PhpConsoleColor;
class InvalidStyleException extends \Exception
{
public function __construct($styleName)
{
parent::__construct("Invalid style $styleName.");
}
}
@@ -1,184 +0,0 @@
<?php
use JakubOnderka\PhpConsoleColor\ConsoleColor;
class ConsoleColorWithForceSupport extends ConsoleColor
{
private $isSupportedForce = true;
private $are256ColorsSupportedForce = true;
public function setIsSupported($isSupported)
{
$this->isSupportedForce = $isSupported;
}
public function isSupported()
{
return $this->isSupportedForce;
}
public function setAre256ColorsSupported($are256ColorsSupported)
{
$this->are256ColorsSupportedForce = $are256ColorsSupported;
}
public function are256ColorsSupported()
{
return $this->are256ColorsSupportedForce;
}
}
class ConsoleColorTest extends \PHPUnit_Framework_TestCase
{
/** @var ConsoleColorWithForceSupport */
private $uut;
protected function setUp()
{
$this->uut = new ConsoleColorWithForceSupport();
}
public function testNone()
{
$output = $this->uut->apply('none', 'text');
$this->assertEquals("text", $output);
}
public function testBold()
{
$output = $this->uut->apply('bold', 'text');
$this->assertEquals("\033[1mtext\033[0m", $output);
}
public function testBoldColorsAreNotSupported()
{
$this->uut->setIsSupported(false);
$output = $this->uut->apply('bold', 'text');
$this->assertEquals("text", $output);
}
public function testBoldColorsAreNotSupportedButAreForced()
{
$this->uut->setIsSupported(false);
$this->uut->setForceStyle(true);
$output = $this->uut->apply('bold', 'text');
$this->assertEquals("\033[1mtext\033[0m", $output);
}
public function testDark()
{
$output = $this->uut->apply('dark', 'text');
$this->assertEquals("\033[2mtext\033[0m", $output);
}
public function testBoldAndDark()
{
$output = $this->uut->apply(array('bold', 'dark'), 'text');
$this->assertEquals("\033[1;2mtext\033[0m", $output);
}
public function test256ColorForeground()
{
$output = $this->uut->apply('color_255', 'text');
$this->assertEquals("\033[38;5;255mtext\033[0m", $output);
}
public function test256ColorWithoutSupport()
{
$this->uut->setAre256ColorsSupported(false);
$output = $this->uut->apply('color_255', 'text');
$this->assertEquals("text", $output);
}
public function test256ColorBackground()
{
$output = $this->uut->apply('bg_color_255', 'text');
$this->assertEquals("\033[48;5;255mtext\033[0m", $output);
}
public function test256ColorForegroundAndBackground()
{
$output = $this->uut->apply(array('color_200', 'bg_color_255'), 'text');
$this->assertEquals("\033[38;5;200;48;5;255mtext\033[0m", $output);
}
public function testSetOwnTheme()
{
$this->uut->setThemes(array('bold_dark' => array('bold', 'dark')));
$output = $this->uut->apply(array('bold_dark'), 'text');
$this->assertEquals("\033[1;2mtext\033[0m", $output);
}
public function testAddOwnTheme()
{
$this->uut->addTheme('bold_own', 'bold');
$output = $this->uut->apply(array('bold_own'), 'text');
$this->assertEquals("\033[1mtext\033[0m", $output);
}
public function testAddOwnThemeArray()
{
$this->uut->addTheme('bold_dark', array('bold', 'dark'));
$output = $this->uut->apply(array('bold_dark'), 'text');
$this->assertEquals("\033[1;2mtext\033[0m", $output);
}
public function testOwnWithStyle()
{
$this->uut->addTheme('bold_dark', array('bold', 'dark'));
$output = $this->uut->apply(array('bold_dark', 'italic'), 'text');
$this->assertEquals("\033[1;2;3mtext\033[0m", $output);
}
public function testHasAndRemoveTheme()
{
$this->assertFalse($this->uut->hasTheme('bold_dark'));
$this->uut->addTheme('bold_dark', array('bold', 'dark'));
$this->assertTrue($this->uut->hasTheme('bold_dark'));
$this->uut->removeTheme('bold_dark');
$this->assertFalse($this->uut->hasTheme('bold_dark'));
}
public function testApplyInvalidArgument()
{
$this->setExpectedException('\InvalidArgumentException');
$this->uut->apply(new stdClass(), 'text');
}
public function testApplyInvalidStyleName()
{
$this->setExpectedException('\JakubOnderka\PhpConsoleColor\InvalidStyleException');
$this->uut->apply('invalid', 'text');
}
public function testApplyInvalid256Color()
{
$this->setExpectedException('\JakubOnderka\PhpConsoleColor\InvalidStyleException');
$this->uut->apply('color_2134', 'text');
}
public function testThemeInvalidStyle()
{
$this->setExpectedException('\JakubOnderka\PhpConsoleColor\InvalidStyleException');
$this->uut->addTheme('invalid', array('invalid'));
}
public function testForceStyle()
{
$this->assertFalse($this->uut->isStyleForced());
$this->uut->setForceStyle(true);
$this->assertTrue($this->uut->isStyleForced());
}
public function testGetPossibleStyles()
{
$this->assertInternalType('array', $this->uut->getPossibleStyles());
$this->assertNotEmpty($this->uut->getPossibleStyles());
}
}
@@ -1,2 +0,0 @@
<?php
$loader = require_once __DIR__ . '/../vendor/autoload.php';
@@ -1,4 +0,0 @@
/.idea/
/build/
/vendor/
/composer.lock
@@ -1,21 +0,0 @@
language: php
php:
- 5.3.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
- hhvm-nightly
matrix:
allowed_failures:
- php: 7.0
- php: hhvm-nightly
before_script:
- composer install --no-interaction --prefer-source
script:
- ant
-21
View File
@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 Jakub Onderka
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-40
View File
@@ -1,40 +0,0 @@
PHP Console Highlighter
=======================
Highlight PHP code in console (terminal).
Example
-------
![Example](http://jakubonderka.github.io/php-console-highlight-example.png)
Install
-------
Just create a `composer.json` file and run the `php composer.phar install` command to install it:
```json
{
"require": {
"jakub-onderka/php-console-highlighter": "0.*"
}
}
```
Usage
-------
```php
<?php
use JakubOnderka\PhpConsoleColor\ConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
require __DIR__ . '/vendor/autoload.php';
$highlighter = new Highlighter(new ConsoleColor());
$fileContent = file_get_contents(__FILE__);
echo $highlighter->getWholeFile($fileContent);
```
------
[![Build Status](https://travis-ci.org/JakubOnderka/PHP-Console-Highlighter.svg?branch=master)](https://travis-ci.org/JakubOnderka/PHP-Console-Highlighter)
-93
View File
@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project default="build">
<!-- Set executables according to OS -->
<condition property="phpunit" value="${basedir}/vendor/bin/phpunit.bat" else="${basedir}/vendor/bin/phpunit">
<os family="windows" />
</condition>
<condition property="phpcs" value="${basedir}/vendor/bin/phpcs.bat" else="${basedir}/vendor/bin/phpcs">
<os family="windows" />
</condition>
<condition property="parallel-lint" value="${basedir}/vendor/bin/parallel-lint.bat" else="${basedir}/vendor/bin/parallel-lint">
<os family="windows" />
</condition>
<condition property="var-dump-check" value="${basedir}/vendor/bin/var-dump-check.bat" else="${basedir}/vendor/bin/var-dump-check">
<os family="windows"/>
</condition>
<!-- Use colors in output can be disabled when calling ant with -Duse-colors=false -->
<property name="use-colors" value="true" />
<condition property="colors-arg.color" value="--colors" else="">
<equals arg1="${use-colors}" arg2="true" />
</condition>
<condition property="colors-arg.no-colors" value="" else="--no-colors">
<equals arg1="${use-colors}" arg2="true" />
</condition>
<!-- Targets -->
<target name="prepare" description="Create build directory">
<mkdir dir="${basedir}/build/logs" />
</target>
<target name="phplint" description="Check syntax errors in PHP files">
<exec executable="${parallel-lint}" failonerror="true">
<arg line='--exclude ${basedir}/vendor/' />
<arg line='${colors-arg.no-colors}' />
<arg line='${basedir}' />
</exec>
</target>
<target name="var-dump-check" description="Check PHP files for forgotten variable dumps">
<exec executable="${var-dump-check}" failonerror="true">
<arg line='--exclude ${basedir}/vendor/' />
<arg line='${colors-arg.no-colors}' />
<arg line='${basedir}' />
</exec>
</target>
<target name="phpcs" depends="prepare" description="Check PHP code style">
<delete file="${basedir}/build/logs/checkstyle.xml" quiet="true" />
<exec executable="${phpcs}">
<arg line='--extensions=php' />
<arg line='--standard="${basedir}/vendor/jakub-onderka/php-code-style/ruleset.xml"' />
<arg line='--report-checkstyle="${basedir}/build/logs/checkstyle.xml"' />
<arg line='--report-full' />
<arg line='"${basedir}/src"' />
</exec>
</target>
<target name="phpunit" depends="prepare" description="PHP unit">
<delete file="${basedir}/build/logs/phpunit.xml" quiet="true" />
<exec executable="${phpunit}">
<arg line='--configuration ${basedir}/phpunit.xml' />
<arg line='-d memory_limit=256M' />
<arg line='--log-junit "${basedir}/build/logs/phpunit.xml"' />
<arg line='${colors-arg.color}' />
</exec>
</target>
<target name="phpunit-coverage" depends="prepare" description="PHP unit with code coverage">
<delete file="${basedir}/build/logs/phpunit.xml" quiet="true" />
<delete file="${basedir}/build/logs/clover.xml" quiet="true" />
<delete dir="${basedir}/build/coverage" quiet="true" />
<mkdir dir="${basedir}/build/coverage" />
<exec executable="${phpunit}" failonerror="true">
<arg line='--configuration ${basedir}/phpunit.xml' />
<arg line='-d memory_limit=256M' />
<arg line='--log-junit "${basedir}/build/logs/phpunit.xml"' />
<arg line='--coverage-clover "${basedir}/build/logs/clover.xml"' />
<arg line='--coverage-html "${basedir}/build/coverage/"' />
<arg line='${colors-arg.color}' />
</exec>
</target>
<target name="build" depends="phplint,var-dump-check,phpcs,phpunit" />
</project>
@@ -1,26 +0,0 @@
{
"name": "jakub-onderka/php-console-highlighter",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Jakub Onderka",
"email": "[email protected]",
"homepage": "http://www.acci.cz/"
}
],
"autoload": {
"psr-0": {"JakubOnderka\\PhpConsoleHighlighter": "src/"}
},
"require": {
"php": ">=5.3.0",
"jakub-onderka/php-console-color": "~0.1"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
"jakub-onderka/php-parallel-lint": "~0.5",
"jakub-onderka/php-var-dump-check": "~0.1",
"squizlabs/php_codesniffer": "~1.5",
"jakub-onderka/php-code-style": "~1.0"
}
}
@@ -1,10 +0,0 @@
<?php
use JakubOnderka\PhpConsoleColor\ConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
require __DIR__ . '/../vendor/autoload.php';
$highlighter = new Highlighter(new ConsoleColor());
$fileContent = file_get_contents(__FILE__);
echo $highlighter->getCodeSnippet($fileContent, 3);
@@ -1,10 +0,0 @@
<?php
use JakubOnderka\PhpConsoleColor\ConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
require __DIR__ . '/../vendor/autoload.php';
$highlighter = new Highlighter(new ConsoleColor());
$fileContent = file_get_contents(__FILE__);
echo $highlighter->getWholeFile($fileContent);
@@ -1,10 +0,0 @@
<?php
use JakubOnderka\PhpConsoleColor\ConsoleColor;
use JakubOnderka\PhpConsoleHighlighter\Highlighter;
require __DIR__ . '/../vendor/autoload.php';
$highlighter = new Highlighter(new ConsoleColor());
$fileContent = file_get_contents(__FILE__);
echo $highlighter->getWholeFileWithLineNumbers($fileContent);
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php">
<testsuites>
<testsuite>
<directory>tests/*</directory>
</testsuite>
</testsuites>
<!-- Ignore vendor folder for code coverage -->
<filter>
<blacklist>
<directory>vendor</directory>
</blacklist>
</filter>
</phpunit>
@@ -1,267 +0,0 @@
<?php
namespace JakubOnderka\PhpConsoleHighlighter;
use JakubOnderka\PhpConsoleColor\ConsoleColor;
class Highlighter
{
const TOKEN_DEFAULT = 'token_default',
TOKEN_COMMENT = 'token_comment',
TOKEN_STRING = 'token_string',
TOKEN_HTML = 'token_html',
TOKEN_KEYWORD = 'token_keyword';
const ACTUAL_LINE_MARK = 'actual_line_mark',
LINE_NUMBER = 'line_number';
/** @var ConsoleColor */
private $color;
/** @var array */
private $defaultTheme = array(
self::TOKEN_STRING => 'red',
self::TOKEN_COMMENT => 'yellow',
self::TOKEN_KEYWORD => 'green',
self::TOKEN_DEFAULT => 'default',
self::TOKEN_HTML => 'cyan',
self::ACTUAL_LINE_MARK => 'red',
self::LINE_NUMBER => 'dark_gray',
);
/**
* @param ConsoleColor $color
*/
public function __construct(ConsoleColor $color)
{
$this->color = $color;
foreach ($this->defaultTheme as $name => $styles) {
if (!$this->color->hasTheme($name)) {
$this->color->addTheme($name, $styles);
}
}
}
/**
* @param string $source
* @param int $lineNumber
* @param int $linesBefore
* @param int $linesAfter
* @return string
* @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
* @throws \InvalidArgumentException
*/
public function getCodeSnippet($source, $lineNumber, $linesBefore = 2, $linesAfter = 2)
{
$tokenLines = $this->getHighlightedLines($source);
$offset = $lineNumber - $linesBefore - 1;
$offset = max($offset, 0);
$length = $linesAfter + $linesBefore + 1;
$tokenLines = array_slice($tokenLines, $offset, $length, $preserveKeys = true);
$lines = $this->colorLines($tokenLines);
return $this->lineNumbers($lines, $lineNumber);
}
/**
* @param string $source
* @return string
* @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
* @throws \InvalidArgumentException
*/
public function getWholeFile($source)
{
$tokenLines = $this->getHighlightedLines($source);
$lines = $this->colorLines($tokenLines);
return implode(PHP_EOL, $lines);
}
/**
* @param string $source
* @return string
* @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
* @throws \InvalidArgumentException
*/
public function getWholeFileWithLineNumbers($source)
{
$tokenLines = $this->getHighlightedLines($source);
$lines = $this->colorLines($tokenLines);
return $this->lineNumbers($lines);
}
/**
* @param string $source
* @return array
*/
private function getHighlightedLines($source)
{
$source = str_replace(array("\r\n", "\r"), "\n", $source);
$tokens = $this->tokenize($source);
return $this->splitToLines($tokens);
}
/**
* @param string $source
* @return array
*/
private function tokenize($source)
{
$tokens = token_get_all($source);
$output = array();
$currentType = null;
$buffer = '';
foreach ($tokens as $token) {
if (is_array($token)) {
switch ($token[0]) {
case T_INLINE_HTML:
$newType = self::TOKEN_HTML;
break;
case T_COMMENT:
case T_DOC_COMMENT:
$newType = self::TOKEN_COMMENT;
break;
case T_ENCAPSED_AND_WHITESPACE:
case T_CONSTANT_ENCAPSED_STRING:
$newType = self::TOKEN_STRING;
break;
case T_WHITESPACE:
break;
case T_OPEN_TAG:
case T_OPEN_TAG_WITH_ECHO:
case T_CLOSE_TAG:
case T_STRING:
case T_VARIABLE:
// Constants
case T_DIR:
case T_FILE:
case T_METHOD_C:
case T_DNUMBER:
case T_LNUMBER:
case T_NS_C:
case T_LINE:
case T_CLASS_C:
case T_FUNC_C:
//case T_TRAIT_C:
$newType = self::TOKEN_DEFAULT;
break;
default:
// Compatibility with PHP 5.3
if (defined('T_TRAIT_C') && $token[0] === T_TRAIT_C) {
$newType = self::TOKEN_DEFAULT;
} else {
$newType = self::TOKEN_KEYWORD;
}
}
} else {
$newType = $token === '"' ? self::TOKEN_STRING : self::TOKEN_KEYWORD;
}
if ($currentType === null) {
$currentType = $newType;
}
if ($currentType != $newType) {
$output[] = array($currentType, $buffer);
$buffer = '';
$currentType = $newType;
}
$buffer .= is_array($token) ? $token[1] : $token;
}
if (isset($newType)) {
$output[] = array($newType, $buffer);
}
return $output;
}
/**
* @param array $tokens
* @return array
*/
private function splitToLines(array $tokens)
{
$lines = array();
$line = array();
foreach ($tokens as $token) {
foreach (explode("\n", $token[1]) as $count => $tokenLine) {
if ($count > 0) {
$lines[] = $line;
$line = array();
}
if ($tokenLine === '') {
continue;
}
$line[] = array($token[0], $tokenLine);
}
}
$lines[] = $line;
return $lines;
}
/**
* @param array $tokenLines
* @return array
* @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
* @throws \InvalidArgumentException
*/
private function colorLines(array $tokenLines)
{
$lines = array();
foreach ($tokenLines as $lineCount => $tokenLine) {
$line = '';
foreach ($tokenLine as $token) {
list($tokenType, $tokenValue) = $token;
if ($this->color->hasTheme($tokenType)) {
$line .= $this->color->apply($tokenType, $tokenValue);
} else {
$line .= $tokenValue;
}
}
$lines[$lineCount] = $line;
}
return $lines;
}
/**
* @param array $lines
* @param null|int $markLine
* @return string
* @throws \JakubOnderka\PhpConsoleColor\InvalidStyleException
*/
private function lineNumbers(array $lines, $markLine = null)
{
end($lines);
$lineStrlen = strlen(key($lines) + 1);
$snippet = '';
foreach ($lines as $i => $line) {
if ($markLine !== null) {
$snippet .= ($markLine === $i + 1 ? $this->color->apply(self::ACTUAL_LINE_MARK, ' > ') : ' ');
}
$snippet .= $this->color->apply(self::LINE_NUMBER, str_pad($i + 1, $lineStrlen, ' ', STR_PAD_LEFT) . '| ');
$snippet .= $line . PHP_EOL;
}
return $snippet;
}
}
@@ -1,263 +0,0 @@
<?php
namespace JakubOnderka\PhpConsoleHighlighter;
class HighlighterTest extends \PHPUnit_Framework_TestCase
{
/** @var Highlighter */
private $uut;
protected function getConsoleColorMock()
{
$mock = $this->getMock('\JakubOnderka\PhpConsoleColor\ConsoleColor');
$mock->expects($this->any())
->method('apply')
->will($this->returnCallback(function ($style, $text) {
return "<$style>$text</$style>";
}));
$mock->expects($this->any())
->method('hasTheme')
->will($this->returnValue(true));
return $mock;
}
protected function setUp()
{
$this->uut = new Highlighter($this->getConsoleColorMock());
}
protected function compare($original, $expected)
{
$output = $this->uut->getWholeFile($original);
$this->assertEquals($expected, $output);
}
public function testVariable()
{
$this->compare(
<<<EOL
<?php
echo \$a;
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_keyword>echo </token_keyword><token_default>\$a</token_default><token_keyword>;</token_keyword>
EOL
);
}
public function testInteger()
{
$this->compare(
<<<EOL
<?php
echo 43;
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_keyword>echo </token_keyword><token_default>43</token_default><token_keyword>;</token_keyword>
EOL
);
}
public function testFloat()
{
$this->compare(
<<<EOL
<?php
echo 43.3;
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_keyword>echo </token_keyword><token_default>43.3</token_default><token_keyword>;</token_keyword>
EOL
);
}
public function testHex()
{
$this->compare(
<<<EOL
<?php
echo 0x43;
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_keyword>echo </token_keyword><token_default>0x43</token_default><token_keyword>;</token_keyword>
EOL
);
}
public function testBasicFunction()
{
$this->compare(
<<<EOL
<?php
function plus(\$a, \$b) {
return \$a + \$b;
}
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_keyword>function </token_keyword><token_default>plus</token_default><token_keyword>(</token_keyword><token_default>\$a</token_default><token_keyword>, </token_keyword><token_default>\$b</token_default><token_keyword>) {</token_keyword>
<token_keyword> return </token_keyword><token_default>\$a </token_default><token_keyword>+ </token_keyword><token_default>\$b</token_default><token_keyword>;</token_keyword>
<token_keyword>}</token_keyword>
EOL
);
}
public function testStringNormal()
{
$this->compare(
<<<EOL
<?php
echo 'Ahoj světe';
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_keyword>echo </token_keyword><token_string>'Ahoj světe'</token_string><token_keyword>;</token_keyword>
EOL
);
}
public function testStringDouble()
{
$this->compare(
<<<EOL
<?php
echo "Ahoj světe";
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_keyword>echo </token_keyword><token_string>"Ahoj světe"</token_string><token_keyword>;</token_keyword>
EOL
);
}
public function testInstanceof()
{
$this->compare(
<<<EOL
<?php
\$a instanceof stdClass;
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_default>\$a </token_default><token_keyword>instanceof </token_keyword><token_default>stdClass</token_default><token_keyword>;</token_keyword>
EOL
);
}
/*
* Constants
*/
public function testConstant()
{
$constants = array(
'__FILE__',
'__LINE__',
'__CLASS__',
'__FUNCTION__',
'__METHOD__',
'__TRAIT__',
'__DIR__',
'__NAMESPACE__'
);
foreach ($constants as $constant) {
$this->compare(
<<<EOL
<?php
$constant;
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_default>$constant</token_default><token_keyword>;</token_keyword>
EOL
);
}
}
/*
* Comments
*/
public function testComment()
{
$this->compare(
<<<EOL
<?php
/* Ahoj */
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_comment>/* Ahoj */</token_comment>
EOL
);
}
public function testDocComment()
{
$this->compare(
<<<EOL
<?php
/** Ahoj */
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_comment>/** Ahoj */</token_comment>
EOL
);
}
public function testInlineComment()
{
$this->compare(
<<<EOL
<?php
// Ahoj
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_comment>// Ahoj</token_comment>
EOL
);
}
public function testHashComment()
{
$this->compare(
<<<EOL
<?php
# Ahoj
EOL
,
<<<EOL
<token_default><?php</token_default>
<token_comment># Ahoj</token_comment>
EOL
);
}
public function testEmpty()
{
$this->compare(
''
,
''
);
}
}
@@ -1,2 +0,0 @@
<?php
$loader = require_once __DIR__ . '/../vendor/autoload.php';
@@ -1,2 +0,0 @@
/vendor
composer.lock
-26
View File
@@ -1,26 +0,0 @@
language: php
php:
- 5.3.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
sudo: false
cache:
directories:
- vendor
- $HOME/.composer/cache
before_script:
- composer self-update
- composer install --no-interaction --prefer-source --dev
- composer require jakub-onderka/php-console-highlighter 0.3
script:
- ./vendor/bin/tester -p php tests
- ./parallel-lint --exclude vendor --exclude tests/examples --no-colors .
- ./parallel-lint --exclude vendor --exclude tests/examples .
-26
View File
@@ -1,26 +0,0 @@
Copyright (c) 2012, Jakub Onderka
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
-93
View File
@@ -1,93 +0,0 @@
# PHP Parallel Lint
This tool check syntax of PHP files faster then serial check with fancier output.
Running parallel jobs in PHP inspired by Nette framework tests.
## Install
Just create a `composer.json` file and run the `php composer.phar install` command to install it:
```json
{
"require-dev": {
"jakub-onderka/php-parallel-lint": "0.*"
}
}
```
For colored output install suggested package `jakub-onderka/php-console-highlighter`. After a `composer.json` file include:
```json
{
"require-dev": {
"jakub-onderka/php-parallel-lint": "0.*",
"jakub-onderka/php-console-highlighter": "0.*"
}
}
```
## Example output
![Alt text](/tests/examples/example-images/use-error.png?raw=true "Example use of tool with error")
## Options for run
- `-p <php>` Specify PHP-CGI executable to run (default: 'php').
- `-s, --short` Set short_open_tag to On (default: Off).
- `-a, -asp` Set asp_tags to On (default: Off).
- `-e <ext>` Check only files with selected extensions separated by comma. (default: php,php3,php4,php5,phtml)
- `--exclude` Exclude directory. If you want exclude multiple directories, use multiple exclude parameters.
- `-j <num>` Run <num> jobs in parallel (default: 10).
- `--no-colors` Disable colors in console output.
- `--json` Output results as JSON string (require PHP 5.4).
- `--blame` Try to show git blame for row with error.
- `--git <git>` Path to Git executable to show blame message (default: 'git').
- `--stdin` Load files and folder to test from standard input.
- `--ignore-fails` Ignore failed tests.
- `-h, --help` Print this help.
## Recommended setting for usage with Symfony framework
For run from command line:
```
$ ./bin/parallel-lint --exclude app --exclude vendor .
```
or setting for ANT:
```xml
<condition property="parallel-lint" value="${basedir}/bin/parallel-lint.bat" else="${basedir}/bin/parallel-lint">
<os family="windows"/>
</condition>
<target name="parallel-lint" description="Run PHP parallel lint">
<exec executable="${parallel-lint}" failonerror="true">
<arg line="--exclude" />
<arg path="${basedir}/app/" />
<arg line="--exclude" />
<arg path="${basedir}/vendor/" />
<arg path="${basedir}" />
</exec>
</target>
```
## Create Phar package
PHP Parallel Lint supports [Box app](https://box-project.github.io/box2/) for creating Phar package. First, install box app:
```
curl -LSs https://box-project.github.io/box2/installer.php | php
```
and then run this command in parallel lint folder, which creates `parallel-lint.phar` file.
```
box build
```
------
[![Downloads this Month](https://img.shields.io/packagist/dm/jakub-onderka/php-parallel-lint.svg)](https://packagist.org/packages/jakub-onderka/php-parallel-lint)
[![Build Status](https://travis-ci.org/JakubOnderka/PHP-Parallel-Lint.svg?branch=master)](https://travis-ci.org/JakubOnderka/PHP-Parallel-Lint)
[![Build status](https://ci.appveyor.com/api/projects/status/5n3qqa3r66aoghjo/branch/master?svg=true)](https://ci.appveyor.com/project/JakubOnderka/php-parallel-lint/branch/master)
[![License](https://poser.pugx.org/jakub-onderka/php-parallel-lint/license.svg)](https://packagist.org/packages/jakub-onderka/php-parallel-lint)

Some files were not shown because too many files have changed in this diff Show More