Merge branch 'origin/master'

Conflicts:
	src/Fenom/Compiler.php
	src/Fenom/Template.php
	tests/cases/Fenom/TemplateTest.php
	tests/cases/Fenom/TokenizerTest.php
	tests/cases/FenomTest.php
This commit is contained in:
Ivan Shalganov
2013-09-15 16:39:29 +04:00
12 changed files with 87 additions and 19 deletions

5
.coveralls.yml Normal file
View File

@ -0,0 +1,5 @@
service_name: travis-ci
src_dir: src
coverage_clover: build/logs/clover.xml

View File

@ -5,6 +5,11 @@ php:
- 5.4 - 5.4
- 5.5 - 5.5
before_script: composer install before_script:
- composer install --dev
script: phpunit script:
- phpunit
after_script:
- php vendor/bin/coveralls

View File

@ -1,7 +1,26 @@
Changelog Changelog
========= =========
## 1.4.0 ### 1.4.4
- Bug fixes
- Tests++
### 1.4.3
- Bug fixes
### 1.4.2 (2013-09-06)
- Added check the cache directory to record
### 1.4.1 (2013-09-05)
- Fix equating for {case} in {switch}
- Fix ternary operator when option `force_verify` is enabled
- Docs++
## 1.4.0 (2013-09-02)
- Redesign tag {switch} - Redesign tag {switch}
- Add tag {insert} - Add tag {insert}

View File

