CLImate   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 359
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 8

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 34
lcom 2
cbo 8
dl 0
loc 359
ccs 93
cts 93
cp 1
rs 9.68
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A setStyle() 0 4 1
A setRouter() 0 4 1
A setSettingsManager() 0 4 1
A setArgumentManager() 0 4 1
A setOutput() 0 4 1
A setUtil() 0 4 1
A extend() 0 6 1
A forceAnsiOn() 0 6 1
A forceAnsiOff() 0 6 1
A to() 0 6 1
A usage() 0 4 1
A description() 0 6 1
A hasOutput() 0 9 4
A parseStyleMethod() 0 15 2
A applyStyleMethods() 0 15 4
A searchForStyleMethods() 0 10 2
A buildTerminalObject() 0 16 1
A routeRemainingMethod() 0 18 4
A __call() 0 20 4
1
<?php
2
3
namespace League\CLImate;
4
5
use League\CLImate\Argument\Manager as ArgumentManager;
6
use League\CLImate\Decorator\Style;
7
use League\CLImate\Settings\Manager as SettingsManager;
8
use League\CLImate\TerminalObject\Dynamic\Spinner;
9
use League\CLImate\TerminalObject\Router\Router;
10
use League\CLImate\Util\Helper;
11
use League\CLImate\Util\Output;
12
use League\CLImate\Util\UtilFactory;
13
14
/**
15
 * @method CLImate black(string $str = null)
16
 * @method CLImate red(string $str = null)
17
 * @method CLImate green(string $str = null)
18
 * @method CLImate yellow(string $str = null)
19
 * @method CLImate blue(string $str = null)
20
 * @method CLImate magenta(string $str = null)
21
 * @method CLImate cyan(string $str = null)
22
 * @method CLImate lightGray(string $str = null)
23
 * @method CLImate darkGray(string $str = null)
24
 * @method CLImate lightRed(string $str = null)
25
 * @method CLImate lightGreen(string $str = null)
26
 * @method CLImate lightYellow(string $str = null)
27
 * @method CLImate lightBlue(string $str = null)
28
 * @method CLImate lightMagenta(string $str = null)
29
 * @method CLImate lightCyan(string $str = null)
30
 * @method CLImate white(string $str = null)
31
 *
32
 * @method CLImate backgroundBlack(string $str = null)
33
 * @method CLImate backgroundRed(string $str = null)
34
 * @method CLImate backgroundGreen(string $str = null)
35
 * @method CLImate backgroundYellow(string $str = null)
36
 * @method CLImate backgroundBlue(string $str = null)
37
 * @method CLImate backgroundMagenta(string $str = null)
38
 * @method CLImate backgroundCyan(string $str = null)
39
 * @method CLImate backgroundLightGray(string $str = null)
40
 * @method CLImate backgroundDarkGray(string $str = null)
41
 * @method CLImate backgroundLightRed(string $str = null)
42
 * @method CLImate backgroundLightGreen(string $str = null)
43
 * @method CLImate backgroundLightYellow(string $str = null)
44
 * @method CLImate backgroundLightBlue(string $str = null)
45
 * @method CLImate backgroundLightMagenta(string $str = null)
46
 * @method CLImate backgroundLightCyan(string $str = null)
47
 * @method CLImate backgroundWhite(string $str = null)
48
 *
49
 * @method CLImate bold(string $str = null)
50
 * @method CLImate dim(string $str = null)
51
 * @method CLImate underline(string $str = null)
52
 * @method CLImate blink(string $str = null)
53
 * @method CLImate invert(string $str = null)
54
 * @method CLImate hidden(string $str = null)
55
 *
56
 * @method CLImate info(string $str = null)
57
 * @method CLImate comment(string $str = null)
58
 * @method CLImate whisper(string $str = null)
59
 * @method CLImate shout(string $str = null)
60
 * @method CLImate error(string $str = null)
61
 *
62
 * @method mixed out(string $str)
63
 * @method mixed inline(string $str)
64
 * @method mixed table(array $data)
65
 * @method mixed json(mixed $var)
66
 * @method mixed br($count = 1)
67
 * @method mixed tab($count = 1)
68
 * @method mixed draw(string $art)
69
 * @method mixed border(string $char = null, integer $length = null)
70
 * @method mixed dump(mixed $var)
71
 * @method mixed flank(string $output, string $char = null, integer $length = null)
72
 * @method mixed progress(integer $total = null)
73
 * @method Spinner spinner(string $label = null, string ...$characters = null)
74
 * @method mixed padding(integer $length = 0, string $char = '.')
75
 * @method mixed input(string $prompt, Util\Reader\ReaderInterface $reader = null)
76
 * @method mixed confirm(string $prompt, Util\Reader\ReaderInterface $reader = null)
77
 * @method mixed password(string $prompt, Util\Reader\ReaderInterface $reader = null)
78
 * @method mixed checkboxes(string $prompt, array $options, Util\Reader\ReaderInterface $reader = null)
79
 * @method mixed radio(string $prompt, array $options, Util\Reader\ReaderInterface $reader = null)
80
 * @method mixed animation(string $art, TerminalObject\Helper\Sleeper $sleeper = null)
81
 * @method mixed columns(array $data, $column_count = null)
82
 * @method mixed clear()
83
 *
84
 * @method CLImate addArt(string $dir)
85
 */
