PK sūzNg_Ķxß ß .travis.ymlnu W+Aķ language: php
matrix:
include:
- php: 7.1
env:
- ENABLE_XDEBUG=true
- php: 7.1
env:
- ENABLE_DEVTOOLS=true
- php: nightly
allow_failures:
- php: nightly
fast_finish: true
os:
- linux
notifications:
irc: "chat.freenode.net#hoaproject"
sudo: false
env:
global:
- secure: "AAAAB3NzaC1yc2EAAAADAQABAAACAQDIf0Rf76Hhkflz5b9UzWjOjk4UlMU5ySk0VY3B4WdHDLWMMK7fBp1Aj9qXWEDwkuX/NbQP1gB8jQNo7i5uZEOfu7Mn2svPkBBtnmKmaJhk90xypM4lcpcdPi4e8kXUgkriNQLQ2bRe1qZIeF115FkuIvActq7iWKY1TVSZbO54cDKMifDZfH09cf4vpwrZJqwZG6PUnUcCYijgDy99HtfRvzf9xalO4yWm55ZEbJ/VNTHlq1EhK73QLdHC7MO+OQFcd5wEyMbNxBj/bDn/udgb0HsrDijComTg/oTdQJMspYDQYV3ZYvpGozTTCVQrVTYYTP9RCNstgJLHDv9fZZW6yRlw4yNsT7jIQRLs/7awTxOAvRlxqaxk0//ECVNhDgawVtlbEIKrqnM1N7QTm0gjE0HkWEzxE0QbgoZqlLFD6qCp6WVvIT3uGY/i4TkVy78wf3/fzCKbrf72kYSbxIOCxVtptOmrgAblNEpiA/uZ9IofR2p2iwiVY1xF/mzxV2M4zCw6WASrlDhkaL0IncEdRtBuV2WTpixmtjmNkE9h/90kzb5cKExU786gZmvyflYvqlNlcMo3dNsDnROjQCAUXGBw5+risdqTT295BGmlEdZUtcf0c6/zEGhR8B7CktWYLSgOL5mpGMVNEBzyzEwnIiWCvI3pGgoV3Z9UzSJWKQ=="
cache:
directories:
- vendor/
before_script:
- export PATH="$PATH:$HOME/.composer/vendor/bin"
- if [[ ! $ENABLE_XDEBUG ]]; then
phpenv config-rm xdebug.ini || echo "ext-xdebug is not available, cannot remove it.";
fi
script:
- composer install
- vendor/bin/hoa test:run
- if [[ $ENABLE_DEVTOOLS ]]; then
composer global require friendsofphp/php-cs-fixer;
vendor/bin/hoa devtools:cs --diff --dry-run .;
fi
PK sūzNũp% p% README.mdnu W+Aķ
---
Hoa is a modular, extensible and
structured set of PHP libraries.
Moreover, Hoa aims at being a bridge between industrial and research worlds.
# Hoa\Consistency
[![Help on IRC](https://img.shields.io/badge/help-%23hoaproject-ff0066.svg)](https://webchat.freenode.net/?channels=#hoaproject)
[![Help on Gitter](https://img.shields.io/badge/help-gitter-ff0066.svg)](https://gitter.im/hoaproject/central)
[![Documentation](https://img.shields.io/badge/documentation-hack_book-ff0066.svg)](https://central.hoa-project.net/Documentation/Library/Consistency)
[![Board](https://img.shields.io/badge/organisation-board-ff0066.svg)](https://waffle.io/hoaproject/consistency)
This library provides a thin layer between PHP VMs and libraries to ensure
consistency accross VM versions and library versions.
[Learn more](https://central.hoa-project.net/Documentation/Library/Consistency).
## Installation
With [Composer](https://getcomposer.org/), to include this library into
your dependencies, you need to
require [`hoa/consistency`](https://packagist.org/packages/hoa/consistency):
```sh
$ composer require hoa/consistency '~2.0'
```
For more installation procedures, please read [the Source
page](https://hoa-project.net/Source.html).
## Testing
Before running the test suites, the development dependencies must be installed:
```sh
$ composer install
```
Then, to run all the test suites:
```sh
$ vendor/bin/hoa test:run
```
For more information, please read the [contributor
guide](https://hoa-project.net/Literature/Contributor/Guide.html).
## Quick usage
We propose a quick overview of how the consistency API ensures foreward and
backward compatibility, also an overview of the [PSR-4
autoloader](http://www.php-fig.org/psr/psr-4/) and the xcallable API.
### Foreward and backward compatibility
The `Hoa\Consistency\Consistency` class ensures foreward and backward
compatibility.
#### Example with keywords
The `Hoa\Consistency\Consistency::isKeyword` checks whether a specific word is
reserved by PHP or not. Let's say your current PHP version does not support the
`callable` keyword or type declarations such as `int`, `float`, `string` etc.,
the `isKeyword` method will tell you if they are reserved keywords: Not only
for your current PHP version, but maybe in an incoming version.
```php
$isKeyword = Hoa\Consistency\Consistency::isKeyword('yield');
```
It avoids to write algorithms that might break in the future or for your users
living on the edge.
#### Example with identifiers
PHP identifiers are defined by a regular expression. It might change in the
future. To prevent breaking your algorithms, you can use the
`Hoa\Consistency\Consistency::isIdentifier` method to check an identifier is
correct regarding current PHP version:
```php
$isValidIdentifier = Hoa\Consistency\Consistency::isIdentifier('foo');
```
#### Flexible entities
Flexible entities are very simple. If we declare `Foo\Bar\Bar` as a flexible
entity, we will be able to access it with the `Foo\Bar\Bar` name or `Foo\Bar`.
This is very useful if your architecture evolves but you want to keep the
backward compatibility. For instance, it often happens that you create a
`Foo\Bar\Exception` class in the `Foo/Bar/Exception.php` file. But after few
versions, you realise other exceptions need to be introduced, so you need an
`Exception` directory. In this case, `Foo\Bar\Exception` should move as
`Foo\Bar\Exception\Exception`. If this latter is declared as a flexible entity,
backward compatibility will be kept.
```php
Hoa\Consistency\Consistency::flexEntity('Foo\Bar\Exception\Exception');
```
Another example is the âentry-classâ (informal naming).
`Hoa\Consistency\Consistency` is a good example. This is more convenient to
write `Hoa\Consistency` instead of `Hoa\Consistency\Consistency`. This is
possible because this is a flexible entity.
#### Throwable & co.
The `Throwable` interface has been introduced to represent a whole new exception
architecture in PHP. Thus, to be compatible with incoming PHP versions, you
might want to use this interface in some cases. Hopefully, the `Throwable`
interface will be created for you if it does not exists.
```php
try {
âĶ
} catch (Throwable $e) {
âĶ
}
```
### Autoloader
`Hoa\Consistency\Autoloader` is a [PSR-4
compatible](http://www.php-fig.org/psr/psr-4/) autoloader. It simply works as
follows:
* `addNamespace` is used to map a namespace prefix to a directory,
* `register` is used to register the autoloader.
The API also provides the `load` method to force the load of an entity,
`unregister` to unregister the autoloader, `getRegisteredAutoloaders` to get
a list of all registered autoloaders etc.
For instance, to map the `Foo\Bar` namespace to the `Source/` directory:
```php
$autoloader = new Hoa\Consistency\Autoloader();
$autoloader->addNamespace('Foo\Bar', 'Source');
$autoloader->register();
$baz = new Foo\Bar\Baz(); // automatically loaded!
```
### Xcallable
Xcallables are âextended callablesâ. It is a unified API to invoke callables of
any kinds, and also extends some Hoa's API (like
[`Hoa\Event`](https://central.hoa-project.net/Resource/Library/Event)
or
[`Hoa\Stream`](https://central.hoa-project.net/Resource/Library/Stream)). It
understands the following kinds:
* `'function'` as a string,
* `'class::method'` as a string,
* `'class', 'method'` as 2Â string arguments,
* `$object, 'method'` as 2Â arguments,
* `$object, ''` as 2Â arguments, the âableâ is unknown,
* `function (âĶ) { âĶ }` as a closure,
* `['class', 'method']` as an array of strings,
* `[$object, 'method']` as an array.
To use it, simply instanciate the `Hoa\Consistency\Xcallable` class and use it
as a function:
```php
$xcallable = new Hoa\Consistency\Xcallable('strtoupper');
var_dump($xcallable('foo'));
/**
* Will output:
* string(3) "FOO"
*/
```
The `Hoa\Consistency\Xcallable::distributeArguments` method invokes the callable
but the arguments are passed as an array:
```php
$xcallable->distributeArguments(['foo']);
```
This is also possible to get a unique hash of the callable:
```php
var_dump($xcallable->getHash());
/**
* Will output:
* string(19) "function#strtoupper"
*/
```
Finally, this is possible to get a reflection instance of the current callable
(can be of kind [`ReflectionFunction`](http://php.net/ReflectionFunction),
[`ReflectionClass`](http://php.net/ReflectionClass),
[`ReflectionMethod`](http://php.net/ReflectionMethod) or
[`ReflectionObject`](http://php.net/ReflectionObject)):
```php
var_dump($xcallable->getReflection());
/**
* Will output:
* object(ReflectionFunction)#42 (1) {
* ["name"]=>
* string(10) "strtoupper"
* }
*/
```
When the object is set but not the method, the latter will be deduced if
possible. If the object is of kind
[`Hoa\Stream`](http://central.hoa-project.net/Resource/Library/Stream), then
according to the type of the arguments given to the callable, the
`writeInteger`, `writeString`, `writeArray` etc. method will be used. If the
argument is of kind `Hoa\Event\Bucket`, then the method name will be deduced
based on the data contained inside the event bucket. This is very handy. For
instance, the following example will work seamlessly:
```php
Hoa\Event\Event::getEvent('hoa://Event/Exception')
->attach(new Hoa\File\Write('Exceptions.log'));
```
The `attach` method on `Hoa\Event\Event` transforms its argument as an
xcallable. In this particular case, the method to call is unknown, we only have
an object (of kind `Hoa\File\Write`). However, because this is a stream, the
method will be deduced according to the data contained in the event bucket fired
on the `hoa://Event/Exception` event channel.
## Documentation
The
[hack book of `Hoa\Consistency`](https://central.hoa-project.net/Documentation/Library/Consistency)
contains detailed information about how to use this library and how it works.
To generate the documentation locally, execute the following commands:
```sh
$ composer require --dev hoa/devtools
$ vendor/bin/hoa devtools:documentation --open
```
More documentation can be found on the project's website:
[hoa-project.net](https://hoa-project.net/).
## Getting help
There are mainly two ways to get help:
* On the [`#hoaproject`](https://webchat.freenode.net/?channels=#hoaproject)
IRC channel,
* On the forum at [users.hoa-project.net](https://users.hoa-project.net).
## Contribution
Do you want to contribute? Thanks! A detailed [contributor
guide](https://hoa-project.net/Literature/Contributor/Guide.html) explains
everything you need to know.
## License
Hoa is under the New BSD License (BSD-3-Clause). Please, see
[`LICENSE`](https://hoa-project.net/LICENSE) for details.
PK sūzNÅ0
.gitignorenu W+Aķ /vendor/
/composer.lock
PK sūzNT*Jï+ ï+ Source/Autoloader.phpnu W+Aķ addNamespace($prefix, $baseDirectoryA); // append
* $autoloader->addNamespace($prefix, $baseDirectoryB, true); // prepend
*
* assert($autoloader->hasBaseDirectory($prefix));
* assert($autoloader->getBaseDirectories($prefix) === [$baseDirectoryB, $baseDirectoryA]);
* ```
*
* Note the position of the base directories: First `B`, second `A`.
*/
public function addNamespace(string $prefix, string $baseDirectory, bool $prepend = false): void
{
$prefix = trim($prefix, '\\') . '\\';
$baseDirectory = rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
if (false === isset($this->_namespacePrefixesToBaseDirectories[$prefix])) {
$this->_namespacePrefixesToBaseDirectories[$prefix] = [];
}
if (true === $prepend) {
array_unshift(
$this->_namespacePrefixesToBaseDirectories[$prefix],
$baseDirectory
);
} else {
array_push(
$this->_namespacePrefixesToBaseDirectories[$prefix],
$baseDirectory
);
}
}
/**
* Try to load the entity file for a given entity name.
*
* For a given entity `E`, this method will try to find at least one base
* directory for its longest to shortest namespace prefix (if `E` is
* `X\Y\Z`, then from `X\Y\Z`, to `X\Y`, to `X`). If one is found, then
* the entity name `E` is mapped into a filename. If it exists, it is
* immediately loaded.
*
* # Examples
*
* The `Foo\Bar\Baz\Qux` entity is expected to be found in the
* `Source/Foo/Bar/Baz/Qux.php` file. This file will be loaded if it exists.
*
* ```php,ignore
* $autoloader = new Hoa\Consistency\Autoloader();
* $autoloader->addNamespace('Foo\Bar\\', 'Source/Foo/Bar/');
*
* $autoloader->load('Foo\Bar\Baz\Qux');
* ```
*/
public function load(string $entity): ?string
{
$entityPrefix = $entity;
$hasBaseDirectory = false;
while (false !== $pos = strrpos($entityPrefix, '\\')) {
$currentEntityPrefix = substr($entity, 0, $pos + 1);
$entityPrefix = rtrim($currentEntityPrefix, '\\');
$entitySuffix = substr($entity, $pos + 1);
$entitySuffixAsPath = str_replace('\\', '/', $entitySuffix);
if (false === $this->hasBaseDirectory($currentEntityPrefix)) {
continue;
}
$hasBaseDirectory = true;
foreach ($this->getBaseDirectories($currentEntityPrefix) as $baseDirectory) {
$file = $baseDirectory . $entitySuffixAsPath . '.php';
if (false !== $this->requireFile($file)) {
return $file;
}
}
}
if (true === $hasBaseDirectory &&
$entity === Consistency::getEntityShortestName($entity) &&
false !== $pos = strrpos($entity, '\\')) {
return $this->runAutoloaderStack(
$entity . '\\' . substr($entity, $pos + 1)
);
}
return null;
}
/**
* Requires a file and returns `true` if it exists, otherwise returns
* `false`.
*
* # Examples
*
* ```php,ignore
* $autoloader = new Hoa\Consistency\Autoloader();
* $autoloader->requireFile('Source/Foo/Bar/Baz/Qux.php');
* ```
*/
public function requireFile(string $filename): bool
{
if (false === file_exists($filename)) {
return false;
}
require $filename;
return true;
}
/**
* A namespace prefix has a base directory if at least one has been
* declared with the `addNamespace` method.
*
* # Examples
*
* ```php
* $autoloader = new Hoa\Consistency\Autoloader();
* $autoloader->addNamespace('Foo\Bar\\', 'Source/Foo/Bar/');
*
* assert(true === $autoloader->hasBaseDirectory('Foo\Bar\\'));
* assert(false === $autoloader->hasBaseDirectory('Baz\Qux\\'));
* ```
*/
public function hasBaseDirectory(string $namespacePrefix): bool
{
return isset($this->_namespacePrefixesToBaseDirectories[$namespacePrefix]);
}
/**
* Returns the collection of declared base directories for a namespace
* prefix.
*
* # Examples
*
* ```php
* $prefix = 'Foo\Bar\\';
* $baseDirectoryA = 'Source/Foo/Bar/';
* $baseDirectoryB = 'Source/Foo/Baz/';
*
* $autoloader = new Hoa\Consistency\Autoloader();
* $autoloader->addNamespace($prefix, $baseDirectoryA);
* $autoloader->addNamespace($prefix, $baseDirectoryB);
*
* assert($autoloader->getBaseDirectories($prefix) === [$baseDirectoryA, $baseDirectoryB]);
* ```
*/
public function getBaseDirectories(string $namespacePrefix): array
{
if (false === $this->hasBaseDirectory($namespacePrefix)) {
return [];
}
return $this->_namespacePrefixesToBaseDirectories[$namespacePrefix];
}
/**
* Returns all the classes that are loaded for this runtime.
*
* # Examples
*
* ```php
* assert(in_array(__CLASS__, Hoa\Consistency\Autoloader::getLoadedClasses()));
* ```
*/
public static function getLoadedClasses(): array
{
return get_declared_classes();
}
/**
* Calls *all* the registered autoloaders with a specific entity.
*
* In other words, try to load an entity by using all the registered
* autoloaders, not only instances of `Hoa\Consistency\Autoloaders`.
*
* # Examples
*
* ```php
* $autoloader = new Hoa\Consistency\Autoloader();
* $autoloader->runAutoloaderStack('Foo\Bar\Baz');
* ```
*/
public function runAutoloaderStack(string $entity): void
{
spl_autoload_call($entity);
}
/**
* Registers this autoloader instance.
*
* Because the autoloader register is a stack, a new autoloader is
* appended. It is possible to prepend it by using the last paramter.
*
* # Examples
*
* ```php
* assert((new Hoa\Consistency\Autoloader())->register());
* ```
*
* The `addNamespace` method can be called before or after the
* registration, it does not matter.
*/
public function register(bool $prepend = false): bool
{
return spl_autoload_register([$this, 'load'], true, $prepend);
}
/**
* Unregisters this autoloader instance.
*
* # Examples
*
* ```php
* $autoloader = new Hoa\Consistency\Autoloader();
* $autoloader->register();
*
* assert($autoloader->unregister());
* ```
*/
public function unregister(): bool
{
return spl_autoload_unregister([$this, 'load']);
}
/**
* Returns a copy of the autoloader stack.
*
* Each autoloader in this copy has the form of a callback, i.e. a pair `[instance, method name]`.
*
* # Examples
*
* ```php
* $autoloader = new Hoa\Consistency\Autoloader();
* $autoloader->register();
*
* assert(in_array([$autoloader, 'load'], $autoloader->getRegisteredAutoloaders()));
* ```
*/
public function getRegisteredAutoloaders(): array
{
return spl_autoload_functions();
}
/**
* Allocates a new entity based on its name and a list of arguments.
*
* The entity will be automatically loaded if needed. If a constructor is
* present, it will be called with the list of arguments.
*
* # Examples
*
* ```php
* $name = 'ArrayIterator';
* $arguments = [['a', 'b', 'c']];
* $iterator = Hoa\Consistency\Autoloader::dnew($name, $arguments);
*
* assert($iterator instanceof $name);
* ```
*/
public static function dnew(string $classname, array $arguments = [])
{
$classname = ltrim($classname, '\\');
if (false === Consistency::entityExists($classname, false)) {
spl_autoload_call($classname);
}
$class = new \ReflectionClass($classname);
if (empty($arguments) || false === $class->hasMethod('__construct')) {
return $class->newInstance();
}
return $class->newInstanceArgs($arguments);
}
}
/**
* Autoloader.
*/
$autoloader = new Autoloader();
$autoloader->addNamespace('Hoa', dirname(__DIR__, 2));
$autoloader->register();
PK sūzN ąā
Source/Prelude.phpnu W+Aķ = $count) {
return $entityName;
}
if ($parts[$count - 2] === $parts[$count - 1]) {
return implode('\\', array_slice($parts, 0, -1));
}
return $entityName;
}
/**
* Declares a flexible entity.
*
* A flexible entity can be referenced with 2 names: Its normal name, and
* its shortest name (see `getEntityShortestName`).
*
* # Examples
*
* ```php,ignore
* Hoa\Consistency\Consistency::flexEntity(Foo\Bar\Bar::class);
*
* // `new Foo\Bar()` will work!
* ```
*/
public static function flexEntity(string $entityName): bool
{
return class_alias(
$entityName,
static::getEntityShortestName($entityName),
false
);
}
/**
* Returns `true` if the given word is a reserved keyword of PHP (based on
* the latest version), otherwise returns `false`.
*
* # Examples
*
* ```php
* assert(true === Hoa\Consistency\Consistency::isKeyword('else'));
* assert(false === Hoa\Consistency\Consistency::isKeyword('otherwise'));
* ```
*/
public static function isKeyword(string $word): bool
{
static $_list = [
// PHP keywords.
'__halt_compiler',
'abstract',
'and',
'array',
'as',
'bool',
'break',
'callable',
'case',
'catch',
'class',
'clone',
'const',
'continue',
'declare',
'default',
'die',
'do',
'echo',
'else',
'elseif',
'empty',
'enddeclare',
'endfor',
'endforeach',
'endif',
'endswitch',
'endwhile',
'eval',
'exit',
'extends',
'false',
'final',
'float',
'for',
'foreach',
'function',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'int',
'interface',
'isset',
'list',
'mixed',
'namespace',
'new',
'null',
'numeric',
'object',
'or',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'resource',
'return',
'static',
'string',
'switch',
'throw',
'trait',
'true',
'try',
'unset',
'use',
'var',
'void',
'while',
'xor',
'yield',
// Compile-time constants.
'__class__',
'__dir__',
'__file__',
'__function__',
'__line__',
'__method__',
'__namespace__',
'__trait__'
];
return in_array(strtolower($word), $_list);
}
/**
* Returns `true` if the given identifier is a valid PHP identifier (based on
* the latest version), otherwise returns `false`.
*
* # Examples
*
* ```php
* assert(true === Hoa\Consistency\Consistency::isIdentifier('hello'));
* assert(false === Hoa\Consistency\Consistency::isIdentifier('world!'));
* ```
*/
public static function isIdentifier(string $id): bool
{
return 0 !== preg_match(
'#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x80-\xff]*$#',
$id
);
}
/**
* Registers a [register shutdown function](http://php.net/register_shutdown_function).
*
* It may be analogous to a super static destructor.
*
* # Examples
*
* ```php
* Hoa\Consistency\Consistency::registerShutdownFunction(
* function (): void {
* echo 'Bye bye!', "\n";
* }
* );
* ```
*/
public static function registerShutdownFunction(callable $callable): void
{
register_shutdown_function($callable);
}
/**
* Returns the absolute path to the PHP binary, or `null` if the method is
* not able to find it.
*/
public static function getPHPBinary(): ?string
{
if (defined('PHP_BINARY')) {
return PHP_BINARY;
}
if (isset($_SERVER['_'])) {
return $_SERVER['_'];
}
foreach (['', '.exe'] as $extension) {
if (file_exists($_ = PHP_BINDIR . DS . 'php' . $extension)) {
return realpath($_);
}
}
return null;
}
/**
* Generates a [Universally Unique
* Identifier](https://en.wikipedia.org/wiki/Universally_unique_identifier)
* (UUID).
*
* # Examples
*
* ```php
* $uuid = Hoa\Consistency\Consistency::uuid();
*
* assert(preg_match('/[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}/', $uuid));
* ```
*/
public static function uuid(): string
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0xffff)
);
}
}
/**
* Curry a function with the ââĶâ character (HORIZONTAL ELLIPSIS Unicode
* character [unicode: 2026, UTF-8: E2 80 A6]).
*
* Obviously, because the first argument is a callable, it is possible to combine it with
* `Hoa\Consistency\Xcallable`.
*
* # Examples
*
* ```php
* $replaceInFoobar = curry('str_replace', âĶ, âĶ, 'foobar');
* $replaceFooByBazIn = curry('str_replace', 'foo', 'baz', âĶ);
*
* assert('bazbar' === $replaceInFoobar('foo', 'baz'));
* assert('bazbarbaz' === $replaceFooByBazIn('foobarbaz'));
* ```
*
* Nested curries also work:
*
* ```php
* $replaceInFoobar = curry('str_replace', âĶ, âĶ, 'foobar');
* $replaceFooInFoobarBy = curry($replaceInFoobar, 'foo', âĶ);
*
* assert('bazbar' === $replaceFooInFoobarBy('baz'));
* ```
*/
function curry(callable $callable, ...$arguments): Closure
{
$ii = array_keys($arguments, âĶ, true);
return function (...$subArguments) use ($callable, $arguments, $ii) {
return $callable(...array_replace($arguments, array_combine($ii, $subArguments)));
};
}
/**
* Flex entity.
*/
Consistency::flexEntity(Consistency::class);
PK sūzN
ÂŪ " " Source/Xcallable.phpnu W+Aķ method` or
* closure. They all have the same behaviour. This callable is an extension of
* native PHP callable (aka callback) to integrate Hoa's structures.
*/
class Xcallable
{
/**
* Callback with the PHP format.
*/
protected $_callback = null;
/**
* Callable hash.
*/
protected $_hash = null;
/**
* Allocates a xcallable based on a callback.
*
* Accepted forms:
* * `'function'`,
* * `'class::method'`,
* * `'class', 'method'`,
* * `$object, 'method'`,
* * `$object, ''`,
* * `function (âĶ) { âĶ }`,
* * `['class', 'method']`,
* * `[$object, 'method']`.
*
* # Examples
*
* ```php
* $toUpper = new Hoa\Consistency\Xcallable('strtoupper');
* assert('FOO' === $toUpper('foo'));
* ```
*
* # Exceptions
*
* A `Hoa\Consistency\Exception` exception is thrown if the callback form
* is invalid.
*
* ```php,must_throw(Hoa\Consistency\Exception)
* new Hoa\Consistency\Xcallable('Foo:');
* ```
*/
public function __construct($call, $able = '')
{
if ($call instanceof \Closure) {
$this->_callback = $call;
return;
}
if (!is_string($able)) {
throw new Exception(
'Bad callback form; the able part must be a string.',
0
);
}
if ('' === $able) {
if (is_string($call)) {
if (false === strpos($call, '::')) {
if (!function_exists($call)) {
throw new Exception(
'Bad callback form; function %s does not exist.',
1,
$call
);
}
$this->_callback = $call;
return;
}
list($call, $able) = explode('::', $call);
} elseif (is_object($call)) {
if ($call instanceof Stream\IStream\Out) {
$able = null;
} elseif (method_exists($call, '__invoke')) {
$able = '__invoke';
} else {
throw new Exception(
'Bad callback form; an object but without a known ' .
'method.',
2
);
}
} elseif (is_array($call) && isset($call[0])) {
if (!isset($call[1])) {
return $this->__construct($call[0]);
}
return $this->__construct($call[0], $call[1]);
} else {
throw new Exception(
'Bad callback form.',
3
);
}
}
$this->_callback = [$call, $able];
return;
}
/**
* Calls the callable.
*/
public function __invoke(...$arguments)
{
$callback = $this->getValidCallback($arguments);
return $callback(...$arguments);
}
/**
* Distributes arguments according to an array.
*/
public function distributeArguments(array $arguments)
{
return $this->__invoke(...$arguments);
}
/**
* Returns a valid PHP callback.
*/
public function getValidCallback(array &$arguments = [])
{
$callback = $this->_callback;
$head = null;
if (isset($arguments[0])) {
$head = &$arguments[0];
}
// If method is undetermined, we find it (we understand event bucket and
// stream).
if (null !== $head &&
is_array($callback) &&
null === $callback[1]) {
if ($head instanceof Event\Bucket) {
$head = $head->getData();
}
switch ($type = gettype($head)) {
case 'string':
if (1 === strlen($head)) {
$method = 'writeCharacter';
} else {
$method = 'writeString';
}
break;
case 'boolean':
case 'integer':
case 'array':
$method = 'write' . ucfirst($type);
break;
case 'double':
$method = 'writeFloat';
break;
default:
$method = 'writeAll';
$head = $head . "\n";
}
$callback[1] = $method;
}
return $callback;
}
/**
* Computes the hash of this callable.
*
* Will produce:
* * `function#âĶ`,
* * `class#âĶ::âĶ`,
* * `object(âĶ)#âĶ::âĶ`,
* * `closure(âĶ)`.
*/
public function getHash(): string
{
if (null !== $this->_hash) {
return $this->_hash;
}
$_ = &$this->_callback;
if (is_string($_)) {
return $this->_hash = 'function#' . $_;
}
if (is_array($_)) {
return
$this->_hash =
(is_object($_[0])
? 'object(' . spl_object_hash($_[0]) . ')' .
'#' . get_class($_[0])
: 'class#' . $_[0]) .
'::' .
(null !== $_[1]
? $_[1]
: '???');
}
return $this->_hash = 'closure(' . spl_object_hash($_) . ')';
}
/**
* Returns the appropriated reflection instance.
*/
public function getReflection(...$arguments): Reflector
{
$callback = $this->getValidCallback($arguments);
if (is_string($callback)) {
return new ReflectionFunction($callback);
}
if ($callback instanceof \Closure) {
return new ReflectionFunction($callback);
}
if (is_array($callback)) {
if (is_string($callback[0])) {
if (false === method_exists($callback[0], $callback[1])) {
return new ReflectionClass($callback[0]);
}
return new ReflectionMethod($callback[0], $callback[1]);
}
$object = new ReflectionObject($callback[0]);
if (null === $callback[1]) {
return $object;
}
return $object->getMethod($callback[1]);
}
}
/**
* The string representation of a callable is its hash.
*/
public function __toString(): string
{
return $this->getHash();
}
}
PK sūzN*Ãn Source/Exception.phpnu W+Aķ given(
$autoloader = new SUT(),
$prefix = 'Foo\Bar\\',
$baseDirectoryA = 'Source/Foo/Bar/',
$baseDirectoryB = 'Source/Foo/Baz/'
)
->when(
$autoloader->addNamespace($prefix, $baseDirectoryA),
$result = $autoloader->addNamespace($prefix, $baseDirectoryB, true)
)
->then
->boolean($autoloader->hasBaseDirectory($prefix))
->isTrue()
->array($autoloader->getBaseDirectories($prefix))
->isEqualTo([
$baseDirectoryB,
$baseDirectoryA
]);
}
public function case_add_namespace_append(): void
{
$this
->given(
$autoloader = new SUT(),
$prefix = 'Foo\Bar\\',
$baseDirectoryA = 'Source/Foo/Bar/',
$baseDirectoryB = 'Source/Foo/Baz/'
)
->when(
$autoloader->addNamespace($prefix, $baseDirectoryA),
$result = $autoloader->addNamespace($prefix, $baseDirectoryB)
)
->then
->boolean($autoloader->hasBaseDirectory($prefix))
->isTrue()
->array($autoloader->getBaseDirectories($prefix))
->isEqualTo([
$baseDirectoryA,
$baseDirectoryB
]);
}
public function case_add_namespace_with_invalid_prefix(): void
{
$this
->given(
$autoloader = new SUT(),
$prefix = '\\\\Foo\Bar',
$baseDirectory = 'Source/Foo/Bar/'
)
->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
->then
->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
->isTrue()
->array($autoloader->getBaseDirectories('Foo\Bar\\'))
->isEqualTo([$baseDirectory]);
}
public function case_add_namespace_with_invalid_base_directory(): void
{
$this
->given(
$autoloader = new SUT(),
$prefix = 'Foo\Bar\\',
$baseDirectory = 'Source/Foo/Bar'
)
->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
->then
->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
->isTrue()
->array($autoloader->getBaseDirectories('Foo\Bar\\'))
->isEqualTo(['Source/Foo/Bar/']);
}
public function case_add_namespace_with_crazy_invalid_base_directory(): void
{
$this
->given(
$autoloader = new SUT(),
$prefix = 'Foo\Bar\\',
$baseDirectory = 'Source/Foo/Bar/////'
)
->when($result = $autoloader->addNamespace($prefix, $baseDirectory))
->then
->boolean($autoloader->hasBaseDirectory('Foo\Bar\\'))
->isTrue()
->array($autoloader->getBaseDirectories('Foo\Bar\\'))
->isEqualTo(['Source/Foo/Bar/']);
}
public function case_load(): void
{
$this
->given(
$autoloader = new \Mock\Hoa\Consistency\Autoloader(),
$autoloader->addNamespace('Foo\Bar\\', 'Source/Foo/Bar/'),
$this->calling($autoloader)->requireFile = function ($file) {
return $file;
}
)
->when($result = $autoloader->load('Foo\Bar\Baz\Qux'))
->then
->string($result)
->isEqualTo('Source/Foo/Bar/Baz/Qux.php');
}
public function case_load_invalid_entity(): void
{
$this
->given($autoloader = new SUT())
->when($result = $autoloader->load('Foo'))
->then
->variable($result)
->isNull();
}
public function case_load_flex_entity(): void
{
$self = $this;
$this
->given(
$autoloader = new \Mock\Hoa\Consistency\Autoloader(),
$autoloader->addNamespace('Foo\Bar\\', 'Source/Foo/'),
$this->calling($autoloader)->runAutoloaderStack = function ($entity) use ($self, &$called): void {
$called = true;
$self
->string($entity)
->isEqualTo('Foo\Bar\Baz\Baz');
return;
},
$autoloader->register()
)
->when($result = $autoloader->load('Foo\Bar\Baz'))
->then
->variable($result)
->isNull()
->boolean($called)
->isTrue();
}
public function case_load_unmapped_flex_entity(): void
{
$self = $this;
$this
->given(
$autoloader = new \Mock\Hoa\Consistency\Autoloader(),
$this->calling($autoloader)->runAutoloaderStack = function ($entity) use ($self, &$called): void {
$called = true;
return;
},
$autoloader->register()
)
->when($result = $autoloader->load('Foo\Bar\Baz'))
->then
->variable($result)
->isNull()
->variable($called)
->isNull();
}
public function case_require_existing_file(): void
{
$this
->given(
$autoloader = new SUT(),
$this->function->file_exists = true,
$constantName = 'HOA_TEST_' . uniqid(),
$filename = 'hoa://Test/Vfs/Foo?type=file',
file_put_contents($filename, 'when($result = $autoloader->requireFile($filename))
->then
->boolean($result)
->isTrue()
->string(constant($constantName))
->isEqualTo('BAR');
}
public function case_require_not_existing_file(): void
{
$this
->given(
$autoloader = new SUT(),
$this->function->file_exists = false
)
->when($result = $autoloader->requireFile('/hoa/flatland'))
->then
->boolean($result)
->isFalse();
}
public function case_has_not_base_directory(): void
{
$this
->given($autoloader = new SUT())
->when($result = $autoloader->hasBaseDirectory('foo'))
->then
->boolean($result)
->isFalse();
}
public function case_get_base_undeclared_namespace_prefix(): void
{
$this
->given($autoloader = new SUT())
->when($result = $autoloader->getBaseDirectories('foo'))
->then
->array($result)
->isEmpty();
}
public function case_dnew(): void
{
$this
->given($classname = 'Hoa\Consistency\Autoloader')
->when($result = SUT::dnew($classname))
->then
->object($result)
->isInstanceOf($classname);
}
public function case_dnew_unknown_class(): void
{
$this
->given($this->function->spl_autoload_call = null)
->exception(function (): void {
SUT::dnew('Foo');
})
->isInstanceOf('ReflectionException');
}
public function case_get_loaded_classes(): void
{
$this
->given(
$declaredClasses = get_declared_classes(),
$this->function->get_declared_classes = $declaredClasses
)
->when($result = SUT::getLoadedClasses())
->then
->array($result)
->isEqualTo($declaredClasses);
}
public function case_register(): void
{
$self = $this;
$this
->given($autoloader = new SUT())
->when($result = $autoloader->register())
->then
->boolean($result)
->isTrue()
->array($autoloader->getRegisteredAutoloaders())
->isEqualTo(spl_autoload_functions());
}
public function case_unregister(): void
{
$this
->given(
$autoloader = new SUT(),
$oldRegisteredAutoloaders = $autoloader->getRegisteredAutoloaders()
)
->when($result = $autoloader->register())
->then
->boolean($result)
->isTrue()
->integer(count($autoloader->getRegisteredAutoloaders()))
->isEqualTo(count($oldRegisteredAutoloaders) + 1)
->when($result = $autoloader->unregister())
->then
->boolean($result)
->isTrue()
->array($autoloader->getRegisteredAutoloaders())
->isEqualTo($oldRegisteredAutoloaders);
}
}
PK sūzNeũS' S' Test/Unit/Consistency.phpnu W+Aķ given(
$this->function->class_exists = $class,
$this->function->interface_exists = $interface,
$this->function->trait_exists = $trait
)
->when($result = SUT::entityExists('foo'))
->then
->boolean($result)
->isTrue();
}
public function case_entity_exists_with_class()
{
return $this->_entity_exists_with_xxx(true, false, false);
}
public function case_entity_exists_with_interface()
{
return $this->_entity_exists_with_xxx(false, true, false);
}
public function case_entity_exists_with_trait()
{
return $this->_entity_exists_with_xxx(false, false, true);
}
public function case_entity_does_not_exists(): void
{
$this
->given(
$this->function->class_exists = false,
$this->function->interface_exists = false,
$this->function->trait_exists = false
)
->when($result = SUT::entityExists('foo'))
->then
->boolean($result)
->isFalse();
}
public function case_get_entity_shortest_name(): void
{
$this
->when($result = SUT::getEntityShortestName('Foo\Bar\Bar'))
->then
->string($result)
->isEqualTo('Foo\Bar');
}
public function case_get_entity_shortest_name_with_already_the_shortest(): void
{
$this
->when($result = SUT::getEntityShortestName('Foo\Bar'))
->then
->string($result)
->isEqualTo('Foo\Bar');
}
public function case_get_entity_shortest_name_with_no_namespace(): void
{
$this
->when($result = SUT::getEntityShortestName('Foo'))
->then
->string($result)
->isEqualTo('Foo');
}
public function case_is_keyword(): void
{
$this
->given(
$keywords = [
'__HALT_COMPILER',
'abstract',
'and',
'array',
'as',
'bool',
'break',
'callable',
'case',
'catch',
'class',
'clone',
'const',
'continue',
'declare',
'default',
'die',
'do',
'echo',
'else',
'elseif',
'empty',
'enddeclare',
'endfor',
'endforeach',
'endif',
'endswitch',
'endwhile',
'eval',
'exit',
'extends',
'false',
'final',
'float',
'for',
'foreach',
'function',
'global',
'goto',
'if',
'implements',
'include',
'include_once',
'instanceof',
'insteadof',
'int',
'interface',
'isset',
'list',
'mixed',
'namespace',
'new',
'null',
'numeric',
'object',
'or',
'print',
'private',
'protected',
'public',
'require',
'require_once',
'resource',
'return',
'static',
'string',
'switch',
'throw',
'trait',
'true',
'try',
'unset',
'use',
'var',
'void',
'while',
'xor',
'yield',
'__CLASS__',
'__DIR__',
'__FILE__',
'__FUNCTION__',
'__LINE__',
'__METHOD__',
'__NAMESPACE__',
'__TRAIT__'
]
)
->when(function () use ($keywords): void {
foreach ($keywords as $keyword) {
$this
->boolean(SUT::isKeyword($keyword))
->isTrue();
}
});
}
public function case_is_identifier(): void
{
$this
->given($_identifier = $this->realdom->regex('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x80-\xff]*$#'))
->when(function () use ($_identifier): void {
foreach ($this->sampleMany($_identifier, 1000) as $identifier) {
$this
->boolean(SUT::isIdentifier($identifier))
->isTrue();
}
});
}
public function case_register_shutdown_function(): void
{
$self = $this;
$this
->given(
$callable = function (): void {
},
$this->function->register_shutdown_function = function ($_callable) use (&$called, $self, &$callable) {
$called = true;
$self
->variable($_callable)
->isEqualTo($callable);
return true;
}
)
->when($result = SUT::registerShutdownFunction($callable))
->then
->variable($result)
->isNull();
}
public function case_get_php_binary_with_constant(): void
{
$this
->given($this->constant->PHP_BINARY = '/foo/php')
->when($result = SUT::getPHPBinary())
->then
->string($result)
->isEqualTo('/foo/php');
}
public function case_get_php_binary_with_server(): void
{
$this
->given(
$this->function->defined = false,
$_SERVER['_'] = '/bar/php'
)
->when($result = SUT::getPHPBinary())
->then
->string($result)
->isEqualTo('/bar/php');
}
public function case_get_php_binary_with_bin_directory(): void
{
unset($_SERVER['_']);
$this
->given(
$this->function->defined = false,
$this->function->file_exists = true,
$this->function->realpath = '/baz/php'
)
->when($result = SUT::getPHPBinary())
->then
->string($result)
->isEqualTo('/baz/php');
}
public function case_uuid(): void
{
$this
->given($this->function->mt_rand = 42)
->when($result = SUT::uuid())
->then
->string($result)
->isEqualTo('002a002a-002a-402a-802a-002a002a002a');
}
public function case_uuid_all_differents(): void
{
$this
->when(function (): void {
$uuids = [];
for ($i = 0; $i < 10000; ++$i) {
$uuids[] = SUT::uuid();
}
$this
->integer(count($uuids))
->isEqualTo(count(array_unique($uuids)));
});
}
}
PK sūzNVđ. . Test/Unit/Xcallable.phpnu W+Aķ when($result = new SUT('strtoupper'))
->then
->string($result('foo'))
->isEqualTo('FOO')
->string($result->getValidCallback())
->isEqualTo('strtoupper')
->string($result->getHash())
->isEqualTo('function#strtoupper')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf(ReflectionFunction::class)
->string($reflection->getName())
->isEqualTo('strtoupper');
}
public function case_form_class___method(): void
{
$this
->when($result = new SUT(__CLASS__ . '::strtoupper'))
->then
->string($result('foo'))
->isEqualTo('FOO')
->array($result->getValidCallback())
->isEqualTo([__CLASS__, 'strtoupper'])
->string($result->getHash())
->isEqualTo('class#' . __CLASS__ . '::strtoupper')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf(ReflectionMethod::class)
->string($reflection->getName())
->isEqualTo('strtoupper');
}
public function case_form_class_method(): void
{
$this
->when($result = new SUT(__CLASS__, 'strtoupper'))
->then
->string($result('foo'))
->isEqualTo('FOO')
->array($result->getValidCallback())
->isEqualTo([__CLASS__, 'strtoupper'])
->string($result->getHash())
->isEqualTo('class#' . __CLASS__ . '::strtoupper')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf(ReflectionMethod::class)
->string($reflection->getName())
->isEqualTo('strtoupper');
}
public function case_form_object_method(): void
{
$this
->when($result = new SUT($this, 'strtolower'))
->then
->string($result('FOO'))
->isEqualTo('foo')
->array($result->getValidCallback())
->isEqualTo([$this, 'strtolower'])
->string($result->getHash())
->matches(
'/^object\([^:]+\)#' .
preg_quote(__CLASS__) .
'::strtolower$/'
)
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf(ReflectionMethod::class)
->string($reflection->getName())
->isEqualTo('strtolower');
}
public function case_form_object_invoke(): void
{
$this
->when($result = new SUT($this))
->then
->string($result('foo'))
->isEqualTo('FOO')
->array($result->getValidCallback())
->isEqualTo([$this, '__invoke'])
->string($result->getHash())
->matches(
'/^object\([^:]+\)#' .
preg_quote(__CLASS__) .
'::__invoke$/'
)
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf(ReflectionMethod::class)
->string($reflection->getName())
->isEqualTo('__invoke');
}
public function case_form_closure(): void
{
$this
->given(
$closure = function ($string) {
return strtoupper($string);
}
)
->when($result = new SUT($closure))
->then
->string($result('foo'))
->isEqualTo('FOO')
->object($result->getValidCallback())
->isIdenticalTo($closure)
->string($result->getHash())
->matches('/^closure\([^:]+\)$/')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf(ReflectionFunction::class)
->string($reflection->getName())
->isEqualTo('Hoa\Consistency\Test\Unit\{closure}');
}
public function case_form_array_of_class_method(): void
{
$this
->when($result = new SUT([__CLASS__, 'strtoupper']))
->then
->string($result('foo'))
->isEqualTo('FOO')
->array($result->getValidCallback())
->isEqualTo([__CLASS__, 'strtoupper'])
->string($result->getHash())
->isEqualTo('class#' . __CLASS__ . '::strtoupper')
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf(ReflectionMethod::class)
->string($reflection->getName())
->isEqualTo('strtoupper');
}
public function case_form_array_of_object_method(): void
{
$this
->when($result = new SUT([$this, 'strtolower']))
->then
->string($result('FOO'))
->isEqualTo('foo')
->array($result->getValidCallback())
->isEqualTo([$this, 'strtolower'])
->string($result->getHash())
->matches(
'/^object\([^:]+\)#' .
preg_quote(__CLASS__) .
'::strtolower$/'
)
->isEqualTo($result . '')
->object($reflection = $result->getReflection())
->isInstanceOf(ReflectionMethod::class)
->string($reflection->getName())
->isEqualTo('strtolower');
}
public function case_form_able_not_a_string(): void
{
$this
->exception(function (): void {
new SUT(__CLASS__, 123);
})
->isInstanceOf(LUT\Exception::class);
}
public function case_form_function_not_defined(): void
{
$this
->exception(function (): void {
new SUT('__hoa_test_undefined_function__');
})
->isInstanceOf(Error::class);
}
public function case_form_able_cannot_be_deduced(): void
{
$this
->given($this->function->method_exists = false)
->exception(function (): void {
new SUT($this);
})
->isInstanceOf(LUT\Exception::class);
}
public function case_invoke(): void
{
$this
->given(
$callable = new SUT(
function ($x, $y, $z) {
return [$x, $y, $z];
}
)
)
->when($result = $callable(7, [4.2], 'foo'))
->then
->array($result)
->isEqualTo([7, [4.2], 'foo']);
}
public function case_distribute_arguments(): void
{
$this
->given(
$callable = new SUT(
function ($x, $y, $z) {
return [$x, $y, $z];
}
)
)
->when($result = $callable->distributeArguments([7, [4.2], 'foo']))
->then
->array($result)
->isEqualTo([7, [4.2], 'foo']);
}
protected function _get_valid_callback_stream_xxx($argument, $method): void
{
$this
->given(
$stream = new \Mock\Hoa\Stream\IStream\Out(),
$arguments = [$argument],
$xcallable = new SUT($stream)
)
->when($result = $xcallable->getValidCallback($arguments))
->then
->array($result)
->isEqualTo([$stream, $method]);
}
public function case_get_valid_callback_stream_character()
{
return $this->_get_valid_callback_stream_xxx('f', 'writeCharacter');
}
public function case_get_valid_callback_stream_string()
{
return $this->_get_valid_callback_stream_xxx('foo', 'writeString');
}
public function case_get_valid_callback_stream_boolean()
{
return $this->_get_valid_callback_stream_xxx(true, 'writeBoolean');
}
public function case_get_valid_callback_stream_integer()
{
return $this->_get_valid_callback_stream_xxx(7, 'writeInteger');
}
public function case_get_valid_callback_stream_array()
{
return $this->_get_valid_callback_stream_xxx([4, 2], 'writeArray');
}
public function case_get_valid_callback_stream_float()
{
return $this->_get_valid_callback_stream_xxx(4.2, 'writeFloat');
}
public function case_get_valid_callback_stream_other()
{
return $this->_get_valid_callback_stream_xxx($this, 'writeAll');
}
public static function strtoupper($string)
{
return strtoupper($string);
}
public function strtolower($string)
{
return strtolower($string);
}
public function __invoke($string)
{
return strtoupper($string);
}
public function __toString()
{
return 'hello';
}
}
PK sūzNÞý Test/Unit/Exception.phpnu W+Aķ when($result = new SUT('foo', 0))
->then
->object($result)
->isInstanceOf(RuntimeException::class);
}
}
PK sūzNųĪôó ó CHANGELOG.mdnu W+Aķ # 2.17.08.29
* fix(autoloader) Take into the move to `Source`. (Ivan Enderlin, 2017-08-29T15:36:49+02:00)
* doc(xcallable) Rewrite. (Ivan Enderlin, 2017-08-29T15:36:25+02:00)
* chore(path) Move code into the `Source` directory. (Ivan Enderlin, 2017-08-29T15:26:24+02:00)
* doc(consistency) Rewrite and add doctests. (Ivan Enderlin, 2017-08-22T11:14:35+02:00)
* chore(php) Remove PHP 7.x implementations. (Ivan Enderlin, 2017-08-22T10:54:32+02:00)
* chore(php) Rewrite `curry` with new PHP features. (Ivan Enderlin, 2017-08-22T10:50:59+02:00)
* doc(consistency) Rewrite the doc. of `curry`. (Ivan Enderlin, 2017-08-22T10:50:27+02:00)
* doc(exception) Rewrite. (Ivan Enderlin, 2017-08-22T10:39:46+02:00)
* doc(autoloader) Rewrite and add doctests. (Ivan Enderlin, 2017-08-22T10:28:31+02:00)
* test(unit) Fix `case_add_namespace_prepend`. (Ivan Enderlin, 2017-08-22T09:43:37+02:00)
* chore(composer) Anticipate future BC breaks. (Ivan Enderlin, 2017-08-21T11:04:35+02:00)
* chore(php) Drop dependency to `hoa/exception`. (Ivan Enderlin, 2017-08-21T11:04:06+02:00)
* chore(php) Migrate to PHP 7.1. (Ivan Enderlin, 2017-08-21T10:54:57+02:00)
* chore(ci) Drop HHVM support. (Grummfy, 2017-07-06T20:34:54+02:00)
# 1.17.05.02
* CI: Set up Travis. (Ivan Enderlin, 2017-03-08T09:52:17+01:00)
* Prelude: Remove the `(unset)` cast. (Ivan Enderlin, 2017-03-07T16:55:13+01:00)
# 1.17.01.10
* Quality: Happy new year! (Alexis von Glasow, 2017-01-09T21:38:10+01:00)
* Documentation: New `README.md` file. (Ivan Enderlin, 2016-10-19T16:27:31+02:00)
* Documentation: Fix `docs` and `source` links. (Ivan Enderlin, 2016-10-05T20:26:20+02:00)
* Documentation: Update `support` properties. (Ivan Enderlin, 2016-10-05T15:56:01+02:00)
* Consistency: `void` is a reserved keyword now. (Ivan Enderlin, 2016-09-02T11:06:18+02:00)
* Consistency: Remove `trait_exists` polyfill. (Ivan Enderlin, 2016-08-23T17:26:07+02:00)
# 1.16.03.03
* Add `STREAM_CRYPTO_METHOD_*` constants on PHP 5.5. (Metalaka, 2016-02-29T21:10:14+01:00)
* Composer: Fix `hoa/stream` dependency. (Ivan Enderlin, 2016-03-03T10:13:50+01:00)
# 1.16.01.14
* Test: Write cases for flex entity in autoloader. (Ivan Enderlin, 2016-01-14T10:45:08+01:00)
* Autoloader: Restrict loads to mapped entities. (Ivan Enderlin, 2016-01-14T10:38:21+01:00)
# 1.16.01.11
* Quality: Drop PHP5.4. (Ivan Enderlin, 2016-01-11T09:15:26+01:00)
* Quality: Run devtools:cs. (Ivan Enderlin, 2016-01-09T08:58:31+01:00)
* Core: Remove `Hoa\Core`. (Ivan Enderlin, 2016-01-09T08:03:33+01:00)
# 0.16.01.06
* Prelude: Introduce the prelude/preamble! (Ivan Enderlin, 2015-12-09T08:34:16+01:00)
* Consistency: Import last methods from `Hoa\Core`. (Ivan Enderlin, 2015-12-09T08:24:02+01:00)
* Quality: Fix CS. (Ivan Enderlin, 2015-12-09T06:43:22+01:00)
* Add a `.gitignore` file. (Metalaka, 2015-12-03T13:21:11+01:00)
* Autoloader: Propagate unknown entity on the stack. (Ivan Enderlin, 2015-12-03T11:04:57+01:00)
* Autoloader: Auto-register to support flex entity. (Ivan Enderlin, 2015-12-03T10:01:23+01:00)
* Composer: Force some files to load. (Ivan Enderlin, 2015-12-03T08:15:55+01:00)
* Test: Simplify `case_register`. (Ivan Enderlin, 2015-12-03T08:15:19+01:00)
* Consistency: Use a strict equality check on trait. (Ivan Enderlin, 2015-12-02T17:11:50+01:00)
* README: First draft. (Ivan Enderlin, 2015-12-02T08:40:34+01:00)
* Documentation: Update API documentation. (Ivan Enderlin, 2015-12-02T08:37:58+01:00)
* Autoloader: Support flex entities. (Ivan Enderlin, 2015-12-02T08:18:39+01:00)
* Test: Write test suite of `âĶnsistency\Autoloader`. (Ivan Enderlin, 2015-12-01T08:42:30+01:00)
* Test: Write test suite of `âĶsistency\Consistency`. (Ivan Enderlin, 2015-11-25T22:10:30+01:00)
* Test: Write test suite of `âĶonsistency\Xcallable`. (Ivan Enderlin, 2015-11-25T08:45:59+01:00)
* Test: Write test suite of `âĶonsistency\Exception`. (Ivan Enderlin, 2015-11-24T16:59:18+01:00)
* Split from `Hoa\Core`. (Ivan Enderlin, 2015-11-23T23:08:19+01:00)
(first snapshot)
PK sūzNõ
Ýg
.Statenu W+Aķ finalized
PK sūzNW§ĀđL L
composer.jsonnu W+Aķ {
"name" : "hoa/consistency",
"description": "The Hoa\\Consistency library.",
"type" : "library",
"keywords" : ["library", "consistency", "autoloader", "entity", "flex",
"keyword", "callable"],
"homepage" : "https://hoa-project.net/",
"license" : "BSD-3-Clause",
"authors" : [
{
"name" : "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name" : "Hoa community",
"homepage": "https://hoa-project.net/"
}
],
"support": {
"email" : "support@hoa-project.net",
"irc" : "irc://chat.freenode.net/hoaproject",
"forum" : "https://users.hoa-project.net/",
"docs" : "https://central.hoa-project.net/Documentation/Library/Consistency",
"source": "https://central.hoa-project.net/Resource/Library/Consistency"
},
"require": {
"php": ">=7.1"
},
"require-dev": {
"hoa/stream": "dev-master",
"hoa/test" : "dev-master"
},
"autoload": {
"psr-4": {
"Hoa\\Consistency\\" : "Source",
"Hoa\\Consistency\\Test\\": "Test"
},
"files": ["Source/Prelude.php"]
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
}
}
PK sūzNg_Ķxß ß .travis.ymlnu W+Aķ PK sūzNũp% p% README.mdnu W+Aķ PK sūzNÅ0
Ã+ .gitignorenu W+Aķ PK sūzNT*Jï+ ï+ , Source/Autoloader.phpnu W+Aķ PK sūzN ąā
IX Source/Prelude.phpnu W+Aķ PK sūzNFg&Ýk' k' f Source/Consistency.phpnu W+Aķ PK sūzN
ÂŪ " " I Source/Xcallable.phpnu W+Aķ PK sūzN*Ãn ° Source/Exception.phpnu W+Aķ PK sūzNĒ&wÜ, Ü, čļ Test/Unit/Autoloader.phpnu W+Aķ PK sūzNeũS' S' æ Test/Unit/Consistency.phpnu W+Aķ PK sūzNVđ. . Ļ
Test/Unit/Xcallable.phpnu W+Aķ PK sūzNÞý < Test/Unit/Exception.phpnu W+Aķ PK sūzNųĪôó ó ÜD CHANGELOG.mdnu W+Aķ PK sūzNõ
Ýg
U .Statenu W+Aķ PK sūzNW§ĀđL L
KU composer.jsonnu W+Aķ PK Á ÔZ