CLImate   A
last analyzed

Coupling/Cohesion

Components 2
Dependencies 8

Complexity

Total Complexity 34

Size/Duplication

Total Lines 359
Duplicated Lines 0 %

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.2
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A forceAnsiOn() 0 6 1
A forceAnsiOff() 0 6 1
A parseStyleMethod() 0 15 2
A applyStyleMethods() 0 15 4
A searchForStyleMethods() 0 10 2
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 to() 0 6 1
A usage() 0 4 1
A description() 0 6 1
A hasOutput() 0 9 4
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\Router\Router;
9
use League\CLImate\Util\Helper;
10
use League\CLImate\Util\Output;
11
use League\CLImate\Util\UtilFactory;
12
13
/**
14
 * @method CLImate black(string $str = null)
15
 * @method CLImate red(string $str = null)
16
 * @method CLImate green(string $str = null)
17
 * @method CLImate yellow(string $str = null)
18
 * @method CLImate blue(string $str = null)
19
 * @method CLImate magenta(string $str = null)
20
 * @method CLImate cyan(string $str = null)
21
 * @method CLImate lightGray(string $str = null)
22
 * @method CLImate darkGray(string $str = null)
23
 * @method CLImate lightRed(string $str = null)
24
 * @method CLImate lightGreen(string $str = null)
25
 * @method CLImate lightYellow(string $str = null)
26
 * @method CLImate lightBlue(string $str = null)
27
 * @method CLImate lightMagenta(string $str = null)
28
 * @method CLImate lightCyan(string $str = null)
29
 * @method CLImate white(string $str = null)
30
 *
31
 * @method CLImate backgroundBlack(string $str = null)
32
 * @method CLImate backgroundRed(string $str = null)
33
 * @method CLImate backgroundGreen(string $str = null)
34
 * @method CLImate backgroundYellow(string $str = null)
35
 * @method CLImate backgroundBlue(string $str = null)
36
 * @method CLImate backgroundMagenta(string $str = null)
37
 * @method CLImate backgroundCyan(string $str = null)
38
 * @method CLImate backgroundLightGray(string $str = null)
39
 * @method CLImate backgroundDarkGray(string $str = null)
40
 * @method CLImate backgroundLightRed(string $str = null)
41
 * @method CLImate backgroundLightGreen(string $str = null)
42
 * @method CLImate backgroundLightYellow(string $str = null)
43
 * @method CLImate backgroundLightBlue(string $str = null)
44
 * @method CLImate backgroundLightMagenta(string $str = null)
45
 * @method CLImate backgroundLightCyan(string $str = null)
46
 * @method CLImate backgroundWhite(string $str = null)
47
 *
48
 * @method CLImate bold(string $str = null)
49
 * @method CLImate dim(string $str = null)
50
 * @method CLImate underline(string $str = null)
51
 * @method CLImate blink(string $str = null)
52
 * @method CLImate invert(string $str = null)
53
 * @method CLImate hidden(string $str = null)
54
 *
55
 * @method CLImate info(string $str = null)
56
 * @method CLImate comment(string $str = null)
57
 * @method CLImate whisper(string $str = null)
58
 * @method CLImate shout(string $str = null)
59
 * @method CLImate error(string $str = null)
60
 *
61
 * @method mixed out(string $str)
62
 * @method mixed inline(string $str)
63
 * @method mixed table(array $data)
64
 * @method mixed json(mixed $var)
65
 * @method mixed br($count = 1)
66
 * @method mixed tab($count = 1)
67
 * @method mixed draw(string $art)
68
 * @method mixed border(string $char = null, integer $length = null)
69
 * @method mixed dump(mixed $var)
70
 * @method mixed flank(string $output, string $char = null, integer $length = null)
71
 * @method mixed progress(integer $total = null)
72
 * @method mixed padding(integer $length = 0, string $char = '.')
73
 * @method mixed input(string $prompt, Util\Reader\ReaderInterface $reader = null)
74
 * @method mixed confirm(string $prompt, Util\Reader\ReaderInterface $reader = null)
75
 * @method mixed password(string $prompt, Util\Reader\ReaderInterface $reader = null)
76
 * @method mixed checkboxes(string $prompt, array $options, Util\Reader\ReaderInterface $reader = null)
77
 * @method mixed radio(string $prompt, array $options, Util\Reader\ReaderInterface $reader = null)
78
 * @method mixed animation(string $art, TerminalObject\Helper\Sleeper $sleeper = null)
79
 * @method mixed columns(array $data, $column_count = null)
80
 * @method mixed clear()
81
 *
82
 * @method CLImate addArt(string $dir)
83
 */
