Add tag filter. Move benchmark to another project

This commit is contained in:
Ivan Shalganov 2013-10-08 17:48:23 +04:00
parent 24f22f8f43
commit 6fec661ea7
23 changed files with 182 additions and 5310 deletions

View File

@ -1,7 +1,18 @@
Changelog
=========
### 1.4.7 (2013-09-19)
## 1.5.0
- Add tag filter
- Redesign `extends` algorithm
- Blocks does not support dynamic names
- Blocks can't be nested
- Add tag options support
- Improve Fenom API
- Move benchmark to another project
- Rename `\Fenom\Compiler` to `\Fenom\Tags`
### 1.4.7 (2013-09-21)
- Bug fixes
- Tests++

View File

@ -1,74 +0,0 @@
<?php
require_once __DIR__.'/scripts/bootstrap.php';
$opt = getopt("h", array(
/** @var string $message */
"cleanup",
/** @var boolean $stress */
"stress:",
/** @var boolean $auto_reload */
"auto_reload",
/** @vat boolean $help */
/** @vat boolean $h */
"help"
));
$opt += array(
"stress" => 0
);
extract($opt);
if(isset($h) || isset($help)) {
echo "
Start: ".basename(__FILE__)." [--stress COUNT] [--auto_reload] [--cleanup]
Usage: ".basename(__FILE__)." [--help | -h]
";
exit;
}
Benchmark::$stress = intval($stress);
Benchmark::$auto_reload = isset($auto_reload);
exec("rm -rf ".__DIR__."/compile/*");
echo "Smarty3 vs Twig vs Fenom\n\n";
echo "Generate templates... ";
passthru("php ".__DIR__."/templates/inheritance/smarty.gen.php");
passthru("php ".__DIR__."/templates/inheritance/twig.gen.php");
echo "Done\n";
echo "Testing a lot output...\n";
Benchmark::runs("smarty3", 'echo/smarty.tpl', __DIR__.'/templates/echo/data.json');
Benchmark::runs("twig", 'echo/twig.tpl', __DIR__.'/templates/echo/data.json');
Benchmark::runs("fenom", 'echo/smarty.tpl', __DIR__.'/templates/echo/data.json');
//if(extension_loaded("phalcon")) {
// Benchmark::runs("volt", 'echo/twig.tpl', __DIR__.'/templates/echo/data.json');
//}
echo "\nTesting 'foreach' of big array...\n";
Benchmark::runs("smarty3", 'foreach/smarty.tpl', __DIR__.'/templates/foreach/data.json');
Benchmark::runs("twig", 'foreach/twig.tpl', __DIR__.'/templates/foreach/data.json');
Benchmark::runs("fenom", 'foreach/smarty.tpl', __DIR__.'/templates/foreach/data.json');
//if(extension_loaded("phalcon")) {
// Benchmark::runs("volt", 'foreach/twig.tpl', __DIR__.'/templates/foreach/data.json');
//}
echo "\nTesting deep 'inheritance'...\n";
Benchmark::runs("smarty3", 'inheritance/smarty/b100.tpl', __DIR__.'/templates/foreach/data.json');
Benchmark::runs("twig", 'inheritance/twig/b100.tpl', __DIR__.'/templates/foreach/data.json');
Benchmark::runs("fenom", 'inheritance/smarty/b100.tpl', __DIR__.'/templates/foreach/data.json');
//if(extension_loaded("phalcon")) {
// Benchmark::runs("volt", 'inheritance/twig/b100.tpl', __DIR__.'/templates/foreach/data.json');
//}
echo "\nDone\n";
if(isset($cleanup)) {
echo "Cleanup.\n";
passthru("rm -rf ".__DIR__."/compile/*");
passthru("rm -f ".__DIR__."/templates/inheritance/smarty/*");
passthru("rm -f ".__DIR__."/templates/inheritance/twig/*");
}

View File

