diff --git a/src/Console/ConsoleIo.php b/src/Console/ConsoleIo.php index d054c3f39fc..63e0bb484cd 100644 --- a/src/Console/ConsoleIo.php +++ b/src/Console/ConsoleIo.php @@ -399,7 +399,10 @@ public function helper($name, array $settings = []) */ public function __call($method, $args) { - $helper = $this->helper($method, $args); + $helper = $this->helper($method); + if (count($args) === 1 && isset($args[0]) && is_array($args[0])) { + $args = $args[0]; + } return $helper->output($args); } } diff --git a/src/Shell/Helper/ProgressHelper.php b/src/Shell/Helper/ProgressHelper.php new file mode 100644 index 00000000000..afa00b27731 --- /dev/null +++ b/src/Shell/Helper/ProgressHelper.php @@ -0,0 +1,131 @@ + null]; + if (isset($args[0])) { + $args['callback'] = $args[0]; + } + if (!$args['callback'] || !is_callable($args['callback'])) { + throw new RuntimeException('Callback option must be a callable.'); + } + $this->init($args); + + $callback = $args['callback']; + while ($this->_progress < $this->_total) { + $callback($this); + $this->draw(); + } + $this->_io->out(''); + } + + /** + * Initialize the progress bar for use. + * + * - `total` The total number of items in the progress bar. Defaults + * to 100. + * - `width` The width of the progress bar. Defaults to 80. + * + * @param array $args The initialization data. + * @return void + */ + public function init(array $args = []) + { + $args += ['total' => 100, 'width' => 80]; + $this->_progress = 0; + $this->_width = $args['width']; + $this->_total = $args['total']; + } + + /** + * Increment the progress bar. + * + * @param int $num The amount of progress to advance by. + * @return void + */ + public function increment($num = 1) + { + $this->_progress = min(max(0, $this->_progress + $num), $this->_total); + } + + /** + * Render the progress bar based on the current state. + * + * @return void + */ + public function draw() + { + $numberLen = strlen(' 100%'); + $complete = round($this->_progress / $this->_total, 2); + $barLen = ($this->_width - $numberLen) * ($this->_progress / $this->_total); + $bar = ''; + if ($barLen > 1) { + $bar = str_repeat('=', $barLen - 1) . '>'; + } + + $pad = $this->_width - $numberLen - $barLen; + if ($pad > 0) { + $bar .= str_repeat(' ', $pad); + } + $percent = ($complete * 100) . '%'; + $bar .= str_pad($percent, $numberLen, ' ', STR_PAD_LEFT); + + $this->_io->overwrite($bar, 0); + } +} diff --git a/src/Shell/Helper/TableHelper.php b/src/Shell/Helper/TableHelper.php index 3d2e527f5af..477e0941489 100644 --- a/src/Shell/Helper/TableHelper.php +++ b/src/Shell/Helper/TableHelper.php @@ -83,9 +83,6 @@ protected function _render($row, $widths) */ public function output($rows) { - if (count($rows) === 1) { - $rows = $rows[0]; - } $widths = $this->_calculateWidths($rows); $this->_rowSeparator($widths); diff --git a/src/Shell/Task/ExtractTask.php b/src/Shell/Task/ExtractTask.php index 1400da40113..8127425eff4 100644 --- a/src/Shell/Task/ExtractTask.php +++ b/src/Shell/Task/ExtractTask.php @@ -349,9 +349,15 @@ public function getOptionParser() */ protected function _extractTokens() { + $progress = $this->_io->helper('progress'); + $progress->init(['total' => count($this->_files)]); + $isVerbose = $this->param('verbose'); + foreach ($this->_files as $file) { $this->_file = $file; - $this->out(sprintf('Processing %s...', $file), 1, Shell::VERBOSE); + if ($isVerbose) { + $this->out(sprintf('Processing %s...', $file), 1, Shell::VERBOSE); + } $code = file_get_contents($file); $allTokens = token_get_all($code); @@ -372,6 +378,10 @@ protected function _extractTokens() $this->_parse('__dx', ['domain', 'context', 'singular']); $this->_parse('__dxn', ['domain', 'context', 'singular', 'plural']); + if (!$isVerbose) { + $progress->increment(1); + $progress->draw(); + } } } diff --git a/src/TestSuite/Stub/ConsoleOutput.php b/src/TestSuite/Stub/ConsoleOutput.php new file mode 100644 index 00000000000..1aec0602f61 --- /dev/null +++ b/src/TestSuite/Stub/ConsoleOutput.php @@ -0,0 +1,63 @@ +_out[] = $message; + } + + /** + * Get the buffered output. + * + * @return array + */ + public function messages() + { + return $this->_out; + } +} diff --git a/tests/TestCase/Console/ConsoleIoTest.php b/tests/TestCase/Console/ConsoleIoTest.php index fdbbcc15c4b..4a463a7b299 100644 --- a/tests/TestCase/Console/ConsoleIoTest.php +++ b/tests/TestCase/Console/ConsoleIoTest.php @@ -380,9 +380,14 @@ public function testHelper() */ public function testHelperCall() { - $this->out->expects($this->once()) + $this->out->expects($this->at(0)) + ->method('write') + ->with('It works!well ish'); + $this->out->expects($this->at(1)) ->method('write') ->with('It works!well ish'); - $helper = $this->io->simple('well', 'ish'); + + $this->io->simple('well', 'ish'); + $this->io->simple(['well', 'ish']); } } diff --git a/tests/TestCase/Shell/Helper/ProgressHelperTest.php b/tests/TestCase/Shell/Helper/ProgressHelperTest.php new file mode 100644 index 00000000000..85c624cb550 --- /dev/null +++ b/tests/TestCase/Shell/Helper/ProgressHelperTest.php @@ -0,0 +1,194 @@ +stub = new ConsoleOutput(); + $this->io = new ConsoleIo($this->stub); + $this->helper = new ProgressHelper($this->io); + } + + /** + * Test that a callback is required. + * + * @expectedException \RuntimeException + */ + public function testOutputFailure() + { + $this->helper->output(['not a callback']); + } + + /** + * Test that the callback is invoked until 100 is reached. + * + * @return void + */ + public function testOutputSuccess() + { + $this->helper->output([function ($progress) { + $progress->increment(20); + }]); + $expected = [ + '', + '==============> 20%', + '', + '=============================> 40%', + '', + '============================================> 60%', + '', + '===========================================================> 80%', + '', + '==========================================================================> 100%', + '', + ]; + $this->assertEquals($expected, $this->stub->messages()); + } + + /** + * Test output with options + * + * @return void + */ + public function testOutputSuccessOptions() + { + $this->helper->output([ + 'total' => 10, + 'width' => 20, + 'callback' => function ($progress) { + $progress->increment(2); + } + ]); + $expected = [ + '', + '==> 20%', + '', + '=====> 40%', + '', + '========> 60%', + '', + '===========> 80%', + '', + '==============> 100%', + '', + ]; + $this->assertEquals($expected, $this->stub->messages()); + } + + /** + * Test using the helper manually. + * + * @return void + */ + public function testIncrementAndRender() + { + $this->helper->init(); + + $this->helper->increment(20); + $this->helper->draw(); + + $this->helper->increment(40); + $this->helper->draw(); + + $this->helper->increment(40); + $this->helper->draw(); + + $expected = [ + '', + '==============> 20%', + '', + '============================================> 60%', + '', + '==========================================================================> 100%', + ]; + $this->assertEquals($expected, $this->stub->messages()); + } + + /** + * Test negative numbers + * + * @return void + */ + public function testIncrementWithNegatives() + { + $this->helper->init(); + + $this->helper->increment(40); + $this->helper->draw(); + + $this->helper->increment(-60); + $this->helper->draw(); + + $this->helper->increment(80); + $this->helper->draw(); + + $expected = [ + '', + '=============================> 40%', + '', + ' 0%', + '', + '===========================================================> 80%', + ]; + $this->assertEquals($expected, $this->stub->messages()); + } + + /** + * Test increment and draw with options + * + * @return void + */ + public function testIncrementWithOptions() + { + $this->helper->init([ + 'total' => 10, + 'width' => 20, + ]); + $expected = [ + '', + '=====> 40%', + '', + '===========> 80%', + '', + '==============> 100%', + ]; + $this->helper->increment(4); + $this->helper->draw(); + $this->helper->increment(4); + $this->helper->draw(); + $this->helper->increment(4); + $this->helper->draw(); + + $this->assertEquals($expected, $this->stub->messages()); + } +} diff --git a/tests/TestCase/Shell/Helper/TableHelperTest.php b/tests/TestCase/Shell/Helper/TableHelperTest.php index 1d07467c6db..2e5e77a7aa1 100644 --- a/tests/TestCase/Shell/Helper/TableHelperTest.php +++ b/tests/TestCase/Shell/Helper/TableHelperTest.php @@ -15,28 +15,10 @@ namespace Cake\Test\TestCase\Shell\Helper; use Cake\Console\ConsoleIo; -use Cake\Console\ConsoleOutput; use Cake\Shell\Helper\TableHelper; +use Cake\TestSuite\Stub\ConsoleOutput; use Cake\TestSuite\TestCase; -/** - * StubOutput makes testing easier. - */ -class StubOutput extends ConsoleOutput -{ - protected $_out = []; - - public function write($message, $newlines = 1) - { - $this->_out[] = $message; - } - - public function messages() - { - return $this->_out; - } -} - /** * TableHelper test. */ @@ -52,7 +34,7 @@ public function setUp() { parent::setUp(); - $this->stub = new StubOutput(); + $this->stub = new ConsoleOutput(); $this->io = new ConsoleIo($this->stub); $this->helper = new TableHelper($this->io); } @@ -81,28 +63,6 @@ public function testOutput() $this->assertEquals($expected, $this->stub->messages()); } - /** - * Test output array shifting - * - * @return voi - */ - public function testOutputShifting() - { - $data = [ - ['Header 1', 'Header', 'Long Header'], - ['short', 'Longish thing', 'short'], - ]; - $this->helper->output([$data]); - $expected = [ - '+----------+---------------+-------------+', - '| Header 1 | Header | Long Header |', - '+----------+---------------+-------------+', - '| short | Longish thing | short |', - '+----------+---------------+-------------+', - ]; - $this->assertEquals($expected, $this->stub->messages()); - } - /** * Test output with multibyte characters * @@ -124,7 +84,6 @@ public function testOutputUtf8() '| Longer thing | longerish | Longest Value |', '+--------------+-----------+---------------+', ]; - debug($this->stub->messages()); $this->assertEquals($expected, $this->stub->messages()); } } diff --git a/tests/TestCase/Shell/Task/ExtractTaskTest.php b/tests/TestCase/Shell/Task/ExtractTaskTest.php index ec6e43ab458..12bb27517dd 100644 --- a/tests/TestCase/Shell/Task/ExtractTaskTest.php +++ b/tests/TestCase/Shell/Task/ExtractTaskTest.php @@ -37,6 +37,9 @@ public function setUp() { parent::setUp(); $this->io = $this->getMock('Cake\Console\ConsoleIo', [], [], '', false); + $progress = $this->getMock('Cake\Shell\Helper\ProgressHelper', [], [$this->io]); + $this->io->method('helper') + ->will($this->returnValue($progress)); $this->Task = $this->getMock( 'Cake\Shell\Task\ExtractTask',