84
class CLImate
85
{
86
    /**
87
     * An instance of the Style class
88
     *
89
     * @var \League\CLImate\Decorator\Style $style
90
     */
91
    public $style;
92
93
    /**
94
     * An instance of the Terminal Object Router class
95
     *
96
     * @var \League\CLImate\TerminalObject\Router\Router $router
97
     */
98
    protected $router;
99
100
    /**
101
     * An instance of the Settings Manager class
102
     *
103
     * @var \League\CLImate\Settings\Manager $settings
104
     */
105
    protected $settings;
106
107
    /**
108
     * An instance of the Argument Manager class
109
     *
110
     * @var \League\CLImate\Argument\Manager $arguments
111
     */
112
    public $arguments;
113
114
    /**
115
     * An instance of the Output class
116
     *
117
     * @var \League\CLImate\Util\Output $output
118
     */
119
    public $output;
120
121
    /**
122
     * An instance of the Util Factory
123
     *
124
     * @var \League\CLImate\Util\UtilFactory $util
125
     */
126
    protected $util;
127
128 948
    public function __construct()
129
    {
130 948
        $this->setStyle(new Style());
131 948
        $this->setRouter(new Router());
132 948
        $this->setSettingsManager(new SettingsManager());
133 948
        $this->setOutput(new Output());
134 948
        $this->setUtil(new UtilFactory());
135 948
        $this->setArgumentManager(new ArgumentManager());
136 948
    }
137
138
    /**
139
     * Set the style property
140
     *
141
     * @param \League\CLImate\Decorator\Style $style
142
     */
143 948
    public function setStyle(Style $style)
144
    {
145 948
        $this->style = $style;
146 948
    }
147
148
    /**
149
     * Set the router property
150
     *
151
     * @param \League\CLImate\TerminalObject\Router\Router $router
152
     */
153 948
    public function setRouter(Router $router)
154
    {
155 948
        $this->router = $router;
156 948
    }
157
158
    /**
159
     * Set the settings property
160
     *
161
     * @param \League\CLImate\Settings\Manager $manager
162
     */
163 948
    public function setSettingsManager(SettingsManager $manager)
164
    {
165 948
        $this->settings = $manager;
166 948
    }
167
168
    /**
169
     * Set the arguments property
170
     *
171
     * @param \League\CLImate\Argument\Manager $manager
172
     */
173 948
    public function setArgumentManager(ArgumentManager $manager)
174
    {
175 948
        $this->arguments = $manager;
176 948
    }
177
178
    /**
179
     * Set the output property
180
     *
181
     * @param \League\CLImate\Util\Output $output
182
     */
183 948
    public function setOutput(Output $output)
184
    {
185 948
        $this->output = $output;
186 948
    }
187
188
    /**
189
     * Set the util property
190
     *
191
     * @param \League\CLImate\Util\UtilFactory $util
192
     */
193 948
    public function setUtil(UtilFactory $util)
194
    {
195 948
        $this->util = $util;
196 948
    }
197
198
    /**
199
     * Extend CLImate with custom methods
200
     *
201
     * @param string|object|array $class
202
     * @param string $key Optional custom key instead of class name
203
     *
204
     * @return \League\CLImate\CLImate
205
     */
206 36
    public function extend($class, $key = null)
207
    {
208 36
        $this->router->addExtension($key, $class);
0 ignored issues
show
Bug introduced by Joe Tannenbaum
It seems like $class defined by parameter $class on line 206 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...
209
210 28
        return $this;
211
    }
212
213
    /**
214
     * Force ansi support on
215
     *
216
     * @return \League\CLImate\CLImate
217
     */
218 4
    public function forceAnsiOn()
219
    {
220 4
        $this->util->system->forceAnsi();
221
222 4
        return $this;
223
    }
224
225
    /**
226
     * Force ansi support off
227
     *
228
     * @return \League\CLImate\CLImate
229
     */
230 4
    public function forceAnsiOff()
231
    {
232 4
        $this->util->system->forceAnsi(false);
233
234 4
        return $this;
235
    }
236
237
    /**
238
     * Write line to writer once
239
     *
240
     * @param string|array $writer
241
     *
242
     * @return \League\CLImate\CLImate
243
     */
244 4
    public function to($writer)
245
    {
246 4
        $this->output->once($writer);
247
248 4
        return $this;
249
    }
250
251
    /**
252
     * Output the program's usage statement
253
     *
254
     * @param array $argv
255
     */
256 4
    public function usage(array $argv = null)
257
    {
258 4
        return $this->arguments->usage($this, $argv);
259
    }
260
261
    /**
262
     * Set the program's description
263
     *
264
     * @param string $description
265
     *
266
     * @return \League\CLImate\CLImate
267
     */
268 4
    public function description($description)
269
    {
270 4
        $this->arguments->description($description);
271
272 4
        return $this;
273
    }
274
275
    /**
276
     * Check if we have valid output
277
     *
278
     * @param  mixed   $output
279
     *
280
     * @return boolean
281
     */
282 76
    protected function hasOutput($output)
283
    {
284 76
        if (!empty($output)) {
285 48
            return true;
286
        }
287
288
        // Check for type first to avoid errors with objects/arrays/etc
289 40
        return ((is_string($output) || is_numeric($output)) && strlen($output) > 0);
290
    }
291
292
    /**
293
     * Search for the method within the string
294
     * and route it if we find one.
295
     *
296
     * @param  string $method
297
     * @param  string $name
298
     *
299
     * @return string The new string without the executed method.
300
     */
301 568
    protected function parseStyleMethod($method, $name)
302
    {
303
        // If the name starts with this method string...
304 568
        if (substr($name, 0, strlen($method)) == $method) {
305
            // ...remove the method name from the beginning of the string...
306 112
            $name = substr($name, strlen($method));
307
308
            // ...and trim off any of those underscores hanging around
309 112
            $name = ltrim($name, '_');
310
311 112
            $this->style->set($method);
312 112
        }
313
314 568
        return $name;
315
    }
316
317
    /**
318
     * Search for any style methods within the name and apply them
319
     *
320
     * @param  string $name
321
     * @param  array $method_search
322
     *
323
     * @return string Anything left over after applying styles
324
     */
325 568
    protected function applyStyleMethods($name, $method_search = null)
326
    {
327
        // Get all of the possible style attributes
328 568
        $method_search = $method_search ?: array_keys($this->style->all());
329
330 568
        $new_name = $this->searchForStyleMethods($name, $method_search);
331
332
        // While we still have a name left and we keep finding methods,
333
        // loop through the possibilities
334 568
        if (strlen($new_name) > 0 && $new_name != $name) {
335 36
            return $this->applyStyleMethods($new_name, $method_search);
336
        }
337
338 568
        return $new_name;
339
    }
340
341
    /**
342
     * Search for style methods in the current name
343
     *
344
     * @param string $name
345
     * @param array $search
346
     * @return string
347
     */
348 568
    protected function searchForStyleMethods($name, $search)
349
    {
350
        // Loop through the possible methods
351 568
        foreach ($search as $method) {
352
            // See if we found a valid method
353 568
            $name = $this->parseStyleMethod($method, $name);
354 568
        }
355
356 568
        return $name;
357
    }
358
359
    /**
360
     * Build up the terminal object and return it
361
     *
362
     * @param string $name
363
     * @param array $arguments
364
     *
365
     * @return object|null
366
     */
367 568
    protected function buildTerminalObject($name, $arguments)
368
    {
369
        // Retrieve the parser for the current set of styles
370 568
        $parser = $this->style->parser($this->util->system);
371
372
        // Reset the styles
373 568
        $this->style->reset();
374
375
        // Execute the terminal object
376 568
        $this->router->settings($this->settings);
377 568
        $this->router->parser($parser);
378 568
        $this->router->output($this->output);
379 568
        $this->router->util($this->util);
380
381 568
        return $this->router->execute($name, $arguments);
382
    }
383
384
    /**
385
     * Route anything leftover after styles were applied
386
     *
387
     * @param string $name
388
     * @param array $arguments
389
     *
390
     * @return object|null
391
     */
392 568
    protected function routeRemainingMethod($name, array $arguments)
393
    {
394
        // If we still have something left, let's figure out what it is
395 568
        if ($this->router->exists($name)) {
396 568
            $obj = $this->buildTerminalObject($name, $arguments);
397
398
            // If something was returned, return it
399 568
            if (is_object($obj)) {
400 224
                return $obj;
401
            }
402 388
        } elseif ($this->settings->exists($name)) {
403 44
            $this->settings->add($name, reset($arguments));
404
        // Handle passthroughs to the arguments manager.
405 44
        } else {
406
            // If we can't find it at this point, let's fail gracefully
407 4
            $this->out(reset($arguments));
408
        }
409 388
    }
410
411
    /**
412
     * Magic method for anything called that doesn't exist
413
     *
414
     * @param string $requested_method
415
     * @param array  $arguments
416
     *
417
     * @return \League\CLImate\CLImate|\League\CLImate\TerminalObject\Dynamic\DynamicTerminalObject
418
     *
419
     * List of many of the possible method being called here
420
     * documented at the top of this class.
421
     */
422 568
    public function __call($requested_method, $arguments)
423
    {
424
        // Apply any style methods that we can find first
425 568
        $name = $this->applyStyleMethods(Helper::snakeCase($requested_method));
426
427
        // The first argument is the string|array|object we want to echo out
428 568
        $output = reset($arguments);
429
430 568
        if (strlen($name)) {
431
            // If we have something left, let's try and route it to the appropriate place
432 568
            if ($result = $this->routeRemainingMethod($name, $arguments)) {
433 224
                return $result;
434
            }
435 388
        } elseif ($this->hasOutput($output)) {
436
            // If we have fulfilled all of the requested methods and we have output, output it
437 48
            $this->out($output);
438 48
        }
439
440 388
        return $this;
441
    }
442
}
443