@ -1,117 +0,0 @@
<?php
require(__DIR__.'/../../vendor/autoload.php');
class Benchmark {
const OUTPUT = "%8s: %-22s %10.4f sec, %10.1f MiB\n";
public static $stress = 0;
public static $auto_reload = false;
public static function smarty3($tpl, $data, $double, $stress = false, $auto_reload = false) {
$smarty = new Smarty();
$smarty->compile_check = $auto_reload;
$smarty->setTemplateDir(__DIR__.'/../templates');
$smarty->setCompileDir(__DIR__."/../compile/");
if($double) {
$smarty->assign($data);
$smarty->fetch($tpl);
}
$start = microtime(true);
if($stress) {
for($i=0; $i<$stress; $i++) {
$smarty->assign($data);
$smarty->fetch($tpl);
}
} else {
$smarty->assign($data);
$smarty->fetch($tpl);
}
return microtime(true) - $start;
// printf(self::$t, __FUNCTION__, $message, round(microtime(true)-$start, 4), round(memory_get_peak_usage()/1024/1024, 2));
}
public static function twig($tpl, $data, $double, $stress = false, $auto_reload = false) {
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem(__DIR__.'/../templates');
$twig = new Twig_Environment($loader, array(
'cache' => __DIR__."/../compile/",
'autoescape' => false,
'auto_reload' => $auto_reload,
));
if($double) {
$twig->loadTemplate($tpl)->render($data);
}
$start = microtime(true);
if($stress) {
for($i=0; $i<$stress; $i++) {
$twig->loadTemplate($tpl)->render($data);
}
} else {
$twig->loadTemplate($tpl)->render($data);
}
return microtime(true) - $start;
}
public static function fenom($tpl, $data, $double, $stress = false, $auto_reload = false) {
$fenom = Fenom::factory(__DIR__.'/../templates', __DIR__."/../compile");
if($auto_reload) {
$fenom->setOptions(Fenom::AUTO_RELOAD);
}
if($double) {
$fenom->fetch($tpl, $data);
}
$start = microtime(true);
if($stress) {
for($i=0; $i<$stress; $i++) {
$fenom->fetch($tpl, $data);
}
} else {
$fenom->fetch($tpl, $data);
}
return microtime(true) - $start;
}
// public static function volt($tpl, $data, $double, $message) {
// $view = new \Phalcon\Mvc\View();
// //$view->setViewsDir(__DIR__.'/../templates');
// $volt = new \Phalcon\Mvc\View\Engine\Volt($view);
//
//
// $volt->setOptions(array(
// "compiledPath" => __DIR__.'/../compile'
// ));
// $tpl = __DIR__.'/../templates/'.$tpl;
// if($double) {
// $volt->render($tpl, $data);
// }
//
// $start = microtime(true);
// $volt->render($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_BINARY." -n -dextension=phalcon.so -ddate.timezone=Europe/Moscow -dmemory_limit=512M %s/run.php --engine '%s' --template '%s' --data '%s' --message '%s' %s --stress %d %s", __DIR__, $engine, $template, $data, $message, $double ? '--double' : '', self::$stress, self::$auto_reload ? '--auto_reload' : ''));
}
/**
* @param $engine
* @param $template
* @param $data
*/
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');
echo "\n";
}
}

View File

@ -1,32 +0,0 @@
<?php
$opt = getopt("", array(
/** @var string $engine */
"engine:",
/** @var string $template */
"template:",
/** @var string $data */
"data:",
/** @var boolean $double */
"double",
/** @var string $message */
"message:",
/** @var boolean $stress */
"stress:",
/** @var boolean $auto_reload */
"auto_reload"
));
require_once __DIR__.'/bootstrap.php';
$opt += array(
"message" => "plain",
"stress" => 0,
);
extract($opt);
$time = Benchmark::$engine($template, json_decode(file_get_contents($data), true), isset($double), $stress, isset($auto_reload));
printf(Benchmark::OUTPUT, $engine, $message, round($time, 4), round(memory_get_peak_usage()/1024/1024, 2));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
<h1>Вывод 10 полей из 1000 элементов в цикле</h1>
{foreach $array as $item}
{$item.id} {$item.title} {$item.var1} {$item.var2} {$item.var3} {$item.var4} {$item.var5} {$item.var6} {$item.var5} {$item.var6}
{/foreach}

View File

