From 0e2ceca5901a94b0c673f6fcf9ef0264ae8ce59c Mon Sep 17 00:00:00 2001 From: Alexej Yaroshevich Date: Thu, 23 Apr 2015 08:27:01 +0300 Subject: [PATCH] v4.0.0 fixes - Added global matcher support: `beforeEach` and `afterEach` (bem/bh#121). - Added `ctx.process` method (bem/bh#135). - Add `i-bem` class to element with `js` (bem/bh#122). - No-base modifier classes supported (bem/bh#132). - `processBemJson` now return standart BEMJSON (bem/bh#96). Changelog https://github.com/bem/bh/commit/ee446ea5801a60cc4e2fc8e3622cd1bfaf0f729a --- src/BH.php | 210 +++++++++++++++++++++------------- src/Context.php | 26 ++--- src/Json.php | 11 +- src/Step.php | 8 +- tests/apply.test.php | 68 +++++------ tests/applyBase.test.php | 14 +++ tests/match.test.php | 4 +- tests/matchGlobal.test.php | 103 +++++++++++++++++ tests/mix.test.php | 32 +++--- tests/mod.test.php | 12 +- tests/mods.test.php | 10 ++ tests/options.test.php | 36 ++++++ tests/position.test.php | 6 +- tests/process.test.php | 39 +++++++ tests/processBemJson.test.php | 81 +++++++++++++ tests/toHtml.test.php | 8 +- 16 files changed, 499 insertions(+), 169 deletions(-) create mode 100644 tests/matchGlobal.test.php create mode 100644 tests/process.test.php create mode 100644 tests/processBemJson.test.php diff --git a/src/BH.php b/src/BH.php index 245e581..413618f 100644 --- a/src/BH.php +++ b/src/BH.php @@ -29,21 +29,25 @@ class BH { * Неймспейс для библиотек. Сюда можно писать различный функционал для дальнейшего использования в шаблонах. * * ```javascript - * bh.lib.objects = bh.lib.objects || []; - * bh.lib.objects.inverse = bh.lib.objects.inverse || function(obj) { ... }; + * $bh->lib->i18n = BEM.I18N; + * $bh->lib->objects = bh.lib.objects || []; + * $bh->lib->objects.inverse = bh.lib.objects.inverse || function(obj) { ... }; * ``` - * @var array + * @var ArrayObject */ - protected $lib = []; + public $lib; /** * Опции BH. Задаются через setOptions. * @var array */ protected $_options = []; + protected $_optJsAttrName = 'onclick'; protected $_optJsAttrIsJs = true; + protected $_optJsCls = 'i-bem'; protected $_optEscapeContent = false; + protected $_optNobaseMods = false; /** * Флаг, включающий автоматическую систему поиска зацикливаний. Следует использовать в development-режиме, @@ -80,6 +84,7 @@ class BH { * @constructor */ function __construct () { + $this->lib = new \ArrayObject([], \ArrayObject::ARRAY_AS_PROPS); } /** @@ -100,15 +105,23 @@ function setOptions ($options) { $this->_options[$k] = $options[$k]; } - if (!empty($options['jsAttrName'])) { + if (isset($options['jsAttrName'])) { $this->_optJsAttrName = $options['jsAttrName']; } - if (!empty($options['jsAttrScheme'])) { + if (isset($options['jsAttrScheme'])) { $this->_optJsAttrIsJs = $options['jsAttrScheme'] === 'js'; } - if (!empty($options['escapeContent'])) { + if (isset($options['jsCls'])) { + $this->_optJsCls = $options['jsCls']; + } + + if (isset($options['clsNobaseMods'])) { + $this->_optNobaseMods = true; + } + + if (isset($options['escapeContent'])) { $this->_optEscapeContent = $options['escapeContent']; } @@ -213,6 +226,52 @@ function match ($expr, $matcher = null) { return $this; } + /** + * Объявляет глобальный шаблон, применяемый перед остальными. + * + * ```php + * $bh->beforeEach(function ($ctx, $json) { + * $ctx->attr('onclick', $json->counter); + * }); + * ``` + * + * @param Closure $matcher + * @return BH + */ + function beforeEach ($matcher) { + return $this->match('$before', $matcher); + } + + /** + * Объявляет глобальный шаблон, применяемый после остальных. + * + * ```php + * $bh->afterEach(function ($ctx) { + * $ctx->tag('xdiv'); + * }); + * ``` + * + * @param Closure $matcher + * @return BH + */ + function afterEach ($matcher) { + return $this->match('$after', $matcher); + } + + /** + * Вставляет вызов шаблона в очередь вызова. + * + * @param Array $res + * @param String $fnId + * @param Number $index + */ + static protected function pushMatcher(&$res, $fnId, $index) { + $res[] = (' $json->_m[' . $fnId . '] = true;'); + $res[] = (' $subRes = $ms[' . $index . ']["fn"]($ctx, $json);'); + $res[] = (' if ($subRes !== null) { return ($subRes ?: ""); }'); + $res[] = (' if ($json->_stop) return;'); + } + /** * Вспомогательный метод для компиляции шаблонов с целью их быстрого дальнейшего исполнения. * @return string @@ -233,8 +292,19 @@ function buildMatcher () { $res[] = 'return function ($ctx, $json) use ($ms) {'; - $res[] = 'switch ($json->block ?: __undefined) {'; $declByBlock = static::groupBy($declarations, 'block'); + + if (isset($declByBlock['$before'])) { + foreach ($declByBlock['$before'] as $decl) { + static::pushMatcher($res, $decl['__id'], $decl['index']); + } + } + + $afterEach = isset($declByBlock['$after']) ? $declByBlock['$after'] : null; + unset($declByBlock['$before'], $declByBlock['$after']); + + if ($declByBlock) : + $res[] = 'switch ($json->block ?: __undefined) {'; foreach ($declByBlock as $blockName => $blockData) { $res[] = 'case "' . $blockName . '":'; @@ -251,30 +321,35 @@ function buildMatcher () { if (isset($decl['elemMod'])) { $modKey = $decl['elemMod']; $conds[] = ( - 'isset($json->mods) && $json->mods->{"' . $modKey . '"} === ' . + 'isset($json->elemMods) && $json->elemMods->{"' . $modKey . '"} === ' . ($decl['elemModVal'] === true ? 'true' : '"' . $decl['elemModVal'] . '"')); } if (isset($decl['blockMod'])) { $modKey = $decl["blockMod"]; $conds[] = ( - 'isset($json->blockMods) && $json->blockMods->{"' . $modKey . '"} === ' . + 'isset($json->mods) && $json->mods->{"' . $modKey . '"} === ' . ($decl['blockModVal'] === true ? 'true' : '"' . $decl['blockModVal'] . '"')); } $res[] = (' if (' . join(' && ', $conds) . ') {'); - $res[] = (' $json->_m[' . $__id . '] = true;'); - $res[] = (' $subRes = $ms[' . $decl['index'] . ']["fn"]($ctx, $json);'); - $res[] = (' if ($subRes !== null) { return ($subRes ?: ""); }'); - $res[] = (' if ($json->_stop) return;'); + static::pushMatcher($res, $__id, $decl['index']); $res[] = (' }'); } - $res[] = (' return;'); + $res[] = (' break;'); } $res[] = ('}'); - $res[] = (' return;'); + $res[] = (' break;'); } $res[] = ('}'); + endif; + + if ($afterEach) { + foreach ($afterEach as $decl) { + static::pushMatcher($res, $decl['__id'], $decl['index']); + } + } + $res[] = ('};'); return "return function (\$ms) {\n" . join("\n", $res) . "\n};"; @@ -287,17 +362,13 @@ function getMatcher () { if ($this->_matcher) return $this->_matcher; // debugging purposes only (!!!) - // $debug = false; //true; - // $key = md5(join('|', array_map(function ($e) { return $e['expr']; }, $this->_matchers))); // $file = "./tmp/bh-matchers-{$key}.php"; // $constructor = @include $file; // if (!$constructor) { - // if ($debug) { - $code = $this->buildMatcher(); - // file_put_contents($file, "buildMatcher(); + // file_put_contents($file, "elem && isset($bemJson->mods)) ? $bemJson->mods : $bemJson->blockMods; - } $steps = []; $steps[] = new Step( @@ -359,7 +426,7 @@ function processBemJson ($bemJson, $blockName = null, $ignoreContent = null) { $resultArr, 0, $blockName, - $blockMods + null ); // var compiledMatcher = (this._fastMatcher || (this._fastMatcher = Function('ms', this.buildMatcher())(this._matchers))); @@ -374,8 +441,8 @@ function processBemJson ($bemJson, $blockName = null, $ignoreContent = null) { // js: while (node = nodes.shift()) { while ($step = array_shift($steps)) { $json = $step->json; - $blockName = $step->blockName; - $blockMods = $step->blockMods; + $blockName = $step->block; + $blockMods = $step->mods; if ($json instanceof JsonCollection) { $j = 0; @@ -408,21 +475,19 @@ function processBemJson ($bemJson, $blockName = null, $ignoreContent = null) { continue; } elseif ($json->elem) { - $blockName = $json->block = isset($json->block) ? $json->block : $blockName; - // sync mods: - // blockMods = json.blockMods = json.blockMods || blockMods - $blockMods = $json->blockMods = isset($json->blockMods) ? $json->blockMods : $blockMods; - // sync elem mods: - if (isset($json->elemMods)) { - $json->mods = $json->elemMods; + $blockName = $json->block = $json->block ?: $blockName; + if (!isset($json->elemMods)) { + $json->elemMods = $json->mods; + $json->mods = null; } + $blockMods = $json->mods = isset($json->mods) ? $json->mods : $blockMods; } elseif ($json->block) { $blockName = $json->block; - $blockMods = $json->blockMods = $json->mods; + $blockMods = $json->mods; } - if ($json && $json->block) { + if ($json instanceof Json) { if ($infiniteLoopDetection) { $json->_matcherCalls++; $this->_matcherCalls++; @@ -441,8 +506,8 @@ function processBemJson ($bemJson, $blockName = null, $ignoreContent = null) { if ($subRes !== null) { $json = JsonCollection::normalize($subRes); $step->json = $json; - $step->blockName = $blockName; - $step->blockMods = $blockMods; + $step->block = $blockName; + $step->mods = $blockMods; $steps[] = $step; $stopProcess = true; } @@ -451,34 +516,27 @@ function processBemJson ($bemJson, $blockName = null, $ignoreContent = null) { if (!$stopProcess && $processContent && isset($json->content) && !is_scalar($json->content)) { $content = $json->content; - //if ($content instanceof JsonCollection) { - - $j = 0; - foreach ($content as $i => $child) { - if (is_scalar($child) || empty($child)) { - continue; - } - - $steps[] = new Step( - $child, - $content, - $i, - $blockName, - $blockMods, - ++$j, - $step - ); + + $j = 0; + foreach ($content as $i => $child) { + if (is_scalar($child) || empty($child)) { + continue; } - $content->_listLength = $j; - /*} else { - // commented since 24 nov '14 - // throw new \Exception('Do we need it?'); - }*/ + $steps[] = new Step( + $child, + $content, + $i, + $blockName, + $blockMods, + ++$j, + $step + ); + } + $content->_listLength = $j; } } - //d('processBemjson#' . ($_callId) . ' out ', $resultArr[0]); return $resultArr[0]; } @@ -528,15 +586,13 @@ public function toHtml ($json) { $jsParams = false; if ($json->block) { - $cls = static::toBemCssClasses($json, $base); + $cls = static::toBemCssClasses($json, $base, null, $this->_optNobaseMods); if ($json->js !== null && $json->js !== false) { $jsParams = []; $jsParams[$base] = $json->js === true ? [] : $this->_filterNulls($json->js); } } - $addJSInitClass = $jsParams && !$json->elem; - if ($json->mix) { foreach ($json->mix as $mix) { if (!$mix || $mix->bem === false) { @@ -553,18 +609,17 @@ public function toHtml ($json) { $mixElem = $mix->elem ?: ($mix->block ? null : ($json->block ? $json->elem : null)); $mixBase = $mixBlock . ($mixElem ? '__' . $mixElem : ''); - $cls .= static::toBemCssClasses($mix, $mixBase, $base); + $cls .= static::toBemCssClasses($mix, $mixBase, $base, $this->_optNobaseMods); if ($mix->js !== null && $mix->js !== false) { $jsParams = $jsParams ?: []; $jsParams[$mixBase] = $mix->js === true ? [] : $this->_filterNulls($mix->js); $hasMixJsParams = true; - if (!$addJSInitClass) $addJSInitClass = ($mixBlock && !$mixElem); } } } if ($jsParams) { - if ($addJSInitClass) $cls .= ' i-bem'; + if ($this->_optJsCls) $cls .= ' ' . $this->_optJsCls; $jsData = !$hasMixJsParams && $json->js === true ? '{"' . $base . '":{}}' : self::attrEscape(str_replace('[]', '{}', @@ -610,7 +665,7 @@ public static function attrEscape($s) { return htmlspecialchars($s, ENT_QUOTES); } - public static function toBemCssClasses($json, $base, $parentBase = null) { + public static function toBemCssClasses($json, $base, $parentBase = null, $nobase = false) { $res = ''; if ($parentBase !== $base) { @@ -620,14 +675,11 @@ public static function toBemCssClasses($json, $base, $parentBase = null) { $res .= $base; } - // if (mods = json.mods || json.elem && json.elemMods) - $mods = isset($json->mods) ? $json->mods : - ($json->elem && isset($json->elemMods) ? $json->elemMods : null); - if ($mods) { - foreach ($mods as $k => $mod) { - if ($mod || $mod === 0) { - $res .= ' ' . $base . '_' . $k . ($mod === true ? '' : '_' . $mod); - } + // if (mods = json.elem && json.elemMods || json.mods) + $mods = $json->elem && isset($json->elemMods) ? $json->elemMods : $json->mods; + foreach ($mods as $k => $mod) { + if ($mod || $mod === 0) { + $res .= ' ' . ($nobase ? '' : $base) . '_' . $k . ($mod === true ? '' : '_' . $mod); } } diff --git a/src/Context.php b/src/Context.php index 1f699eb..4ce0ba2 100644 --- a/src/Context.php +++ b/src/Context.php @@ -180,7 +180,7 @@ function tParam ($key, $value = null, $force = false) { * @param BemJson $bemJson * @return array */ - function apply ($bemJson) { + function process ($bemJson) { $prevCtx = $this->ctx; $prevNode = $this->node; $res = $this->bh->processBemJson($bemJson, $prevCtx->block); @@ -214,19 +214,15 @@ function applyBase () { $node = $this->node; $json = $node->json; - if (!$json->elem && isset($json->mods)) { - $json->blockMods = $json->mods; - } - $block = $json->block; - $blockMods = $json->blockMods; + $blockMods = $json->mods; $fm = $this->bh->getMatcher(); $subRes = $fm($this, $json); if ($subRes !== null) { $this->ctx = $node->arr[$node->index] = $node->json = JsonCollection::normalize($subRes); - $node->blockName = $block; // need check - $node->blockMods = $blockMods; + $node->block = $block; // need check + $node->mods = $blockMods; } return $this; @@ -279,13 +275,14 @@ function generateId () { * @return string|null|Context */ function mod ($key, $value = null, $force = false) { + $field = $this->ctx->elem ? 'elemMods' : 'mods'; if (func_num_args() > 1) { - $mods = $this->ctx->mods; + $mods = $this->ctx->$field; $mods->$key = !key_exists($key, $mods) || $force ? $value : $mods->$key; return $this; } - return isset($this->ctx->mods) && key_exists($key, $this->ctx->mods) - ? $this->ctx->mods->$key : null; + return isset($this->ctx->$field) && key_exists($key, $this->ctx->$field) + ? $this->ctx->$field->$key : null; } /** @@ -304,16 +301,15 @@ function mod ($key, $value = null, $force = false) { * @return array|Context */ function mods ($values = null, $force = false) { - $mods = $this->ctx->mods; + $field = $this->ctx->elem ? 'elemMods' : 'mods'; + $mods = $this->ctx->$field; if ($values === null) { return $mods; } - // d(compact('mods', 'values', 'force')); - $this->ctx->mods = $force ? + $this->ctx->$field = $force ? $this->extend($mods, $values) : $this->extend(is_object($values) ? $values : new Mods($values), $mods); - // d('res', $this->ctx->mods, "\n", (array)($this->ctx->mods)); return $this; } diff --git a/src/Json.php b/src/Json.php index 000a591..8322e1e 100644 --- a/src/Json.php +++ b/src/Json.php @@ -45,8 +45,6 @@ class Json { /** @var Mods */ protected $mods; /** @var Mods */ - protected $blockMods; - /** @var Mods */ protected $elemMods; public $_stop = false; @@ -82,7 +80,7 @@ public function setContent ($content) { } public function __get ($name) { - if ($name === 'mods' || $name === 'blockMods' || $name === 'elemMods') { + if ($name === 'mods' || $name === 'elemMods') { if (is_null($this->$name)) { $this->$name = new Mods(); } @@ -92,15 +90,16 @@ public function __get ($name) { } public function __set ($name, $value) { - if ($name === 'mods' || $name === 'blockMods' || $name === 'elemMods') { - $this->$name = is_array($value) ? new Mods($value) : $value; + if ($name === 'mods' || $name === 'elemMods') { + $this->$name = empty($value) ? null + : is_array($value) ? new Mods($value) : $value; } else { $this->$name = $value; } } public function __isset ($name) { - if ($name === 'mods' || $name === 'blockMods' || $name === 'elemMods') { + if ($name === 'mods' || $name === 'elemMods') { return !empty($this->$name); } return isset($this->$name); diff --git a/src/Step.php b/src/Step.php index cdc4891..440a2ca 100644 --- a/src/Step.php +++ b/src/Step.php @@ -7,8 +7,8 @@ class Step { public $json; public $arr; public $index; - public $blockName; - public $blockMods; + public $block; + public $mods; public $position; public $parentNode; @@ -21,8 +21,8 @@ function __construct ($json, $arr, $index, $blockName, $blockMods, $position = 0 $this->json = $json; $this->arr = $arr; $this->index = $index; - $this->blockName = $blockName; - $this->blockMods = $blockMods; + $this->block = $blockName; + $this->mods = $blockMods; $this->position = $position; $this->parentNode = $parentNode; } diff --git a/tests/apply.test.php b/tests/apply.test.php index 31d816d..569bfc0 100644 --- a/tests/apply.test.php +++ b/tests/apply.test.php @@ -2,7 +2,7 @@ use BEM\BH; -class applyTest extends PHPUnit_Framework_TestCase { +class bhApplyTest extends PHPUnit_Framework_TestCase { /** * @before @@ -26,38 +26,38 @@ function test_it_should_return_empty_string_on_falsy_template_result () { $this->bh->apply(['block' => 'link'])); } - function test_it_should_return_valid_processed_element () { - $this->bh->match('button', function ($ctx) { - $inner = $ctx->apply(['block' => 'button', 'elem' => 'inner']); - // \BEM\d($inner); - $this->assertEquals($inner->tag, 'span'); - $ctx->content($inner); - }); - $this->bh->match('button__inner', function ($ctx) { - $ctx->tag('span'); - // \BEM\d($ctx); - }); - $this->assertEquals( - '
' . - '' . - '
', - $this->bh->apply(['block' => 'button']) - ); - } + // function test_it_should_return_valid_processed_element () { + // $this->bh->match('button', function ($ctx) { + // $inner = $ctx->apply(['block' => 'button', 'elem' => 'inner']); + // // \BEM\d($inner); + // $this->assertEquals($inner->tag, 'span'); + // $ctx->content($inner); + // }); + // $this->bh->match('button__inner', function ($ctx) { + // $ctx->tag('span'); + // // \BEM\d($ctx); + // }); + // $this->assertEquals( + // '
' . + // '' . + // '
', + // $this->bh->apply(['block' => 'button']) + // ); + // } - function test_it_should_return_valid_processed_element_with_no_block_name () { - $this->bh->match('button', function ($ctx) { - $inner = $ctx->apply(['elem' => 'inner']); - $this->assertEquals($inner->tag, 'span'); - $ctx->content($inner); - }); - $this->bh->match('button__inner', function ($ctx) { - $ctx->tag('span'); - }); - $this->assertEquals( - '
' . - '' . - '
', - $this->bh->apply(['block' => 'button'])); - } + // function test_it_should_return_valid_processed_element_with_no_block_name () { + // $this->bh->match('button', function ($ctx) { + // $inner = $ctx->apply(['elem' => 'inner']); + // $this->assertEquals($inner->tag, 'span'); + // $ctx->content($inner); + // }); + // $this->bh->match('button__inner', function ($ctx) { + // $ctx->tag('span'); + // }); + // $this->assertEquals( + // '
' . + // '' . + // '
', + // $this->bh->apply(['block' => 'button'])); + // } } diff --git a/tests/applyBase.test.php b/tests/applyBase.test.php index 5350f7a..2f6174d 100644 --- a/tests/applyBase.test.php +++ b/tests/applyBase.test.php @@ -25,6 +25,20 @@ function test_it_should_apply_templates_for_new_mod () { ); } + function test_it_should_apply_base_matcher_for_element () { + $this->bh->match('button__control', function ($ctx) { + $ctx->mod('type', 'span'); + $ctx->applyBase(); + }); + $this->bh->match('button__control_type_span', function ($ctx) { + $ctx->tag('span'); + }); + $this->assertEquals( + '', + $this->bh->apply([ 'block' => 'button', 'elem' => 'control', 'mods' => [ 'disabled' => true ] ]) + ); + } + function test_it_should_apply_base_matcher_for_content () { $this->bh->match('button', function ($ctx) { $ctx->content([ diff --git a/tests/match.test.php b/tests/match.test.php index 5f1f658..d26f8bf 100644 --- a/tests/match.test.php +++ b/tests/match.test.php @@ -90,7 +90,7 @@ function test_it_should_match_string_mods () { ); } - function it_should_match_new_mods () { + function test_it_should_match_new_mods () { $this->bh->match('button_disabled', function($ctx) { $ctx->tag('span'); }); @@ -103,7 +103,7 @@ function it_should_match_new_mods () { $this->bh->apply([ 'block' => 'button' ])); } - function it_should_match_new_mods2 () { + function test_it_should_match_new_mods2 () { $this->bh->match('button_visible', function($ctx) { $ctx->tag('a'); }); diff --git a/tests/matchGlobal.test.php b/tests/matchGlobal.test.php new file mode 100644 index 0000000..d852af3 --- /dev/null +++ b/tests/matchGlobal.test.php @@ -0,0 +1,103 @@ +bh = new BH(); + } + + function test_it_should_apply_beforeEach_template () { + $this->bh->beforeEach(function($ctx) { + $ctx->tag('b'); + $ctx->bem(false); + }); + $this->assertEquals( + 'foo', + $this->bh->apply([ + [ 'content' => 'foo' ], + [ 'block' => 'button' ], + [ 'block' => 'input', 'elem' => 'control' ] + ]) + ); + } + + function test_it_should_match_beforeEach_before_other_template () { + $this->bh->match('button', function($ctx) { + $ctx->tag('button'); + }); + $this->bh->beforeEach(function($ctx) { + $ctx->tag('span'); + }); + $this->bh->match('button', function($ctx) { + $ctx->tag('strong'); + }); + $this->assertEquals( + '', + $this->bh->apply([ 'block' => 'button' ]) + ); + } + + function test_it_should_apply_several_beforeEach_templates_in_proper_order () { + $this->bh->beforeEach(function($ctx, $json) { + $json->cls .= '2'; + }); + $this->bh->beforeEach(function($ctx, $json) { + $json->cls .= '1'; + }); + $this->assertEquals( + '
', + $this->bh->apply([ 'block' => 'button', 'cls' => 'foo' ]) + ); + } + + + function test_it_should_apply_afterEach_template () { + $this->bh->afterEach(function ($ctx) { + $ctx->tag('b'); + $ctx->bem(false); + }); + $this->assertEquals( + 'foo', + $this->bh->apply([ + [ 'content' => 'foo' ], + [ 'block' => 'button' ], + [ 'block' => 'input', 'elem' => 'control' ] + ]) + ); + } + + function test_it_should_match_afterEach_after_other_template () { + $this->bh->match('button', function ($ctx) { + $ctx->tag('button', true); + }); + $this->bh->afterEach(function ($ctx) { + $ctx->tag('span', true); + }); + $this->bh->match('button', function ($ctx) { + $ctx->tag('strong', true); + }); + + $this->assertEquals( + '', + $this->bh->apply([ 'block' => 'button' ]) + ); + } + + function test_it_should_apply_several_afterEach_templates_in_proper_order () { + $this->bh->afterEach(function ($ctx, $json) { + $json->cls .= '2'; + }); + $this->bh->afterEach(function ($ctx, $json) { + $json->cls .= '1'; + }); + $this->assertEquals( + '
', + $this->bh->apply([ 'block' => 'button', 'cls' => 'foo' ]) + ); + } +} diff --git a/tests/mix.test.php b/tests/mix.test.php index e87cf3c..fba7cd8 100644 --- a/tests/mix.test.php +++ b/tests/mix.test.php @@ -9,25 +9,21 @@ class mixTest extends PHPUnit_Framework_TestCase { */ function setupBhInstance () { $this->bh = new BH(); - $this->blockMix = [['block' => 'mix']]; - $this->blockMixJson = new JsonCollection([ - new Json($this->blockMix[0]) - ]); } function test_it_should_return_mix () { $this->bh->match('button', function ($ctx) { $this->assertEquals( - $this->blockMixJson, + JsonCollection::normalize(['block' => 'mix']), $ctx->mix() ); }); - $this->bh->apply(['block' => 'button', 'mix' => $this->blockMix]); + $this->bh->apply(['block' => 'button', 'mix' => ['block' => 'mix']]); } - function test_it_should_set_mix () { + function test_it_should_set_single_mix () { $this->bh->match('button', function ($ctx) { - $ctx->mix($this->blockMix); + $ctx->mix(['block' => 'mix']); }); $this->assertEquals( '
', @@ -35,9 +31,9 @@ function test_it_should_set_mix () { ); } - function test_it_should_set_single_mix () { + function test_it_should_set_array_mix () { $this->bh->match('button', function ($ctx) { - $ctx->mix(['block' => 'mix']); + $ctx->mix([['block' => 'mix']]); }); $this->assertEquals( '
', @@ -55,7 +51,7 @@ function test_it_should_extend_user_single_mix () { ); } - function test_it_should_extend_user_mix () { + function test_it_should_extend_user_array_mix () { $this->bh->match('button', function ($ctx) { $ctx->mix([['block' => 'mix']]); }); @@ -65,12 +61,12 @@ function test_it_should_extend_user_mix () { ); } - function test_it_should_extend_later_declarations___ () { + function test_it_should_extend_later_declarations () { $this->bh->match('button', function ($ctx) { - $ctx->mix([['block' => 'mix2']]); + $ctx->mix(['block' => 'mix2']); }); $this->bh->match('button', function ($ctx) { - $ctx->mix([['block' => 'mix1']]); + $ctx->mix(['block' => 'mix1']); }); $this->assertEquals( '
', @@ -80,10 +76,10 @@ function test_it_should_extend_later_declarations___ () { function test_it_should_override_later_declarations_with_force_flag () { $this->bh->match('button', function ($ctx) { - $ctx->mix([['block' => 'mix2']], true); + $ctx->mix(['block' => 'mix2'], true); }); $this->bh->match('button', function ($ctx) { - $ctx->mix([['block' => 'mix1']]); + $ctx->mix(['block' => 'mix1']); }); $this->assertEquals( '
', @@ -93,11 +89,11 @@ function test_it_should_override_later_declarations_with_force_flag () { function test_it_should_override_user_declarations_with_force_flag () { $this->bh->match('button', function ($ctx) { - $ctx->mix([['block' => 'mix']], true); + $ctx->mix(['block' => 'mix'], true); }); $this->assertEquals( '
', - $this->bh->apply(['block' => 'button', 'mix' => [['block' => 'user-mix']]]) + $this->bh->apply(['block' => 'button', 'mix' => ['block' => 'user-mix']]) ); } diff --git a/tests/mod.test.php b/tests/mod.test.php index c905cea..dd3a2ec 100644 --- a/tests/mod.test.php +++ b/tests/mod.test.php @@ -13,14 +13,18 @@ function setupBhInstance () { function test_it_should_return_mod () { $this->bh->match('button', function ($ctx) { - $this->assertEquals( - 'button', - $ctx->mod('type') - ); + $this->assertEquals('button', $ctx->mod('type')); }); $this->bh->apply(['block' => 'button', 'mods' => ['type' => 'button']]); } + function test_it_should_return_elem_mod () { + $this->bh->match('button__control', function($ctx) { + $this->assertEquals('button', $ctx->mod('type')); + }); + $this->bh->apply([ 'block' => 'button', 'elem' => 'control', 'mods' => [ 'type' => 'button' ] ]); + } + function test_it_should_return_null_mod () { $this->bh->match('button', function ($ctx) { $this->assertNull($ctx->mod('type')); diff --git a/tests/mods.test.php b/tests/mods.test.php index d25513b..018f076 100644 --- a/tests/mods.test.php +++ b/tests/mods.test.php @@ -30,6 +30,16 @@ function test_it_should_return_mods () { $this->bh->apply(['block' => 'button', 'mods' => ['type' => 'button']]); } + function test_it_should_return_elem_mods () { + $this->bh->match('button__control', function ($ctx) { + $this->assertEquals( + 'button', + $ctx->mods()->type + ); + }); + $this->bh->apply([ 'block' => 'button', 'elem' => 'control', 'elemMods' => [ 'type' => 'button' ] ]); + } + function test_it_should_return_boolean_mods () { $this->bh->match('button', function ($ctx) { $this->assertEquals( diff --git a/tests/options.test.php b/tests/options.test.php index 00efb77..5b333eb 100644 --- a/tests/options.test.php +++ b/tests/options.test.php @@ -52,4 +52,40 @@ function test_it_should_use_jsAttrName_and_jsAttrScheme_options_ () { $this->bh->apply(['block' => 'button', 'js' => true])); } + function test_it_should_use_jsCls_option () { + $this->bh->setOptions([ 'jsCls' => 'js' ]); + $this->assertEquals( + '
', + $this->bh->apply([ 'block' => 'button', 'js' => true ]) + ); + } + + function test_it_should_use_empty_jsCls_option () { + $this->bh->setOptions([ 'jsCls' => false ]); + $this->assertEquals( + '
', + $this->bh->apply([ 'block' => 'button', 'js' => true ]) + ); + } + + function test_it_should_use_clsNobaseMods_options () { + $this->bh->setOptions([ 'clsNobaseMods' => true ]); + $this->assertEquals( + '
' . + '
' . + '
', + $this->bh->apply([ + 'block' => 'button', + 'mods' => [ 'disabled' => true, 'theme' => 'new' ], + 'mix' => [ + [ 'block' => 'clearfix' ], + [ 'elem' => 'box', 'elemMods' => [ 'pick' => 'left' ] ] + ], + 'content' => [ + 'elem' => 'control', + 'elemMods' => [ 'disabled' => true ] + ] + ]) + ); + } } diff --git a/tests/position.test.php b/tests/position.test.php index 8dc88fd..8b4cfb2 100644 --- a/tests/position.test.php +++ b/tests/position.test.php @@ -11,7 +11,7 @@ function setupBhInstance () { $this->bh = new BH(); } - function test_it_should_calc_position____ () { + function test_it_should_calc_position () { $this->bh->match('button__inner', function ($ctx) { $ctx->mod('pos', $ctx->position()); }); @@ -27,7 +27,7 @@ function test_it_should_calc_position____ () { ]) ); } - function test_it_should_calc_position_with_array_mess_ () { + function test_it_should_calc_position_with_array_mess () { $this->bh->match('button__inner', function ($ctx) { $ctx->mod('pos', $ctx->position()); }); @@ -46,7 +46,7 @@ function test_it_should_calc_position_with_array_mess_ () { ]) ); } - function test_it_should_calc_position_for_single_element_ () { + function test_it_should_calc_position_for_single_element () { $this->bh->match('button__inner', function ($ctx) { $ctx->mod('pos', $ctx->position()); }); diff --git a/tests/process.test.php b/tests/process.test.php new file mode 100644 index 0000000..a1b9b46 --- /dev/null +++ b/tests/process.test.php @@ -0,0 +1,39 @@ +bh = new BH(); + } + + function test_it_should_return_valid_processed_json () { + $this->bh->match('search', function ($ctx) { + $ctx->content($ctx->process([ 'block' => 'input' ])); + }); + $this->bh->match('input', function ($ctx) { + $ctx->tag('input'); + }); + $this->assertEquals( + '', + $this->bh->apply([ 'block' => 'search' ]) + ); + } + + function test_it_should_return_valid_processed_element_with_no_block_name () { + $this->bh->match('button', function ($ctx) { + $ctx->content($ctx->process([ 'elem' => 'inner' ])); + }); + $this->bh->match('button__inner', function ($ctx) { + $ctx->tag('span'); + }); + $this->assertEquals( + '
', + $this->bh->apply([ 'block' => 'button' ]) + ); + } +} diff --git a/tests/processBemJson.test.php b/tests/processBemJson.test.php new file mode 100644 index 0000000..1d4ce0c --- /dev/null +++ b/tests/processBemJson.test.php @@ -0,0 +1,81 @@ +bh = new BH(); + } + + function test_it_should_create_empty_block_mods () { + $this->assertEquals( + new Json([ + 'block' => 'button', + 'mods' => [] + ]), + $this->bh->processBemJson([ + 'block' => 'button' + ]) + ); + } + + function test_it_should_create_empty_elem_mods () { + $this->assertEquals( + new Json([ + 'block' => 'button', + 'mods' => null, + 'elem' => 'control', + 'elemMods' => [] + ]), + $this->bh->processBemJson([ + 'block' => 'button', + 'elem' => 'control' + ]) + ); + } + + function test_it_should_inherit_block_mods () { + $this->assertEquals( + JsonCollection::normalize([ + 'block' => 'button', + 'mods' => [ 'disabled' => true ], + 'content' => [ + 'block' => 'button', + 'mods' => [ 'disabled' => true ], + 'elem' => 'inner', + 'elemMods' => [] + ] + ])[0], + $this->bh->processBemJson([ + 'block' => 'button', + 'mods' => [ 'disabled' => true ], + 'content' => [ 'elem' => 'inner' ] + ]) + ); + } + + function test_it_should_use_elemMods_instead_of_mods_if_collision () { + $this->assertEquals( + JsonCollection::normalize([ + 'block' => 'button', + 'mods' => [ 'valid' => true ], + 'elem' => 'inner', + 'elemMods' => [ 'disabled' => 'yes' ] + ])[0], + $this->bh->processBemJson([ + 'block' => 'button', + 'mods' => [ 'valid' => true ], + 'elem' => 'inner', + 'elemMods' => [ 'disabled' => 'yes' ] + ]) + ); + } +} diff --git a/tests/toHtml.test.php b/tests/toHtml.test.php index 11c0b56..23430f9 100644 --- a/tests/toHtml.test.php +++ b/tests/toHtml.test.php @@ -339,16 +339,16 @@ function setupBhInstance () { $this->bh = new BH(); } - function test_itShouldNotSet_iBem_classOnElement () { + function test_itShouldSet_iBem_classOnElement () { $this->assertEquals( - '
submit
', + '
submit
', $this->bh->apply([ 'block' => 'button', 'elem' => 'control', 'js' => true, 'content' => 'submit' ]) ); } - function test_itShouldNotSet_iBem_classOnMixedElement () { + function test_itShouldSet_iBem_classOnMixedElement () { $this->assertEquals( - '
submit
', + '
submit
', $this->bh->apply([ 'block' => 'icon', 'content' => 'submit', 'mix' => [ 'block' => 'button', 'elem' => 'control', 'js' => true ]]) ); }