Permalink
Browse files

FIX Arguments to method calls reseting scope

  • Loading branch information...
1 parent 7349682 commit ae3e3f3b44ce1c01832222b257ca2c26966027dc Hamish Friedlander committed Jun 25, 2013
Showing with 89 additions and 8 deletions.
  1. +67 −2 tests/view/SSViewerTest.php
  2. +1 −1 view/SSTemplateParser.php
  3. +1 −1 view/SSTemplateParser.php.inc
  4. +20 −4 view/SSViewer.php
@@ -1074,7 +1074,7 @@ public function testRenderWithSourceFileComments() {
$origEnv = Config::inst()->get('Director', 'environment_type');
Config::inst()->update('Director', 'environment_type', 'dev');
Config::inst()->update('SSViewer', 'source_file_comments', true);
- $f = FRAMEWORK_PATH . '/tests/templates/SSViewerTestComments';
+ $f = FRAMEWORK_PATH . '/tests/templates/SSViewerTestComments';
$templates = array(
array(
'name' => 'SSViewerTestCommentsFullSource',
@@ -1090,7 +1090,8 @@ public function testRenderWithSourceFileComments() {
array(
'name' => 'SSViewerTestCommentsFullSourceHTML4Doctype',
'expected' => ""
- . "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\t\t\"http://www.w3.org/TR/html4/strict.dtd\">"
+ . "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML "
+ . "4.01//EN\"\t\t\"http://www.w3.org/TR/html4/strict.dtd\">"
. "<!-- template $f/SSViewerTestCommentsFullSourceHTML4Doctype.ss -->"
. "<html>"
. "\t<head></head>"
@@ -1209,6 +1210,45 @@ public function testRequireCallInTemplateInclude() {
"tests/forms/RequirementsTest_a.js"
));
}
+
+ public function testCallsWithArguments() {
+ $data = new ArrayData(array(
+ 'Set' => new ArrayList(array(
+ new SSViewerTest_Object("1"),
+ new SSViewerTest_Object("2"),
+ new SSViewerTest_Object("3"),
+ new SSViewerTest_Object("4"),
+ new SSViewerTest_Object("5"),
+ )),
+ 'Level' => new SSViewerTest_LevelTest(1),
+ 'Nest' => array(
+ 'Level' => new SSViewerTest_LevelTest(2),
+ ),
+ ));
+
+ $tests = array(
+ '$Level.output(1)' => '1-1',
+ '$Nest.Level.output($Set.First.Number)' => '2-1',
+ '<% with $Set %>$Up.Level.output($First.Number)<% end_with %>' => '1-1',
+ '<% with $Set %>$Top.Nest.Level.output($First.Number)<% end_with %>' => '2-1',
+ '<% loop $Set %>$Up.Nest.Level.output($Number)<% end_loop %>' => '2-12-22-32-42-5',
+ '<% loop $Set %>$Top.Level.output($Number)<% end_loop %>' => '1-11-21-31-41-5',
+ '<% with $Nest %>$Level.output($Top.Set.First.Number)<% end_with %>' => '2-1',
+ '<% with $Level %>$output($Up.Set.Last.Number)<% end_with %>' => '1-5',
+ '<% with $Level.forWith($Set.Last.Number) %>$output("hi")<% end_with %>' => '5-hi',
+ '<% loop $Level.forLoop($Set.First.Number) %>$Number<% end_loop %>' => '!0',
+ '<% with $Nest %>
+ <% with $Level.forWith($Up.Set.First.Number) %>$output("hi")<% end_with %>
+ <% end_with %>' => '1-hi',
+ '<% with $Nest %>
+ <% loop $Level.forLoop($Top.Set.Last.Number) %>$Number<% end_loop %>
+ <% end_with %>' => '!0!1!2!3!4',
+ );
+
+ foreach($tests as $template => $expected) {
+ $this->assertEquals($expected, trim($this->render($template, $data)));
+ }
+ }
}
/**
@@ -1347,3 +1387,28 @@ public static function get_argmix() {
}
}
+
+class SSViewerTest_LevelTest extends ViewableData implements TestOnly {
+ protected $depth;
+
+ public function __construct($depth = 1) {
+ $this->depth = $depth;
+ }
+
+ public function output($val) {
+ return "$this->depth-$val";
+ }
+
+ public function forLoop($number) {
+ $ret = array();
+ for($i = 0; $i < (int)$number; ++$i) {
+ $ret[] = new SSViewerTest_Object("!$i");
+ }
+ return new ArrayList($ret);
+ }
+
+ public function forWith($number) {
+ return new self($number);
+ }
+}
+
@@ -615,7 +615,7 @@ function match_Lookup ($stack = array()) {
function Lookup__construct(&$res) {
- $res['php'] = '$scope';
+ $res['php'] = '$scope->locally()';
$res['LookupSteps'] = array();
}
@@ -157,7 +157,7 @@ class SSTemplateParser extends Parser {
*/
function Lookup__construct(&$res) {
- $res['php'] = '$scope';
+ $res['php'] = '$scope->locally()';
$res['LookupSteps'] = array();
}
View
@@ -49,18 +49,34 @@ class SSViewer_Scope {
public function __construct($item){
$this->item = $item;
- $this->localIndex=0;
+ $this->localIndex = 0;
+ $this->localStack = array();
$this->itemStack[] = array($this->item, null, 0, null, null, 0);
}
public function getItem(){
return $this->itemIterator ? $this->itemIterator->current() : $this->item;
}
-
- public function resetLocalScope(){
+
+ /** Called at the start of every lookup chain by SSTemplateParser to indicate a new lookup from local scope */
+ public function locally() {
list($this->item, $this->itemIterator, $this->itemIteratorTotal, $this->popIndex, $this->upIndex,
$this->currentIndex) = $this->itemStack[$this->localIndex];
- array_splice($this->itemStack, $this->localIndex+1);
+
+ // Remember any un-completed (resetLocalScope hasn't been called) lookup chain. Even if there isn't an
+ // un-completed chain we need to store an empty item, as resetLocalScope doesn't know the difference later
+ $this->localStack[] = array_splice($this->itemStack, $this->localIndex+1);
+
+ return $this;
+ }
+
+ public function resetLocalScope(){
+ $previousLocalState = $this->localStack ? array_pop($this->localStack) : null;
+
+ array_splice($this->itemStack, $this->localIndex+1, count($this->itemStack), $previousLocalState);
+
+ list($this->item, $this->itemIterator, $this->itemIteratorTotal, $this->popIndex, $this->upIndex,
+ $this->currentIndex) = end($this->itemStack);
}
public function getObj($name, $arguments = null, $forceReturnedObject = true, $cache = false, $cacheName = null) {

0 comments on commit ae3e3f3

Please sign in to comment.