소스 검색

Merge branch 'release/2.6.1'

Justin Hileman 11 년 전
부모
커밋
1430ca8849

+ 9 - 9
bin/build_bootstrap.php

@@ -20,13 +20,13 @@
  * containing all Mustache library classes. This file can then be included in
  * your project, rather than requiring the Mustache Autoloader.
  */
-$baseDir = realpath(dirname(__FILE__).'/..');
+$baseDir = realpath(dirname(__FILE__) . '/..');
 
-require $baseDir.'/src/Mustache/Autoloader.php';
+require $baseDir . '/src/Mustache/Autoloader.php';
 Mustache_Autoloader::register();
 
 // delete the old file
-$file = $baseDir.'/mustache.php';
+$file = $baseDir . '/mustache.php';
 if (file_exists($file)) {
     unlink($file);
 }
@@ -77,7 +77,7 @@ SymfonyClassCollectionLoader::load(array(
  */
 class SymfonyClassCollectionLoader
 {
-    static private $loaded;
+    private static $loaded;
 
     const HEADER = <<<EOS
 <?php
@@ -102,7 +102,7 @@ EOS;
      *
      * @throws InvalidArgumentException When class can't be loaded
      */
-    static public function load(array $classes, $cacheDir, $name, $extension = '.php')
+    public static function load(array $classes, $cacheDir, $name, $extension = '.php')
     {
         // each $name can only be loaded once per PHP process
         if (isset(self::$loaded[$name])) {
@@ -121,9 +121,9 @@ EOS;
             $content .= preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($r->getFileName()));
         }
 
-        $cache  = $cacheDir.'/'.$name.$extension;
+        $cache  = $cacheDir . '/' . $name . $extension;
         $header = sprintf(self::HEADER, strftime('%Y'));
-        self::writeCacheFile($cache, $header . substr(self::stripComments('<?php '.$content), 5));
+        self::writeCacheFile($cache, $header . substr(self::stripComments('<?php ' . $content), 5));
     }
 
     /**
@@ -134,7 +134,7 @@ EOS;
      *
      * @throws RuntimeException when a cache file cannot be written
      */
-    static private function writeCacheFile($file, $content)
+    private static function writeCacheFile($file, $content)
     {
         $tmpFile = tempnam(dirname($file), basename($file));
         if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {
@@ -156,7 +156,7 @@ EOS;
      *
      * @return string The PHP string with the comments removed
      */
-    static private function stripComments($source)
+    private static function stripComments($source)
     {
         if (!function_exists('token_get_all')) {
             return $source;

+ 18 - 13
bin/create_example.php

@@ -24,7 +24,6 @@ USAGE
 
 define('EXAMPLE_PATH', realpath(dirname(__FILE__) . '/../test/fixtures/examples'));
 
-
 /**
  * transform a string to lowercase using underlines.
  * Examples:
@@ -37,7 +36,8 @@ define('EXAMPLE_PATH', realpath(dirname(__FILE__) . '/../test/fixtures/examples'
  * @access public
  * @return string
  */
-function getLowerCaseName($name) {
+function getLowerCaseName($name)
+{
     return preg_replace_callback("/([A-Z])/", create_function (
         '$match',
         'return "_" . strtolower($match[1]);'
@@ -56,14 +56,14 @@ function getLowerCaseName($name) {
  * @access public
  * @return string
  */
-function getUpperCaseName($name) {
+function getUpperCaseName($name)
+{
     return preg_replace_callback("/_([a-z])/", create_function (
         '$match',
         'return strtoupper($match{1});'
     ), ucfirst($name));
 }
 
-
 /**
  * return the given value and echo it out appending "\n"
  *
@@ -71,8 +71,10 @@ function getUpperCaseName($name) {
  * @access public
  * @return mixed
  */
-function out($value) {
+function out($value)
+{
     echo $value . "\n";
+
     return $value;
 }
 
@@ -88,7 +90,8 @@ function out($value) {
  * @access public
  * @return string
  */
-function buildPath($directory, $filename = null,  $extension = null) {
+function buildPath($directory, $filename = null,  $extension = null)
+{
     return out(EXAMPLE_PATH . '/' . $directory.
                     ($extension !== null && $filename !== null ? '/' . $filename. "." . $extension : ""));
 }
@@ -101,8 +104,9 @@ function buildPath($directory, $filename = null,  $extension = null) {
  * @access public
  * @return void
  */
-function createDirectory($directory) {
-    if(!@mkdir(buildPath($directory))) {
+function createDirectory($directory)
+{
+    if (!@mkdir(buildPath($directory))) {
         die("FAILED to create directory\n");
     }
 }
@@ -118,9 +122,10 @@ function createDirectory($directory) {
  * @access public
  * @return void
  */
-function createFile($directory, $filename, $extension, $content = "") {
+function createFile($directory, $filename, $extension, $content = "")
+{
     $handle = @fopen(buildPath($directory, $filename, $extension), "w");
-    if($handle) {
+    if ($handle) {
         fwrite($handle, $content);
         fclose($handle);
     } else {
@@ -128,7 +133,6 @@ function createFile($directory, $filename, $extension, $content = "") {
     }
 }
 
-
 /**
  * routine to create the example directory and 3 files
  *
@@ -142,7 +146,8 @@ function createFile($directory, $filename, $extension, $content = "") {
  * @access public
  * @return void
  */
-function main($example_name) {
+function main($example_name)
+{
     $lowercase = getLowerCaseName($example_name);
     $uppercase = getUpperCaseName($example_name);
     createDirectory($lowercase);
@@ -160,7 +165,7 @@ CONTENT
 }
 
 // check if enougth arguments are given
-if(count($argv) > 1) {
+if (count($argv) > 1) {
     // get the name of the example
     $example_name = $argv[1];
 

+ 0 - 1
src/Mustache/Autoloader.php

@@ -14,7 +14,6 @@
  */
 class Mustache_Autoloader
 {
-
     private $baseDir;
 
     /**

+ 0 - 1
src/Mustache/Compiler.php

@@ -16,7 +16,6 @@
  */
 class Mustache_Compiler
 {
-
     private $sections;
     private $source;
     private $indentNextLine;

+ 3 - 0
src/Mustache/Context.php

@@ -134,6 +134,9 @@ class Mustache_Context
     {
         for ($i = count($stack) - 1; $i >= 0; $i--) {
             if (is_object($stack[$i]) && !($stack[$i] instanceof Closure)) {
+
+                // Note that is_callable() *will not work here*
+                // See https://github.com/bobthecow/mustache.php/wiki/Magic-Methods
                 if (method_exists($stack[$i], $id)) {
                     return $stack[$i]->$id();
                 } elseif (isset($stack[$i]->$id)) {

+ 2 - 2
src/Mustache/Engine.php

@@ -23,7 +23,7 @@
  */
 class Mustache_Engine
 {
-    const VERSION        = '2.6.0';
+    const VERSION        = '2.6.1';
     const SPEC_VERSION   = '1.1.2';
 
     const PRAGMA_FILTERS = 'FILTERS';
@@ -213,7 +213,7 @@ class Mustache_Engine
      */
     public function getEntityFlags()
     {
-      return $this->entityFlags;
+        return $this->entityFlags;
     }
 
     /**

+ 10 - 8
src/Mustache/HelperCollection.php

@@ -27,14 +27,16 @@ class Mustache_HelperCollection
      */
     public function __construct($helpers = null)
     {
-        if ($helpers !== null) {
-            if (!is_array($helpers) && !$helpers instanceof Traversable) {
-                throw new Mustache_Exception_InvalidArgumentException('HelperCollection constructor expects an array of helpers');
-            }
-
-            foreach ($helpers as $name => $helper) {
-                $this->add($name, $helper);
-            }
+        if ($helpers === null) {
+            return;
+        }
+
+        if (!is_array($helpers) && !$helpers instanceof Traversable) {
+            throw new Mustache_Exception_InvalidArgumentException('HelperCollection constructor expects an array of helpers');
+        }
+
+        foreach ($helpers as $name => $helper) {
+            $this->add($name, $helper);
         }
     }
 

+ 0 - 1
src/Mustache/Loader.php

@@ -14,7 +14,6 @@
  */
 interface Mustache_Loader
 {
-
     /**
      * Load a Template by name.
      *

+ 0 - 1
src/Mustache/Loader/MutableLoader.php

@@ -14,7 +14,6 @@
  */
 interface Mustache_Loader_MutableLoader
 {
-
     /**
      * Set an associative array of Template sources for this loader.
      *

+ 0 - 1
src/Mustache/Loader/StringLoader.php

@@ -25,7 +25,6 @@
  */
 class Mustache_Loader_StringLoader implements Mustache_Loader
 {
-
     /**
      * Load a Template by source.
      *

+ 0 - 1
src/Mustache/Template.php

@@ -16,7 +16,6 @@
  */
 abstract class Mustache_Template
 {
-
     /**
      * @var Mustache_Engine
      */

+ 34 - 13
src/Mustache/Tokenizer.php

@@ -16,7 +16,6 @@
  */
 class Mustache_Tokenizer
 {
-
     // Finite state machine states
     const IN_TEXT     = 0;
     const IN_TAG_TYPE = 1;
@@ -85,6 +84,8 @@ class Mustache_Tokenizer
     /**
      * Scan and tokenize template source.
      *
+     * @throws Mustache_Exception_SyntaxException when mismatched section tags are encountered.
+     *
      * @param string $text       Mustache template source to tokenize
      * @param string $delimiters Optionally, pass initial opening and closing delimiters (default: null)
      *
@@ -117,7 +118,7 @@ class Mustache_Tokenizer
                     } else {
                         $char = $text[$i];
                         $this->buffer .= $char;
-                        if ($char == "\n") {
+                        if ($char === "\n") {
                             $this->flushBuffer();
                             $this->line++;
                         }
@@ -152,29 +153,49 @@ class Mustache_Tokenizer
 
                 default:
                     if ($this->tagChange($this->ctag, $this->ctagLen, $text, $i)) {
-                        $this->tokens[] = array(
+                        $token = array(
                             self::TYPE  => $this->tagType,
                             self::NAME  => trim($this->buffer),
                             self::OTAG  => $this->otag,
                             self::CTAG  => $this->ctag,
                             self::LINE  => $this->line,
-                            self::INDEX => ($this->tagType == self::T_END_SECTION) ? $this->seenTag - $this->otagLen : $i + $this->ctagLen
+                            self::INDEX => ($this->tagType === self::T_END_SECTION) ? $this->seenTag - $this->otagLen : $i + $this->ctagLen
                         );
 
-                        $this->buffer = '';
-                        $i += $this->ctagLen - 1;
-                        $this->state = self::IN_TEXT;
-                        if ($this->tagType == self::T_UNESCAPED) {
-                            if ($this->ctag == '}}') {
-                                $i++;
+                        if ($this->tagType === self::T_UNESCAPED) {
+                            // Clean up `{{{ tripleStache }}}` style tokens.
+                            if ($this->ctag === '}}') {
+                                if (($i + 2 < $len) && $text[$i + 2] === '}') {
+                                    $i++;
+                                } else {
+                                    $msg = sprintf(
+                                        'Mismatched tag delimiters: %s on line %d',
+                                        $token[self::NAME],
+                                        $token[self::LINE]
+                                    );
+
+                                    throw new Mustache_Exception_SyntaxException($msg, $token);
+                                }
                             } else {
-                                // Clean up `{{{ tripleStache }}}` style tokens.
-                                $lastName = $this->tokens[count($this->tokens) - 1][self::NAME];
+                                $lastName = $token[self::NAME];
                                 if (substr($lastName, -1) === '}') {
-                                    $this->tokens[count($this->tokens) - 1][self::NAME] = trim(substr($lastName, 0, -1));
+                                    $token[self::NAME] = trim(substr($lastName, 0, -1));
+                                } else {
+                                    $msg = sprintf(
+                                        'Mismatched tag delimiters: %s on line %d',
+                                        $token[self::NAME],
+                                        $token[self::LINE]
+                                    );
+
+                                    throw new Mustache_Exception_SyntaxException($msg, $token);
                                 }
                             }
                         }
+
+                        $this->buffer = '';
+                        $i += $this->ctagLen - 1;
+                        $this->state = self::IN_TEXT;
+                        $this->tokens[] = $token;
                     } else {
                         $this->buffer .= $text[$i];
                     }

+ 2 - 2
test/Mustache/Test/Cache/FilesystemCacheTest.php

@@ -17,7 +17,7 @@ class Mustache_Test_Cache_FilesystemCacheTest extends Mustache_Test_FunctionalTe
     public function testCacheGetNone()
     {
         $key = 'some key';
-        $cache = new Mustache_Cache_FilesystemCache(self::$tempDir);;
+        $cache = new Mustache_Cache_FilesystemCache(self::$tempDir);
         $loaded = $cache->load($key);
 
         $this->assertFalse($loaded);
@@ -27,7 +27,7 @@ class Mustache_Test_Cache_FilesystemCacheTest extends Mustache_Test_FunctionalTe
     {
         $key = 'some key';
         $value = '<?php /* some value */';
-        $cache = new Mustache_Cache_FilesystemCache(self::$tempDir);;
+        $cache = new Mustache_Cache_FilesystemCache(self::$tempDir);
         $cache->cache($key, $value);
         $loaded = $cache->load($key);
 

+ 2 - 2
test/Mustache/Test/FiveThree/Functional/FiltersTest.php

@@ -46,7 +46,7 @@ class Mustache_Test_FiveThree_Functional_FiltersTest extends PHPUnit_Framework_T
             array(
                 '{{% FILTERS }}{{ date | longdate }}',
                 $helpers,
-                (object) array('date' => new DateTime('1/1/2000')),
+                (object) array('date' => new DateTime('1/1/2000', new DateTimeZone("UTC"))),
                 '2000-01-01 12:01:00'
             ),
 
@@ -72,7 +72,7 @@ class Mustache_Test_FiveThree_Functional_FiltersTest extends PHPUnit_Framework_T
         });
 
         $foo = new \StdClass;
-        $foo->date = new DateTime('1/1/2000');
+        $foo->date = new DateTime('1/1/2000', new DateTimeZone("UTC"));
 
         $this->assertEquals('[[2000-01-01 12:01:00]]', $tpl->render($foo));
     }

+ 2 - 2
test/Mustache/Test/FiveThree/Functional/PartialLambdaIndentTest.php

@@ -42,12 +42,12 @@ EOS;
 
         $tpl = $m->loadTemplate($src);
 
-        $data = new Mustache_Test_Functional_ClassWithLambda();
+        $data = new Mustache_Test_FiveThree_Functional_ClassWithLambda();
         $this->assertEquals($expected, $tpl->render($data));
     }
 }
 
-class Mustache_Test_Functional_ClassWithLambda
+class Mustache_Test_FiveThree_Functional_ClassWithLambda
 {
     public function _t()
     {

+ 85 - 0
test/Mustache/Test/TokenizerTest.php

@@ -24,6 +24,28 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
         $this->assertSame($expected, $tokenizer->scan($text, $delimiters));
     }
 
+    /**
+     * @expectedException Mustache_Exception_SyntaxException
+     */
+    public function testUnevenBracesThrowExceptions()
+    {
+        $tokenizer = new Mustache_Tokenizer;
+
+        $text = "{{{ name }}";
+        $tokenizer->scan($text, null);
+    }
+
+    /**
+     * @expectedException Mustache_Exception_SyntaxException
+     */
+    public function testUnevenBracesWithCustomDelimiterThrowExceptions()
+    {
+        $tokenizer = new Mustache_Tokenizer;
+
+        $text = "<%{ name %>";
+        $tokenizer->scan($text, "<% %>");
+    }
+
     public function getTokens()
     {
         return array(
@@ -188,6 +210,69 @@ class Mustache_Test_TokenizerTest extends PHPUnit_Framework_TestCase
                     ),
                 )
             ),
+
+            // custom delimiters don't swallow the next character, even if it is a }, }}}, or the same delimiter
+            array(
+                "<% a %>} <% b %>%> <% c %>}}}",
+                "<% %>",
+                array(
+                    array(
+                        Mustache_Tokenizer::TYPE  => Mustache_Tokenizer::T_ESCAPED,
+                        Mustache_Tokenizer::NAME  => 'a',
+                        Mustache_Tokenizer::OTAG  => '<%',
+                        Mustache_Tokenizer::CTAG  => '%>',
+                        Mustache_Tokenizer::LINE  => 0,
+                        Mustache_Tokenizer::INDEX => 7,
+                    ),
+                    array(
+                        Mustache_Tokenizer::TYPE  => Mustache_Tokenizer::T_TEXT,
+                        Mustache_Tokenizer::LINE  => 0,
+                        Mustache_Tokenizer::VALUE => "} ",
+                    ),
+                    array(
+                        Mustache_Tokenizer::TYPE  => Mustache_Tokenizer::T_ESCAPED,
+                        Mustache_Tokenizer::NAME  => 'b',
+                        Mustache_Tokenizer::OTAG  => '<%',
+                        Mustache_Tokenizer::CTAG  => '%>',
+                        Mustache_Tokenizer::LINE  => 0,
+                        Mustache_Tokenizer::INDEX => 16,
+                    ),
+                    array(
+                        Mustache_Tokenizer::TYPE  => Mustache_Tokenizer::T_TEXT,
+                        Mustache_Tokenizer::LINE  => 0,
+                        Mustache_Tokenizer::VALUE => "%> ",
+                    ),
+                    array(
+                        Mustache_Tokenizer::TYPE  => Mustache_Tokenizer::T_ESCAPED,
+                        Mustache_Tokenizer::NAME  => 'c',
+                        Mustache_Tokenizer::OTAG  => '<%',
+                        Mustache_Tokenizer::CTAG  => '%>',
+                        Mustache_Tokenizer::LINE  => 0,
+                        Mustache_Tokenizer::INDEX => 26,
+                    ),
+                    array(
+                        Mustache_Tokenizer::TYPE  => Mustache_Tokenizer::T_TEXT,
+                        Mustache_Tokenizer::LINE  => 0,
+                        Mustache_Tokenizer::VALUE => "}}}",
+                    ),
+                )
+            ),
+
+            // unescaped custom delimiters are properly parsed
+            array(
+                "<%{ a }%>",
+                "<% %>",
+                array(
+                    array(
+                        Mustache_Tokenizer::TYPE  => Mustache_Tokenizer::T_UNESCAPED,
+                        Mustache_Tokenizer::NAME  => 'a',
+                        Mustache_Tokenizer::OTAG  => '<%',
+                        Mustache_Tokenizer::CTAG  => '%>',
+                        Mustache_Tokenizer::LINE  => 0,
+                        Mustache_Tokenizer::INDEX => 9,
+                    )
+                )
+            ),
         );
     }
 }

+ 3 - 3
test/bootstrap.php

@@ -9,8 +9,8 @@
  * file that was distributed with this source code.
  */
 
-require dirname(__FILE__).'/../src/Mustache/Autoloader.php';
+require dirname(__FILE__) . '/../src/Mustache/Autoloader.php';
 Mustache_Autoloader::register();
-Mustache_Autoloader::register(dirname(__FILE__).'/../test');
+Mustache_Autoloader::register(dirname(__FILE__) . '/../test');
 
-require dirname(__FILE__).'/../vendor/yaml/lib/sfYamlParser.php';
+require dirname(__FILE__) . '/../vendor/yaml/lib/sfYamlParser.php';