[Console] Added formatter style stack.

This commit is contained in:
Jean-François Simon 2012-03-16 09:39:23 +01:00
parent 93ffe54886
commit 4f298dd7c7
2 changed files with 210 additions and 0 deletions

View File

@ -0,0 +1,136 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Formatter;
/**
* @author: Jean-François Simon <contact@jfsimon.fr>
*/
class OutputFormatterStyleStack
{
/**
* @var array
*/
private $foregrounds;
/**
* @var array
*/
private $backgrounds;
/**
* @var array
*/
private $options;
/**
* Constructor.
*/
public function __construct()
{
$this->reset();
}
/**
* Resets stack (ie. empty internal arrays).
*/
public function reset()
{
$this->foregrounds = array();
$this->backgrounds = array();
$this->options = array();
}
/**
* Pushes a style in the stack.
*
* @param OutputFormatterStyleInterface $style
*/
public function pushStyle(OutputFormatterStyleInterface $style)
{
$foreground = $style->getForeground();
if (null !== $foreground) {
$this->foregrounds[] = $foreground;
}
$background = $style->getBackground();
if (null !== $background) {
$this->backgrounds[] = $background;
}
foreach ($style->getOptions() as $option) {
if (!isset($this->options[$option])) {
$this->options[$option] = 0;
}
$this->options[$option] += 1;
}
}
/**
* Pops a style from the stack.
*
* @param OutputFormatterStyleInterface $style
*
* @throws \InvalidArgumentException When style tags incorrectly nested
*/
public function popStyle(OutputFormatterStyleInterface $style)
{
$this->popArrayCode($this->foregrounds, $style->getForeground());
$this->popArrayCode($this->backgrounds, $style->getBackground());
foreach ($style->getOptions() as $option) {
if (!isset($this->options[$option])) {
throw new \InvalidArgumentException('Unexpected style "'.$option.'" option end.');
}
$this->options[$option] -= 1;
if (0 === $this->options[$option]) {
unset($this->options[$option]);
}
}
}
/**
* Computes current style with stacks top codes.
*
* @return OutputFormatterStyle
*/
public function getCurrentStyle()
{
return new OutputFormatterStyle(
end($this->foregrounds) ?: null,
end($this->backgrounds) ?: null,
array_keys($this->options)
);
}
/**
* Pops a color from a stack.
*
* @param array $stack An array of color names
* @param int $color A color name
*
* @throws \InvalidArgumentException When poped color is not the expected one
*/
private function popArrayCode(&$stack, $color)
{
if (null === $color) {
return;
}
$current = end($stack);
if ($current !== $color) {
throw new \InvalidArgumentException('Expected style "'.$current.'" color end but "'.$color.'" end found.');
}
array_pop($stack);
}
}

View File

@ -0,0 +1,74 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Tests\Component\Console\Formatter;
use Symfony\Component\Console\Formatter\OutputFormatterStyleStack;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
class OutputFormatterStyleStackTest extends \PHPUnit_Framework_TestCase
{
public function testPush()
{
$stack = new OutputFormatterStyleStack();
$stack->pushStyle(new OutputFormatterStyle('white'));
$stack->pushStyle(new OutputFormatterStyle(null, 'black'));
$stack->pushStyle(new OutputFormatterStyle(null, null, array('bold')));
$style = $stack->getCurrentStyle();
$this->assertEquals('white', $style->getForeground());
$this->assertEquals('black', $style->getBackground());
$this->assertEquals(array('bold'), $style->getOptions());
$stack->pushStyle(new OutputFormatterStyle('yellow', null, array('blink')));
$style = $stack->getCurrentStyle();
$this->assertEquals('yellow', $style->getForeground());
$this->assertEquals('black', $style->getBackground());
$this->assertEquals(array('bold', 'blink'), $style->getOptions());
}
public function testPop()
{
$stack = new OutputFormatterStyleStack();
$stack->pushStyle(new OutputFormatterStyle('white', 'black', array('blink', 'bold')));
$stack->pushStyle(new OutputFormatterStyle('yellow', 'blue'));
$style = $stack->getCurrentStyle();
$this->assertEquals('yellow', $style->getForeground());
$this->assertEquals('blue', $style->getBackground());
$this->assertEquals(array('blink', 'bold'), $style->getOptions());
$stack->popStyle(new OutputFormatterStyle(null, 'blue', array('blink')));
$style = $stack->getCurrentStyle();
$this->assertEquals('yellow', $style->getForeground());
$this->assertEquals('black', $style->getBackground());
$this->assertEquals(array('bold'), $style->getOptions());
$stack->popStyle(new OutputFormatterStyle('yellow', 'black', array('bold')));
$style = $stack->getCurrentStyle();
$this->assertEquals('white', $style->getForeground());
$this->assertEquals(null, $style->getBackground());
$this->assertEquals(array(), $style->getOptions());
}
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidPop()
{
$stack = new OutputFormatterStyleStack();
$stack->pushStyle(new OutputFormatterStyle('white', 'black', array('blink', 'bold')));
$stack->popStyle(new OutputFormatterStyle('yellow'));
}
}