Add segment-literal notation for expressions

This commit is contained in:
Dmitriy Simushev 2014-02-04 16:11:29 +00:00
parent 6a3e666258
commit b4c019372b
3 changed files with 61 additions and 5 deletions

52
src/Handlebars/Context.php Executable file → Normal file
View File

@ -11,6 +11,7 @@
* @author Behrooz Shabani <everplays@gmail.com>
* @author Chris Gray <chris.w.gray@gmail.com>
* @author Ulrik Lystbaek <ulrik@bettertaste.dk>
* @author Dmitriy Simushev <simushevds@gmail.com>
* @copyright 2012 (c) ParsPooyesh Co
* @copyright 2013 (c) Behrooz Shabani
* @copyright 2013 (c) f0ruD A
@ -38,6 +39,17 @@ namespace Handlebars;
class Context
{
/**
* List of charcters that cannot be used in identifiers.
*/
const NOT_VALID_NAME_CHARS = '!"#%&\'()*+,./;<=>@[\\]^`{|}~';
/**
* List of characters that cannot be used in identifiers in segment-literal
* notation.
*/
const NOT_VALID_SEGMENT_NAME_CHARS = "]";
/**
* @var array stack for context only top stack is available
*/
@ -179,13 +191,14 @@ class Context
/**
* Get a available from current context
* Supported types :
* variable , ../variable , variable.variable , .
* variable , ../variable , variable.variable , variable.[variable] , .
*
* @param string $variableName variable name to get from current context
* @param boolean $strict strict search? if not found then throw exception
*
* @throws \InvalidArgumentException in strict mode and variable not found
* @throws \RuntimeException if supplied argument is a malformed quoted string
* @throws \InvalidArgumentException if variable name is invalid
* @return mixed
*/
public function get($variableName, $strict = false)
@ -228,7 +241,7 @@ class Context
} elseif ($variableName == '@key') {
$current = $this->lastKey();
} else {
$chunks = explode('.', $variableName);
$chunks = $this->_splitVariableName($variableName);
foreach ($chunks as $chunk) {
if (is_string($current) and $current == '') {
return $current;
@ -275,4 +288,39 @@ class Context
return $value;
}
/**
* Splits variable name to chunks.
*
* @param string $variable_name Fully qualified name of a variable.
*
* @throws \InvalidArgumentException if variable name is invalid.
* @return array
*/
private function _splitVariableName($variable_name)
{
$bad_chars = preg_quote(self::NOT_VALID_NAME_CHARS, '/');
$bad_seg_chars = preg_quote(self::NOT_VALID_SEGMENT_NAME_CHARS, '/');
$name_pattern = "(?:[^" . $bad_chars . "\s]+)|(?:\[[^" . $bad_seg_chars . "]+\])";
$check_pattern = "/^((" . $name_pattern . ")\.)*(" . $name_pattern . ")\.?$/";
$get_pattern = "/(?:" . $name_pattern . ")/";
if (!preg_match($check_pattern, $variable_name)) {
throw new \InvalidArgumentException('variable name is invalid');
}
preg_match_all($get_pattern, $variable_name, $matches);
$chunks = array();
foreach ($matches[0] as $chunk) {
// Remove wrapper braces if needed
if ($chunk[0] == '[') {
$chunk = substr($chunk, 1, -1);
}
$chunks[] = $chunk;
}
return $chunks;
}
}

View File

@ -455,7 +455,7 @@ class Template
public function parseArguments($string)
{
$args = array();
preg_match_all('#(?<!\\\\)("|\')(?:[^\\\\]|\\\\.)*?\1|\S+#s', $string, $args);
preg_match_all('#(?:[^\'"\[\]\s]|\[.+?\])+|(?<!\\\\)("|\')(?:[^\\\\]|\\\\.)*?\1|\S+#s', $string, $args);
$args = isset($args[0])?$args[0]:array();
for ($x=0, $argc = count($args); $x<$argc;$x++) {

View File

@ -476,12 +476,18 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
{
$test = new stdClass();
$test->value = 'value';
$test->array = array('a' => '1', 'b' => '2');
$test->array = array(
'a' => '1',
'b' => '2',
'!"#%&\'()*+,./;<=>@[\\^`{|}~ ' => '3',
);
$context = new \Handlebars\Context($test);
$this->assertEquals('value', $context->get('value'));
$this->assertEquals('value', $context->get('value', true));
$this->assertEquals('value', $context->get('[value]', true));
$this->assertEquals('1', $context->get('array.a', true));
$this->assertEquals('2', $context->get('array.b', true));
$this->assertEquals('3', $context->get('array.[!"#%&\'()*+,./;<=>@[\\^`{|}~ ]', true));
$new = array('value' => 'new value');
$context->push($new);
$this->assertEquals('new value', $context->get('value'));
@ -546,7 +552,9 @@ class HandlebarsTest extends \PHPUnit_Framework_TestCase
array('arg1 "arg\"2" "\"arg3\""', array("arg1",'arg"2', '"arg3"')),
array("'arg1 arg2'", array("arg1 arg2")),
array("arg1 arg2 'arg number 3'", array("arg1","arg2","arg number 3")),
array('arg1 "arg\"2" "\\\'arg3\\\'"', array("arg1",'arg"2', "'arg3'"))
array('arg1 "arg\"2" "\\\'arg3\\\'"', array("arg1",'arg"2', "'arg3'")),
array('arg1 arg2.[value\'s "segment"].val', array("arg1", 'arg2.[value\'s "segment"].val')),
array('"arg1.[value 1]" arg2', array("arg1.[value 1]", 'arg2')),
);
}
/**