diff --git a/src/Fenom.php b/src/Fenom.php index e4c0c11..8c52654 100644 --- a/src/Fenom.php +++ b/src/Fenom.php @@ -17,7 +17,7 @@ use Fenom\Template; */ class Fenom { - const VERSION = '1.3'; + const VERSION = '1.4'; /* Actions */ const INLINE_COMPILER = 1; @@ -246,10 +246,6 @@ class Fenom 'type' => self::BLOCK_COMPILER, 'open' => 'Fenom\Compiler::autoescapeOpen', 'close' => 'Fenom\Compiler::autoescapeClose' - ), - 'unset' => array( - 'type' => self::INLINE_COMPILER, - 'parser' => 'Fenom\Compiler::tagUnset' ) ); @@ -434,18 +430,18 @@ class Fenom "float_tags" => array() ); if (method_exists($storage, $compiler . "Open")) { - $c["open"] = $compiler . "Open"; + $c["open"] = array($storage, $compiler . "Open"); } else { throw new \LogicException("Open compiler {$compiler}Open not found"); } if (method_exists($storage, $compiler . "Close")) { - $c["close"] = $compiler . "Close"; + $c["close"] = array($storage, $compiler . "Close"); } else { throw new \LogicException("Close compiler {$compiler}Close not found"); } foreach ($tags as $tag) { if (method_exists($storage, "tag" . $tag)) { - $c["tags"][$tag] = "tag" . $tag; + $c["tags"][$tag] = array($storage, "tag" . $tag); if ($floats && in_array($tag, $floats)) { $c['float_tags'][$tag] = 1; } @@ -544,17 +540,6 @@ class Fenom return false; } - /** - * @param string $function - * @param Fenom\Template $template - * @return bool|string - * @deprecated - */ - public function getFunction($function, Template $template = null) - { - return $this->getTag($function, $template); - } - /** * Returns tag info * @@ -771,7 +756,6 @@ class Fenom $fenom = $this; // used in template $_tpl = include($this->_compile_dir . "/" . $file_name); /* @var Fenom\Render $_tpl */ -// var_dump($tpl, $_tpl->isValid()); exit; if (!($this->_options & self::AUTO_RELOAD) || ($this->_options & self::AUTO_RELOAD) && $_tpl->isValid()) { return $_tpl; } diff --git a/src/Fenom/Compiler.php b/src/Fenom/Compiler.php index 75ca77b..59ef3f0 100644 --- a/src/Fenom/Compiler.php +++ b/src/Fenom/Compiler.php @@ -1034,4 +1034,5 @@ class Compiler { $scope->tpl->escape = $scope["escape"]; } + } diff --git a/src/Fenom/Error/UnexpectedTokenException.php b/src/Fenom/Error/UnexpectedTokenException.php index f72ea4b..3087148 100644 --- a/src/Fenom/Error/UnexpectedTokenException.php +++ b/src/Fenom/Error/UnexpectedTokenException.php @@ -25,10 +25,6 @@ class UnexpectedTokenException extends \RuntimeException } if (!$tokens->curr) { $this->message = "Unexpected end of " . ($where ? : "expression") . "$expect"; - } elseif ($tokens->curr[0] === T_WHITESPACE) { - $this->message = "Unexpected whitespace$expect"; - } elseif ($tokens->curr[0] === T_BAD_CHARACTER) { - $this->message = "Unexpected bad characters (below ASCII 32 except \\t, \\n and \\r) in " . ($where ? : "expression") . "$expect"; } else { $this->message = "Unexpected token '" . $tokens->current() . "' in " . ($where ? : "expression") . "$expect"; } diff --git a/src/Fenom/Render.php b/src/Fenom/Render.php index 468d08a..138af26 100644 --- a/src/Fenom/Render.php +++ b/src/Fenom/Render.php @@ -85,6 +85,7 @@ class Render extends \ArrayObject $this->_fenom = $fenom; $props += self::$_props; $this->_name = $props["name"]; + $this->_base_name = $props["base_name"]; $this->_scm = $props["scm"]; $this->_time = $props["time"]; $this->_depends = $props["depends"]; diff --git a/src/Fenom/Template.php b/src/Fenom/Template.php index 8030371..ce85a37 100644 --- a/src/Fenom/Template.php +++ b/src/Fenom/Template.php @@ -163,7 +163,7 @@ class Template extends Render { $this->_name = $name; $this->_crc = crc32($this->_name); - if ($provider = strstr($name, ":", true)) { + if ($provider = strstr($name, ':', true)) { $this->_scm = $provider; $this->_base_name = substr($name, strlen($provider) + 1); } else { diff --git a/tests/TestCase.php b/tests/TestCase.php index 05a6624..629b495 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -114,6 +114,7 @@ class TestCase extends \PHPUnit_Framework_TestCase * @param string $result expected result. * @param int $options * @param bool $dump dump source and result code (for debug) + * @return \Fenom\Template */ public function exec($code, $vars, $result, $options = 0, $dump = false) { @@ -123,6 +124,7 @@ class TestCase extends \PHPUnit_Framework_TestCase echo "\n========= DUMP BEGIN ===========\n" . $code . "\n--- to ---\n" . $tpl->getBody() . "\n========= DUMP END =============\n"; } $this->assertSame(Modifier::strip($result), Modifier::strip($tpl->fetch($vars), true), "Test $code"); + return $tpl; } public function execTpl($name, $code, $vars, $result, $dump = false) @@ -162,9 +164,10 @@ class TestCase extends \PHPUnit_Framework_TestCase { $template = $this->fenom->compileCode($tpl); if ($debug) { - print_r("$tpl:\n" . $template->getBody()); + print_r("\nDEBUG $tpl:\n" . $template->getBody()); } $this->assertSame($result, $template->fetch($this->values)); + return $template; } @@ -271,37 +274,3 @@ class TestCase extends \PHPUnit_Framework_TestCase ); } } - -class Fake implements \ArrayAccess -{ - public $vars; - - public function offsetExists($offset) - { - return true; - } - - public function offsetGet($offset) - { - if ($offset == "object") { - return new self(); - } else { - return new self($offset); - } - } - - public function offsetSet($offset, $value) - { - $this->vars[$offset] = $value; - } - - public function offsetUnset($offset) - { - unset($this->vars[$offset]); - } - - public function proxy() - { - return implode(", ", func_get_args()); - } -} diff --git a/tests/cases/Fenom/CustomProviderTest.php b/tests/cases/Fenom/CustomProviderTest.php index 137ead6..483ed1c 100644 --- a/tests/cases/Fenom/CustomProviderTest.php +++ b/tests/cases/Fenom/CustomProviderTest.php @@ -14,6 +14,8 @@ class CustomProviderTest extends TestCase public function testCustom() { + $this->assertTrue($this->fenom->templateExists('my:include.tpl')); + $this->assertFalse($this->fenom->templateExists('my:include-none.tpl')); $this->assertRender("start: {include 'my:include.tpl'}", 'start: include template'); //$this->assertRender("start: {import 'my:macros.tpl' as ops} {ops.add a=3 b=6}"); } diff --git a/tests/cases/Fenom/TemplateTest.php b/tests/cases/Fenom/TemplateTest.php index 7dbd658..aec2a94 100644 --- a/tests/cases/Fenom/TemplateTest.php +++ b/tests/cases/Fenom/TemplateTest.php @@ -209,6 +209,7 @@ class TemplateTest extends TestCase array('If: {$a != 5 => 4} end', 'Fenom\Error\CompileException', "Unexpected token '=>'"), array('If: {$a + (*6)} end', 'Fenom\Error\CompileException', "Unexpected token '*'"), array('If: {$a + ( 6} end', 'Fenom\Error\CompileException', "Unexpected end of expression, expect ')'"), + array('If: {$a end', 'Fenom\Error\CompileException', "Unclosed tag in line"), ); } @@ -266,7 +267,7 @@ class TemplateTest extends TestCase "username" => "Master", "email" => "dev@null.net" ); - $result = 'Include Welcome, Master (dev@null.net) template'; + $result = 'Include Welcome, Master (dev@null.net) template'; return array( array('Include {insert "welcome.tpl"} template', $a, $result), array("Include {insert 'welcome.tpl'} template", $a, $result), @@ -684,6 +685,7 @@ class TemplateTest extends TestCase array('{if null is set} block1 {else} block2 {/if}', 'block2'), array('{if 0 is empty} block1 {else} block2 {/if}', 'block1'), array('{if "" is empty} block1 {else} block2 {/if}', 'block1'), + array('{if [] is empty} block1 {else} block2 {/if}', 'block1'), array('{if "data" is empty} block1 {else} block2 {/if}', 'block2'), array('{if time() is not empty} block1 {else} block2 {/if}', 'block1'), // is empty @@ -700,8 +702,10 @@ class TemplateTest extends TestCase // event, odd array('{if $one is odd} block1 {else} block2 {/if}', 'block1'), array('{if $one is even} block1 {else} block2 {/if}', 'block2'), + array('{if ($one + 1) is even} block1 {else} block2 {/if}', 'block1'), array('{if $two is even} block1 {else} block2 {/if}', 'block1'), array('{if $two is odd} block1 {else} block2 {/if}', 'block2'), + array('{if ($two+1) is odd} block1 {else} block2 {/if}', 'block1'), // template array('{if "welcome.tpl" is template} block1 {else} block2 {/if}', 'block1'), array('{if "welcome2.tpl" is template} block1 {else} block2 {/if}', 'block2'), @@ -754,13 +758,19 @@ class TemplateTest extends TestCase array('{$.get.one?}', '1'), array('{$.get.one is set}', '1'), array('{$.get.two is empty}', '1'), + + array('{$.version}', Fenom::VERSION), + array('{$.tpl?}', '1'), + array('{$.tpl.name}', 'runtime.tpl'), + array('{$.tpl.time}', '0'), + array('{$.tpl.schema}', ''), ); } public function _testSandbox() { try { - var_dump($this->fenom->setOptions(Fenom::FORCE_VERIFY)->compileCode('{if $unexist} block1 {else} block2 {/if}')->getBody()); + var_dump($this->fenom->setOptions(Fenom::FORCE_VERIFY)->addFilter(function ($txt) {return $txt;})->compileCode('- -')->fetch(['a' => 1])); } catch (\Exception $e) { print_r($e->getMessage() . "\n" . $e->getTraceAsString()); } @@ -839,7 +849,11 @@ class TemplateTest extends TestCase */ public function testInsert($code, $vars, $result) { - $this->exec($code, $vars, $result); + $this->values = $vars; + $this->tpl("insert.tpl", $code); + $tpl = $this->fenom->getTemplate('insert.tpl'); + $this->assertSame($result, $tpl->fetch($vars)); + $this->assertTrue($tpl->isValid()); } /** diff --git a/tests/cases/Fenom/TokenizerTest.php b/tests/cases/Fenom/TokenizerTest.php index ff656af..5fbfb42 100644 --- a/tests/cases/Fenom/TokenizerTest.php +++ b/tests/cases/Fenom/TokenizerTest.php @@ -1,5 +1,6 @@ assertSame("sin", $tokens->getNext($tokens::MACRO_STRING)); $this->assertSame("sin", $tokens->current()); + $this->assertTrue($tokens->isPrev(":")); $this->assertSame(T_STRING, $tokens->key()); $this->assertTrue($tokens->is(T_STRING)); $this->assertTrue($tokens->is($tokens::MACRO_STRING)); @@ -58,8 +60,9 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase $tokens->next(); $this->assertSame("+", $tokens->getNext($tokens::MACRO_BINARY)); - $this->assertSame('sin($x)+tan($x*$t)', $tokens->getSnippetAsString(-4, 6)); $this->assertSame($code, $tokens->getSnippetAsString(-100, 100)); + $this->assertSame('+', $tokens->getSnippetAsString(100, -100)); + $this->assertSame('sin($x)+tan($x*$t)', $tokens->getSnippetAsString(-4, 6)); } public function testSkip() diff --git a/tests/cases/FenomTest.php b/tests/cases/FenomTest.php index 1810718..00ba02e 100644 --- a/tests/cases/FenomTest.php +++ b/tests/cases/FenomTest.php @@ -21,13 +21,26 @@ class FenomTest extends \Fenom\TestCase } public function testCreating() { - $time = $this->tpl('template1.tpl', 'Template 1 a'); - Fenom::factory(FENOM_RESOURCES . '/template', FENOM_RESOURCES . '/compile'); - $fenom = new Fenom($provider =new \Fenom\Provider(FENOM_RESOURCES . '/template'), FENOM_RESOURCES . '/compile', Fenom::AUTO_ESCAPE); - $this->assertInstanceOf('Fenom\Template', $tpl = $fenom->getTemplate('template1.tpl')); + $time = $this->tpl('temp.tpl', 'Template 1 a'); + $fenom = new Fenom($provider = new \Fenom\Provider(FENOM_RESOURCES . '/template')); + $fenom->setCompileDir(FENOM_RESOURCES . '/compile'); + $this->assertInstanceOf('Fenom\Template', $tpl = $fenom->getTemplate('temp.tpl')); $this->assertSame($provider, $tpl->getProvider()); - $this->assertSame('template1.tpl', $tpl->getBaseName()); + $this->assertSame('temp.tpl', $tpl->getBaseName()); + $this->assertSame('temp.tpl', $tpl->getName()); $this->assertSame($time, $tpl->getTime()); + $fenom->clearAllCompiles(); + } + + public function testFactory() { + $time = $this->tpl('temp.tpl', 'Template 1 a'); + $fenom = Fenom::factory($provider = new \Fenom\Provider(FENOM_RESOURCES . '/template'), FENOM_RESOURCES . '/compile', Fenom::AUTO_ESCAPE); + $this->assertInstanceOf('Fenom\Template', $tpl = $fenom->getTemplate('temp.tpl')); + $this->assertSame($provider, $tpl->getProvider()); + $this->assertSame('temp.tpl', $tpl->getBaseName()); + $this->assertSame('temp.tpl', $tpl->getName()); + $this->assertSame($time, $tpl->getTime()); + $fenom->clearAllCompiles(); } public function testCompileFile() @@ -146,6 +159,48 @@ class FenomTest extends \Fenom\TestCase return "|--- $text ---|"; }); - $this->assertSame('+++ |--- == hello ---||--- world == ---| +++', $this->fenom->compileCode('hello {var $user} god {/var} world')->fetch(array())); + $this->assertSame('+++ |--- == hello ---||--- world == ---| +++', $this->fenom->compileCode('hello {var $user} misterio {/var} world')->fetch(array())); + $this->assertSame('+++ |--- == hello ---||--- world == ---| +++', $this->fenom->compileCode('hello {var $user} {/var} world')->fetch(array())); } -} \ No newline at end of file + + public function testAddInlineCompilerSmart() { + $this->fenom->addCompilerSmart('SayA','TestTags'); + $this->tpl('inline_compiler.tpl', 'I just {SayA}.'); + $this->assertSame('I just Say A.', $this->fenom->fetch('inline_compiler.tpl', array())); + } + + public function testAddBlockCompilerSmart() { + $this->fenom->addBlockCompilerSmart('SayBlock', 'TestTags', array('SaySomething'), array('SaySomething')); + $this->tpl('block_compiler.tpl', '{SayBlock} and {SaySomething}. It is all, {/SayBlock}'); + $this->assertSame('Start saying and say blah-blah-blah. It is all, Stop saying', + $this->fenom->fetch('block_compiler.tpl', array())); + } + + public function testAddFunctions() { + $this->fenom->setOptions(Fenom::DENY_NATIVE_FUNCS); + $this->assertFalse($this->fenom->isAllowedFunction('substr')); + $this->fenom->addAllowedFunctions(array('substr')); + $this->assertTrue($this->fenom->isAllowedFunction('substr')); + } +} + + + +class TestTags { + + public static function tagSayA() { + return 'echo "Say A"'; + } + + public static function SayBlockOpen() { + return 'echo "Start saying"'; + } + + public static function tagSaySomething() { + return 'echo "say blah-blah-blah"'; + } + + public static function SayBlockClose() { + return 'echo "Stop saying"'; + } +}