diff --git a/Mustache.php b/Mustache.php index 9ec1f84..d0ff274 100644 --- a/Mustache.php +++ b/Mustache.php @@ -14,7 +14,7 @@ */ class Mustache { - const VERSION = '0.8.1'; + const VERSION = '0.9.0'; const SPEC_VERSION = '1.1.2'; /** @@ -819,7 +819,7 @@ class Mustache { * @return string */ protected function _getPartial($tag_name) { - if (is_array($this->_partials) && isset($this->_partials[$tag_name])) { + if ((is_array($this->_partials) || $this->_partials instanceof ArrayAccess) && isset($this->_partials[$tag_name])) { return $this->_partials[$tag_name]; } diff --git a/MustacheLoader.php b/MustacheLoader.php new file mode 100644 index 0000000..9c4b386 --- /dev/null +++ b/MustacheLoader.php @@ -0,0 +1,85 @@ +baseDir = $baseDir; + $this->extension = $extension; + } + + /** + * @param string $offset Name of partial + * @return boolean + */ + public function offsetExists($offset) { + return (isset($this->partialsCache[$offset]) || file_exists($this->pathName($offset))); + } + + /** + * @throws InvalidArgumentException if the given partial doesn't exist + * @param string $offset Name of partial + * @return string Partial template contents + */ + public function offsetGet($offset) { + if (!$this->offsetExists($offset)) { + throw new InvalidArgumentException('Partial does not exist: ' . $offset); + } + + if (!isset($this->partialsCache[$offset])) { + $this->partialsCache[$offset] = file_get_contents($this->pathName($offset)); + } + + return $this->partialsCache[$offset]; + } + + /** + * MustacheLoader is an immutable filesystem loader. offsetSet throws a LogicException if called. + * + * @throws LogicException + * @return void + */ + public function offsetSet($offset, $value) { + throw new LogicException('Unable to set offset: MustacheLoader is an immutable ArrayAccess object.'); + } + + /** + * MustacheLoader is an immutable filesystem loader. offsetUnset throws a LogicException if called. + * + * @throws LogicException + * @return void + */ + public function offsetUnset($offset) { + throw new LogicException('Unable to unset offset: MustacheLoader is an immutable ArrayAccess object.'); + } + + /** + * An internal helper for generating path names. + * + * @param string $file Partial name + * @return string File path + */ + protected function pathName($file) { + return $this->baseDir . '/' . $file . '.' . $this->extension; + } +} diff --git a/README.markdown b/README.markdown index 830df90..730264f 100644 --- a/README.markdown +++ b/README.markdown @@ -44,7 +44,7 @@ Along with the associated Mustache class: Render it like so: render($template); ?> diff --git a/bin/create_example.php b/bin/create_example.php new file mode 100755 index 0000000..1f0b894 --- /dev/null +++ b/bin/create_example.php @@ -0,0 +1,172 @@ +#!/usr/bin/env php + string + * AString -> a_string + * SomeStrings -> some_strings + * AStringMore -> a_string_more + * + * @param string $name + * @access public + * @return string + */ +function getLowerCaseName($name) { + return preg_replace_callback("/([A-Z])/", create_function ( + '$match', + 'return "_" . strtolower($match[1]);' + ), lcfirst($name)); +} + +/** + * transform a string to Uppercase (camelcase) + * Examples + * string -> String + * a_string -> AString + * some_strings -> SomeStrings + * a_string_more -> AStringMore -> a_string_more + * + * @param string $name + * @access public + * @return string + */ +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" + * + * @param mixed $value + * @access public + * @return mixed + */ +function out($value) { + echo $value . "\n"; + return $value; +} + +/** + * create Path for certain files in an example + * returns the directory name if only $directory is given. + * if an extension is given a complete filename is returned. + * the returned filename will be echoed out + * + * @param string $directory directory without / at the end + * @param string $filename filename without path and extension + * @param string $extension extension of the file without "." + * @access public + * @return string + */ +function buildPath($directory, $filename = null, $extension = null) { + return out(EXAMPLE_PATH . DS . $directory. + ($extension !== null && $filename !== null ? DS . $filename. "." . $extension : "")); +} + +/** + * creates the directory for the example + * the script die()'s if mkdir() fails + * + * @param string $directory + * @access public + * @return void + */ +function createDirectory($directory) { + if(!@mkdir(buildPath($directory))) { + die("FAILED to create directory\n"); + } +} + +/** + * create a file for the example with the given $content + * the script die()'s if fopen() fails + * + * @param string $directory directory without / at the end + * @param string $filename filename without path and extension + * @param string $extension extension of the file without "." + * @param string $content the content of the file + * @access public + * @return void + */ +function createFile($directory, $filename, $extension, $content = "") { + $handle = @fopen(buildPath($directory, $filename, $extension), "w"); + if($handle) { + fwrite($handle, $content); + fclose($handle); + } else { + die("FAILED to create file\n"); + } +} + + +/** + * routine to create the example directory and 3 files + * + * if the $example_name is "SomeThing" the following files will be created + * examples/some_thing + * examples/some_thing/some_thing.mustache + * examples/some_thing/some_thing.txt + * examples/some_thing/SomeThing.php + * + * @param mixed $example_name + * @access public + * @return void + */ +function main($example_name) { + $lowercase = getLowerCaseName($example_name); + $uppercase = getUpperCaseName($example_name); + createDirectory($lowercase); + createFile($lowercase, $lowercase, "mustache"); + createFile($lowercase, $lowercase, "txt"); + createFile($lowercase, $uppercase, "php", << 1) { + // get the name of the example + $example_name = $argv[1]; + + main($example_name); + +} else { + echo USAGE; +} diff --git a/examples/i18n/I18n.php b/examples/i18n/I18n.php new file mode 100644 index 0000000..980e649 --- /dev/null +++ b/examples/i18n/I18n.php @@ -0,0 +1,20 @@ + 'Hola.', + 'My name is {{ name }}.' => 'Me llamo {{ name }}.', + ); + + public function __trans($text) { + return isset($this->dictionary[$text]) ? $this->dictionary[$text] : $text; + } +} \ No newline at end of file diff --git a/examples/i18n/i18n.mustache b/examples/i18n/i18n.mustache new file mode 100644 index 0000000..eef169b --- /dev/null +++ b/examples/i18n/i18n.mustache @@ -0,0 +1 @@ +{{#__}}Hello.{{/__}} {{#__}}My name is {{ name }}.{{/__}} \ No newline at end of file diff --git a/examples/i18n/i18n.txt b/examples/i18n/i18n.txt new file mode 100644 index 0000000..650a71a --- /dev/null +++ b/examples/i18n/i18n.txt @@ -0,0 +1 @@ +Hola. Me llamo Bob. \ No newline at end of file diff --git a/test/MustacheLoaderTest.php b/test/MustacheLoaderTest.php new file mode 100644 index 0000000..2674a0f --- /dev/null +++ b/test/MustacheLoaderTest.php @@ -0,0 +1,60 @@ +assertEquals(file_get_contents(dirname(__FILE__).'/fixtures/foo.mustache'), $loader['foo']); + $this->assertEquals(file_get_contents(dirname(__FILE__).'/fixtures/bar.mustache'), $loader['bar']); + } + + public function testMustacheUsesFilesystemLoader() { + $template = '{{> foo }} {{> bar }}'; + $data = array( + 'truthy' => true, + 'foo' => 'FOO', + 'bar' => 'BAR', + ); + $output = 'FOO BAR'; + $m = new Mustache(); + $partials = new MustacheLoader(dirname(__FILE__).'/fixtures'); + $this->assertEquals($output, $m->render($template, $data, $partials)); + } + + public function testMustacheUsesDifferentLoadersToo() { + $template = '{{> foo }} {{> bar }}'; + $data = array( + 'truthy' => true, + 'foo' => 'FOO', + 'bar' => 'BAR', + ); + $output = 'FOO BAR'; + $m = new Mustache(); + $partials = new DifferentMustacheLoader(); + $this->assertEquals($output, $m->render($template, $data, $partials)); + } +} + +class DifferentMustacheLoader implements ArrayAccess { + protected $partials = array( + 'foo' => '{{ foo }}', + 'bar' => '{{# truthy }}{{ bar }}{{/ truthy }}', + ); + + public function offsetExists($offset) { + return isset($this->partials[$offset]); + } + + public function offsetGet($offset) { + return $this->partials[$offset]; + } + + public function offsetSet($offset, $value) {} + public function offsetUnset($offset) {} +} diff --git a/test/fixtures/bar.mustache b/test/fixtures/bar.mustache new file mode 100644 index 0000000..139594d --- /dev/null +++ b/test/fixtures/bar.mustache @@ -0,0 +1 @@ +{{# truthy }}{{ bar }}{{/ truthy }} \ No newline at end of file diff --git a/test/fixtures/foo.mustache b/test/fixtures/foo.mustache new file mode 100644 index 0000000..008c714 --- /dev/null +++ b/test/fixtures/foo.mustache @@ -0,0 +1 @@ +{{ foo }} \ No newline at end of file