From a3c93a2f12b91583b930b1636843e8267391c780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torben=20K=C3=B6hn?= Date: Fri, 6 Nov 2015 17:54:55 +0100 Subject: [PATCH] New features, more tests, minor bugfixes Fixed: Do-While-Checking Added: For-Loops including tests (#5) Added: Variable-Assignments! (#20) Added: more tests --- Compiler.php | 174 ++++++++++++++++-- Compiler/Exception.php | 4 +- Filter.php | 4 +- Lexer.php | 43 ++++- Lexer/Exception.php | 4 +- Parser.php | 41 ++++- Parser/Exception.php | 4 +- Parser/Node.php | 4 +- Renderer.php | 6 +- Renderer/Adapter/File.php | 4 +- Renderer/Adapter/Stream.php | 4 +- Renderer/Adapter/Stream/Wrapper.php | 4 +- Renderer/AdapterBase.php | 4 +- Test/AntiTest.php | 15 ++ Test/AttributeTest.php | 28 +++ Test/LoopTest.php | 61 ++++++ Test/MixedTest.php | 58 ------ Test/VariableTest.php | 38 ++++ .../single-value.jade} | 0 Test/views/loops/each.jade | 13 ++ Test/views/loops/for.jade | 5 + Test/views/loops/while.jade | 14 ++ Test/views/variables/assignment.jade | 28 +++ functions.php | 2 +- tasks.php | 2 +- 25 files changed, 454 insertions(+), 110 deletions(-) create mode 100644 Test/LoopTest.php delete mode 100644 Test/MixedTest.php create mode 100644 Test/VariableTest.php rename Test/views/{mixed/single-attribute-value.jade => attributes/single-value.jade} (100%) create mode 100644 Test/views/loops/each.jade create mode 100644 Test/views/loops/for.jade create mode 100644 Test/views/loops/while.jade create mode 100644 Test/views/variables/assignment.jade diff --git a/Compiler.php b/Compiler.php index 190325e..5ec30f1 100644 --- a/Compiler.php +++ b/Compiler.php @@ -21,7 +21,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Compiler.html * @since File available since Release 1.0 */ @@ -74,7 +74,7 @@ * //Make sure the variables are accessible by the included template * extract($variables); * - * //Compiler needs an $__args variable to pass arguments on to mixins + * //Compiler needs an $__args variables to pass arguments on to mixins * $__args = $variables; * * //Include the rendered PHTML directly @@ -91,7 +91,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Compiler.html * @since File available since Release 1.0 */ @@ -396,7 +396,7 @@ public function addFilter($name, $callback) * * Look at Renderer to get this done for you * - * Before evaluating you should set a $__args variable + * Before evaluating you should set a $__args variables * that will be passed through mixins. * It like a global scope. * @@ -489,7 +489,7 @@ public function compileFile($path) } /** - * Checks if a variable is scalar (or "not an expression"). + * Checks if a variables is scalar (or "not an expression"). * * These values don't get much special handling, they are mostly * simple attributes values like `type="button"` or `method='post'` @@ -528,9 +528,9 @@ protected function compileScalar($value, $attribute = false) } /** - * Checks if a value is a variable. + * Checks if a value is a variables. * - * A variable needs to start with $. + * A variables needs to start with $. * After that only a-z, A-Z and _ can follow * After that you can use any character of * a-z, A-Z, 0-9, _, [, ], -, >, ' and " @@ -558,7 +558,7 @@ protected function isVariable($value) * * Interpolation is initialized with # (escaped) or ! (not escaped) * - * After that use either {} brackets for variable expressions + * After that use either {} brackets for variables expressions * or [] for Jade-expressions * * e.g. @@ -1098,7 +1098,7 @@ protected function handleMixin(Node $node) * Compiles found mixins under each other into a single PHTML block. * * Mixins will be anonymous functions inside a $__mixins array - * The mixins also pass the global $__args variable on (so that it _is_ global) + * The mixins also pass the global $__args variables on (so that it _is_ global) * * @return string The compile PHTML */ @@ -1144,7 +1144,7 @@ protected function compileMixins() $phtml .= $this->createCode( '$__mixins[\''.$name.'\'] = function(array $__arguments) use($__args, $__mixins) { - static $__defaults = '.var_export($args, true).'; + static $__defaults = '.$this->exportArray($args).'; $__arguments = array_replace($__defaults, $__arguments); $__args = array_replace($__args, $__arguments); extract($__args); '.$variadic.' @@ -1443,7 +1443,7 @@ protected function compileWhen(Node $node) /** * Compiles a each-instruction into a foreach-loop PHTML block. * - * the $ in the variable names are optional + * the $ in the variables names are optional * * @param Node $node the each-node to compile * @@ -1460,8 +1460,9 @@ protected function compileEach(Node $node) $subject = "isset({$subject}) ? {$subject} : []"; $as = "\${$node->itemName}"; + if ($node->keyName) - $as .= " => \${$node->keyName}"; + $as = "\${$node->keyName} => ".$as; $var = '$__iterator'.($id++); $phtml = $this->createCode("$var = {$subject};").$this->newLine(); @@ -1479,8 +1480,6 @@ protected function compileEach(Node $node) * Notice that if it has no children, we assume it's a do/while loop * and don't print brackets * - * @todo Check for do-instruction via $node->prev() - * * @param Node $node the while-node to compile * * @return string The compiled PHTML @@ -1494,7 +1493,22 @@ protected function compileWhile(Node $node) $subject = "isset({$subject}) ? {$subject} : null"; $hasChildren = count($node->children) > 0; - $phtml = $this->createCode("while ({$subject})".($hasChildren ? ' {' : '')).$this->newLine(); + $isDoWhile = $node->prev() && $node->prev()->type === 'do'; + + if (!$hasChildren && !$isDoWhile) + $this->throwException( + 'A while-loop without children you loop through is not valid if' + .' there\'s no do-statement before it.', + $node + ); + else if ($isDoWhile && $hasChildren) + $this->throwException( + 'In a do-while statement the while-part shouldn\'t have any children', + $node + ); + + $phtml = $this->createCode("while ({$subject})".($hasChildren ? ' {' : ''), $isDoWhile ? ' ' : 'newLine(); + if ($hasChildren) { $phtml .= $this->compileChildren($node->children).$this->newLine(); @@ -1504,6 +1518,24 @@ protected function compileWhile(Node $node) return $phtml; } + /** + * Compiles a for-loop into PHTML. + * + * @param Node $node the while-node to compile + * + * @return string The compiled PHTML + */ + protected function compileFor(Node $node) + { + + $subject = $node->subject; + $phtml = $this->createCode("for ({$subject}) {").$this->newLine(); + $phtml .= $this->compileChildren($node->children).$this->newLine(); + $phtml .= $this->indent().$this->createCode('}').$this->newLine(); + + return $phtml; + } + /** * Compiles a do-instruction into PHTML. * @@ -1530,15 +1562,91 @@ protected function compileDo(Node $node) "A do-statement needs a while-statement following immediately" ); + //Notice that the } wont have closing ? >, php needs this. + //Check compileWhile to see the combination of both $phtml = $this->createCode("do {").$this->newLine(); $phtml .= $this->compileChildren($node->children).$this->newLine(); - $phtml .= $this->indent().$this->createCode('}').$this->newLine(); + $phtml .= $this->indent().$this->createCode('}', 'newLine(); return $phtml; } /** - * Compiles a filter-node intp PHTML. + * Compiles a variable-node into PHTML. + * + * @param Node $node the variable node to compile + * + * @return string The compiled PHTML + * @throws Exception + */ + protected function compileVariable(Node $node) + { + + //Attribute-style assignment + //$variable(a=b, c=d) + if (count($node->attributes)) { + + if (count($node->children)) + $this->throwException( + 'A variable node with attributes cant have any children', + $node + ); + + //Attribute-based assignment + $array = []; + foreach ($node->attributes as $attr) { + + $name = $attr->name; + $value = trim($attr->value, '"\''); + + if (!$name) + $array[] = $value; + else { + + if (isset($array[$name])) { + + if (is_array($array[$name])) + $array[$name][] = $value; + else + $array[$name] = [$array[$name], $value]; + } else + $array[$name] = $value; + } + } + + //In $array we have the final array to assign on the variable, sadly + //we can't just use var_export, since we might have variables inside + //the array that shouldn't be converted to strings. + //We convert it ourself + + return $this->createCode( + "\$__value = ".$this->exportArray($array)."; " + ."\${$node->name} = isset(\${$node->name}) ? array_replace_recursive(\${$node->name}, \$__value) : \$__value; " + ."unset(\$__value);" + ); + } + + if (!count($node->children)) { + + //No children, this is simple variable output (Escaped!) + return $this->createShortCode( + "htmlentities(\${$node->name}, \\ENT_QUOTES, '".$this->_options['escapeCharset']."')" + ); + } + + if ($node->children[0]->type !== 'expression') { + + $this->throwException( + 'Variable nodes can only have expression children', + $node + ); + } + + return $this->createCode("\${$node->name} = ".$node->children[0]->value); + } + + /** + * Compiles a filter-node into PHTML. * * The filters are drawn from the filters-option * @@ -1893,6 +2001,38 @@ protected function compileComment(Node $node) return $node->rendered ? $this->createMarkupComment($content) : $this->createPhpComment($content); } + /** + * Exports an array to a string. + * + * This works similar to var_export in PHP, with the difference + * that it won't try to convert variable-style strings to + * quote-enclosed strings + * + * @param array $array the array to export + * + * @return string the exported array + */ + protected function exportArray(array $array) + { + + $pairs = []; + foreach ($array as $key => $val) { + + $pair = var_export($key, true).' => '; + + if (is_array($val)) + $pair .= $this->exportArray($val); + else if ($this->isVariable($val)) + $pair .= $val; + else + $pair .= var_export($val, true); + + $pairs[] = $pair; + } + + return '['.implode(', ', $pairs).']'; + } + /** * Compiles a simple error helper in a string to be prepended to the final PHTML. * diff --git a/Compiler/Exception.php b/Compiler/Exception.php index a4421e5..2f103e1 100644 --- a/Compiler/Exception.php +++ b/Compiler/Exception.php @@ -16,7 +16,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Compiler.Exception.html * @since File available since Release 1.0 */ @@ -35,7 +35,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Compiler.Exception.html * @since File available since Release 1.0 */ diff --git a/Filter.php b/Filter.php index d8d1c50..9e357ba 100644 --- a/Filter.php +++ b/Filter.php @@ -20,7 +20,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Filter.html * @since File available since Release 1.0 */ @@ -48,7 +48,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Filter.html * @since File available since Release 1.0 */ diff --git a/Lexer.php b/Lexer.php index 2aa6aef..d225867 100644 --- a/Lexer.php +++ b/Lexer.php @@ -18,7 +18,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Lexer.html * @since File available since Release 1.0 */ @@ -60,7 +60,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Lexer.html * @since File available since Release 1.0 */ @@ -190,11 +190,12 @@ public function __construct(array $options = null) 'newLine', 'indent', 'import', 'block', - 'conditional', 'each', 'case', 'when', 'do', 'while', + 'conditional', 'each', 'case', 'when', 'do', 'while', 'forLoop', 'mixin', 'mixinCall', 'doctype', 'tag', 'classes', 'id', 'attributes', 'assignment', + 'variable', 'comment', 'filter', 'expression', 'code', @@ -1221,10 +1222,14 @@ protected function scanControlStatement($type, array $names, $nameAttribute = nu //each is a special little unicorn if ($name === 'each') { - if (!$this->match('\$?(?[a-zA-Z_][a-zA-Z0-9_]*)(?:[\t ]*,[\t ]*\$?(?[a-zA-Z_][a-zA-Z0-9_]*))?[\t ]+in[\t ]+')) + if (!$this->match( + '\$?(?[a-zA-Z_][a-zA-Z0-9_]*)(?:[\t ]*,[\t ]*\$?(?[a-zA-Z_][a-zA-Z0-9_]*))?[\t ]+in[\t ]+' + )) { $this->throwException( - "The syntax for each is `each [$]itemName[, [$]keyName] in [subject]`" + "The syntax for each is `each [$]itemName[, [$]keyName]] in [subject]`, not ".$this->peek(20), + $token ); + } $this->consumeMatch(); $token['itemName'] = $this->getMatch('itemName'); @@ -1256,6 +1261,20 @@ protected function scanControlStatement($type, array $names, $nameAttribute = nu } } + /** + * Scans for a -token. + * + * Variable-tokens always have: + * name, which is the name of the variables to work on + * + * @return \Generator + */ + protected function scanVariable() + { + + return $this->scanToken('variable', '\$(?[a-zA-Z_][a-zA-Z0-9_]*)[\t ]*'); + } + /** * Scans for an -token. * @@ -1288,6 +1307,20 @@ protected function scanWhile() return $this->scanControlStatement('while', ['while']); } + /** + * Scans for a -token. + * + * For-tokens always have: + * subject, which is the expression between the parenthesis + * + * @return \Generator + */ + protected function scanForLoop() + { + + return $this->scanControlStatement('for', ['for']); + } + /** * Scans for a -token. * diff --git a/Lexer/Exception.php b/Lexer/Exception.php index d28f063..373f2ea 100644 --- a/Lexer/Exception.php +++ b/Lexer/Exception.php @@ -16,7 +16,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Lexer.Exception.html * @since File available since Release 1.0 */ @@ -34,7 +34,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Lexer.Exception.html * @since File available since Release 1.0 */ diff --git a/Parser.php b/Parser.php index e1f296f..3fef57e 100644 --- a/Parser.php +++ b/Parser.php @@ -18,7 +18,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Parser.html * @since File available since Release 1.0 */ @@ -57,7 +57,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Parser.html * @since File available since Release 1.0 */ @@ -595,9 +595,9 @@ protected function handleAttributeStart(array $token) if (!$this->_current) $this->_current = $this->createElement(); - if (!in_array($this->_current->type, ['element', 'assignment', 'import', 'mixin', 'mixinCall'])) + if (!in_array($this->_current->type, ['element', 'assignment', 'import', 'variable', 'mixin', 'mixinCall'])) $this->throwException( - "Attributes can only be placed on element, assignment, import, mixin and mixinCall" + "Attributes can only be placed on element, assignment, import, variable, mixin and mixinCall" ); foreach ($this->lookUpNext(['attribute']) as $subToken) { @@ -849,6 +849,22 @@ protected function handleId(array $token) $this->_current->attributes[] = $attr; } + /** + * Handles a -token and parses it into a variable assignment. + * + * @param array $token the -token + * + * @throws Exception + */ + protected function handleVariable(array $token) + { + + $node = $this->createNode('variable'); + $node->name = $token['name']; + $node->attributes = []; + $this->_current = $node; + } + /** * Handles an -token and parses it into an import-node. * @@ -859,9 +875,6 @@ protected function handleId(array $token) * Only "include" can have filters, though. * This gets checked in the Compiler, not here * - * @todo ^ Why not? - * @todo Maybe this one could need a "createImport" method? - * * @param array $token the -token * * @throws Exception @@ -1162,6 +1175,20 @@ protected function handleWhile(array $token) } + /** + * Handles a -token and parses it into a for-node. + * + * @param array $token the -token + */ + protected function handleFor(array $token) + { + + $node = $this->createNode('for', $token); + $node->subject = $token['subject']; + $this->_current = $node; + } + + /** * Throws a Parser-Exception. * diff --git a/Parser/Exception.php b/Parser/Exception.php index ab31feb..9ffc385 100644 --- a/Parser/Exception.php +++ b/Parser/Exception.php @@ -16,7 +16,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Parser.Exception.html * @since File available since Release 1.0 */ @@ -34,7 +34,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Parser.Exception.html * @since File available since Release 1.0 */ diff --git a/Parser/Node.php b/Parser/Node.php index d310207..38b24a4 100644 --- a/Parser/Node.php +++ b/Parser/Node.php @@ -20,7 +20,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Parser.Node.html * @since File available since Release 1.0 */ @@ -40,7 +40,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Parser.Node.html * @since File available since Release 1.0 */ diff --git a/Renderer.php b/Renderer.php index 2d4844c..13be67c 100644 --- a/Renderer.php +++ b/Renderer.php @@ -18,7 +18,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Renderer.html * @since File available since Release 1.0 */ @@ -51,7 +51,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Renderer.html * @since File available since Release 1.0 */ @@ -282,7 +282,7 @@ public function getAdapter() * * Use ->render() to get this done for you * - * Before evaluating you should set a $__args variable + * Before evaluating you should set a $__args variables * that will be passed through mixins. * It like a global scope. * diff --git a/Renderer/Adapter/File.php b/Renderer/Adapter/File.php index 8144466..13494e4 100644 --- a/Renderer/Adapter/File.php +++ b/Renderer/Adapter/File.php @@ -20,7 +20,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Renderer.Adapter.File.html * @since File available since Release 1.0 */ @@ -58,7 +58,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Renderer.Adapter.File.html * @since File available since Release 1.0 */ diff --git a/Renderer/Adapter/Stream.php b/Renderer/Adapter/Stream.php index 5768358..9d3fee0 100644 --- a/Renderer/Adapter/Stream.php +++ b/Renderer/Adapter/Stream.php @@ -20,7 +20,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Renderer.Adapter.Stream.html * @since File available since Release 1.0 */ @@ -70,7 +70,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Renderer.Adapter.Stream.html * @since File available since Release 1.0 */ diff --git a/Renderer/Adapter/Stream/Wrapper.php b/Renderer/Adapter/Stream/Wrapper.php index ac09af5..e1f0055 100644 --- a/Renderer/Adapter/Stream/Wrapper.php +++ b/Renderer/Adapter/Stream/Wrapper.php @@ -18,7 +18,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Renderer.Adapter.Stream.Wrapper.html * @since File available since Release 1.0 */ @@ -40,7 +40,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Renderer.Adapter.Stream.Wrapper.html * @since File available since Release 1.0 */ diff --git a/Renderer/AdapterBase.php b/Renderer/AdapterBase.php index 82e4949..46d2c9d 100644 --- a/Renderer/AdapterBase.php +++ b/Renderer/AdapterBase.php @@ -18,7 +18,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/Renderer.AdapterBase.html * @since File available since Release 1.0 */ @@ -40,7 +40,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/classes/Tale.Jade.Renderer.AdapterBase.html * @since File available since Release 1.0 */ diff --git a/Test/AntiTest.php b/Test/AntiTest.php index 0cf2698..68b3845 100644 --- a/Test/AntiTest.php +++ b/Test/AntiTest.php @@ -63,4 +63,19 @@ public function testDoWithoutWhile() $this->_compiler->compile("do\n\tp Something\nnot-a-while-element"); } + + public function testStandaloneWhile() + { + $this->setExpectedException(Compiler\Exception::class); + + $this->_compiler->compile("while \$something"); + } + + public function testDoWhileWithWhileChildren() + { + + $this->setExpectedException(Compiler\Exception::class); + + $this->_compiler->compile("do\n\tp Something\nwhile \$something\n\tp Anything"); + } } \ No newline at end of file diff --git a/Test/AttributeTest.php b/Test/AttributeTest.php index e1d003d..2cfd1c9 100644 --- a/Test/AttributeTest.php +++ b/Test/AttributeTest.php @@ -105,4 +105,32 @@ public function testStyleRepeation() 'a(style="first: first-value", style=\'second: second-value\')' )); } + + /** + * @dataProvider attributeValueProvider + */ + public function testAttributeValues($value, $expected) + { + + $this->assertEquals($expected, $this->_renderer->render( + 'single-value', + ['value' => $value] + )); + } + + public function attributeValueProvider() + { + + return [ + [1, ''], + [4.5, ''], + ['test', ''], + ['?"/\":\'&', ''], + [false, ''], + [null, ''], + [true, ''], + [['one', 'two', 'three'], ''], + [(object)['one', 'two', 'three'], ''] + ]; + } } \ No newline at end of file diff --git a/Test/LoopTest.php b/Test/LoopTest.php new file mode 100644 index 0000000..3e840a8 --- /dev/null +++ b/Test/LoopTest.php @@ -0,0 +1,61 @@ +_renderer = new Renderer([ + 'adapter' => 'file', + 'adapterOptions' => [ + 'path' => __DIR__.'/cache', + 'lifeTime' => 0 + ], + 'compilerOptions' => [ + 'pretty' => false, + 'handleErrors' => false, + 'paths' => [__DIR__.'/views/loops'] + ] + ]); + } + + /** + * @dataProvider arrayValueProvider + */ + public function testEach($array, $expected) + { + + $this->assertEquals($expected, $this->_renderer->render('each', ['array' => $array])); + } + + public function arrayValueProvider() + { + + return [ + [range('a', 'z'), '

1 The value is a

1 The value is b

1 The value is c

1 The value is d

1 The value is e

1 The value is f

1 The value is g

1 The value is h

1 The value is i

1 The value is j

1 The value is k

1 The value is l

1 The value is m

1 The value is n

1 The value is o

1 The value is p

1 The value is q

1 The value is r

1 The value is s

1 The value is t

1 The value is u

1 The value is v

1 The value is w

1 The value is x

1 The value is y

1 The value is z

2 The value is a

2 The value is b

2 The value is c

2 The value is d

2 The value is e

2 The value is f

2 The value is g

2 The value is h

2 The value is i

2 The value is j

2 The value is k

2 The value is l

2 The value is m

2 The value is n

2 The value is o

2 The value is p

2 The value is q

2 The value is r

2 The value is s

2 The value is t

2 The value is u

2 The value is v

2 The value is w

2 The value is x

2 The value is y

2 The value is z

3 The value is a, the key is 0

3 The value is b, the key is 1

3 The value is c, the key is 2

3 The value is d, the key is 3

3 The value is e, the key is 4

3 The value is f, the key is 5

3 The value is g, the key is 6

3 The value is h, the key is 7

3 The value is i, the key is 8

3 The value is j, the key is 9

3 The value is k, the key is 10

3 The value is l, the key is 11

3 The value is m, the key is 12

3 The value is n, the key is 13

3 The value is o, the key is 14

3 The value is p, the key is 15

3 The value is q, the key is 16

3 The value is r, the key is 17

3 The value is s, the key is 18

3 The value is t, the key is 19

3 The value is u, the key is 20

3 The value is v, the key is 21

3 The value is w, the key is 22

3 The value is x, the key is 23

3 The value is y, the key is 24

3 The value is z, the key is 25

4 The value is a, the key is 0

4 The value is b, the key is 1

4 The value is c, the key is 2

4 The value is d, the key is 3

4 The value is e, the key is 4

4 The value is f, the key is 5

4 The value is g, the key is 6

4 The value is h, the key is 7

4 The value is i, the key is 8

4 The value is j, the key is 9

4 The value is k, the key is 10

4 The value is l, the key is 11

4 The value is m, the key is 12

4 The value is n, the key is 13

4 The value is o, the key is 14

4 The value is p, the key is 15

4 The value is q, the key is 16

4 The value is r, the key is 17

4 The value is s, the key is 18

4 The value is t, the key is 19

4 The value is u, the key is 20

4 The value is v, the key is 21

4 The value is w, the key is 22

4 The value is x, the key is 23

4 The value is y, the key is 24

4 The value is z, the key is 25

'], + [range(0, 25), '

1 The value is 0

1 The value is 1

1 The value is 2

1 The value is 3

1 The value is 4

1 The value is 5

1 The value is 6

1 The value is 7

1 The value is 8

1 The value is 9

1 The value is 10

1 The value is 11

1 The value is 12

1 The value is 13

1 The value is 14

1 The value is 15

1 The value is 16

1 The value is 17

1 The value is 18

1 The value is 19

1 The value is 20

1 The value is 21

1 The value is 22

1 The value is 23

1 The value is 24

1 The value is 25

2 The value is 0

2 The value is 1

2 The value is 2

2 The value is 3

2 The value is 4

2 The value is 5

2 The value is 6

2 The value is 7

2 The value is 8

2 The value is 9

2 The value is 10

2 The value is 11

2 The value is 12

2 The value is 13

2 The value is 14

2 The value is 15

2 The value is 16

2 The value is 17

2 The value is 18

2 The value is 19

2 The value is 20

2 The value is 21

2 The value is 22

2 The value is 23

2 The value is 24

2 The value is 25

3 The value is 0, the key is 0

3 The value is 1, the key is 1

3 The value is 2, the key is 2

3 The value is 3, the key is 3

3 The value is 4, the key is 4

3 The value is 5, the key is 5

3 The value is 6, the key is 6

3 The value is 7, the key is 7

3 The value is 8, the key is 8

3 The value is 9, the key is 9

3 The value is 10, the key is 10

3 The value is 11, the key is 11

3 The value is 12, the key is 12

3 The value is 13, the key is 13

3 The value is 14, the key is 14

3 The value is 15, the key is 15

3 The value is 16, the key is 16

3 The value is 17, the key is 17

3 The value is 18, the key is 18

3 The value is 19, the key is 19

3 The value is 20, the key is 20

3 The value is 21, the key is 21

3 The value is 22, the key is 22

3 The value is 23, the key is 23

3 The value is 24, the key is 24

3 The value is 25, the key is 25

4 The value is 0, the key is 0

4 The value is 1, the key is 1

4 The value is 2, the key is 2

4 The value is 3, the key is 3

4 The value is 4, the key is 4

4 The value is 5, the key is 5

4 The value is 6, the key is 6

4 The value is 7, the key is 7

4 The value is 8, the key is 8

4 The value is 9, the key is 9

4 The value is 10, the key is 10

4 The value is 11, the key is 11

4 The value is 12, the key is 12

4 The value is 13, the key is 13

4 The value is 14, the key is 14

4 The value is 15, the key is 15

4 The value is 16, the key is 16

4 The value is 17, the key is 17

4 The value is 18, the key is 18

4 The value is 19, the key is 19

4 The value is 20, the key is 20

4 The value is 21, the key is 21

4 The value is 22, the key is 22

4 The value is 23, the key is 23

4 The value is 24, the key is 24

4 The value is 25, the key is 25

'], + [array_combine(range('a', 'z'), range(0, 25)), '

1 The value is 0

1 The value is 1

1 The value is 2

1 The value is 3

1 The value is 4

1 The value is 5

1 The value is 6

1 The value is 7

1 The value is 8

1 The value is 9

1 The value is 10

1 The value is 11

1 The value is 12

1 The value is 13

1 The value is 14

1 The value is 15

1 The value is 16

1 The value is 17

1 The value is 18

1 The value is 19

1 The value is 20

1 The value is 21

1 The value is 22

1 The value is 23

1 The value is 24

1 The value is 25

2 The value is 0

2 The value is 1

2 The value is 2

2 The value is 3

2 The value is 4

2 The value is 5

2 The value is 6

2 The value is 7

2 The value is 8

2 The value is 9

2 The value is 10

2 The value is 11

2 The value is 12

2 The value is 13

2 The value is 14

2 The value is 15

2 The value is 16

2 The value is 17

2 The value is 18

2 The value is 19

2 The value is 20

2 The value is 21

2 The value is 22

2 The value is 23

2 The value is 24

2 The value is 25

3 The value is 0, the key is a

3 The value is 1, the key is b

3 The value is 2, the key is c

3 The value is 3, the key is d

3 The value is 4, the key is e

3 The value is 5, the key is f

3 The value is 6, the key is g

3 The value is 7, the key is h

3 The value is 8, the key is i

3 The value is 9, the key is j

3 The value is 10, the key is k

3 The value is 11, the key is l

3 The value is 12, the key is m

3 The value is 13, the key is n

3 The value is 14, the key is o

3 The value is 15, the key is p

3 The value is 16, the key is q

3 The value is 17, the key is r

3 The value is 18, the key is s

3 The value is 19, the key is t

3 The value is 20, the key is u

3 The value is 21, the key is v

3 The value is 22, the key is w

3 The value is 23, the key is x

3 The value is 24, the key is y

3 The value is 25, the key is z

4 The value is 0, the key is a

4 The value is 1, the key is b

4 The value is 2, the key is c

4 The value is 3, the key is d

4 The value is 4, the key is e

4 The value is 5, the key is f

4 The value is 6, the key is g

4 The value is 7, the key is h

4 The value is 8, the key is i

4 The value is 9, the key is j

4 The value is 10, the key is k

4 The value is 11, the key is l

4 The value is 12, the key is m

4 The value is 13, the key is n

4 The value is 14, the key is o

4 The value is 15, the key is p

4 The value is 16, the key is q

4 The value is 17, the key is r

4 The value is 18, the key is s

4 The value is 19, the key is t

4 The value is 20, the key is u

4 The value is 21, the key is v

4 The value is 22, the key is w

4 The value is 23, the key is x

4 The value is 24, the key is y

4 The value is 25, the key is z

'] + ]; + } + + public function testWhile() + { + + $this->assertEquals('

1 My $i is 0!

1 My $i is 1!

1 My $i is 2!

1 My $i is 3!

1 My $i is 4!

1 My $i is 5!

1 My $i is 6!

1 My $i is 7!

1 My $i is 8!

1 My $i is 9!

1 My $i is 10!

1 My $i is 11!

1 My $i is 12!

1 My $i is 13!

1 My $i is 14!

1 My $i is 15!

1 My $i is 16!

1 My $i is 17!

1 My $i is 18!

1 My $i is 19!

1 My $i is 20!

1 My $i is 21!

1 My $i is 22!

1 My $i is 23!

1 My $i is 24!

2 My $i is 0

2 My $i is 1

2 My $i is 2

2 My $i is 3

2 My $i is 4

2 My $i is 5

2 My $i is 6

2 My $i is 7

2 My $i is 8

2 My $i is 9

2 My $i is 10

2 My $i is 11

2 My $i is 12

2 My $i is 13

2 My $i is 14

2 My $i is 15

2 My $i is 16

2 My $i is 17

2 My $i is 18

2 My $i is 19

2 My $i is 20

2 My $i is 21

2 My $i is 22

2 My $i is 23

2 My $i is 24

', $this->_renderer->render('while')); + } + + public function testFor() + { + + $this->assertEquals('

1 Character at 0 is a

1 Character at 1 is b

1 Character at 2 is c

1 Character at 3 is d

1 Character at 4 is e

1 Character at 5 is f

1 Character at 6 is g

1 Character at 7 is h

1 Character at 8 is i

1 Character at 9 is j

1 Character at 10 is k

1 Character at 11 is l

1 Character at 12 is m

1 Character at 13 is n

1 Character at 14 is o

1 Character at 15 is p

1 Character at 16 is q

1 Character at 17 is r

1 Character at 18 is s

1 Character at 19 is t

1 Character at 20 is u

1 Character at 21 is v

1 Character at 22 is w

1 Character at 23 is x

1 Character at 24 is y

1 Character at 25 is z

', $this->_renderer->render('for')); + } +} \ No newline at end of file diff --git a/Test/MixedTest.php b/Test/MixedTest.php deleted file mode 100644 index 621b0fd..0000000 --- a/Test/MixedTest.php +++ /dev/null @@ -1,58 +0,0 @@ -_renderer = new Renderer([ - 'adapter' => 'file', - 'adapterOptions' => [ - 'path' => __DIR__.'/cache', - 'lifeTime' => 0 - ], - 'compilerOptions' => [ - 'pretty' => false, - 'handleErrors' => false, - 'paths' => [__DIR__.'/views/mixed'] - ] - ]); - } - - /** - * @dataProvider attributeValueProvider - */ - public function testAttributeValues($value, $expected) - { - - $this->assertEquals($expected, $this->_renderer->render( - 'single-attribute-value', - ['value' => $value] - )); - } - - public function attributeValueProvider() - { - - return [ - [1, ''], - [4.5, ''], - ['test', ''], - ['?"/\":\'&', ''], - [false, ''], - [null, ''], - [true, ''], - [['one', 'two', 'three'], ''], - [(object)['one', 'two', 'three'], ''] - ]; - } -} \ No newline at end of file diff --git a/Test/VariableTest.php b/Test/VariableTest.php new file mode 100644 index 0000000..14a1b36 --- /dev/null +++ b/Test/VariableTest.php @@ -0,0 +1,38 @@ +_renderer = new Renderer([ + 'adapter' => 'file', + 'adapterOptions' => [ + 'path' => __DIR__.'/cache', + 'lifeTime' => 0 + ], + 'compilerOptions' => [ + 'pretty' => false, + 'handleErrors' => false, + 'paths' => [__DIR__.'/views/variables'] + ] + ]); + } + + public function testAssignment() + { + + $this->assertEquals('

Hello World!

THE REAL VALUE222', $this->_renderer->render('assignment', [ + 'existing' => ['style' => ['width' => '100%', 'height' => '50%']]] + )); + } +} \ No newline at end of file diff --git a/Test/views/mixed/single-attribute-value.jade b/Test/views/attributes/single-value.jade similarity index 100% rename from Test/views/mixed/single-attribute-value.jade rename to Test/views/attributes/single-value.jade diff --git a/Test/views/loops/each.jade b/Test/views/loops/each.jade new file mode 100644 index 0000000..6763cc7 --- /dev/null +++ b/Test/views/loops/each.jade @@ -0,0 +1,13 @@ + +each $item in $array + p 1 The value is #{$item} + +each item in $array + p 2 The value is #{$item} + +each $item, $key in $array + p 3 The value is #{$item}, the key is #{$key} + +each item, key in $array + p 4 The value is #{$item}, the key is #{$key} + diff --git a/Test/views/loops/for.jade b/Test/views/loops/for.jade new file mode 100644 index 0000000..2288a9a --- /dev/null +++ b/Test/views/loops/for.jade @@ -0,0 +1,5 @@ + +- $array = range('a', 'z') + +for $i = 0; $i < count($array); $i++ + p 1 Character at #{$i} is #{$array[$i]} \ No newline at end of file diff --git a/Test/views/loops/while.jade b/Test/views/loops/while.jade new file mode 100644 index 0000000..2237c1d --- /dev/null +++ b/Test/views/loops/while.jade @@ -0,0 +1,14 @@ + + +- $i = 0 + +while $i < 25 + p 1 My $i is #{$i}! + - $i++ + + +- $i = 0 +do + p 2 My $i is #{$i} + - $i++ +while $i < 25 \ No newline at end of file diff --git a/Test/views/variables/assignment.jade b/Test/views/variables/assignment.jade new file mode 100644 index 0000000..6190d7a --- /dev/null +++ b/Test/views/variables/assignment.jade @@ -0,0 +1,28 @@ + +$helloWorld = 'Hello World!' + +p + $helloWorld + + +$i= 100 + +$array= ['a', 'b', 'c'] + +$array2('d', 'e', 'f') + +$existing(class='b', class='c') + + +$options = ['nowrap' => 'THE REAL VALUE'] + +$column( + 'id', + 'tracker_id', + clientOptions= $options +) + += $column['clientOptions']['nowrap'] += count($existing) += count($existing['class']) += count($existing['style']) \ No newline at end of file diff --git a/functions.php b/functions.php index 99f9934..d59c8ad 100644 --- a/functions.php +++ b/functions.php @@ -18,7 +18,7 @@ * @author Talesoft * @copyright Copyright (c) 2015 Talesoft (http://talesoft.io) * @license http://licenses.talesoft.io/2015/MIT.txt MIT License - * @version 1.1.1 + * @version 1.2 * @link http://jade.talesoft.io/docs/files/functions.html * @since File available since Tag 1.0.1 */ diff --git a/tasks.php b/tasks.php index ad63095..5706bd9 100644 --- a/tasks.php +++ b/tasks.php @@ -8,7 +8,7 @@ './tasks.php' ]; -$newVersion = '1.1.1'; +$newVersion = '1.2'; if (!$newVersion) {