1
0
mirror of https://github.com/guzzle/guzzle.git synced 2025-02-13 03:45:22 +01:00

[Common] Removing the ability to skip cache in the Inflector. Adding a cap to the number of items that can be cached by the Inflector.

This commit is contained in:
Michael Dowling 2011-03-27 17:08:35 -05:00
parent 08d18f6187
commit 8d266bb314
2 changed files with 87 additions and 23 deletions

View File

@ -7,19 +7,27 @@
namespace Guzzle\Common;
/**
* Static inflector class
* Guzzle inflector class to transform snake_case to CamelCase and vice-versa.
*
* Previously computed values are cached internally using a capped array. When
* the cache is filled, the first 10% of the cached array will be removed.
*
* @author Michael Dowling <michael@guzzlephp.org>
*/
class Inflector
{
/**
* @var array Setter/Getter snake transformation cache
* @var int Cap each internal cache
*/
const MAX_ENTRIES_PER_CACHE = 1000;
/**
* @var array snake_case transformation cache
*/
protected static $snakeCache = array();
/**
* @var array Setter/Getter camelCase transformation cache
* @var array CamelCase transformation cache
*/
protected static $camelCache = array();
@ -30,13 +38,14 @@ class Inflector
* Borrowed from Magento
*
* @param string $word Word to convert to snake case
* @param bool $skipCache (optional) Set to TRUE to not cache the result
*
* @return string
*/
public static function snake($word, $skipCache = false)
public static function snake($word)
{
if (!$skipCache && isset(self::$snakeCache[$word])) {
static $cached = 0;
if (isset(self::$snakeCache[$word])) {
return self::$snakeCache[$word];
}
@ -46,34 +55,52 @@ class Inflector
$result = strtolower(preg_replace('/(.)([A-Z])/', "$1_$2", $word));
}
if (!$skipCache) {
self::$snakeCache[$word] = $result;
if (++$cached > self::MAX_ENTRIES_PER_CACHE) {
$toRemove = self::MAX_ENTRIES_PER_CACHE * 0.1;
self::$snakeCache = array_slice(self::$snakeCache, $toRemove);
$cached -= $toRemove;
}
return $result;
return self::$snakeCache[$word] = $result;
}
/**
* Converts strings from snake case to camel case (e.g. snake_case
* CamelCase)
* Converts strings from snake_case to upper CamelCase
*
* @param string $word Value to camelize
* @param bool $skipCache (optional) Set to TRUE to not cache the result
* @param string $word Value to convert into upper CamelCase
*
* @return string
*/
public static function camel($word, $skipCache = false)
public static function camel($word)
{
if (!$skipCache && isset(self::$camelCache[$word])) {
static $cached = 0;
if (isset(self::$camelCache[$word])) {
return self::$camelCache[$word];
}
$result = lcfirst(str_replace(' ', '', ucwords(strtr($word, '_-', ' '))));
$result = str_replace(' ', '', ucwords(strtr($word, '_-', ' ')));
if (!$skipCache) {
self::$camelCache[$word] = $result;
if (++$cached > self::MAX_ENTRIES_PER_CACHE) {
$toRemove = self::MAX_ENTRIES_PER_CACHE * 0.1;
self::$camelCache = array_slice(self::$camelCache, $toRemove);
$cached -= $toRemove;
}
return $result;
return self::$camelCache[$word] = $result;
}
/**
* Get cache information from the inflector
*
* @return array Returns an array containing a snake and camel key, and each
* value of each cache in a sub-array
*/
public static function getCache()
{
return array(
'snake' => self::$snakeCache,
'camel' => self::$camelCache
);
}
}

View File

@ -32,12 +32,49 @@ class InflectorTest extends \Guzzle\Tests\GuzzleTestCase
*/
public function testCamel()
{
$this->assertEquals('camelCase', Inflector::camel('camel_case'));
$this->assertEquals('camelCaseWords', Inflector::camel('camel_case_words'));
$this->assertEquals('test', Inflector::camel('test'));
$this->assertEquals('CamelCase', Inflector::camel('camel_case'));
$this->assertEquals('CamelCaseWords', Inflector::camel('camel_case_words'));
$this->assertEquals('Test', Inflector::camel('test'));
$this->assertEquals('Expect100Continue', ucfirst(Inflector::camel('expect100_continue')));
// Get from cache
$this->assertEquals('test', Inflector::camel('test', false));
$this->assertEquals('Test', Inflector::camel('test', false));
}
/**
* @covers Guzzle\Common\Inflector::camel
* @covers Guzzle\Common\Inflector::snake
* @covers Guzzle\Common\Inflector::getCache
*/
public function testProtectsAgainstCacheOverflow()
{
$perCachePurge = Inflector::MAX_ENTRIES_PER_CACHE * 0.1;
$cached = Inflector::getCache();
$currentSnake = count($cached['snake']);
$currentCamel = count($cached['camel']);
unset($cached);
// Fill each cache with garbage, then make sure it flushes out cached
// entries and maintains a cache cap
while (++$currentSnake < Inflector::MAX_ENTRIES_PER_CACHE + 1) {
Inflector::snake(uniqid());
}
while (++$currentCamel < Inflector::MAX_ENTRIES_PER_CACHE + 1) {
Inflector::camel(uniqid());
}
$cached = Inflector::getCache();
$this->assertEquals(Inflector::MAX_ENTRIES_PER_CACHE, count($cached['snake']));
$this->assertEquals(Inflector::MAX_ENTRIES_PER_CACHE, count($cached['camel']));
unset($cached);
// Add another element to each cache to remove 10% of the cache
Inflector::snake(uniqid());
Inflector::camel(uniqid());
$cached = Inflector::getCache();
$this->assertEquals(Inflector::MAX_ENTRIES_PER_CACHE - $perCachePurge + 1, count($cached['snake']));
$this->assertEquals(Inflector::MAX_ENTRIES_PER_CACHE - $perCachePurge + 1, count($cached['camel']));
}
}