Merge branch 'origin/develop'

This commit is contained in:
Ivan Shalganov 2013-09-15 16:41:37 +04:00
commit 847e594aa6
10 changed files with 96 additions and 71 deletions

View File

@ -17,7 +17,7 @@ use Fenom\Template;
*/ */
class Fenom class Fenom
{ {
const VERSION = '1.3'; const VERSION = '1.4';
/* Actions */ /* Actions */
const INLINE_COMPILER = 1; const INLINE_COMPILER = 1;
@ -246,10 +246,6 @@ class Fenom
'type' => self::BLOCK_COMPILER, 'type' => self::BLOCK_COMPILER,
'open' => 'Fenom\Compiler::autoescapeOpen', 'open' => 'Fenom\Compiler::autoescapeOpen',
'close' => 'Fenom\Compiler::autoescapeClose' 'close' => 'Fenom\Compiler::autoescapeClose'
),
'unset' => array(
'type' => self::INLINE_COMPILER,
'parser' => 'Fenom\Compiler::tagUnset'
) )
); );
@ -434,18 +430,18 @@ class Fenom
"float_tags" => array() "float_tags" => array()
); );
if (method_exists($storage, $compiler . "Open")) { if (method_exists($storage, $compiler . "Open")) {
$c["open"] = $compiler . "Open"; $c["open"] = array($storage, $compiler . "Open");
} else { } else {
throw new \LogicException("Open compiler {$compiler}Open not found"); throw new \LogicException("Open compiler {$compiler}Open not found");
} }
if (method_exists($storage, $compiler . "Close")) { if (method_exists($storage, $compiler . "Close")) {
$c["close"] = $compiler . "Close"; $c["close"] = array($storage, $compiler . "Close");
} else { } else {
throw new \LogicException("Close compiler {$compiler}Close not found"); throw new \LogicException("Close compiler {$compiler}Close not found");
} }
foreach ($tags as $tag) { foreach ($tags as $tag) {
if (method_exists($storage, "tag" . $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)) { if ($floats && in_array($tag, $floats)) {
$c['float_tags'][$tag] = 1; $c['float_tags'][$tag] = 1;
} }
@ -544,17 +540,6 @@ class Fenom
return false; 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 * Returns tag info
* *
@ -771,7 +756,6 @@ class Fenom
$fenom = $this; // used in template $fenom = $this; // used in template
$_tpl = include($this->_compile_dir . "/" . $file_name); $_tpl = include($this->_compile_dir . "/" . $file_name);
/* @var Fenom\Render $_tpl */ /* @var Fenom\Render $_tpl */
// var_dump($tpl, $_tpl->isValid()); exit;
if (!($this->_options & self::AUTO_RELOAD) || ($this->_options & self::AUTO_RELOAD) && $_tpl->isValid()) { if (!($this->_options & self::AUTO_RELOAD) || ($this->_options & self::AUTO_RELOAD) && $_tpl->isValid()) {
return $_tpl; return $_tpl;
} }

View File

@ -1034,4 +1034,5 @@ class Compiler
{ {
$scope->tpl->escape = $scope["escape"]; $scope->tpl->escape = $scope["escape"];
} }
} }

View File

