diff --git a/src/Mustache/Engine.php b/src/Mustache/Engine.php index e843d1e..38c05c9 100644 --- a/src/Mustache/Engine.php +++ b/src/Mustache/Engine.php @@ -605,12 +605,18 @@ class Mustache_Engine * This method must be updated any time options are added which make it so * the same template could be parsed and compiled multiple different ways. * - * @param string $source + * @param string|Mustache_Source $source * * @return string Mustache Template class name */ public function getTemplateClassName($source) { + if ($source instanceof Mustache_Source) { + $key = $source->getKey(); + } else { + $key = sprintf('source:%s', $source); + } + // For the most part, adding a new option here should do the trick. // // Pick a value here which is unique for each possible way the template @@ -629,7 +635,7 @@ class Mustache_Engine 'version' => self::VERSION, ); - return $this->templateClassPrefix . md5(json_encode($options) . "\n" . $source); + return $this->templateClassPrefix . md5(json_encode($options) . "\n" . $key); } /** @@ -706,8 +712,8 @@ class Mustache_Engine * @see Mustache_Engine::loadPartial * @see Mustache_Engine::loadLambda * - * @param string $source - * @param Mustache_Cache $cache (default: null) + * @param string|Mustache_Source $source + * @param Mustache_Cache $cache (default: null) * * @return Mustache_Template */ @@ -775,13 +781,12 @@ class Mustache_Engine * * @see Mustache_Compiler::compile * - * @param string $source + * @param string|Mustache_Source $source * * @return string generated Mustache template class code */ private function compile($source) { - $tree = $this->parse($source); $name = $this->getTemplateClassName($source); $this->log( @@ -790,6 +795,11 @@ class Mustache_Engine array('className' => $name) ); + if ($source instanceof Mustache_Source) { + $source = $source->getSource(); + } + $tree = $this->parse($source); + $compiler = $this->getCompiler(); $compiler->setPragmas($this->getPragmas()); diff --git a/src/Mustache/Loader.php b/src/Mustache/Loader.php index c5e1a19..b8be775 100644 --- a/src/Mustache/Loader.php +++ b/src/Mustache/Loader.php @@ -21,7 +21,7 @@ interface Mustache_Loader * * @param string $name * - * @return string Mustache Template source + * @return string|Mustache_Source Mustache Template source */ public function load($name); } diff --git a/src/Mustache/Loader/ProductionFilesystemLoader.php b/src/Mustache/Loader/ProductionFilesystemLoader.php new file mode 100644 index 0000000..a79b6f4 --- /dev/null +++ b/src/Mustache/Loader/ProductionFilesystemLoader.php @@ -0,0 +1,40 @@ +getFileName($name); + + if (!file_exists($fileName)) { + throw new Mustache_Exception_UnknownTemplateException($name); + } + + return new Mustache_Source_FilesystemSource($fileName); + } +} diff --git a/src/Mustache/Source.php b/src/Mustache/Source.php new file mode 100644 index 0000000..3eded91 --- /dev/null +++ b/src/Mustache/Source.php @@ -0,0 +1,32 @@ +filename = $filename; + } + + /** + * Get the Source key (used to generate the compiled class name). + * + * @throws RuntimeException when a source file cannot be read + * + * @return string + */ + public function getKey() + { + if (!isset($this->stat)) { + $this->stat = stat($this->filename); + } + + if ($this->stat === false) { + throw new RuntimeException(sprintf('Failed to read source file "%s".', $this->filename)); + } + + return sprintf('filename:%s,size:%s,mtime:%s', $this->filename, $this->stat['size'], $this->stat['mtime']); + } + + /** + * Get the template Source. + * + * @return string + */ + public function getSource() + { + return file_get_contents($this->filename); + } +} diff --git a/test/Mustache/Test/EngineTest.php b/test/Mustache/Test/EngineTest.php index e8743d7..eb5a27a 100644 --- a/test/Mustache/Test/EngineTest.php +++ b/test/Mustache/Test/EngineTest.php @@ -331,6 +331,15 @@ class Mustache_Test_EngineTest extends Mustache_Test_FunctionalTestCase )); } + public function testCompileFromMustacheSourceInstance() + { + $baseDir = realpath(dirname(__FILE__) . '/../../fixtures/templates'); + $mustache = new Mustache_Engine(array( + 'loader' => new Mustache_Loader_ProductionFilesystemLoader($baseDir), + )); + $this->assertEquals('one contents', $mustache->render('one')); + } + private function getLoggedMustache($level = Mustache_Logger::ERROR) { $name = tempnam(sys_get_temp_dir(), 'mustache-test'); diff --git a/test/Mustache/Test/Loader/ProductionFilesystemLoaderTest.php b/test/Mustache/Test/Loader/ProductionFilesystemLoaderTest.php new file mode 100644 index 0000000..300b6e8 --- /dev/null +++ b/test/Mustache/Test/Loader/ProductionFilesystemLoaderTest.php @@ -0,0 +1,82 @@ + '.ms')); + $this->assertInstanceOf('Mustache_Source', $loader->load('alpha')); + $this->assertEquals('alpha contents', $loader->load('alpha')->getSource()); + $this->assertInstanceOf('Mustache_Source', $loader->load('beta.ms')); + $this->assertEquals('beta contents', $loader->load('beta.ms')->getSource()); + } + + public function testTrailingSlashes() + { + $baseDir = dirname(__FILE__) . '/../../../fixtures/templates/'; + $loader = new Mustache_Loader_ProductionFilesystemLoader($baseDir); + $this->assertEquals('one contents', $loader->load('one')->getSource()); + } + + public function testConstructorWithProtocol() + { + $baseDir = realpath(dirname(__FILE__) . '/../../../fixtures/templates'); + + $loader = new Mustache_Loader_ProductionFilesystemLoader('file://' . $baseDir, array('extension' => '.ms')); + $this->assertEquals('alpha contents', $loader->load('alpha')->getSource()); + $this->assertEquals('beta contents', $loader->load('beta.ms')->getSource()); + } + + public function testLoadTemplates() + { + $baseDir = realpath(dirname(__FILE__) . '/../../../fixtures/templates'); + $loader = new Mustache_Loader_ProductionFilesystemLoader($baseDir); + $this->assertEquals('one contents', $loader->load('one')->getSource()); + $this->assertEquals('two contents', $loader->load('two.mustache')->getSource()); + } + + public function testEmptyExtensionString() + { + $baseDir = realpath(dirname(__FILE__) . '/../../../fixtures/templates'); + + $loader = new Mustache_Loader_ProductionFilesystemLoader($baseDir, array('extension' => '')); + $this->assertEquals('one contents', $loader->load('one.mustache')->getSource()); + $this->assertEquals('alpha contents', $loader->load('alpha.ms')->getSource()); + + $loader = new Mustache_Loader_ProductionFilesystemLoader($baseDir, array('extension' => null)); + $this->assertEquals('two contents', $loader->load('two.mustache')->getSource()); + $this->assertEquals('beta contents', $loader->load('beta.ms')->getSource()); + } + + /** + * @expectedException Mustache_Exception_RuntimeException + */ + public function testMissingBaseDirThrowsException() + { + new Mustache_Loader_ProductionFilesystemLoader(dirname(__FILE__) . '/not_a_directory'); + } + + /** + * @expectedException Mustache_Exception_UnknownTemplateException + */ + public function testMissingTemplateThrowsException() + { + $baseDir = realpath(dirname(__FILE__) . '/../../../fixtures/templates'); + $loader = new Mustache_Loader_ProductionFilesystemLoader($baseDir); + + $loader->load('fake'); + } +}