@ -1,4 +0,0 @@
<h1>Вывод 10 полей из 1000 элементов в цикле<h1>
{% for item in array %}
{{ item.id }} {{ item.title }} {{ item.var1 }} {{ item.var2 }} {{ item.var3 }} {{ item.var4 }} {{ item.var5 }} {{ item.var6 }} {{ item.var5 }} {{ item.var6 }}
{% endfor %}

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +0,0 @@
<?php
$b0 = '<h1>Вывод статических данных в 500 наследуемых блоков</h1>' . "\r\n";
for($i = 1; $i < 501; $i++)
{
$b0 .= '{block b'.$i.'}{/block}'."\r\n";
$data = '{extends "inheritance/smarty/b'.($i-1).'.tpl"}' . "\r\n";
$data .= '{block b'.$i.'}data'.$i.'{/block}' . "\r\n";
file_put_contents(__DIR__.'/smarty/b'.$i.'.tpl', $data);
}
file_put_contents(__DIR__.'/smarty/b0.tpl', $b0);

View File

@ -1,10 +0,0 @@
<?php
$b0 = '<h1>Вывод статических данных в 500 наследуемых блоков</h1>' . "\r\n";
for($i = 1; $i < 501; $i++)
{
$b0 .= '{% block b'.$i.' %}{% endblock %}'."\r\n";
$data = '{% extends "inheritance/twig/b'.($i-1).'.tpl" %}' . "\r\n";
$data .= '{% block b'.$i.' %}data'.$i.'{% endblock %}' . "\r\n";
file_put_contents(__DIR__.'/twig/b'.$i.'.tpl', $data);
}
file_put_contents(__DIR__.'/twig/b0.tpl', $b0);

View File

