From 56874b4d090ea324ec2882ad4bd74a8043858e3a Mon Sep 17 00:00:00 2001 From: Corey Frenette Date: Thu, 18 Feb 2016 19:15:51 -0400 Subject: [PATCH 1/3] Take method + writable collection trait tests --- src/Interfaces/WritableCollection.php | 11 +++++++++++ src/Traits/WritableCollectionTrait.php | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/Interfaces/WritableCollection.php b/src/Interfaces/WritableCollection.php index b10ac8b..327a214 100644 --- a/src/Interfaces/WritableCollection.php +++ b/src/Interfaces/WritableCollection.php @@ -30,6 +30,17 @@ public function set($key, $value); */ public function lazy($key, callable $initializer); + /** + * Removes a key from the collection and returns its value + * + * @param mixed $key The key + * @param mixed $default (optional) A default value to return if the collection does not + * contain `$key`. Prevents NoSuchValueException from being thrown. + * + * @return mixed The value associated with the key + */ + public function take($key, $default = null); + /** * Removes a key from the array * diff --git a/src/Traits/WritableCollectionTrait.php b/src/Traits/WritableCollectionTrait.php index 055dff5..2994e58 100644 --- a/src/Traits/WritableCollectionTrait.php +++ b/src/Traits/WritableCollectionTrait.php @@ -1,5 +1,6 @@ collection[$key] = new LazyInitializer($initializer); } + /** + * {@inheritdoc} + */ + public function take($key, $default = null) { + if(!array_key_exists($key, $this->collection)) { + if(func_num_args() < 2) { + throw new NoSuchKeyException($key); + } else { + return $default; + } + } + + $value = $this->collection[$key]; + + if($value instanceof LazyInitializer) { + $value = $value($key); + $this->collection[$key] = $value; + } + + $this->remove($key); + + return $value; + } + /** * Removes a key from the array * From ee2ed3ae5c92a84b8a31a750924d5ea0e00d6b9c Mon Sep 17 00:00:00 2001 From: Corey Frenette Date: Thu, 18 Feb 2016 19:16:28 -0400 Subject: [PATCH 2/3] Tests --- tests/WritableCollectionTraitTest.php | 77 +++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 tests/WritableCollectionTraitTest.php diff --git a/tests/WritableCollectionTraitTest.php b/tests/WritableCollectionTraitTest.php new file mode 100644 index 0000000..39cf623 --- /dev/null +++ b/tests/WritableCollectionTraitTest.php @@ -0,0 +1,77 @@ +trait = $this + ->getMockBuilder(WritableCollectionTrait::class) + ->getMockForTrait() + ; + + $class = new ReflectionClass($this->trait); + $this->collection = $class->getProperty('collection'); + $this->collection->setAccessible(true); + } + + public function testAdd() { + $this->trait->add('test'); + + $this->assertSame(['test'], $this->getCollection()); + + $this->trait->add('test2'); + + $this->assertSame(['test', 'test2'], $this->getCollection()); + } + + public function testSet() { + $this->trait->set('key1', 'val1'); + + $this->assertSame(['key1' => 'val1'], $this->getCollection()); + + $this->trait->set('key2', 'val2'); + + $this->assertSame(['key1' => 'val1', 'key2' => 'val2'], $this->getCollection()); + } + + public function testAddAndSet() { + $this->trait->add('test'); + $this->trait->set('key1', 'val1'); + + $this->assertSame(['test', 'key1' => 'val1'], $this->getCollection()); + } + + public function testTake() { + $this->setCollection(['key1' => 'val1', 'key2' => 'val2']); + + $this->assertSame(['key1' => 'val1', 'key2' => 'val2'], $this->getCollection()); + $this->assertSame('val1', $this->trait->take('key1')); + $this->assertSame(['key2' => 'val2'], $this->getCollection()); + $this->assertSame('already removed', $this->trait->take('key1', 'already removed')); + + $this->setExpectedException(NoSuchKeyException::class); + $this->trait->take('non-existant key'); + } + + public function testRemove() { + $this->setCollection(['key1' => 'val1', 'key2' => 'val2']); + + $this->assertSame(['key1' => 'val1', 'key2' => 'val2'], $this->getCollection()); + + $this->trait->remove('key1'); + + $this->assertSame(['key2' => 'val2'], $this->getCollection()); + } + + private function getCollection() { + return $this->collection->getValue($this->trait); + } + + private function setCollection(array $collection) { + $this->collection->setValue($this->trait, $collection); + } +} From 2ccdbc1c816ca82610b3ac8ff316d9804baffebd Mon Sep 17 00:00:00 2001 From: Corey Frenette Date: Thu, 18 Feb 2016 20:28:13 -0400 Subject: [PATCH 3/3] Improved lazy-loading (closes #2, closes #4) --- src/LazyInitializer.php | 34 ------------------- src/Traits/ReadableCollectionTrait.php | 45 +++++++++++++++++++------- src/Traits/WritableCollectionTrait.php | 18 +++++++---- 3 files changed, 46 insertions(+), 51 deletions(-) delete mode 100644 src/LazyInitializer.php diff --git a/src/LazyInitializer.php b/src/LazyInitializer.php deleted file mode 100644 index 5ba4200..0000000 --- a/src/LazyInitializer.php +++ /dev/null @@ -1,34 +0,0 @@ -initializer = $initializer; - } - - /** - * Invokes the callable registered for this value - * - * @param mixed $key The key - * - * @returns mixed The lazy-loaded value - */ - public function __invoke($key) { - $initializer = $this->initializer; - return $initializer($key); - } -} diff --git a/src/Traits/ReadableCollectionTrait.php b/src/Traits/ReadableCollectionTrait.php index dd60a6a..348f11e 100644 --- a/src/Traits/ReadableCollectionTrait.php +++ b/src/Traits/ReadableCollectionTrait.php @@ -1,7 +1,6 @@ collection[$key]; - // Is it a lazy-loaded value - if($value instanceof LazyInitializer) { - // Evaluate and cache the result + if(array_key_exists($key, $this->lazy)) { $value = $value($key); $this->collection[$key] = $value; + unset($this->lazy[$key]); } return $value; @@ -68,7 +65,16 @@ public function first() { throw new NoSuchKeyException(null, 'Can\'t get first value from empty collection'); } - return reset($this->collection); + $value = reset($this->collection); + $key = key($this->collection); + + if(array_key_exists($key, $this->lazy)) { + $value = $value($key); + $this->collection[$key] = $value; + unset($this->lazy[$key]); + } + + return $value; } /** @@ -83,7 +89,16 @@ public function last() { throw new NoSuchKeyException(null, 'Can\'t get last value from empty collection'); } - return end($this->collection); + $value = end($this->collection); + $key = key($this->collection); + + if(array_key_exists($key, $this->lazy)) { + $value = $value($key); + $this->collection[$key] = $value; + unset($this->lazy[$key]); + } + + return $value; } /** @@ -93,6 +108,14 @@ public function last() { * values contained in the collection. */ public function all() { + if(!empty($this->lazy)) { + foreach($this->lazy as $key) { + $this->collection[$key] = $this->collection[$key]($key); + } + + $this->lazy = []; + } + return $this->collection; } @@ -105,7 +128,7 @@ public function all() { * `function($key, $value)` */ public function each(callable $callback) { - array_walk($this->collection, $callback); + array_walk($this->all(), $callback); } /** @@ -114,7 +137,7 @@ public function each(callable $callback) { * @returns array An array of all keys contained in the collection */ public function keys() { - return array_keys($this->collection); + return array_keys($this->all()); } /** @@ -123,7 +146,7 @@ public function keys() { * @returns array An array of all values contained in the collection */ public function values() { - return array_values($this->collection); + return array_values($this->all()); } /** @@ -132,7 +155,7 @@ public function values() { * @returns int The size of the collection */ public function size() { - return count($this->collection); + return count($this->all()); } /** diff --git a/src/Traits/WritableCollectionTrait.php b/src/Traits/WritableCollectionTrait.php index 2994e58..e9d51fd 100644 --- a/src/Traits/WritableCollectionTrait.php +++ b/src/Traits/WritableCollectionTrait.php @@ -1,7 +1,6 @@ + */ + protected $lazy = []; + /** * Constructs a new WritableCollectionTrait * @@ -51,7 +57,8 @@ public function set($key, $value) { * the desired value upon first request. */ public function lazy($key, callable $initializer) { - $this->collection[$key] = new LazyInitializer($initializer); + $this->collection[$key] = $initializer; + $this->lazy[$key] = $key; } /** @@ -67,14 +74,13 @@ public function take($key, $default = null) { } $value = $this->collection[$key]; + $this->remove($key); - if($value instanceof LazyInitializer) { + if(array_key_exists($key, $this->lazy)) { $value = $value($key); - $this->collection[$key] = $value; + unset($this->lazy[$key]); } - $this->remove($key); - return $value; }