Merge pull request #1 from jobyone/v1.5

V1.5
This commit is contained in:
Joby Elliott 2023-02-02 10:35:38 -07:00 committed by GitHub
commit d64a982582
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 460 additions and 198 deletions

14
.github/workflows/phpstan.yml vendored Normal file
View file

@ -0,0 +1,14 @@
name: phpstan
on: push
jobs:
phpstan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: php-actions/composer@v6
with:
dev: yes
- uses: php-actions/phpstan@v3
with:
memory_limit: 1G
args: --memory-limit 1G

11
.github/workflows/phpunit.yml vendored Normal file
View file

@ -0,0 +1,11 @@
name: phpunit
on: push
jobs:
phpunit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: php-actions/composer@v6
with:
dev: yes
- uses: php-actions/phpunit@v3

6
.gitignore vendored
View file

@ -1,2 +1,4 @@
/vendor/ /vendor
composer.lock /composer.lock
/.phpunit.result.cache
/coverage

View file

@ -1,6 +1,7 @@
# Flatrr # Flatrr
[![Build Status](https://travis-ci.org/jobyone/flatrr.svg?branch=main)](https://travis-ci.org/jobyone/flatrr) [![phpstan](https://github.com/jobyone/flatrr/actions/workflows/phpstan.yml/badge.svg?branch=v1.5)](https://github.com/jobyone/flatrr/actions/workflows/phpstan.yml)
[![phpunit](https://github.com/jobyone/flatrr/actions/workflows/phpunit.yml/badge.svg?branch=v1.5)](https://github.com/jobyone/flatrr/actions/workflows/phpunit.yml)
[![Latest Stable Version](http://poser.pugx.org/byjoby/flatrr/v)](https://packagist.org/packages/byjoby/flatrr) [![Latest Stable Version](http://poser.pugx.org/byjoby/flatrr/v)](https://packagist.org/packages/byjoby/flatrr)
[![Total Downloads](http://poser.pugx.org/byjoby/flatrr/downloads)](https://packagist.org/packages/byjoby/flatrr) [![Total Downloads](http://poser.pugx.org/byjoby/flatrr/downloads)](https://packagist.org/packages/byjoby/flatrr)
[![Latest Unstable Version](http://poser.pugx.org/byjoby/flatrr/v/unstable)](https://packagist.org/packages/byjoby/flatrr) [![Latest Unstable Version](http://poser.pugx.org/byjoby/flatrr/v/unstable)](https://packagist.org/packages/byjoby/flatrr)

View file

@ -3,12 +3,16 @@
"description": "A library for working with multi-dimensional arrays through flattened keys", "description": "A library for working with multi-dimensional arrays through flattened keys",
"type": "library", "type": "library",
"license": "MIT", "license": "MIT",
"authors": [{ "authors": [
"name": "Joby Elliott", {
"email": "joby@byjoby.com" "name": "Joby Elliott",
}], "email": "joby@byjoby.com"
}
],
"require-dev": { "require-dev": {
"phpunit/phpunit": "^7.3" "phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^1.9",
"squizlabs/php_codesniffer": "^3.7"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -21,12 +25,12 @@
} }
}, },
"scripts": { "scripts": {
"test": [ "test": "phpunit",
"phpunit" "stan": "phpstan",
] "sniff": "phpcs"
}, },
"require": { "require": {
"php": ">=7.1", "php": ">=8.1",
"mustangostang/spyc": "^0.6.3" "mustangostang/spyc": "^0.6.3"
} }
} }

19
phpcs.xml Normal file
View file

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="PHP_CodeSniffer"
xsi:noNamespaceSchemaLocation="./vendor/squizlabs/php_codesniffer/phpcs.xsd">
<description>Coding Standard</description>
<file>src</file>
<arg name="basepath" value="." />
<arg name="colors" />
<arg name="parallel" value="75" />
<arg value="np" />
<rule ref="PSR12">
<exclude name="Generic.Files.LineEndings" />
<exclude name="Generic.NamingConventions.CamelCapsFunctionName" />
<exclude name="PSR1.Methods.CamelCapsMethodName" />
</rule>
</ruleset>

4
phpstan.neon Normal file
View file

@ -0,0 +1,4 @@
parameters:
level: 7
paths:
- src

View file

@ -1,7 +1,31 @@
<phpunit bootstrap="vendor/autoload.php"> <?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
executionOrder="random"
failOnWarning="true"
failOnRisky="true"
failOnEmptyTestSuite="true"
beStrictAboutOutputDuringTests="true"
verbose="true"
bootstrap="vendor/autoload.php">
<php>
<ini name="display_errors" value="On" />
<ini name="error_reporting" value="-1" />
<ini name="xdebug.mode" value="coverage" />
</php>
<testsuites> <testsuites>
<testsuite name="All"> <testsuite name="Tests">
<directory>tests</directory> <directory>tests/</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
</phpunit> <coverage>
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<html outputDirectory="coverage" lowUpperBound="50" highLowerBound="90" />
</report>
</coverage>
</phpunit>

View file

@ -1,5 +1,6 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
namespace Flatrr\Config; namespace Flatrr\Config;
@ -8,98 +9,68 @@ use Spyc;
class Config extends SelfReferencingFlatArray implements ConfigInterface class Config extends SelfReferencingFlatArray implements ConfigInterface
{ {
public $strict = false; public function readDir(string $dir, string $name = null, bool $overwrite = false): static
public function readDir($dir, string $name = null, bool $overwrite = false)
{ {
$dir = realpath($dir); $dir = realpath($dir);
if (!$dir || !is_dir($dir)) { if ($dir && is_dir($dir)) {
return; $glob = glob("$dir/*");
} if ($glob) {
foreach (glob("$dir/*") as $f) { foreach ($glob as $f) {
if (is_file($f)) { if (is_file($f)) {
$this->readFile($f, $name, $overwrite); $this->readFile($f, $name, $overwrite);
}
}
} }
} }
return $this;
} }
protected function parse(string $input, string $format): array public function json(bool $raw = false): string
{ {
$fn = 'parse_' . $format; return json_encode($this->get(null, $raw), JSON_PRETTY_PRINT); // @phpstan-ignore-line
if (!method_exists($this, $fn)) {
if ($this->strict) {
throw new \Exception("Don't know how to parse the format \"$format\"");
} else {
return null;
}
}
if ($out = $this->$fn($input)) {
return $out;
}
return array();
} }
protected function parse_yaml($input) public function yaml(bool $raw = false): string
{
return Spyc::YAMLLoadString($input);
}
public function json($raw = false): string
{
return json_encode($this->get(null, $raw), JSON_PRETTY_PRINT);
}
public function yaml($raw = false): string
{ {
return Spyc::YAMLDump($this->get(null, $raw), 2); return Spyc::YAMLDump($this->get(null, $raw), 2);
} }
protected function read_ini($filename) /** @return array<mixed|mixed> */
protected function read_ini(string $filename): false|array
{ {
return parse_ini_file($filename, true); return parse_ini_file($filename, true);
} }
protected function read_json($filename) /** @return array<mixed|mixed> */
protected function read_json(string $filename): null|array
{ {
return json_decode(file_get_contents($filename), true); /** @var string */
$data = file_get_contents($filename);
return json_decode($data, true);
} }
protected function read_yaml($filename) /** @return array<mixed|mixed> */
protected function read_yaml(string $filename): array
{ {
return Spyc::YAMLLoad($filename); return Spyc::YAMLLoad($filename);
} }
protected function read_yml($filename) /** @return array<mixed|mixed> */
protected function read_yml(string $filename): array
{ {
return $this->read_yaml($filename); return $this->read_yaml($filename);
} }
public function readFile($filename, string $name = null, bool $overwrite = false) public function readFile(string $filename, string $name = null, bool $overwrite = false): static
{ {
if (!is_file($filename) || !is_readable($filename)) {
if ($this->strict) {
throw new \Exception("Couldn't read config file \"$filename\"");
} else {
return null;
}
}
$format = strtolower(preg_replace('/.+\./', '', $filename)); $format = strtolower(preg_replace('/.+\./', '', $filename));
$fn = 'read_' . $format; $fn = 'read_' . $format;
if (!method_exists($this, $fn)) { if (is_file($filename) && is_readable($filename) && method_exists($this, $fn)) {
if ($this->strict) { $data = $this->$fn($filename);
throw new \Exception("Don't know how to read the format \"$format\""); if ($data !== null) {
} else { $this->merge($data, $name, $overwrite);
return null;
} }
} }
$data = $this->$fn($filename); return $this;
if (!$data) {
if ($this->strict) {
throw new \Exception("Error reading \"" . $filename . "\"");
} else {
return null;
}
}
$this->merge($data, $name, $overwrite);
} }
} }

View file

@ -1,12 +1,17 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
namespace Flatrr\Config; namespace Flatrr\Config;
interface ConfigInterface extends \ArrayAccess use Flatrr\FlatArrayInterface;
interface ConfigInterface extends FlatArrayInterface
{ {
public function readFile($filename, string $name = null, bool $overwrite = false); public function readDir(string $dir, string $name = null, bool $overwrite = false): static;
public function json($raw = false) : string; public function readFile(string $filename, string $name = null, bool $overwrite = false): static;
public function yaml($raw = false) : string; public function json(bool $raw = false): string;
public function get(string $name = null, bool $raw = false); public function yaml(bool $raw = false): string;
public function merge($value, string $name = null, bool $overwrite = false); public function get(null|string $name = null, bool $raw = false): mixed;
public function merge(mixed $value, string $name = null, bool $overwrite = false): static;
} }

View file

@ -1,12 +1,18 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
namespace Flatrr; namespace Flatrr;
class FlatArray implements FlatArrayInterface class FlatArray implements FlatArrayInterface
{ {
use FlatArrayTrait; use FlatArrayTrait;
public function __construct(array $data = null) /**
* @param null|array<string|mixed> $data
* @return void
*/
public function __construct(null|array $data = null)
{ {
$this->merge($data); $this->merge($data);
} }

View file

@ -1,16 +1,25 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
namespace Flatrr; namespace Flatrr;
interface FlatArrayInterface extends \ArrayAccess, \Iterator use ArrayAccess;
{ use Iterator;
public function set(?string $name, $value);
public function get(?string $name = null);
public function unset(?string $name);
public function merge($value, string $name = null, bool $overwrite = false);
public function push(?string $name, $value); /**
public function pop(?string $name); * @extends ArrayAccess<string,mixed>
public function unshift(?string $name, $value); * @extends Iterator<string,mixed>
public function shift(?string $name); */
interface FlatArrayInterface extends ArrayAccess, Iterator
{
public function set(null|string $name, mixed $value): mixed;
public function get(null|string $name = null): mixed;
public function unset(null|string $name): static;
public function merge(mixed $value, string $name = null, bool $overwrite = false): static;
public function push(null|string $name, mixed $value): static;
public function pop(null|string $name): mixed;
public function unshift(null|string $name, mixed $value): static;
public function shift(null|string $name): mixed;
} }

View file

@ -1,117 +1,126 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
namespace Flatrr; namespace Flatrr;
trait FlatArrayTrait trait FlatArrayTrait
{ {
private $_arrayData = array(); /** @var array<string|mixed> */
private $_flattenCache = array(); protected $_arrayData = [];
/** @var array<string|mixed> */
protected $_flattenCache = [];
public function push(?string $name, $value) public function push(null|string $name, mixed $value): static
{ {
$arr = $this->flattenSearch($name); $arr = $this->flattenSearch($name);
if ($arr !== null && !is_array($arr)) { if ($arr !== null && !is_array($arr)) {
return; return $this;
} }
if ($arr === null) { if ($arr === null) {
$arr = []; $arr = [];
} }
$arr[] = $value; $arr[] = $value;
$this->set($name, $arr); $this->set($name, $arr);
return $this;
} }
public function pop(?string $name) public function pop(null|string $name): mixed
{ {
$arr = $this->flattenSearch($name); $arr = $this->flattenSearch($name);
if ($arr !== null && !is_array($arr)) { if ($arr !== null && !is_array($arr)) {
return; return null;
} }
$out = array_pop($arr); $out = array_pop($arr);
$this->unset($name);
$this->set($name, $arr); $this->set($name, $arr);
return $out; return $out;
} }
public function unshift(?string $name, $value) public function unshift(null|string $name, mixed $value): static
{ {
$arr = $this->flattenSearch($name); $arr = $this->flattenSearch($name);
if ($arr !== null && !is_array($arr)) { if ($arr !== null && !is_array($arr)) {
return; return $this;
} }
if ($arr === null) { if ($arr === null) {
$arr = []; $arr = [];
} }
array_unshift($arr, $value); array_unshift($arr, $value);
$this->set($name, $arr); $this->set($name, $arr);
return $this;
} }
public function shift(?string $name) public function shift(null|string $name): mixed
{ {
$arr = $this->flattenSearch($name); $arr = $this->flattenSearch($name);
if ($arr !== null && !is_array($arr)) { if ($arr !== null && !is_array($arr)) {
return; return null;
} }
$out = array_shift($arr); $out = array_shift($arr);
$this->unset($name);
$this->set($name, $arr); $this->set($name, $arr);
return $out; return $out;
} }
public function set(?string $name, $value) public function set(null|string $name, mixed $value): static
{ {
return $this->flattenSearch($name, $value); $this->flattenSearch($name, $value);
return $this;
} }
public function get(?string $name = null) public function get(null|string $name = null): mixed
{ {
return $this->flattenSearch($name); return $this->flattenSearch($name);
} }
function unset(?string $name) public function unset(null|string $name): static
{ {
$this->flattenSearch($name, null, true); $this->flattenSearch($name, null, true);
return $this;
} }
public function offsetSet($name, $value) public function offsetSet($name, $value): void
{ {
return $this->set($name, $value); $this->set($name, $value);
} }
public function offsetGet($name) public function offsetGet($name): mixed
{ {
return $this->get($name); return $this->get($name);
} }
public function offsetExists($name) public function offsetExists($name): bool
{ {
return $this->flattenSearch($name) !== null; return $this->flattenSearch($name) !== null;
} }
public function offsetUnset($name) public function offsetUnset($name): void
{ {
$this->unset($name); $this->unset($name);
} }
public function rewind() public function rewind(): void
{ {
return reset($this->_arrayData); reset($this->_arrayData);
} }
public function current() public function current(): mixed
{ {
return current($this->_arrayData); return current($this->_arrayData);
} }
public function next() public function next(): void
{ {
return next($this->_arrayData); next($this->_arrayData);
} }
public function key() public function key(): null|string|int
{ {
return key($this->_arrayData); return key($this->_arrayData);
} }
public function valid() public function valid(): bool
{ {
return isset($this->_arrayData[$this->key()]); return isset($this->_arrayData[$this->key()]);
} }
@ -120,12 +129,11 @@ trait FlatArrayTrait
* Recursively set a value, with control over whether existing values or new * Recursively set a value, with control over whether existing values or new
* values take precedence * values take precedence
*/ */
public function merge($value, string $name = null, bool $overwrite = false) public function merge(mixed $value, string $name = null, bool $overwrite = false): static
{ {
if (!isset($this[$name])) { if (!isset($this[$name])) {
//easiest possible outcome, old value doesn't exist, so we can just write the value //easiest possible outcome, old value doesn't exist, so we can just write the value
$this->set($name, $value); $this->set($name, $value);
return;
} elseif (is_array($value) && is_array($this->flattenSearch($name))) { } elseif (is_array($value) && is_array($this->flattenSearch($name))) {
//both new and old values are arrays //both new and old values are arrays
foreach ($value as $k => $v) { foreach ($value as $k => $v) {
@ -134,14 +142,13 @@ trait FlatArrayTrait
} }
$this->merge($v, $k, $overwrite); $this->merge($v, $k, $overwrite);
} }
return;
} else { } else {
//old and new values exist, and one or both are not arrays, $overwrite rules the day //old and new values exist, and one or both are not arrays, $overwrite rules the day
if ($overwrite) { if ($overwrite) {
$this->set($name, $value); $this->set($name, $value);
} }
return;
} }
return $this;
} }
/** /**
@ -149,10 +156,10 @@ trait FlatArrayTrait
* string. It sets it if $value exists, otherwise it returns the value if it * string. It sets it if $value exists, otherwise it returns the value if it
* exists. * exists.
*/ */
protected function flattenSearch(?string $name, $value = null, $unset = false) protected function flattenSearch(null|string $name, mixed $value = null, bool $unset = false): mixed
{ {
if ($value !== null || $unset) { if ($value !== null || $unset) {
$this->_flattenCache = array(); $this->_flattenCache = [];
} }
if (!isset($this->_flattenCache[$name])) { if (!isset($this->_flattenCache[$name])) {
$this->_flattenCache[$name] = $this->doFlattenSearch($name, $value, $unset); $this->_flattenCache[$name] = $this->doFlattenSearch($name, $value, $unset);
@ -160,7 +167,7 @@ trait FlatArrayTrait
return $this->_flattenCache[$name]; return $this->_flattenCache[$name];
} }
protected function doFlattenSearch(?string $name, $value = null, $unset = false) protected function doFlattenSearch(null|string $name, mixed $value = null, bool $unset = false): mixed
{ {
//check for home strings //check for home strings
if ($name == '' || $name === null) { if ($name == '' || $name === null) {
@ -178,7 +185,7 @@ trait FlatArrayTrait
if ($value !== null) { if ($value !== null) {
foreach ($name as $part) { foreach ($name as $part) {
if (!isset($parent[$part])) { if (!isset($parent[$part])) {
$parent[$part] = array(); $parent[$part] = [];
} }
$parent = &$parent[$part]; $parent = &$parent[$part];
} }
@ -199,9 +206,9 @@ trait FlatArrayTrait
//both value and destination are arrays, merge them //both value and destination are arrays, merge them
$parent[$key] = array_replace_recursive($parent[$key], $value); $parent[$key] = array_replace_recursive($parent[$key], $value);
} else { } else {
//set the hard way //destination is not an array, to set this we must overwrite it with an empty array
if (!is_array($parent)) { if (!is_array(@$parent[$key])) {
$parent = array(); $parent[$key] = [];
} }
$parent[$key] = $value; $parent[$key] = $value;
} }

View file

@ -1,13 +1,15 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */
/* Flatrr | https://github.com/jobyone/flatrr | MIT License */
namespace Flatrr; namespace Flatrr;
class SelfReferencingFlatArray extends FlatArray class SelfReferencingFlatArray extends FlatArray
{ {
/** @var array<string,string> */
protected $cache = []; protected $cache = [];
public function get(string $name = null, bool $raw = false, $unescape = true) public function get(string $name = null, bool $raw = false, bool $unescape = true): mixed
{ {
$out = parent::get($name); $out = parent::get($name);
if ($raw) { if ($raw) {
@ -20,48 +22,29 @@ class SelfReferencingFlatArray extends FlatArray
return $out; return $out;
} }
public function set(?string $name, $value) public function set(null|string $name, mixed $value): static
{ {
$this->cache = []; $this->cache = [];
return $this->filter(parent::set($name, $value)); $this->filter(parent::set($name, $value));
return $this;
} }
public function push(?string $name, $value) public function pop(null|string $name): mixed
{
return $this->filter(parent::push($name, $value));
}
public function pop(?string $name)
{ {
return $this->filter(parent::pop($name)); return $this->filter(parent::pop($name));
} }
public function unshift(?string $name, $value) public function shift(null|string $name): mixed
{
return $this->filter(parent::unshift($name, $value));
}
public function shift(?string $name)
{ {
return $this->filter(parent::shift($name)); return $this->filter(parent::shift($name));
} }
public function rewind() public function current(): mixed
{
return $this->filter(parent::rewind());
}
public function next()
{
return $this->filter(parent::next());
}
public function current()
{ {
return $this->filter(parent::current()); return $this->filter(parent::current());
} }
protected function unescape($value) protected function unescape(mixed $value): mixed
{ {
//map this function onto array values //map this function onto array values
if (is_array($value)) { if (is_array($value)) {
@ -88,7 +71,7 @@ class SelfReferencingFlatArray extends FlatArray
/** /**
* Recursively replace ${var/name} type strings in string values with * Recursively replace ${var/name} type strings in string values with
*/ */
protected function filter($value) protected function filter(mixed $value): mixed
{ {
//map this function onto array values //map this function onto array values
if (is_array($value)) { if (is_array($value)) {
@ -114,9 +97,14 @@ class SelfReferencingFlatArray extends FlatArray
return $value; return $value;
} }
protected function filter_regex($matches) /**
* @param array<int,null|string> $matches
* @return string
*/
protected function filter_regex(array $matches): string
{ {
if (null !== $value = $this->get($matches[1], false, false)) { $value = $this->get($matches[1], false, false);
if ($value !== null) {
if (!is_array($value)) { if (!is_array($value)) {
return $value; return $value;
} }

View file

@ -1,6 +1,8 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */ /* Flatrr | https://github.com/jobyone/flatrr | MIT License */
declare(strict_types=1); declare(strict_types=1);
namespace Flatrr\Config; namespace Flatrr\Config;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -30,12 +32,17 @@ class ConfigTest extends TestCase
]; ];
//json //json
$a = new Config(); $a = new Config();
$a->readFile(__DIR__.'/configtest.json'); $a->readFile(__DIR__ . '/configtest.json');
$this->assertEquals($data, $a->get()); $this->assertEquals($data, $a->get());
//yaml //yaml
$a = new Config(); $a = new Config();
$a->readFile(__DIR__.'/configtest.yaml'); $a->readFile(__DIR__ . '/configtest.yaml');
$this->assertEquals($data, $a->get()); $this->assertEquals($data, $a->get());
//nonexistant files
$a = new Config();
$a->readFile(__DIR__ . '/does-not-exist.json');
$a->readFile(__DIR__ . '/does-not-exist.yaml');
$this->assertEquals([], $a->get());
} }
public function testSerializing() public function testSerializing()
@ -52,4 +59,16 @@ class ConfigTest extends TestCase
//yaml //yaml
$this->assertEquals($data, Spyc::YAMLLoad($c->yaml())); $this->assertEquals($data, Spyc::YAMLLoad($c->yaml()));
} }
public function testReadingDirectory()
{
$config = new Config;
$config->readDir(__DIR__ . '/nonexistantdir');
$this->assertEquals([], $config->get());
$config->readDir(__DIR__ . '/configtestdir');
$this->assertEquals('b', $config['ini_file.a']);
$this->assertEquals('a', $config['yaml_file']);
$this->assertEquals('a', $config['json_file']);
$this->assertEquals('a', $config['yml_file']);
}
} }

View file

@ -0,0 +1,2 @@
[ini_file]
a = b

View file

@ -0,0 +1,3 @@
{
"json_file": "a"
}

View file

@ -0,0 +1 @@
yaml_file: a

View file

@ -0,0 +1 @@
yml_file: a

View file

@ -1,6 +1,8 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */ /* Flatrr | https://github.com/jobyone/flatrr | MIT License */
declare(strict_types=1); declare(strict_types=1);
namespace Flatrr; namespace Flatrr;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -12,11 +14,27 @@ class FlatArrayPushPopTest extends TestCase
$f = new FlatArray(); $f = new FlatArray();
$f->push(null, 'foo'); $f->push(null, 'foo');
$f->push(null, 'bar'); $f->push(null, 'bar');
$this->assertEquals(['foo','bar'], $f->get()); $this->assertEquals(['foo', 'bar'], $f->get());
$this->assertEquals('bar', $f->pop(null)); $this->assertEquals('bar', $f->pop(null));
$this->assertEquals(['foo'], $f->get()); $this->assertEquals(['foo'], $f->get());
$this->assertEquals('foo', $f->pop(null)); $this->assertEquals('foo', $f->pop(null));
$this->assertEquals([], $f->get()); $this->assertEquals([], $f->get());
$this->assertNull($f->pop(null));
}
public function testPushIndexCreation()
{
// pushing to a nonexistent index creates it as an array
$f = new FlatArray();
$f->push('a.b', 'c');
$this->assertEquals(['c'], $f['a.b']);
$this->assertEquals(['a' => ['b' => ['c']]], $f->get());
// pushing to an existing non-array index does nothing
$f = new FlatArray(['a' => 'b']);
$f->push('a', 'c');
$this->assertEquals(['a' => 'b'], $f->get());
// poping off a non-array does nothing
$this->assertNull($f->pop('a'));
} }
public function testShiftUnshift() public function testShiftUnshift()
@ -24,10 +42,25 @@ class FlatArrayPushPopTest extends TestCase
$f = new FlatArray(); $f = new FlatArray();
$f->unshift(null, 'foo'); $f->unshift(null, 'foo');
$f->unshift(null, 'bar'); $f->unshift(null, 'bar');
$this->assertEquals(['bar','foo'], $f->get()); $this->assertEquals(['bar', 'foo'], $f->get());
$this->assertEquals('bar', $f->shift(null)); $this->assertEquals('bar', $f->shift(null));
$this->assertEquals(['foo'], $f->get()); $this->assertEquals(['foo'], $f->get());
$this->assertEquals('foo', $f->shift(null)); $this->assertEquals('foo', $f->shift(null));
$this->assertEquals([], $f->get()); $this->assertEquals([], $f->get());
} }
public function testUnshiftIndexCreation()
{
// unshifting to a nonexistent index creates it as an array
$f = new FlatArray();
$f->unshift('a.b', 'c');
$this->assertEquals(['c'], $f['a.b']);
$this->assertEquals(['a' => ['b' => ['c']]], $f->get());
// unshifting to an existing non-array index does nothing
$f = new FlatArray(['a' => 'b']);
$f->unshift('a', 'c');
$this->assertEquals(['a' => 'b'], $f->get());
// shifting off a non-array does nothing
$this->assertNull($f->shift('a'));
}
} }

View file

@ -1,6 +1,8 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */ /* Flatrr | https://github.com/jobyone/flatrr | MIT License */
declare(strict_types=1); declare(strict_types=1);
namespace Flatrr; namespace Flatrr;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -11,7 +13,7 @@ class FlatArrayTest extends TestCase
{ {
$data = [ $data = [
'a' => 'A', 'a' => 'A',
'b' => ['c'=>'C'] 'b' => ['c' => 'C']
]; ];
$a = new FlatArray($data); $a = new FlatArray($data);
//first level //first level
@ -21,8 +23,8 @@ class FlatArrayTest extends TestCase
$this->assertEquals('C', $a['b.c']); $this->assertEquals('C', $a['b.c']);
$this->assertEquals('C', $a->get('b.c')); $this->assertEquals('C', $a->get('b.c'));
//returning array //returning array
$this->assertEquals(['c'=>'C'], $a['b']); $this->assertEquals(['c' => 'C'], $a['b']);
$this->assertEquals(['c'=>'C'], $a->get('b')); $this->assertEquals(['c' => 'C'], $a->get('b'));
//returning entire array by requesting null or empty string //returning entire array by requesting null or empty string
$this->assertEquals($data, $a[null]); $this->assertEquals($data, $a[null]);
$this->assertEquals($data, $a->get()); $this->assertEquals($data, $a->get());
@ -62,7 +64,7 @@ class FlatArrayTest extends TestCase
{ {
$data = [ $data = [
'a' => 'A', 'a' => 'A',
'b' => ['c'=>'C'] 'b' => ['c' => 'C']
]; ];
$a = new FlatArray($data); $a = new FlatArray($data);
//setting on first layer //setting on first layer
@ -91,7 +93,7 @@ class FlatArrayTest extends TestCase
public function testSettingFalseyValues() public function testSettingFalseyValues()
{ {
$a = new FlatArray(['foo'=>['bar'=>'baz']]); $a = new FlatArray(['foo' => ['bar' => 'baz']]);
$a['foo.bar'] = false; $a['foo.bar'] = false;
$this->assertFalse($a['foo.bar']); $this->assertFalse($a['foo.bar']);
$a['foo.bar'] = 0; $a['foo.bar'] = 0;
@ -104,21 +106,21 @@ class FlatArrayTest extends TestCase
public function testMerginFalseyValues() public function testMerginFalseyValues()
{ {
$a = new FlatArray(['foo'=>['bar'=>'baz']]); $a = new FlatArray(['foo' => ['bar' => 'baz']]);
$a->merge(['foo'=>['bar'=>false]], null, true); $a->merge(['foo' => ['bar' => false]], null, true);
$this->assertFalse($a['foo.bar']); $this->assertFalse($a['foo.bar']);
$a->merge(['foo'=>['bar'=>0]], null, true); $a->merge(['foo' => ['bar' => 0]], null, true);
$this->assertSame(0, $a['foo.bar']); $this->assertSame(0, $a['foo.bar']);
$a->merge(['foo'=>['bar'=>'']], null, true); $a->merge(['foo' => ['bar' => '']], null, true);
$this->assertSame('', $a['foo.bar']); $this->assertSame('', $a['foo.bar']);
$a->merge(['foo'=>['bar'=>[]]], null, true); $a->merge(['foo' => ['bar' => []]], null, true);
$this->assertSame([], $a['foo.bar']); $this->assertSame([], $a['foo.bar']);
} }
public function testCaseSensitivity() public function testCaseSensitivity()
{ {
$h = new FlatArray([ $h = new FlatArray([
'ABC'=>['ABC'=>'ABC'] 'ABC' => ['ABC' => 'ABC']
]); ]);
$this->assertNull($h['abc.abc']); $this->assertNull($h['abc.abc']);
$this->assertNull($h['Abc.aBC']); $this->assertNull($h['Abc.aBC']);
@ -126,7 +128,7 @@ class FlatArrayTest extends TestCase
public function testAccidentalSubstrings() public function testAccidentalSubstrings()
{ {
$h = new FlatArray(['foo'=>'bar']); $h = new FlatArray(['foo' => 'bar']);
$this->assertNull($h['foo.baz']); $this->assertNull($h['foo.baz']);
} }
@ -169,7 +171,7 @@ class FlatArrayTest extends TestCase
//overwrite false with mismatched array-ness //overwrite false with mismatched array-ness
$c = new FlatArray($data); $c = new FlatArray($data);
$c->merge([ $c->merge([
'a' => ['b'=>'c'], 'a' => ['b' => 'c'],
'c' => 'd' 'c' => 'd'
]); ]);
$this->assertEquals('b', $c['a']); $this->assertEquals('b', $c['a']);
@ -177,21 +179,116 @@ class FlatArrayTest extends TestCase
//overwrite true with mismatched array-ness //overwrite true with mismatched array-ness
$c = new FlatArray($data); $c = new FlatArray($data);
$c->merge([ $c->merge([
'a' => ['b'=>'c'], 'a' => ['b' => 'c'],
'c' => 'd' 'c' => 'd'
], null, true); ], null, true);
$this->assertEquals('c', $c['a.b']); $this->assertEquals('c', $c['a.b']);
$this->assertEquals('d', $c['c']); $this->assertEquals('d', $c['c']);
} }
public function testMergeViaSet()
{
$arr = new FlatArray([
'a' => [
'a' => 'b',
'c' => 'd'
]
]);
$arr->set('a', [
'e' => 'f',
'g' => 'h'
]);
$this->assertEquals(
[
'a' => [
'a' => 'b',
'c' => 'd',
'e' => 'f',
'g' => 'h'
]
],
$arr->get()
);
}
public function testNoMergeRootViaSet()
{
$arr = new FlatArray([
'a' => 'b',
'c' => 'd'
]);
$arr->set(null, [
'e' => 'f',
'g' => 'h'
]);
$this->assertEquals(
[
'e' => 'f',
'g' => 'h'
],
$arr->get()
);
}
public function testMergeViaSetOverNonArray()
{
$arr = new FlatArray([
'a' => 'b'
]);
$arr->set('a', [
'e' => 'f',
'g' => 'h'
]);
$this->assertEquals(
[
'a' => [
'e' => 'f',
'g' => 'h'
]
],
$arr->get()
);
}
public function testConstructionUnflattening() public function testConstructionUnflattening()
{ {
$arr = new FlatArray([ $arr = new FlatArray([
'foo.bar' => 'baz' 'foo.bar' => 'baz'
]); ]);
$this->assertEquals( $this->assertEquals(
['foo'=>['bar'=>'baz']], ['foo' => ['bar' => 'baz']],
$arr->get() $arr->get()
); );
} }
public function testUnset()
{
$arr = new FlatArray([
'a' => [
'b' => 'c',
'd' => 'e'
]
]);
unset($arr['a.b']);
$this->assertEquals([
'a' => [
'd' => 'e'
]
], $arr->get());
// unset root
$arr->unset(null);
$this->assertEquals([], $arr->get());
}
public function testForeach()
{
$reference = [
'b' => 'c',
'd' => 'e'
];
$arr = new FlatArray($reference);
foreach ($arr as $key => $value) {
$this->assertEquals($reference[$key], $value);
}
}
} }

View file

@ -1,6 +1,8 @@
<?php <?php
/* Flatrr | https://gitlab.com/byjoby/flatrr | MIT License */ /* Flatrr | https://github.com/jobyone/flatrr | MIT License */
declare(strict_types=1); declare(strict_types=1);
namespace Flatrr; namespace Flatrr;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -11,7 +13,7 @@ class SelfReferencingFlatArrayTest extends TestCase
{ {
$f = new SelfReferencingFlatArray([ $f = new SelfReferencingFlatArray([
'foo' => 'bar', 'foo' => 'bar',
'bar' => ['baz'=>'qux'], 'bar' => ['baz' => 'qux'],
'test' => [ 'test' => [
'foo' => '${foo}', 'foo' => '${foo}',
'bar' => '${bar.baz}', 'bar' => '${bar.baz}',
@ -49,11 +51,13 @@ class SelfReferencingFlatArrayTest extends TestCase
$this->assertEquals('${foo}', $f['nested.escaped.full']); $this->assertEquals('${foo}', $f['nested.escaped.full']);
$this->assertEquals('${foo}', $f['nested.escaped.left']); $this->assertEquals('${foo}', $f['nested.escaped.left']);
$this->assertEquals('${foo}', $f['nested.escaped.right']); $this->assertEquals('${foo}', $f['nested.escaped.right']);
//raw
$this->assertEquals('${foo}', $f->get('test.foo', true));
} }
public function testSettingFalseyValues() public function testSettingFalseyValues()
{ {
$a = new SelfReferencingFlatArray(['foo'=>['bar'=>'baz']]); $a = new SelfReferencingFlatArray(['foo' => ['bar' => 'baz']]);
$a['foo.bar'] = false; $a['foo.bar'] = false;
$this->assertFalse($a['foo.bar']); $this->assertFalse($a['foo.bar']);
$a['foo.bar'] = 0; $a['foo.bar'] = 0;
@ -64,16 +68,53 @@ class SelfReferencingFlatArrayTest extends TestCase
$this->assertSame([], $a['foo.bar']); $this->assertSame([], $a['foo.bar']);
} }
public function testMerginFalseyValues() public function testMergingFalseyValues()
{ {
$a = new SelfReferencingFlatArray(['foo'=>['bar'=>'baz']]); $a = new SelfReferencingFlatArray(['foo' => ['bar' => 'baz']]);
$a->merge(['foo'=>['bar'=>false]], null, true); $a->merge(['foo' => ['bar' => false]], null, true);
$this->assertFalse($a['foo.bar']); $this->assertFalse($a['foo.bar']);
$a->merge(['foo'=>['bar'=>0]], null, true); $a->merge(['foo' => ['bar' => 0]], null, true);
$this->assertSame(0, $a['foo.bar']); $this->assertSame(0, $a['foo.bar']);
$a->merge(['foo'=>['bar'=>'']], null, true); $a->merge(['foo' => ['bar' => '']], null, true);
$this->assertSame('', $a['foo.bar']); $this->assertSame('', $a['foo.bar']);
$a->merge(['foo'=>['bar'=>[]]], null, true); $a->merge(['foo' => ['bar' => []]], null, true);
$this->assertSame([], $a['foo.bar']); $this->assertSame([], $a['foo.bar']);
} }
public function testForeach()
{
$reference = [
'a' => 'b',
'b' => '${a}',
'd' => '${b}'
];
$arr = new SelfReferencingFlatArray($reference);
foreach ($arr as $key => $value) {
$this->assertEquals('b', $value);
}
}
public function testPop()
{
$f = new SelfReferencingFlatArray([
'a' => 'b',
'c' => [
'${a}'
]
]);
$this->assertEquals('b', $f->pop('c'));
$this->assertNull($f->pop('c'));
}
public function testShift()
{
$f = new SelfReferencingFlatArray([
'a' => 'b',
'c' => [
'${a}'
]
]);
$this->assertEquals('b', $f->shift('c'));
$this->assertNull($f->shift('c'));
}
} }