@ -16,8 +16,6 @@
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"smarty/smarty": "3.*",
"twig/twig": "1.*",
"satooshi/php-coveralls": "dev-master"
},
"autoload": {

View File

@ -0,0 +1,61 @@
<?php
/** Fenom template 'greeting.tpl' compiled at 2013-09-02 17:37:18 */
return new Fenom\Render($fenom, function ($tpl) {
?>
A1
<?php
/* greeting.tpl:4: {mc.factorial num=10} */
$_tpl4154309674_1 = $tpl->exchangeArray(array("num" => 10));
?><?php
/* macros.tpl:2: {if $num} */
if($tpl["num"]) { ?>
<?php
/* macros.tpl:3: {$num} */
echo $tpl["num"]; ?> <?php
/* macros.tpl:3: {macro.factorial num=$num-1} */
$_tpl2531688351_1 = $tpl->exchangeArray(array("num" => $tpl["num"] - 1));
$tpl->getMacro("factorial")->__invoke($tpl);
$tpl->exchangeArray($_tpl2531688351_1); /* X */ unset($_tpl2531688351_1); ?> <?php
/* macros.tpl:3: {$num} */
echo $tpl["num"]; ?>
<?php
/* macros.tpl:4: {/if} */
} ?>
<?php
$tpl->exchangeArray($_tpl4154309674_1); /* X */ unset($_tpl4154309674_1); ?>
A2<?php
}, array(
'options' => 128,
'provider' => false,
'name' => 'greeting.tpl',
'base_name' => 'greeting.tpl',
'time' => 1378125225,
'depends' => array (
0 =>
array (
'macros.tpl' => 1378129033,
'greeting.tpl' => 1378125225,
),
),
'macros' => array(
'factorial' => function ($tpl) {
?><?php
/* macros.tpl:2: {if $num} */
if($tpl["num"]) { ?>
<?php
/* macros.tpl:3: {$num} */
echo $tpl["num"]; ?> <?php
/* macros.tpl:3: {macro.factorial num=$num-1} */
$_tpl2531688351_1 = $tpl->exchangeArray(array("num" => $tpl["num"] - 1));
$tpl->getMacro("factorial")->__invoke($tpl);
$tpl->exchangeArray($_tpl2531688351_1); /* X */ unset($_tpl2531688351_1); ?> <?php
/* macros.tpl:3: {$num} */
echo $tpl["num"]; ?>
<?php
/* macros.tpl:4: {/if} */
} ?>
<?php
}),
));

View File

@ -0,0 +1,61 @@
<?php
/** Fenom template 'greeting.tpl' compiled at 2013-09-02 17:37:39 */
return new Fenom\Render($fenom, function ($tpl) {
?>
A1
<?php
/* greeting.tpl:4: {mc.factorial num=10} */
$_tpl4154309674_1 = $tpl->exchangeArray(array("num" => 10));
?><?php
/* macros.tpl:2: {if $num} */
if($tpl["num"]) { ?>
<?php
/* macros.tpl:3: {$num} */
echo $tpl["num"]; ?> <?php
/* macros.tpl:3: {macro.factorial num=$num-1} */
$_tpl2531688351_1 = $tpl->exchangeArray(array("num" => $tpl["num"] - 1));
$tpl->getMacro("factorial")->__invoke($tpl);
$tpl->exchangeArray($_tpl2531688351_1); /* X */ unset($_tpl2531688351_1); ?> <?php
/* macros.tpl:3: {$num} */
echo $tpl["num"]; ?>
<?php
/* macros.tpl:4: {/if} */
} ?>
<?php
$tpl->exchangeArray($_tpl4154309674_1); /* X */ unset($_tpl4154309674_1); ?>
A2<?php
}, array(
'options' => 0,
'provider' => false,
'name' => 'greeting.tpl',
'base_name' => 'greeting.tpl',
'time' => 1378125225,
'depends' => array (
0 =>
array (
'macros.tpl' => 1378129033,
'greeting.tpl' => 1378125225,
),
),
'macros' => array(
'factorial' => function ($tpl) {
?><?php
/* macros.tpl:2: {if $num} */
if($tpl["num"]) { ?>
<?php
/* macros.tpl:3: {$num} */
echo $tpl["num"]; ?> <?php
/* macros.tpl:3: {macro.factorial num=$num-1} */
$_tpl2531688351_1 = $tpl->exchangeArray(array("num" => $tpl["num"] - 1));
$tpl->getMacro("factorial")->__invoke($tpl);
$tpl->exchangeArray($_tpl2531688351_1); /* X */ unset($_tpl2531688351_1); ?> <?php
/* macros.tpl:3: {$num} */
echo $tpl["num"]; ?>
<?php
/* macros.tpl:4: {/if} */
} ?>
<?php
}),
));

View File

@ -79,6 +79,11 @@ class Fenom
*/
public $filters = array();
/**
* @var callable[]
*/
public $tag_filters = array();
/**
* @var callable[]
*/
@ -349,6 +354,22 @@ class Fenom
return $this->filters;
}
/**
* @param callable $cbcd
* @return self
*/
public function addTagFilter($cb)
{
$this->tag_filters[] = $cb;
return $this;
}
public function getTagFilters()
{
return $this->tag_filters;
}
/**
* Add modifier
*

View File

@ -139,9 +139,10 @@ class Template extends Render
*/
public function __construct(Fenom $fenom, $options)
{
$this->_fenom = $fenom;
$this->_options = $options;
$this->_filters = $this->_fenom->getFilters();
$this->_fenom = $fenom;
$this->_options = $options;
$this->_filters = $this->_fenom->getFilters();
$this->_tag_filters = $this->_fenom->getTagFilters();
}
/**
@ -248,6 +249,11 @@ class Template extends Render
$this->_appendText($tag);
}
} else {
if($this->_tag_filters) {
foreach($this->_tag_filters as $filter) {
$_tag = call_user_func($filter, $_tag, $this);
}
}
$tokens = new Tokenizer($_tag); // tokenize the tag
if ($tokens->isIncomplete()) { // all strings finished?
$need_more = true;
@ -607,6 +613,7 @@ class Template extends Render
* Parse expressions. The mix of operators and terms.
*
* @param Tokenizer $tokens
* @return string
* @throws Error\UnexpectedTokenException
*/
public function parseExpr(Tokenizer $tokens)

View File

@ -163,6 +163,23 @@ class FenomTest extends \Fenom\TestCase
$this->assertSame('+++ |--- == hello ---||--- world == ---| +++', $this->fenom->compileCode('hello {var $user} <?php misterio ?> {/var} world')->fetch(array()));
}
/**
* @group tag-filter
*/
public function testTagFilter() {
$tags = array();
$punit = $this;
$this->fenom->addTagFilter(function ($text, $tpl) use (&$tags, $punit) {
$punit->assertInstanceOf('Fenom\Template', $tpl);
$tags[] = $text;
return $text;
});
$this->fenom->compileCode('hello {var $a} misterio {/var} world, {$b}!');
$this->assertSame(array('var $a', '/var', '$b'), $tags);
}
public function testAddInlineCompilerSmart() {
$this->fenom->addCompilerSmart('SayA','TestTags');
$this->tpl('inline_compiler.tpl', 'I just {SayA}.');