@ -3,7 +3,9 @@ Fenom - Template Engine for PHP
> Composer package: `{"fenom/fenom": "dev-master"}`. See on [Packagist.org](https://packagist.org/packages/fenom/fenom) > Composer package: `{"fenom/fenom": "dev-master"}`. See on [Packagist.org](https://packagist.org/packages/fenom/fenom)
[![Latest Stable Version](https://poser.pugx.org/fenom/fenom/v/stable.png)](https://packagist.org/packages/fenom/fenom)
[![Build Status](https://travis-ci.org/bzick/fenom.png?branch=master)](https://travis-ci.org/bzick/fenom) [![Build Status](https://travis-ci.org/bzick/fenom.png?branch=master)](https://travis-ci.org/bzick/fenom)
[![Coverage Status](https://coveralls.io/repos/bzick/fenom/badge.png?branch=master)](https://coveralls.io/r/bzick/fenom?branch=master)
## [Usage](./docs/usage.md) :: [Documentation](./docs/readme.md) :: [Benchmark](./docs/benchmark.md) :: [Articles](./docs/articles.md) ## [Usage](./docs/usage.md) :: [Documentation](./docs/readme.md) :: [Benchmark](./docs/benchmark.md) :: [Articles](./docs/articles.md)
* Simple [syntax](./docs/syntax.md) * Simple [syntax](./docs/syntax.md)

View File

@ -17,7 +17,8 @@
"require-dev": { "require-dev": {
"phpunit/phpunit": "3.7.*", "phpunit/phpunit": "3.7.*",
"smarty/smarty": "3.*", "smarty/smarty": "3.*",
"twig/twig": "1.*" "twig/twig": "1.*",
"satooshi/php-coveralls": "dev-master"
}, },
"autoload": { "autoload": {
"psr-0": { "Fenom\\": "src/" }, "psr-0": { "Fenom\\": "src/" },

View File

@ -30,7 +30,6 @@ $fenom->setOptions($options);
* **auto_escape**, `Fenom::AUTO_ESCAPE`, все выводящие переменные и результаты функций будут экранироваться * **auto_escape**, `Fenom::AUTO_ESCAPE`, все выводящие переменные и результаты функций будут экранироваться
* **auto_trim**, `Fenom::AUTO_TRIM`, при компиляции, все пробельные символы между тегами будут удлаены. * **auto_trim**, `Fenom::AUTO_TRIM`, при компиляции, все пробельные символы между тегами будут удлаены.
* **force_verify**, `Fenom::FORCE_VERIFY`, проверять обращение каждой переменной и возвращать NULL если переменной не существует. * **force_verify**, `Fenom::FORCE_VERIFY`, проверять обращение каждой переменной и возвращать NULL если переменной не существует.
* **deny_static_methods**, `Fenom::DENY_STATIC_METHODS`, отключает возможность вызова статичных методов в шаблоне.
```php ```php
$fenom->setOptions(array( $fenom->setOptions(array(

View File

@ -1,6 +1,12 @@
Tag {switch} Tag {switch}
============ ============
The `{switch}` tag is similar to a series of `{if}` statements on the same expression.
In many occasions, you may want to compare the same variable (or expression) with many different values,
and execute a different piece of code depending on which value it equals to. This is exactly what the `{switch}` tag is for.
Tag `{switch}` accepts any expression. But `{case}` accepts only static scalar values or constants.
```smarty ```smarty
{switch <condition>} {switch <condition>}
{case <value1>} {case <value1>}
@ -9,7 +15,7 @@ Tag {switch}
... ...
{case <value3>} {case <value3>}
... ...
{default} {default case <value1>}
... ...
{/switch} {/switch}
``` ```
@ -24,14 +30,14 @@ For example,
It is new or current item It is new or current item
{case 'current'} {case 'current'}
It is current item It is current item
{case 'new'} {case 'new', $.const.NEW_STATUS}
It is new item, again It is new item, again
{default} {default}
I don't know the type {$type} I don't know the type {$type}
{/switch} {/switch}
``` ```
set `$type = 'new'`, then template output if `$type = 'new'` then template output
``` ```
It is new item It is new item

View File

@ -34,8 +34,8 @@
<directory>./src/</directory> <directory>./src/</directory>
</whitelist> </whitelist>
</filter> </filter>
<logging> <logging>
<log type="coverage-clover" target="build/logs/clover.xml"/> <log type="coverage-clover" target="build/logs/clover.xml"/>
<!--<log type="coverage-php" target="build/cov/coverage.cov"/>-->
</logging> </logging>
</phpunit> </phpunit>

View File

@ -35,7 +35,7 @@ class Fenom
const FORCE_COMPILE = 0x100; const FORCE_COMPILE = 0x100;
const AUTO_ESCAPE = 0x200; const AUTO_ESCAPE = 0x200;
const DISABLE_CACHE = 0x400; const DISABLE_CACHE = 0x400;
const FORCE_VERIFY = 0x800; // reserved const FORCE_VERIFY = 0x800;
const AUTO_TRIM = 0x1000; // reserved const AUTO_TRIM = 0x1000; // reserved
const DENY_STATICS = 0x2000; // reserved const DENY_STATICS = 0x2000; // reserved
@ -288,10 +288,14 @@ class Fenom
* Set compile directory * Set compile directory
* *
* @param string $dir directory to store compiled templates in * @param string $dir directory to store compiled templates in
* @throws LogicException
* @return Fenom * @return Fenom
*/ */
public function setCompileDir($dir) public function setCompileDir($dir)
{ {
if(!is_writable($dir)) {
throw new LogicException("Cache directory $dir is not writable");
}
$this->_compile_dir = $dir; $this->_compile_dir = $dir;
return $this; return $this;
} }
@ -796,7 +800,7 @@ class Fenom
fclose($tpl_fp); fclose($tpl_fp);
$file_name = $this->_compile_dir . "/" . $cache; $file_name = $this->_compile_dir . "/" . $cache;
if (!rename($tpl_tmp, $file_name)) { if (!rename($tpl_tmp, $file_name)) {
throw new \RuntimeException("Can't to move $tpl_tmp to $tpl"); throw new \RuntimeException("Can't to move $tpl_tmp to $file_name");
} }
} }
return $template; return $template;

View File

@ -39,7 +39,8 @@ class Compiler
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) { if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) {
$inc = $tpl->getStorage()->compile($name, false); $inc = $tpl->getStorage()->compile($name, false);
$tpl->addDepend($inc); $tpl->addDepend($inc);
return '$_tpl = (array)$tpl; $tpl->exchangeArray(' . self::toArray($p) . '+$_tpl); ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);'; $var = $tpl->tmpVar();
return $var.' = (array)$tpl; $tpl->exchangeArray(' . self::toArray($p) . '+'.$var.'); ?>' . $inc->getBody() . '<?php $tpl->exchangeArray('.$var.'); unset('.$var.');';
} else { } else {
return '$tpl->getStorage()->getTemplate(' . $cname . ')->display(' . self::toArray($p) . '+(array)$tpl);'; return '$tpl->getStorage()->getTemplate(' . $cname . ')->display(' . self::toArray($p) . '+(array)$tpl);';
} }
@ -47,7 +48,8 @@ class Compiler
if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) { if ($name && ($tpl->getStorage()->getOptions() & \Fenom::FORCE_INCLUDE)) {
$inc = $tpl->getStorage()->compile($name, false); $inc = $tpl->getStorage()->compile($name, false);
$tpl->addDepend($inc); $tpl->addDepend($inc);
return '$_tpl = (array)$tpl; ?>' . $inc->getBody() . '<?php $tpl->exchangeArray($_tpl); unset($_tpl);'; $var = $tpl->tmpVar();
return $var.' = (array)$tpl; ?>' . $inc->getBody() . '<?php $tpl->exchangeArray('.$var.'); unset('.$var.');';
} else { } else {
return '$tpl->getStorage()->getTemplate(' . $cname . ')->display((array)$tpl);'; return '$tpl->getStorage()->getTemplate(' . $cname . ')->display((array)$tpl);';
} }
@ -332,10 +334,12 @@ class Compiler
*/ */
public static function switchOpen(Tokenizer $tokens, Scope $scope) public static function switchOpen(Tokenizer $tokens, Scope $scope)
{ {
$scope["expr"] = $scope->tpl->parseExpr($tokens); $expr = $scope->tpl->parseExpr($tokens);
$scope["case"] = array(); $scope["case"] = array();
$scope["last"] = array(); $scope["last"] = array();
$scope["default"] = ''; $scope["default"] = '';
$scope["var"] = $scope->tpl->tmpVar();
$scope["expr"] = $scope["var"].' = strval('.$expr.')';
// lazy init // lazy init
return ''; return '';
} }
@ -409,13 +413,16 @@ class Compiler
public static function switchClose(Tokenizer $tokens, Scope $scope) public static function switchClose(Tokenizer $tokens, Scope $scope)
{ {
self::_caseResort($scope); self::_caseResort($scope);
$expr = $scope["expr"]; $expr = $scope["var"];
$code = ""; $code = $scope["expr"].";\n";
$default = $scope["default"]; $default = $scope["default"];
foreach ($scope["case"] as $case => $content) { foreach ($scope["case"] as $case => $content) {
if(is_numeric($case)) {
$case = "'$case'";
}
$code .= "if($expr == $case) {\n?>$content<?php\n} else"; $code .= "if($expr == $case) {\n?>$content<?php\n} else";
} }
$code .= " {\n?>$default<?php\n}"; $code .= " {\n?>$default<?php\n}\nunset(".$scope["var"].")";
return $code; return $code;
} }

View File

@ -1,6 +1,8 @@
<?php <?php
require_once __DIR__ . "/../vendor/autoload.php"; $loader = include(__DIR__ . "/../vendor/autoload.php");
/* @var Composer\Autoload\ClassLoader $loader */
$loader->add('Fenom', __DIR__.'/cases');
define('FENOM_RESOURCES', __DIR__ . "/resources"); define('FENOM_RESOURCES', __DIR__ . "/resources");

View File

@ -8,12 +8,16 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
public function testTokens() public function testTokens()
{ {
$code = 'hello, please resolve this example: sin($x)+tan($x*$t) = {U|[0,1]}'; $code = 'hello, please resolve this example: sin($x)+tan($x*$t) = {U|[0,1]}';
$tokens = new Tokenizer($code); $tokens = new Tokenizer($code);
$this->assertSame($tokens, $tokens->back());
$this->assertSame(T_STRING, $tokens->key()); $this->assertSame(T_STRING, $tokens->key());
$this->assertSame("hello", $tokens->current()); $this->assertSame("hello", $tokens->current());
$this->assertSame(1, $tokens->getLine());
$this->assertTrue($tokens->isNext(",")); $this->assertTrue($tokens->isNext(","));
$this->assertFalse($tokens->isNext("=")); $this->assertFalse($tokens->isNext("="));
$this->assertFalse($tokens->isNext(T_STRING)); $this->assertFalse($tokens->isNext(T_STRING));
$this->assertFalse($tokens->isNext($tokens::MACRO_UNARY)); $this->assertFalse($tokens->isNext($tokens::MACRO_UNARY));
@ -24,6 +28,13 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
$this->assertSame(",", $tokens->getNext()); $this->assertSame(",", $tokens->getNext());
$this->assertSame(",", $tokens->key()); $this->assertSame(",", $tokens->key());
$this->assertSame("please", $tokens->getNext(T_STRING)); $this->assertSame("please", $tokens->getNext(T_STRING));
$this->assertSame(array(
T_STRING,
'please',
' ',
1,
'T_STRING'
), $tokens->curr);
$this->assertSame("resolve", $tokens->getNext($tokens::MACRO_UNARY, T_STRING)); $this->assertSame("resolve", $tokens->getNext($tokens::MACRO_UNARY, T_STRING));
$tokens->next(); $tokens->next();
@ -51,6 +62,7 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
$this->assertSame($code, $tokens->getSnippetAsString(-100, 100)); $this->assertSame($code, $tokens->getSnippetAsString(-100, 100));
$this->assertSame('+', $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()
@ -67,8 +79,14 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
} }
$this->assertTrue($tokens->valid()); $this->assertTrue($tokens->valid());
$this->assertSame("3", $tokens->current()); $this->assertSame("3", $tokens->current());
$this->assertSame(T_LNUMBER, $tokens->key()); $this->assertSame(T_LNUMBER, $tokens->key());
$this->assertSame($tokens, $tokens->next());
$tokens->next(); $tokens->next();
$this->assertSame("double", $tokens->getAndNext());
$this->assertSame(")", $tokens->current());
$this->assertTrue($tokens->isLast());
$this->assertSame($tokens, $tokens->next());
} }
} }