Skip to content

Commit

Permalink
Merge pull request #29 from phug-php/feature/scope-each-element-varia…
Browse files Browse the repository at this point in the history
…bles

Scope values created by each-in/for-in loops
  • Loading branch information
kylekatarnls authored Jul 29, 2019
2 parents 9485daf + 4ac5fec commit fcd727d
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 5 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"require": {
"php": ">=5.5.0",
"phug/util": "^0.4.0",
"phug/formatter": "^0.5.48",
"phug/formatter": "^0.5.50",
"phug/dependency-injection": "^1.1.2",
"phug/parser": "^0.5.0"
},
Expand Down
1 change: 1 addition & 0 deletions src/Phug/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ public function __construct($options = null)
'default_doctype' => 'html',
'extensions' => ['', '.pug', '.jade'],
'get_file_contents' => 'file_get_contents',
'scope_each_variables' => true,
'on_compile' => null,
'on_output' => null,
'on_node' => null,
Expand Down
41 changes: 40 additions & 1 deletion src/Phug/Compiler/NodeCompiler/EachNodeCompiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Phug\Compiler\NodeCompiler;

use Phug\CompilerInterface;
use Phug\Formatter\Element\CodeElement;
use Phug\Formatter\ElementInterface;
use Phug\Parser\Node\CommentNode;
Expand All @@ -11,16 +12,54 @@

class EachNodeCompiler extends AbstractStatementNodeCompiler
{
const EACH_SCOPE_VARIABLE_NAME = '__eachScopeVariables';

protected function getScopeVariablesDump($eachScopeVariableName, array $variables)
{
$dump = [];

foreach ($variables as $name) {
$dump[] = "'$name' => isset(\$$name) ? \$$name : null";
}

return '$'.$eachScopeVariableName.' = ['.implode(', ', $dump).'];';
}

protected function getScopeVariablesRestore($eachScopeVariableName)
{
return 'extract($'.$eachScopeVariableName.');';
}

protected function scopeEachVariables(CompilerInterface $compiler, CodeElement $loop, array $variables)
{
$eachScopeVariableName = $compiler->getOption('scope_each_variables');

if ($eachScopeVariableName === true) {
$eachScopeVariableName = static::EACH_SCOPE_VARIABLE_NAME;
}

if ($eachScopeVariableName) {
$loop->setPreHook($this->getScopeVariablesDump($eachScopeVariableName, $variables));
$loop->setPostHook($this->getScopeVariablesRestore($eachScopeVariableName));
}
}

protected function compileLoop(NodeInterface $node, $items, $key, $item)
{
$subject = $this->getCompiler()->getFormatter()->formatCode($items).' as ';
$variables = [$item];
$compiler = $this->getCompiler();
$subject = $compiler->getFormatter()->formatCode($items).' as ';

if ($key) {
$variables[] = $key;
$subject .= '$'.$key.' => ';
}

$subject .= '$'.$item;

/** @var CodeElement $loop */
$loop = $this->wrapStatement($node, 'foreach', $subject);
$this->scopeEachVariables($compiler, $loop, $variables);
$next = $node->getNextSibling();

while ($next && $next instanceof CommentNode) {
Expand Down
7 changes: 5 additions & 2 deletions tests/Phug/AbstractCompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,12 @@ protected function assertSameLines($expected, $actual)
self::assertSame($this->implodeLines($expected), $this->implodeLines($actual));
}

protected function assertCompile($expected, $actual)
protected function assertCompile($expected, $actual, array $options = [])
{
return $this->assertSameLines($expected, $this->compiler->compile($this->implodeLines($actual)));
$compiler = clone $this->compiler;
$compiler->setOptionsRecursive($options);

return $this->assertSameLines($expected, $compiler->compile($this->implodeLines($actual)));
}

protected function assertCompileFile($expected, $actual)
Expand Down
148 changes: 148 additions & 0 deletions tests/Phug/Compiler/NodeCompiler/EachNodeCompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class EachNodeCompilerTest extends AbstractCompilerTest
/**
* @covers ::<public>
* @covers ::compileLoop
* @covers ::getScopeVariablesDump
* @covers ::getScopeVariablesRestore
* @covers ::scopeEachVariables
* @covers \Phug\Compiler\NodeCompiler\AbstractStatementNodeCompiler::wrapStatement
*/
public function testCompile()
Expand All @@ -28,6 +31,9 @@ public function testCompile()
[
'each $item in $items'."\n",
' p?!=$item',
],
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
Expand All @@ -45,6 +51,9 @@ public function testCompile()
' p?!=$item'."\n",
'else'."\n",
' p no items',
],
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
Expand All @@ -56,6 +65,145 @@ public function testCompile()
[
'each $item, $key in $items'."\n",
' p?!=$item',
],
[
'scope_each_variables' => false,
]
);
}

