before_script: composer install
-script: phpunit --coverage-text --color tests
+script: phpunit --coverage-text --colors tests
{
"name": "m6w6/merry",
"type": "library",
- "description": "Merry Configuration Container",
+ "description": "Merry container and configuration",
"keywords": ["merry", "config", "configuration", "container"],
"homepage": "http://github.com/m6w6/merry",
"license": "BSD-2-Clause",
}
],
"autoload": {
- "psr-0": {
- "merry\\Config": "lib"
+ "psr-4": {
+ "merry\\": "lib/merry"
}
}
}
* @see https://github.com/m6w6/merry
* @package merry\Config
*/
-class Config implements \ArrayAccess, \RecursiveIterator
+class Config extends Container
{
- /**
- * Index for a numerically indexed array
- * @internal
- * @var int
- */
- private $index = 0;
-
- /**
- * Container
- * @internal
- * @var stdClass
- */
- private $props;
-
- /**
- * State for the RecursiveIterator
- * @internal
- * @var array
- */
- private $riter;
-
/**
* Create a new configuration container
* @param array $array the configuration array
* @param string $key_sep a separator for key traversal
*/
public function __construct(array $array = null, $section = null, $section_sep = ":", $key_sep = ".") {
- $this->props = new \stdClass;
-
if (isset($section) && strlen($section_sep)) {
$array = $this->combine($array, $section_sep)[$section];
}
$this->walk($config, $key, $val, $key_sep);
}
}
-
- foreach ($config as $property => $value) {
- $this->__set($property, $value);
- }
+ parent::__construct($config, false);
}
}
}
$ptr = $val;
}
-
- /**
- * Recursively turn a Config instance and its childs into an array
- * @param \merry\Config $o the Config instance to convert to an array
- * @return array
- */
- protected function arrayify(Config $o) {
- $a = [];
-
- foreach ($o->props as $k => $v) {
- if ($v instanceof Config) {
- $a[$k] = $this->arrayify($v);
- } else {
- $a[$k] = $v;
- }
- }
-
- return $a;
- }
-
- /**
- * Apply one or mor modifier callbacks
- * @param mixed $modifier
- * @return \merry\Config
- */
- public function apply($modifier) {
- if (is_callable($modifier)) {
- foreach ($this->props as $prop => $value) {
- $this->__set($prop, $modifier($value, $prop));
- }
- } else {
- foreach ($modifier as $key => $mod) {
- if (is_callable($mod)) {
- $this->props->$key = $mod(isset($this->props->$key) ? $this->props->$key : null, $key);
- } elseif (is_array($mod)) {
- $this->props->$key->apply($mod);
- } else {
- /* */
- }
- }
- }
- return $this;
- }
-
- /**
- * Return the complete config as array
- * @return array
- */
- function toArray() {
- return $this->arrayify($this);
- }
-
- /**
- * @ignore
- */
- function __get($prop) {
- return $this->props->$prop;
- }
-
- /**
- * @ignore
- */
- function __set($prop, $value) {
- if (isset($value) && !is_scalar($value) && !($value instanceof Config)) {
- $value = new static((array) $value);
- }
- if (!strlen($prop)) {
- $prop = $this->index++;
- } elseif (is_numeric($prop) && !strcmp($prop, (int) $prop)) {
- /* update internal index */
- if ($prop >= $this->index) {
- $this->index = $prop + 1;
- }
- }
-
- $this->props->$prop = $value;
- }
-
- /**
- * @ignore
- */
- function __isset($prop) {
- return isset($this->props->$prop);
- }
-
- /**
- * @ignore
- */
- function __unset($prop) {
- unset($this->props->$prop);
- }
-
- /**
- * @ignore
- */
- function offsetGet($o) {
- return $this->props->$o;
- }
-
- /**
- * @ignore
- */
- function offsetSet($o, $v) {
- $this->__set($o, $v);
- }
-
- /**
- * @ignore
- */
- function offsetExists($o) {
- return isset($this->props->$o);
- }
-
- /**
- * @ignore
- */
- function offsetUnset($o) {
- unset($this->props->$o);
- }
-
- /**
- * @ignore
- */
- function rewind() {
- $this->riter = (array) $this->props;
- reset($this->riter);
- }
-
- /**
- * @ignore
- */
- function valid() {
- return NULL !== key($this->riter);
- }
-
- /**
- * @ignore
- */
- function next() {
- next($this->riter);
- }
-
- /**
- * @ignore
- */
- function key() {
- return key($this->riter);
- }
-
- /**
- * @ignore
- */
- function current() {
- return current($this->riter);
- }
-
- /**
- * @ignore
- */
- function hasChildren() {
- return current($this->riter) instanceof Config;
- }
-
- /**
- * @ignore
- */
- function getChildren() {
- return current($this->riter);
- }
}
+
+/* vim: set noet ts=4 sw=4: */
--- /dev/null
+<?php
+
+namespace merry;
+
+class Container implements \ArrayAccess, \RecursiveIterator, \JsonSerializable
+{
+ /**
+ * Index for a numerically indexed array
+ * @internal
+ * @var int
+ */
+ private $index = 0;
+
+ /**
+ * Container
+ * @internal
+ * @var stdClass
+ */
+ private $props;
+
+ /**
+ * State for the RecursiveIterator
+ * @internal
+ * @var array
+ */
+ private $riter;
+
+ /**
+ * Whether to auto populate a requested property with a new container
+ * @internal
+ * @var bool
+ */
+ private $auto;
+
+ /**
+ * Create a new container
+ * @param array $array container data
+ * @param bool $auto whether to auto populate a requested property with a new container
+ */
+ function __construct(array $array = null, $auto = true) {
+ $this->props = new \stdClass;
+ $this->auto = $auto;
+
+ foreach ((array) $array as $property => $value) {
+ $this->__set($property, $value);
+ }
+ }
+
+ /**
+ * Recursively turn a container and its childs into an array
+ * @param \merry\Container $o the Container instance to convert to an array
+ * @return array
+ */
+ protected function arrayify(Container $o) {
+ $a = [];
+
+ foreach ($o->props as $k => $v) {
+ if ($v instanceof Container) {
+ $a[$k] = $this->arrayify($v);
+ } else {
+ $a[$k] = $v;
+ }
+ }
+
+ return $a;
+ }
+
+ /**
+ * Apply one or mor modifier callbacks
+ * @param mixed $modifier
+ * @return \merry\Config
+ */
+ public function apply($modifier) {
+ if (is_callable($modifier)) {
+ foreach ($this->props as $prop => $value) {
+ $this->__set($prop, $modifier($value, $prop));
+ }
+ } else {
+ foreach ($modifier as $key => $mod) {
+ if (is_callable($mod)) {
+ $this->props->$key = $mod(isset($this->props->$key) ? $this->props->$key : null, $key);
+ } elseif (is_array($mod)) {
+ $this->props->$key->apply($mod);
+ } else {
+ /* */
+ }
+ }
+ }
+ return $this;
+ }
+
+ /**
+ * Return the complete config as array
+ * @return array
+ */
+ function toArray() {
+ return $this->arrayify($this);
+ }
+
+ /**
+ * @ignore
+ */
+ function &__get($prop) {
+ if ($this->auto && !isset($this->props->$prop)) {
+ $this->props->$prop = new static;
+ }
+ return $this->props->$prop;
+ }
+
+ /**
+ * @ignore
+ */
+ function __set($prop, $value) {
+ if (isset($value) && !is_scalar($value) && !($value instanceof Config)) {
+ $value = new static((array) $value);
+ }
+ if (!strlen($prop)) {
+ $prop = $this->index++;
+ } elseif (is_numeric($prop) && !strcmp($prop, (int) $prop)) {
+ /* update internal index */
+ if ($prop >= $this->index) {
+ $this->index = $prop + 1;
+ }
+ }
+
+ $this->props->$prop = $value;
+ }
+
+ /**
+ * @ignore
+ */
+ function __isset($prop) {
+ return isset($this->props->$prop);
+ }
+
+ /**
+ * @ignore
+ */
+ function __unset($prop) {
+ unset($this->props->$prop);
+ }
+
+ /**
+ * @ignore
+ */
+ function offsetGet($o) {
+ return $this->props->$o;
+ }
+
+ /**
+ * @ignore
+ */
+ function offsetSet($o, $v) {
+ $this->__set($o, $v);
+ }
+
+ /**
+ * @ignore
+ */
+ function offsetExists($o) {
+ return isset($this->props->$o);
+ }
+
+ /**
+ * @ignore
+ */
+ function offsetUnset($o) {
+ unset($this->props->$o);
+ }
+
+ /**
+ * @ignore
+ */
+ function rewind() {
+ $this->riter = (array) $this->props;
+ reset($this->riter);
+ }
+
+ /**
+ * @ignore
+ */
+ function valid() {
+ return NULL !== key($this->riter);
+ }
+
+ /**
+ * @ignore
+ */
+ function next() {
+ next($this->riter);
+ }
+
+ /**
+ * @ignore
+ */
+ function key() {
+ return key($this->riter);
+ }
+
+ /**
+ * @ignore
+ */
+ function current() {
+ return current($this->riter);
+ }
+
+ /**
+ * @ignore
+ */
+ function hasChildren() {
+ return current($this->riter) instanceof Container;
+ }
+
+ /**
+ * @ignore
+ */
+ function getChildren() {
+ return current($this->riter);
+ }
+
+ /**
+ * @ignore
+ */
+ function jsonSerialize() {
+ return $this->arrayify($this);
+ }
+}
+
+/* vim: set noet ts=4 sw=4: */
/**
* @covers merry\Config
*/
-class ConfigTest extends \PHPUnit_Framework_TestCase {
-
- public function testBasic() {
- $config = ["foo" => "bar", "bar" => "foo"];
- $object = new Config($config);
- $this->assertEquals($config, $object->toArray());
- $this->assertEquals("bar", $object->foo);
- $this->assertEquals("foo", $object->bar);
- $this->assertTrue(isset($object->foo));
- $this->assertFalse(isset($object->foobar));
- unset($object->bar);
- $this->assertFalse(isset($object->bar));
- }
-
- public function testBasicOffset() {
- $config = ["foo" => "bar", "bar" => "foo"];
- $object = new Config($config);
- $this->assertEquals("bar", $object["foo"]);
- $this->assertEquals("foo", $object["bar"]);
- $this->assertTrue(isset($object["foo"]));
- $this->assertFalse(isset($object["foobar"]));
- unset($object["bar"]);
- $this->assertFalse(isset($object["bar"]));
- }
-
+class ConfigTest extends \PHPUnit_Framework_TestCase
+{
public function testBasicSection() {
$config = [
"primary" => [
$object = new Config($config, "alternative");
$this->assertEquals($config["alternative : primary"] + $config["primary"], $object->toArray());
}
-
- public function testSetArray() {
- $config = ["foo" => "bar", "arr" => [1,2,3]];
- $object = new Config($config);
- $object["foo"] = [$object->foo, "baz"];
- $object["arr"][] = 4;
-
- $this->assertEquals(["bar", "baz"], $object["foo"]->toArray());
- $this->assertEquals([1,2,3,4], $object["arr"]->toArray());
-
- $this->assertEquals(["foo"=>["bar","baz"], "arr"=>[1,2,3,4]], $object->toArray());
- }
-
- public function testApply() {
- $config = [
- "level1" => [
- "level2" => [
- "level3" => "123"
- ],
- "level2-1" => [
- "level3-1" => "321"
- ]
- ]
- ];
- $object = new Config($config);
- $this->assertEquals("123", $object->level1["level2"]->level3);
- $reverse = function ($v){return strrev($v);};
- $object->apply([
- "level1" => [
- "level2" => [
- "level3" => $reverse
- ],
- "level2-1" => [
- "level3-1" => $reverse
- ]
- ]
- ]);
- $compare = [
- "level1" => [
- "level2" => [
- "level3" => "321"
- ],
- "level2-1" => [
- "level3-1" => "123"
- ]
- ]
- ];
- $this->assertEquals($compare, $object->toArray());
-
- $object->apply(function() {
- return null;
- });
- $this->assertEquals(["level1" => null], $object->toArray());
- }
-
- public function testIterator() {
- $config = [
- "level1-0" => [
- "level2-0" => "1-0.2-0",
- "level2-1" => "1-0.2-1",
- "level2-2" => [
- "level3" => "1-0.2-2.3"
- ]
- ],
- "level1-1" => [
- 1,2,3
- ]
- ];
- $object = new Config($config);
- $array = [];
- foreach (new \RecursiveIteratorIterator($object) as $key => $val) {
- $array[$key] = $val;
- }
- $compare = [
- 'level2-0' => '1-0.2-0',
- 'level2-1' => '1-0.2-1',
- 'level3' => '1-0.2-2.3',
- 1, 2, 3
- ];
- $this->assertEquals($compare, $array);
- }
}
--- /dev/null
+<?php
+
+namespace merry;
+
+require __DIR__."/../../vendor/autoload.php";
+
+/**
+ * @covers merry\Container
+ */
+class ContainerTest extends \PHPUnit_Framework_TestCase
+{
+ public function testBasic() {
+ $config = ["foo" => "bar", "bar" => "foo"];
+ $object = new Container($config);
+ $this->assertEquals($config, $object->toArray());
+ $this->assertEquals("bar", $object->foo);
+ $this->assertEquals("foo", $object->bar);
+ $this->assertTrue(isset($object->foo));
+ $this->assertFalse(isset($object->foobar));
+ unset($object->bar);
+ $this->assertFalse(isset($object->bar));
+ }
+
+ public function testBasicOffset() {
+ $config = ["foo" => "bar", "bar" => "foo"];
+ $object = new Container($config);
+ $this->assertEquals("bar", $object["foo"]);
+ $this->assertEquals("foo", $object["bar"]);
+ $this->assertTrue(isset($object["foo"]));
+ $this->assertFalse(isset($object["foobar"]));
+ unset($object["bar"]);
+ $this->assertFalse(isset($object["bar"]));
+ }
+
+ public function testSetArray() {
+ $config = ["foo" => "bar", "arr" => [1,2,3]];
+ $object = new Container($config);
+ $object["foo"] = [$object->foo, "baz"];
+ $object["arr"][] = 4;
+
+ $this->assertEquals(["bar", "baz"], $object["foo"]->toArray());
+ $this->assertEquals([1,2,3,4], $object["arr"]->toArray());
+
+ $this->assertEquals(["foo"=>["bar","baz"], "arr"=>[1,2,3,4]], $object->toArray());
+ }
+
+ public function testApply() {
+ $config = [
+ "level1" => [
+ "level2" => [
+ "level3" => "123"
+ ],
+ "level2-1" => [
+ "level3-1" => "321"
+ ]
+ ]
+ ];
+ $object = new Container($config);
+ $this->assertEquals("123", $object->level1["level2"]->level3);
+ $reverse = function ($v){return strrev($v);};
+ $object->apply([
+ "level1" => [
+ "level2" => [
+ "level3" => $reverse
+ ],
+ "level2-1" => [
+ "level3-1" => $reverse
+ ]
+ ]
+ ]);
+ $compare = [
+ "level1" => [
+ "level2" => [
+ "level3" => "321"
+ ],
+ "level2-1" => [
+ "level3-1" => "123"
+ ]
+ ]
+ ];
+ $this->assertEquals($compare, $object->toArray());
+
+ $object->apply(function() {
+ return null;
+ });
+ $this->assertEquals(["level1" => null], $object->toArray());
+ }
+
+ public function testIterator() {
+ $config = [
+ "level1-0" => [
+ "level2-0" => "1-0.2-0",
+ "level2-1" => "1-0.2-1",
+ "level2-2" => [
+ "level3" => "1-0.2-2.3"
+ ]
+ ],
+ "level1-1" => [
+ 1,2,3
+ ]
+ ];
+ $object = new Container($config);
+ $array = [];
+ foreach (new \RecursiveIteratorIterator($object) as $key => $val) {
+ $array[$key] = $val;
+ }
+ $compare = [
+ 'level2-0' => '1-0.2-0',
+ 'level2-1' => '1-0.2-1',
+ 'level3' => '1-0.2-2.3',
+ 1, 2, 3
+ ];
+ $this->assertEquals($compare, $array);
+ }
+
+ public function testJsonSerialize() {
+ $container = new Container;
+ $container->foo = "bar";
+ $container->bar->foo = "bar";
+ $this->assertJsonStringEqualsJsonString(
+ '{"foo": "bar", "bar": {"foo": "bar"}}',
+ json_encode($container)
+ );
+ }
+}