86
class CLImate
87
{
88
    /**
89
     * An instance of the Style class
90
     *
91
     * @var \League\CLImate\Decorator\Style $style
92
     */
93
    public $style;
94
95
    /**
96
     * An instance of the Terminal Object Router class
97
     *
98
     * @var \League\CLImate\TerminalObject\Router\Router $router
99
     */
100
    protected $router;
101
102
    /**
103
     * An instance of the Settings Manager class
104
     *
105
     * @var \League\CLImate\Settings\Manager $settings
106
     */
107
    protected $settings;
108
109
    /**
110
     * An instance of the Argument Manager class
111
     *
112
     * @var \League\CLImate\Argument\Manager $arguments
113
     */
114
    public $arguments;
115
116
    /**
117
     * An instance of the Output class
118
     *
119
     * @var \League\CLImate\Util\Output $output
120
     */
121
    public $output;
122
123
    /**
124
     * An instance of the Util Factory
125
     *
126
     * @var \League\CLImate\Util\UtilFactory $util
127
     */
128 948
    protected $util;
129
130 948
    public function __construct()
131 948
    {
132 948
        $this->setStyle(new Style());
133 948
        $this->setRouter(new Router());
134 948
        $this->setSettingsManager(new SettingsManager());
135 948
        $this->setOutput(new Output());
136 948
        $this->setUtil(new UtilFactory());
137
        $this->setArgumentManager(new ArgumentManager());
138
    }
139
140
    /**
141
     * Set the style property
142
     *
143 948
     * @param \League\CLImate\Decorator\Style $style
144
     */
145 948
    public function setStyle(Style $style)
146 948
    {
147
        $this->style = $style;
148
    }
149
150
    /**
151
     * Set the router property
152
     *
153 948
     * @param \League\CLImate\TerminalObject\Router\Router $router
154
     */
155 948
    public function setRouter(Router $router)
156 948
    {
157
        $this->router = $router;
158
    }
159
160
    /**
161
     * Set the settings property
162
     *
163 948
     * @param \League\CLImate\Settings\Manager $manager
164
     */
165 948
    public function setSettingsManager(SettingsManager $manager)
166 948
    {
167
        $this->settings = $manager;
168
    }
169
170
    /**
171
     * Set the arguments property
172
     *
173 948
     * @param \League\CLImate\Argument\Manager $manager
174
     */
175 948
    public function setArgumentManager(ArgumentManager $manager)
176 948
    {
177
        $this->arguments = $manager;
178
    }
179
180
    /**
181
     * Set the output property
182
     *
183 948
     * @param \League\CLImate\Util\Output $output
184
     */
185 948
    public function setOutput(Output $output)
186 948
    {
187
        $this->output = $output;
188
    }
189
190
    /**
191
     * Set the util property
192
     *
193 948
     * @param \League\CLImate\Util\UtilFactory $util
194
     */
195 948
    public function setUtil(UtilFactory $util)
196 948
    {
197
        $this->util = $util;
198
    }
199
200
    /**
201
     * Extend CLImate with custom methods
202
     *
203
     * @param string|object|array $class
204
     * @param string $key Optional custom key instead of class name
205
     *
206 36
     * @return \League\CLImate\CLImate
207
     */
208 36
    public function extend($class, $key = null)
209
    {
210 28
        $this->router->addExtension($key, $class);
0 ignored issues
show
Bug introduced by Joe Tannenbaum
It seems like $class defined by parameter $class on line 208 can also be of type array or object; however, League\CLImate\TerminalO...\Router::addExtension() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
211
212
        return $this;
213
    }
214
215
    /**
216
     * Force ansi support on
217
     *
218 4
     * @return \League\CLImate\CLImate
219
     */
220 4
    public function forceAnsiOn()
221
    {
222 4
        $this->util->system->forceAnsi();
223
224
        return $this;
225
    }
226
227
    /**
228
     * Force ansi support off
229
     *
230 4
     * @return \League\CLImate\CLImate
231
     */
232 4
    public function forceAnsiOff()
233
    {
234 4
        $this->util->system->forceAnsi(false);
235
236
        return $this;
237
    }
238
239
    /**
240
     * Write line to writer once
241
     *
242
     * @param string|array $writer
243
     *
244 4
     * @return \League\CLImate\CLImate
245
     */
246 4
    public function to($writer)
247
    {
248 4
        $this->output->once($writer);
249
250
        return $this;
251
    }
252
253
    /**
254
     * Output the program's usage statement
255
     *
256 4
     * @param array $argv
257
     */
258 4
    public function usage(array $argv = null)
259
    {
260
        return $this->arguments->usage($this, $argv);
261
    }
262
263
    /**
264
     * Set the program's description
265
     *
266
     * @param string $description
267
     *
268 4
     * @return \League\CLImate\CLImate
269
     */
270 4
    public function description($description)
271
    {
272 4
        $this->arguments->description($description);
273
274
        return $this;
275
    }
276
277
    /**
278
     * Check if we have valid output
279
     *
280
     * @param  mixed   $output
281
     *
282 76
     * @return boolean
283
     */
284 76
    protected function hasOutput($output)
285 48
    {
286
        if (!empty($output)) {
287
            return true;
288
        }
289 40
290
        // Check for type first to avoid errors with objects/arrays/etc
291
        return ((is_string($output) || is_numeric($output)) && strlen($output) > 0);
292
    }
293
294
    /**
295
     * Search for the method within the string
296
     * and route it if we find one.
297
     *
298
     * @param  string $method
299
     * @param  string $name
300
     *
301 568
     * @return string The new string without the executed method.
302
     */
303
    protected function parseStyleMethod($method, $name)
304 568
    {
305
        // If the name starts with this method string...
306 112
        if (substr($name, 0, strlen($method)) == $method) {
307
            // ...remove the method name from the beginning of the string...
308
            $name = substr($name, strlen($method));
309 112
310
            // ...and trim off any of those underscores hanging around
311 112
            $name = ltrim($name, '_');
312 112
313
            $this->style->set($method);
314 568
        }
315
316
        return $name;
317
    }
318
319
    /**
320
     * Search for any style methods within the name and apply them
321
     *
322
     * @param  string $name
323
     * @param  array $method_search
324
     *
325 568
     * @return string Anything left over after applying styles
326
     */
327
    protected function applyStyleMethods($name, $method_search = null)
328 568
    {
329
        // Get all of the possible style attributes
330 568
        $method_search = $method_search ?: array_keys($this->style->all());
331
332
        $new_name = $this->searchForStyleMethods($name, $method_search);
333
334 568
        // While we still have a name left and we keep finding methods,
335 36
        // loop through the possibilities
336
        if (strlen($new_name) > 0 && $new_name != $name) {
337
            return $this->applyStyleMethods($new_name, $method_search);
338 568
        }
339
340
        return $new_name;
341
    }
342
343
    /**
344
     * Search for style methods in the current name
345
     *
346
     * @param string $name
347
     * @param array $search
348 568
     * @return string
349
     */
350
    protected function searchForStyleMethods($name, $search)
351 568
    {
352
        // Loop through the possible methods
353 568
        foreach ($search as $method) {
354 568
            // See if we found a valid method
355
            $name = $this->parseStyleMethod($method, $name);
356 568
        }
357
358
        return $name;
359
    }
360
361
    /**
362
     * Build up the terminal object and return it
363
     *
364
     * @param string $name
365
     * @param array $arguments
366
     *
367 568
     * @return object|null
368
     */
369
    protected function buildTerminalObject($name, $arguments)
370 568
    {
371
        // Retrieve the parser for the current set of styles
372
        $parser = $this->style->parser($this->util->system);
373 568
374
        // Reset the styles
375
        $this->style->reset();
376 568
377 568
        // Execute the terminal object
378 568
        $this->router->settings($this->settings);
379 568
        $this->router->parser($parser);
380
        $this->router->output($this->output);
381 568
        $this->router->util($this->util);
382
383
        return $this->router->execute($name, $arguments);
384
    }
385
386
    /**
387
     * Route anything leftover after styles were applied
388
     *
389
     * @param string $name
390
     * @param array $arguments
391
     *
392 568
     * @return object|null
393
     */
394
    protected function routeRemainingMethod($name, array $arguments)
395 568
    {
396 568
        // If we still have something left, let's figure out what it is
397
        if ($this->router->exists($name)) {
398
            $obj = $this->buildTerminalObject($name, $arguments);
399 568
400 224
            // If something was returned, return it
401
            if (is_object($obj)) {
402 388
                return $obj;
403 44
            }
404
        } elseif ($this->settings->exists($name)) {
405 44
            $this->settings->add($name, reset($arguments));
406
        // Handle passthroughs to the arguments manager.
407 4
        } else {
408
            // If we can't find it at this point, let's fail gracefully
409 388
            $this->out(reset($arguments));
410
        }
411
    }
412
413
    /**
414
     * Magic method for anything called that doesn't exist
415
     *
416
     * @param string $requested_method
417
     * @param array  $arguments
418
     *
419
     * @return \League\CLImate\CLImate|\League\CLImate\TerminalObject\Dynamic\DynamicTerminalObject
420
     *
421
     * List of many of the possible method being called here
422 568
     * documented at the top of this class.
423
     */
424
    public function __call($requested_method, $arguments)
425 568
    {
426
        // Apply any style methods that we can find first
427
        $name = $this->applyStyleMethods(Helper::snakeCase($requested_method));
428 568
429
        // The first argument is the string|array|object we want to echo out
430 568
        $output = reset($arguments);
431
432 568
        if (strlen($name)) {
433 224
            // If we have something left, let's try and route it to the appropriate place
434
            if ($result = $this->routeRemainingMethod($name, $arguments)) {
435 388
                return $result;
436
            }
437 48
        } elseif ($this->hasOutput($output)) {
438 48
            // If we have fulfilled all of the requested methods and we have output, output it
439
            $this->out($output);
440 388
        }
441
442
        return $this;
443
    }
444
}
445