/**
* @covers ::<public>
* @covers ::compileLoop
* @covers ::getScopeVariablesDump
* @covers ::getScopeVariablesRestore
* @covers ::scopeEachVariables
* @covers \Phug\Compiler\NodeCompiler\AbstractStatementNodeCompiler::wrapStatement
*/
public function testCompileVariablesScope()
{
$this->assertRender(
[
'<p>42</p>',
'<ul>',
'<li>1</li>',
'<li>2</li>',
'<li>3</li>',
'</ul>',
'<p>42</p>',
],
[
'- $val = 42'."\n",
'p= $val'."\n",
'ul'."\n",
' each $val in [1, 2, 3]'."\n",
' li= $val'."\n",
'p= $val',
]
);
$this->assertRender(
[
'<p>x 42</p>',
'<ul>',
'<li>0 1</li>',
'<li>1 2</li>',
'<li>2 3</li>',
'</ul>',
'<p>x 42</p>',
],
[
'- $val = 42'."\n",
'- $index = "x"'."\n",
'p #{$index} #{$val}'."\n",
'ul'."\n",
' each $val, $index in [1, 2, 3]'."\n",
' li #{$index} #{$val}'."\n",
'p #{$index} #{$val}',
]
);
$this->assertRender(
[
'<p>42</p>',
'<ul>',
'<li>1</li>',
'<li>2</li>',
'<li>3</li>',
'</ul>',
'<p>3</p>',
],
[
'- $val = 42'."\n",
'p= $val'."\n",
'ul'."\n",
' each $val in [1, 2, 3]'."\n",
' li= $val'."\n",
'p= $val',
],
[
'scope_each_variables' => false,
]
);
$this->assertRender(
[
'<p>x 42</p>',
'<ul>',
'<li>0 1</li>',
'<li>1 2</li>',
'<li>2 3</li>',
'</ul>',
'<p>2 3</p>',
],
[
'- $val = 42'."\n",
'- $index = "x"'."\n",
'p #{$index} #{$val}'."\n",
'ul'."\n",
' each $val, $index in [1, 2, 3]'."\n",
' li #{$index} #{$val}'."\n",
'p #{$index} #{$val}',
],
[
'scope_each_variables' => false,
]
);
$this->assertRender(
[
'<p>42</p>',
'<ul>',
'<li>1</li>',
'<li>2</li>',
'<li>3</li>',
'</ul>',
'<p>42</p>',
],
[
'- $val = 42'."\n",
'p= $val'."\n",
'ul'."\n",
' each $val in [1, 2, 3]'."\n",
' li= $val'."\n",
'p= $val',
],
[
'scope_each_variables' => '__anyName',
]
);
$this->assertRender(
[
'<p></p>',
'<ul>',
'<li>1</li>',
'<li>2</li>',
'<li>3</li>',
'</ul>',
'<p></p>',
],
[
'p= $val'."\n",
'ul'."\n",
' each $val in [1, 2, 3]'."\n",
' li= $val'."\n",
'p= $val',
]
);
}
Expand Down
26 changes: 25 additions & 1 deletion tests/Phug/Compiler/NodeCompiler/ForNodeCompilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ public function testCompile()
{
$this->assertCompile(
'<?php foreach ($items as $item) {} ?>',
'for $item in $items'
'for $item in $items',
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
[
Expand All @@ -34,6 +37,9 @@ public function testCompile()
'for $item in $items'."\n",
' //- for each item of items'."\n",
' p?!=$item',
],
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
Expand All @@ -51,6 +57,9 @@ public function testCompile()
' p?!=$item'."\n",
'else'."\n",
' p no items',
],
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
Expand All @@ -69,6 +78,9 @@ public function testCompile()
'//- comments does not count'."\n",
'else'."\n",
' p no items',
],
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
Expand All @@ -80,6 +92,9 @@ public function testCompile()
[
'for $item, $key in $items'."\n",
' p?!=$item',
],
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
Expand All @@ -91,6 +106,9 @@ public function testCompile()
[
'for $key of $items'."\n",
' p?!=$key',
],
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
Expand All @@ -102,6 +120,9 @@ public function testCompile()
[
'for $key, $item of $items'."\n",
' p?!=$item',
],
[
'scope_each_variables' => false,
]
);
$this->assertCompile(
Expand All @@ -113,6 +134,9 @@ public function testCompile()
[
'for $i = 0; $i < 5; $i++'."\n",
' p?!=$i',
],
[
'scope_each_variables' => false,
]
);
}
Expand Down

0 comments on commit fcd727d

Please sign in to comment.