@ -25,10 +25,6 @@ class UnexpectedTokenException extends \RuntimeException
} }
if (!$tokens->curr) { if (!$tokens->curr) {
$this->message = "Unexpected end of " . ($where ? : "expression") . "$expect"; $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 { } else {
$this->message = "Unexpected token '" . $tokens->current() . "' in " . ($where ? : "expression") . "$expect"; $this->message = "Unexpected token '" . $tokens->current() . "' in " . ($where ? : "expression") . "$expect";
} }

View File

@ -85,6 +85,7 @@ class Render extends \ArrayObject
$this->_fenom = $fenom; $this->_fenom = $fenom;
$props += self::$_props; $props += self::$_props;
$this->_name = $props["name"]; $this->_name = $props["name"];
$this->_base_name = $props["base_name"];
$this->_scm = $props["scm"]; $this->_scm = $props["scm"];
$this->_time = $props["time"]; $this->_time = $props["time"];
$this->_depends = $props["depends"]; $this->_depends = $props["depends"];

View File

@ -163,7 +163,7 @@ class Template extends Render
{ {
$this->_name = $name; $this->_name = $name;
$this->_crc = crc32($this->_name); $this->_crc = crc32($this->_name);
if ($provider = strstr($name, ":", true)) { if ($provider = strstr($name, ':', true)) {
$this->_scm = $provider; $this->_scm = $provider;
$this->_base_name = substr($name, strlen($provider) + 1); $this->_base_name = substr($name, strlen($provider) + 1);
} else { } else {

View File

@ -114,6 +114,7 @@ class TestCase extends \PHPUnit_Framework_TestCase
* @param string $result expected result. * @param string $result expected result.
* @param int $options * @param int $options
* @param bool $dump dump source and result code (for debug) * @param bool $dump dump source and result code (for debug)
* @return \Fenom\Template
*/ */
public function exec($code, $vars, $result, $options = 0, $dump = false) 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"; 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"); $this->assertSame(Modifier::strip($result), Modifier::strip($tpl->fetch($vars), true), "Test $code");
return $tpl;
} }
public function execTpl($name, $code, $vars, $result, $dump = false) public function execTpl($name, $code, $vars, $result, $dump = false)
@ -162,9 +164,10 @@ class TestCase extends \PHPUnit_Framework_TestCase
{ {
$template = $this->fenom->compileCode($tpl); $template = $this->fenom->compileCode($tpl);
if ($debug) { if ($debug) {
print_r("$tpl:\n" . $template->getBody()); print_r("\nDEBUG $tpl:\n" . $template->getBody());
} }
$this->assertSame($result, $template->fetch($this->values)); $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());
}
}

View File

@ -14,6 +14,8 @@ class CustomProviderTest extends TestCase
public function testCustom() 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: {include 'my:include.tpl'}", 'start: include template');
//$this->assertRender("start: {import 'my:macros.tpl' as ops} {ops.add a=3 b=6}"); //$this->assertRender("start: {import 'my:macros.tpl' as ops} {ops.add a=3 b=6}");
} }

View File

