mirror of
https://github.com/fenom-template/fenom.git
synced 2023-08-10 21:13:07 +03:00
Done static inheritance
Add TestCase
This commit is contained in:
parent
8c618c2b34
commit
ad2e7316b1
@ -50,19 +50,23 @@ class Benchmark {
|
||||
if($double) {
|
||||
$aspect->fetch($tpl, $data);
|
||||
}
|
||||
$start = microtime(true);
|
||||
$_SERVER["t"] = $start = microtime(true);
|
||||
$aspect->fetch($tpl, $data);
|
||||
printf(self::$t, __FUNCTION__, $message, round(microtime(true)-$start, 4), round(memory_get_peak_usage()/1024/1024, 2));
|
||||
}
|
||||
|
||||
public static function run($engine, $template, $data, $double, $message) {
|
||||
passthru(sprintf("php %s/run.php --engine '%s' --template '%s' --data '%s' --message '%s' %s", __DIR__, $engine, $template, $data, $message, $double ? '--double' : ''));
|
||||
passthru(sprintf("php -dmemory_limit=512M %s/run.php --engine '%s' --template '%s' --data '%s' --message '%s' %s", __DIR__, $engine, $template, $data, $message, $double ? '--double' : ''));
|
||||
}
|
||||
|
||||
public static function runs($engine, $template, $data) {
|
||||
self::run($engine, $template, $data, false, '!compiled and !loaded');
|
||||
self::run($engine, $template, $data, false, 'compiled and !loaded');
|
||||
self::run($engine, $template, $data, true, 'compiled and loaded');
|
||||
self::run($engine, $template, $data, false, ' compiled and !loaded');
|
||||
self::run($engine, $template, $data, true, ' compiled and loaded');
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
function t() {
|
||||
if(isset($_SERVER["t"])) var_dump(round(microtime(1) - $_SERVER["t"], 4));
|
||||
}
|
@ -526,7 +526,6 @@ class Aspect {
|
||||
* @return Aspect\Template
|
||||
*/
|
||||
public function getTemplate($template) {
|
||||
|
||||
if(isset($this->_storage[ $template ])) {
|
||||
/** @var Aspect\Template $tpl */
|
||||
$tpl = $this->_storage[ $template ];
|
||||
@ -562,6 +561,7 @@ class Aspect {
|
||||
if(!is_file($this->_compile_dir."/".$file_name)) {
|
||||
return $this->compile($tpl);
|
||||
} else {
|
||||
$aspect = $this;
|
||||
/** @var Aspect\Render $tpl */
|
||||
return include($this->_compile_dir."/".$file_name);
|
||||
}
|
||||
|
@ -388,28 +388,18 @@ class Compiler {
|
||||
public static function extendBody(&$body, $tpl) {
|
||||
if(isset($tpl->_extends)) { // is child
|
||||
if(is_object($tpl->_extends)) { // static extends
|
||||
$t = $tpl;
|
||||
while(isset($t->_extends)) {
|
||||
$t = $tpl->_extends;
|
||||
/* @var Template $t */
|
||||
do {
|
||||
$t->_blocks = &$tpl->_blocks;
|
||||
$t->compile();
|
||||
$t->_blocks += (array)$t->_extends->_blocks;
|
||||
$t = $t->_extends;
|
||||
|
||||
}
|
||||
|
||||
if(empty($t->_blocks)) {
|
||||
$body = $t->getBody();
|
||||
} else {
|
||||
$b = $t->getBody();
|
||||
foreach($t->_blocks as $name => $pos) {
|
||||
|
||||
}
|
||||
}
|
||||
$tpl->addDepend($t);
|
||||
} while(isset($t->_extends) && $t = $t->_extends);
|
||||
$body = $t->_body;
|
||||
} else { // dynamic extends
|
||||
$body .= '<?php $parent->blocks = &$tpl->blocks; $parent->display((array)$tpl); unset($tpl->blocks, $parent->blocks); ?>';
|
||||
//return '$tpl->blocks['.$scope["name"].'] = ob_get_clean();';
|
||||
}
|
||||
}
|
||||
/*$body = '<?php if(!isset($tpl->blocks)) {$tpl->blocks = array();} ob_start(); ?>'.$body.'<?php ob_end_clean(); $parent->blocks = &$tpl->blocks; $parent->display((array)$tpl); unset($tpl->blocks, $parent->blocks); ?>';*/
|
||||
}
|
||||
|
||||
|
||||
@ -425,25 +415,30 @@ class Compiler {
|
||||
* @throws ImproperUseException
|
||||
*/
|
||||
public static function tagBlockOpen(Tokenizer $tokens, Scope $scope) {
|
||||
$p = $scope->tpl->parseParams($tokens);
|
||||
if (isset($p[0])) {
|
||||
$scope["name"] = $p[0];
|
||||
$p = $scope->tpl->parseFirstArg($tokens, $name);
|
||||
if ($name) {
|
||||
$scope["static"] = true;
|
||||
$scope["name"] = $name;
|
||||
$scope["cname"] = '"'.addslashes($name).'"';
|
||||
} else {
|
||||
throw new ImproperUseException("{block} must be named");
|
||||
$scope["static"] = false;
|
||||
$scope["name"] = $scope["cname"] = $p;
|
||||
}
|
||||
if(isset($scope->tpl->_extends)) { // is child
|
||||
if(is_object($scope->tpl->_extends)) { // static extends
|
||||
if(is_object($scope->tpl->_extends) && $scope["static"]) { // static extends
|
||||
$code = "";
|
||||
} else { // dynamic extends
|
||||
$code = 'if(empty($tpl->blocks['.$scope["name"].'])) { ob_start();';
|
||||
$code = 'if(empty($tpl->blocks['.$scope["cname"].'])) { $tpl->blocks['.$scope["cname"].'] = function($tpl) {';
|
||||
}
|
||||
} else { // is parent
|
||||
if(isset($scope->tpl->_blocks)) { // has blocks from child
|
||||
if(isset($scope->tpl->_blocks[ $scope["name"] ])) { // skip own block and insert child's block after
|
||||
$scope["body"] = $scope->tpl->_body;
|
||||
$scope->tpl->_body = "";
|
||||
} // else just put block content as is
|
||||
return '';
|
||||
} else {
|
||||
$code = 'if(isset($tpl->blocks['.$scope["name"].'])) { echo $tpl->blocks['.$scope["name"].']; } else {';
|
||||
$code = 'if(isset($tpl->blocks['.$scope["cname"].'])) { echo $tpl->blocks['.$scope["cname"].']->__invoke($tpl); } else {';
|
||||
}
|
||||
}
|
||||
$scope["offset"] = strlen($scope->tpl->getBody()) + strlen($code);
|
||||
@ -457,35 +452,26 @@ class Compiler {
|
||||
* @return string
|
||||
*/
|
||||
public static function tagBlockClose($tokens, Scope $scope) {
|
||||
$scope->tpl->_blocks[ $scope["name"] ] = substr($scope->tpl->getBody(), $scope["offset"]);
|
||||
|
||||
if(isset($scope->tpl->_extends)) { // is child
|
||||
if(is_object($scope->tpl->_extends)) { // static extends
|
||||
if(is_object($scope->tpl->_extends) && $scope["static"]) { // static extends
|
||||
if(!isset($scope->tpl->_blocks[ $scope["name"] ])) {
|
||||
$scope->tpl->_blocks[ $scope["name"] ] = substr($scope->tpl->getBody(), $scope["offset"]);
|
||||
}
|
||||
return "";
|
||||
} else { // dynamic extends
|
||||
return '$tpl->blocks['.$scope["name"].'] = ob_get_clean(); }';
|
||||
return '} }';
|
||||
}
|
||||
} else { // is parent
|
||||
if(isset($scope->tpl->_blocks)) {
|
||||
if(isset($scope["body"])) {
|
||||
$scope->tpl->_body = $scope["body"].$scope->tpl->_blocks[ $scope["name"] ];
|
||||
}
|
||||
return "";
|
||||
} else {
|
||||
return '}';
|
||||
}
|
||||
}
|
||||
/* $scope->tpl->_blocks[ $scope["name"] ] = substr($scope->tpl->getBody(), $scope["offset"]);
|
||||
return '}';*/
|
||||
/*if(isset($scope->tpl->_extends) && is_object($scope->tpl->_extends)) {
|
||||
|
||||
//var_dump("fetched block ".$scope->tpl->_blocks[ $scope["name"] ]);
|
||||
} else {
|
||||
return '}';
|
||||
}*/
|
||||
/*if(isset($scope->tpl->_extends)) {
|
||||
$var = '$i'.$scope->tpl->i++;
|
||||
return $var.' = ob_get_clean(); if('.$var.') $tpl->blocks['.$scope["name"].'] = '.$var.';';
|
||||
} else {
|
||||
return 'if(empty($tpl->blocks['.$scope["name"].'])) { ob_end_flush(); } else { print($tpl->blocks['.$scope["name"].']); ob_end_clean(); }';
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,6 +28,11 @@ class Misc {
|
||||
return $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean directory from files
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public static function clean($path) {
|
||||
if(is_file($path)) {
|
||||
unlink($path);
|
||||
@ -46,6 +51,11 @@ class Misc {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive remove directory
|
||||
*
|
||||
* @param string $path
|
||||
*/
|
||||
public static function rm($path) {
|
||||
self::clean($path);
|
||||
if(is_dir($path)) {
|
||||
|
@ -66,6 +66,10 @@ class Render extends \ArrayObject {
|
||||
return $this->_aspect;
|
||||
}
|
||||
|
||||
public function getDepends() {
|
||||
return $this->_depends;
|
||||
}
|
||||
|
||||
public function getScm() {
|
||||
return $this->_scm;
|
||||
}
|
||||
@ -93,7 +97,7 @@ class Render extends \ArrayObject {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
public function getCompileTime() {
|
||||
public function getTime() {
|
||||
return $this->_time;
|
||||
}
|
||||
|
||||
@ -108,7 +112,7 @@ class Render extends \ArrayObject {
|
||||
return false;
|
||||
}
|
||||
foreach($this->_depends as $tpl => $time) {
|
||||
if($this->_aspect->getTemplate($tpl)->getCompileTime() !== $time) {
|
||||
if($this->_aspect->getTemplate($tpl)->getTime() !== $time) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -137,16 +137,29 @@ class Template extends Render {
|
||||
// $frag = ltrim($frag);
|
||||
//}
|
||||
|
||||
$this->_body .= str_replace("<?", '<?php echo "<?" ?>', $frag);
|
||||
$this->_body .= str_replace("<?", '<?php echo "<?"; ?>', $frag);
|
||||
|
||||
$tag = $this->_tag($tag, $this->_trim); // dispatching tags
|
||||
$this->_body .= $this->_tag($tag, $this->_trim); // dispatching tags
|
||||
|
||||
// duplicate new line http://docs.php.net/manual/en/language.basic-syntax.instruction-separation.php
|
||||
/*if(isset($this->_src[ $end+1 ])) {
|
||||
$c = $this->_src[ $end+1 ];
|
||||
if($c === "\n") {
|
||||
$this->_body .= "\n";
|
||||
} elseif($c === "\r") {
|
||||
if(isset($this->_src[ $end+2 ]) && $this->_src[ $end+2 ] == "\n") {
|
||||
$this->_body .= "\r\n";
|
||||
} else {
|
||||
$this->_body .= "\r";
|
||||
}
|
||||
}
|
||||
}*/
|
||||
//if($this->_trim) { // if current tag has trim flag
|
||||
// $frag = rtrim($frag);
|
||||
//}
|
||||
$this->_body .= $tag;
|
||||
//$this->_body .= $tag;
|
||||
}
|
||||
$this->_body .= str_replace("<?", '<?php echo "<?" ?>', substr($this->_src, $this->_pos));
|
||||
$this->_body .= str_replace("<?", '<?php echo "<?"; ?>', substr($this->_src, $this->_pos));
|
||||
if($this->_stack) {
|
||||
$_names = array();
|
||||
$_line = 0;
|
||||
@ -185,7 +198,7 @@ class Template extends Render {
|
||||
public function getTemplateCode() {
|
||||
return "<?php \n".
|
||||
"/** Aspect template '".$this->_name."' compiled at ".date('Y-m-d H:i:s')." */\n".
|
||||
"return new Aspect\\Render(\$this, ".$this->_getClosureSource().", ".var_export(array(
|
||||
"return new Aspect\\Render(\$aspect, ".$this->_getClosureSource().", ".var_export(array(
|
||||
//"options" => $this->_options,
|
||||
"provider" => $this->_scm,
|
||||
"name" => $this->_name,
|
||||
@ -227,8 +240,7 @@ class Template extends Render {
|
||||
* @param Render $tpl
|
||||
*/
|
||||
public function addDepend(Render $tpl) {
|
||||
|
||||
$this->_depends[$tpl->getName()] = $tpl->getCompileTime();
|
||||
$this->_depends[$tpl->getScm()][$tpl->getName()] = $tpl->getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
|
57
tests/TestCase.php
Normal file
57
tests/TestCase.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
namespace Aspect;
|
||||
use Aspect;
|
||||
|
||||
class TestCase extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var Aspect
|
||||
*/
|
||||
public $aspect;
|
||||
|
||||
public function setUp() {
|
||||
if(!file_exists(ASPECT_RESOURCES.'/compile')) {
|
||||
mkdir(ASPECT_RESOURCES.'/compile', 0777, true);
|
||||
} else {
|
||||
Misc::clean(ASPECT_RESOURCES.'/compile/');
|
||||
}
|
||||
$this->aspect = Aspect::factory(ASPECT_RESOURCES.'/template', ASPECT_RESOURCES.'/compile');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile and execute template
|
||||
*
|
||||
* @param string $code source of template
|
||||
* @param array $vars variables of template
|
||||
* @param string $result expected result.
|
||||
* @param bool $dump dump source and result code (for debug)
|
||||
*/
|
||||
public function exec($code, $vars, $result, $dump = false) {
|
||||
$tpl = $this->aspect->compileCode($code, "runtime.tpl");
|
||||
if($dump) {
|
||||
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");
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to compile the invalid template
|
||||
* @param string $code source of the template
|
||||
* @param string $exception exception class
|
||||
* @param string $message exception message
|
||||
* @param int $options Aspect's options
|
||||
*/
|
||||
public function execError($code, $exception, $message, $options = 0) {
|
||||
$opt = $this->aspect->getOptions();
|
||||
$this->aspect->setOptions($options);
|
||||
try {
|
||||
$this->aspect->compileCode($code, "inline.tpl");
|
||||
} catch(\Exception $e) {
|
||||
$this->assertSame($exception, get_class($e), "Exception $code");
|
||||
$this->assertStringStartsWith($message, $e->getMessage());
|
||||
$this->aspect->setOptions($opt);
|
||||
return;
|
||||
}
|
||||
self::$aspect->setOptions($opt);
|
||||
$this->fail("Code $code must be invalid");
|
||||
}
|
||||
}
|
@ -7,3 +7,11 @@ require_once __DIR__."/../vendor/autoload.php";
|
||||
define('ASPECT_RESOURCES', __DIR__."/resources");
|
||||
|
||||
require_once ASPECT_RESOURCES."/actions.php";
|
||||
require_once __DIR__."/TestCase.php";
|
||||
|
||||
function drop() {
|
||||
call_user_func_array("var_dump", func_get_args());
|
||||
$e = new Exception();
|
||||
echo "-------\nDump trace: \n".$e->getTraceAsString()."\n";
|
||||
exit();
|
||||
}
|
@ -1,22 +1,8 @@
|
||||
<?php
|
||||
namespace Aspect\Template;
|
||||
use Aspect, Aspect\Modifier;
|
||||
|
||||
class ExtendsTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var Aspect
|
||||
*/
|
||||
public static $aspect;
|
||||
|
||||
public function setUp() {
|
||||
if(!file_exists(ASPECT_RESOURCES.'/compile')) {
|
||||
mkdir(ASPECT_RESOURCES.'/compile', 0777, true);
|
||||
} else {
|
||||
exec("rm -f ".ASPECT_RESOURCES.'/compile/*');
|
||||
}
|
||||
self::$aspect = Aspect::factory(ASPECT_RESOURCES.'/template', ASPECT_RESOURCES.'/compile');
|
||||
}
|
||||
use Aspect, Aspect\Modifier, Aspect\TestCase;
|
||||
|
||||
class ExtendsTest extends TestCase {
|
||||
public static function providerExtends() {
|
||||
return array(
|
||||
array('{extends "parent.tpl"}{block "bk1"} block1 {/block}', "Template extended by block1"),
|
||||
@ -26,47 +12,26 @@ class ExtendsTest extends \PHPUnit_Framework_TestCase {
|
||||
);
|
||||
}
|
||||
|
||||
public function exec($code, $vars, $result, $dump = false) {
|
||||
$tpl = self::$aspect->compileCode($code, "inline.tpl");
|
||||
if($dump) {
|
||||
echo "\n===========================\n".$code.": ".$tpl->getBody();
|
||||
}
|
||||
$this->assertSame(Modifier::strip($result), Modifier::strip($tpl->fetch($vars), true), "Test $code");
|
||||
}
|
||||
|
||||
public function execError($code, $exception, $message, $options) {
|
||||
self::$aspect->setOptions($options);
|
||||
try {
|
||||
self::$aspect->compileCode($code, "inline.tpl");
|
||||
} catch(\Exception $e) {
|
||||
$this->assertSame($exception, get_class($e), "Exception $code");
|
||||
$this->assertStringStartsWith($message, $e->getMessage());
|
||||
self::$aspect->setOptions(0);
|
||||
return;
|
||||
}
|
||||
self::$aspect->setOptions(0);
|
||||
$this->fail("Code $code must be invalid");
|
||||
/**
|
||||
* @group extends
|
||||
*/
|
||||
public function testParentLevel() {
|
||||
//echo($this->aspect->getTemplate("parent.tpl")->_body); exit;
|
||||
$this->assertSame($this->aspect->fetch("parent.tpl", array("a" => "a char")), "Parent template\nBlock1: Block2: Block3: default");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group extends
|
||||
*/
|
||||
public function testParent() {
|
||||
//echo(self::$aspect->getTemplate("parent.tpl")->getBody()); exit;
|
||||
public function testChildLevel1() {
|
||||
//echo($this->aspect->fetch("child1.tpl", array("a" => "a char"))); exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @group extends
|
||||
*/
|
||||
public function ___testChildLevel1() {
|
||||
echo(self::$aspect->getTemplate("child1.tpl")->getBody()); exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @group extends
|
||||
*/
|
||||
public function __testExtends() {
|
||||
echo(self::$aspect->fetch("child1.tpl", array("a" => "value", "z" => ""))."\n"); exit;
|
||||
public function _testChildLevel3() {
|
||||
echo($this->aspect->getTemplate("child3.tpl")->getBody()); exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,20 +4,11 @@ use Aspect\Template,
|
||||
Aspect,
|
||||
Aspect\Render;
|
||||
|
||||
class TemplateTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @var Aspect
|
||||
*/
|
||||
public static $aspect;
|
||||
class TemplateTest extends TestCase {
|
||||
|
||||
public function setUp() {
|
||||
if(!file_exists(ASPECT_RESOURCES.'/compile')) {
|
||||
mkdir(ASPECT_RESOURCES.'/compile', 0777, true);
|
||||
} else {
|
||||
exec("rm -f ".ASPECT_RESOURCES.'/compile/*');
|
||||
}
|
||||
self::$aspect = Aspect::factory(ASPECT_RESOURCES.'/template', ASPECT_RESOURCES.'/compile');
|
||||
self::$aspect->addTemplate(new Render(self::$aspect, function ($tpl) {
|
||||
parent::setUp();
|
||||
$this->aspect->addTemplate(new Render($this->aspect, function ($tpl) {
|
||||
echo "<b>Welcome, ".$tpl["username"]." (".$tpl["email"].")</b>";
|
||||
}, array(
|
||||
"name" => "welcome.tpl"
|
||||
@ -569,28 +560,6 @@ class TemplateTest extends \PHPUnit_Framework_TestCase {
|
||||
);
|
||||
}
|
||||
|
||||
public function exec($code, $vars, $result, $dump = false) {
|
||||
$tpl = self::$aspect->compileCode($code, "inline.tpl");
|
||||
if($dump) {
|
||||
echo "\n===========================\n".$code.": ".$tpl->getBody();
|
||||
}
|
||||
$this->assertSame(Modifier::strip($result), Modifier::strip($tpl->fetch($vars), true), "Test $code");
|
||||
}
|
||||
|
||||
public function execError($code, $exception, $message, $options) {
|
||||
self::$aspect->setOptions($options);
|
||||
try {
|
||||
self::$aspect->compileCode($code, "inline.tpl");
|
||||
} catch(\Exception $e) {
|
||||
$this->assertSame($exception, get_class($e), "Exception $code");
|
||||
$this->assertStringStartsWith($message, $e->getMessage());
|
||||
self::$aspect->setOptions(0);
|
||||
return;
|
||||
}
|
||||
self::$aspect->setOptions(0);
|
||||
$this->fail("Code $code must be invalid");
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerVars
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
{extends "parent.tpl"}
|
||||
{extends "child1.tpl"}
|
||||
{block blk2}
|
||||
<b>blk2.{$a}</b>
|
||||
{/block}
|
@ -1,7 +1,7 @@
|
||||
{extends "parent.tpl"}
|
||||
{extends "child2.tpl"}
|
||||
|
||||
{block blk1}
|
||||
<b>blk1.{$a} (rewrited)</b>
|
||||
<b>blk1.{$a} (overwritten)</b>
|
||||
{/block}
|
||||
|
||||
{block blk3}
|
||||
|
Loading…
Reference in New Issue
Block a user