diff --git a/docs/core/variables.md b/docs/core/variables.md index c2b99ba..cf2ea0e 100644 --- a/docs/core/variables.md +++ b/docs/core/variables.md @@ -42,6 +42,7 @@ Sections of CSS can be included and excluded on the basis of variable existence ```crush @set foo #f00; +@set bar true; @ifset foo { p { @@ -54,5 +55,8 @@ p { @ifset not foo { line-height: 1.5; } + @ifset bar(true) { + margin-bottom: 5px; + } } -``` +``` \ No newline at end of file diff --git a/lib/CssCrush/Process.php b/lib/CssCrush/Process.php index b3c1607..c15c7ee 100644 --- a/lib/CssCrush/Process.php +++ b/lib/CssCrush/Process.php @@ -457,7 +457,7 @@ protected function resolveSettings() protected function resolveIfDefines() { - $ifdefinePatt = Regex::make('~@if(?:set|define) \s+ (?not \s+)? (?{{ ident }}) \s* \{~ixS'); + $ifdefinePatt = Regex::make('~@if(?:set|define) \s+ (?not \s+)? (?{{ ident }}) \s* {{ parens }}? \s* \{~ixS'); $matches = $this->string->matchAll($ifdefinePatt); @@ -472,7 +472,20 @@ protected function resolveIfDefines() $negate = $match['negate'][1] != -1; $nameDefined = isset($this->vars[$match['name'][0]]); - if (! $negate && $nameDefined || $negate && ! $nameDefined) { + $valueDefined = isset($match['parens_content'][0]); + $valueMatch = false; + if ($nameDefined && $valueDefined) { + $testValue = Util::rawValue(trim($match['parens_content'][0])); + $varValue = Util::rawValue($this->vars[$match['name'][0]]); + $valueMatch = $varValue == $testValue; + } + + if ( + ( $valueDefined && !$negate && $valueMatch ) + || ( $valueDefined && $negate && !$valueMatch ) + || ( !$valueDefined && !$negate && $nameDefined ) + || ( !$valueDefined && $negate && !$nameDefined ) + ) { $curlyMatch->unWrap(); } else { diff --git a/lib/CssCrush/Regex.php b/lib/CssCrush/Regex.php index eaa0218..1928eb5 100644 --- a/lib/CssCrush/Regex.php +++ b/lib/CssCrush/Regex.php @@ -85,6 +85,7 @@ public static function init() $patt->ruleDirective = '~^(?:(@include)|(@extends?)|(@name))[\s]+~iS'; $patt->argListSplit = '~\s*[,\s]\s*~S'; $patt->cruftyHex = Regex::make('~\#({{hex}})\1({{hex}})\2({{hex}})\3~S'); + $patt->token = Regex::make('~^ \? (?[a-zA-Z]) {{token_id}} \? $~xS'); } public static function make($pattern) diff --git a/lib/CssCrush/Tokens.php b/lib/CssCrush/Tokens.php index cd794ff..43a1475 100644 --- a/lib/CssCrush/Tokens.php +++ b/lib/CssCrush/Tokens.php @@ -146,11 +146,16 @@ public static function pad($label, $replaced_text) public static function is($label, $of_type) { - if (preg_match(Regex::make('~^ \? (?[a-zA-Z]) {{token_id}} \? $~xS'), $label, $m)) { + if (preg_match(Regex::$patt->token, $label, $m)) { return $of_type ? ($of_type === $m['type']) : true; } return false; } + + public static function test($value) + { + return preg_match(Regex::$patt->token, $value, $m) ? $m['type'] : false; + } } diff --git a/lib/CssCrush/Util.php b/lib/CssCrush/Util.php index f3a5d00..4f02c32 100644 --- a/lib/CssCrush/Util.php +++ b/lib/CssCrush/Util.php @@ -228,6 +228,23 @@ public static function readConfigFile($path) return Options::filter(get_defined_vars()); } + /* + * Get raw value (useful if testing values that may or may not be a token). + */ + public static function rawValue($value) + { + if ($tokenType = Tokens::test($value)) { + if ($tokenType == 'u') { + $value = Crush::$process->tokens->get($value)->value; + } + elseif ($tokenType == 's') { + $value = Crush::$process->tokens->get($value); + } + } + + return $value; + } + /* * Encode integer to Base64 VLQ. */ diff --git a/tests/unit/CssCrush/TokensTest.php b/tests/unit/CssCrush/TokensTest.php index f544ca0..2c4880a 100644 --- a/tests/unit/CssCrush/TokensTest.php +++ b/tests/unit/CssCrush/TokensTest.php @@ -111,4 +111,11 @@ public function testIs() { $this->assertTrue(Tokens::is($this->tokens->createLabel('s'), 's')); } + + public function testTest() + { + $this->assertFalse(Tokens::test('foobar')); + $this->assertEquals(Tokens::test($this->tokens->createLabel('u')), 'u'); + $this->assertEquals(Tokens::test($this->tokens->createLabel('s')), 's'); + } } diff --git a/tests/unit/CssCrush/UtilTest.php b/tests/unit/CssCrush/UtilTest.php index c50aefe..04536cd 100644 --- a/tests/unit/CssCrush/UtilTest.php +++ b/tests/unit/CssCrush/UtilTest.php @@ -3,9 +3,17 @@ namespace CssCrush\UnitTest; use CssCrush\Util; +use CssCrush\Tokens; +use CssCrush\Url; class UtilTest extends \PHPUnit_Framework_TestCase { + public function setUp() + { + $this->process = bootstrap_process(array('minify' => false)); + $this->tokens = $this->process->tokens; + } + public function testNormalizePath() { $this->assertEquals('/Some/crazy/Path', Util::normalizePath('C:\\Some\crazy/Path\\', true)); @@ -90,6 +98,24 @@ public function testFilePutContents() $this->assertTrue(Util::filePutContents($test_file, 'Hello Mum')); } + public function testRawValue() + { + $url1 = $this->tokens->add(new Url('foo.jpg')); + $url2 = $this->tokens->add(new Url('foo.jpg')); + $this->assertNotEquals($url1, $url2); + $this->assertEquals(Util::rawValue($url1), Util::rawValue($url2)); + $this->assertEquals(Util::rawValue($url1), 'foo.jpg'); + + $string1 = $this->tokens->add('"bar"', 's'); + $string2 = $this->tokens->add('"bar"', 's'); + $this->assertNotEquals($string1, $string2); + $this->assertEquals(Util::rawValue($string1), Util::rawValue($string2)); + $this->assertEquals(Util::rawValue($string1), '"bar"'); + + $this->assertEquals(Util::rawValue('foobar'), 'foobar'); + $this->assertNotEquals(Util::rawValue('foobar'), 'notFoobar'); + } + public function testReadConfigFile() { $contents = <<<'NOW_DOC'