@ -209,6 +209,7 @@ class TemplateTest extends TestCase
array('If: {$a != 5 => 4} end', 'Fenom\Error\CompileException', "Unexpected token '=>'"), 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 token '*'"),
array('If: {$a + ( 6} end', 'Fenom\Error\CompileException', "Unexpected end of expression, expect ')'"), 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", "username" => "Master",
"email" => "dev@null.net" "email" => "dev@null.net"
); );
$result = 'Include <b>Welcome, Master (dev@null.net)</b> template'; $result = 'Include <b>Welcome, Master (dev@null.net)</b> template';
return array( return array(
array('Include {insert "welcome.tpl"} template', $a, $result), array('Include {insert "welcome.tpl"} template', $a, $result),
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 null is set} block1 {else} block2 {/if}', 'block2'),
array('{if 0 is empty} block1 {else} block2 {/if}', 'block1'), 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 [] is empty} block1 {else} block2 {/if}', 'block1'),
array('{if "data" is empty} block1 {else} block2 {/if}', 'block2'), array('{if "data" is empty} block1 {else} block2 {/if}', 'block2'),
array('{if time() is not empty} block1 {else} block2 {/if}', 'block1'), array('{if time() is not empty} block1 {else} block2 {/if}', 'block1'),
// is empty // is empty
@ -700,8 +702,10 @@ class TemplateTest extends TestCase
// event, odd // event, odd
array('{if $one is odd} block1 {else} block2 {/if}', 'block1'), array('{if $one is odd} block1 {else} block2 {/if}', 'block1'),
array('{if $one is even} block1 {else} block2 {/if}', 'block2'), 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 even} block1 {else} block2 {/if}', 'block1'),
array('{if $two is odd} block1 {else} block2 {/if}', 'block2'), array('{if $two is odd} block1 {else} block2 {/if}', 'block2'),
array('{if ($two+1) is odd} block1 {else} block2 {/if}', 'block1'),
// template // template
array('{if "welcome.tpl" is template} block1 {else} block2 {/if}', 'block1'), array('{if "welcome.tpl" is template} block1 {else} block2 {/if}', 'block1'),
array('{if "welcome2.tpl" is template} block1 {else} block2 {/if}', 'block2'), 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?}', '1'),
array('{$.get.one is set}', '1'), array('{$.get.one is set}', '1'),
array('{$.get.two is empty}', '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() public function _testSandbox()
{ {
try { 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('- <?php {$a} ?> -')->fetch(['a' => 1]));
} catch (\Exception $e) { } catch (\Exception $e) {
print_r($e->getMessage() . "\n" . $e->getTraceAsString()); print_r($e->getMessage() . "\n" . $e->getTraceAsString());
} }
@ -839,7 +849,11 @@ class TemplateTest extends TestCase
*/ */
public function testInsert($code, $vars, $result) 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());
} }
/** /**

View File

@ -1,5 +1,6 @@
<?php <?php
namespace Fenom; namespace Fenom;
use Fenom\Error\UnexpectedTokenException;
use Fenom\Tokenizer; use Fenom\Tokenizer;
class TokenizerTest extends \PHPUnit_Framework_TestCase class TokenizerTest extends \PHPUnit_Framework_TestCase
@ -46,6 +47,7 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
$this->assertSame("sin", $tokens->getNext($tokens::MACRO_STRING)); $this->assertSame("sin", $tokens->getNext($tokens::MACRO_STRING));
$this->assertSame("sin", $tokens->current()); $this->assertSame("sin", $tokens->current());
$this->assertTrue($tokens->isPrev(":"));
$this->assertSame(T_STRING, $tokens->key()); $this->assertSame(T_STRING, $tokens->key());
$this->assertTrue($tokens->is(T_STRING)); $this->assertTrue($tokens->is(T_STRING));
$this->assertTrue($tokens->is($tokens::MACRO_STRING)); $this->assertTrue($tokens->is($tokens::MACRO_STRING));
@ -58,8 +60,9 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
$tokens->next(); $tokens->next();
$this->assertSame("+", $tokens->getNext($tokens::MACRO_BINARY)); $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($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() public function testSkip()

View File

@ -21,13 +21,26 @@ class FenomTest extends \Fenom\TestCase
} }
public function testCreating() { public function testCreating() {
$time = $this->tpl('template1.tpl', 'Template 1 a'); $time = $this->tpl('temp.tpl', 'Template 1 a');
Fenom::factory(FENOM_RESOURCES . '/template', FENOM_RESOURCES . '/compile'); $fenom = new Fenom($provider = new \Fenom\Provider(FENOM_RESOURCES . '/template'));
$fenom = new Fenom($provider =new \Fenom\Provider(FENOM_RESOURCES . '/template'), FENOM_RESOURCES . '/compile', Fenom::AUTO_ESCAPE); $fenom->setCompileDir(FENOM_RESOURCES . '/compile');
$this->assertInstanceOf('Fenom\Template', $tpl = $fenom->getTemplate('template1.tpl')); $this->assertInstanceOf('Fenom\Template', $tpl = $fenom->getTemplate('temp.tpl'));
$this->assertSame($provider, $tpl->getProvider()); $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()); $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() public function testCompileFile()
@ -146,6 +159,48 @@ class FenomTest extends \Fenom\TestCase
return "|--- $text ---|"; 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} <?php misterio ?> {/var} world')->fetch(array()));
}
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"';
} }
} }