Passed
Push — master ( 96250d...20e888 )
by Alec
02:06
created

Spinner::updatePercent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php declare(strict_types=1);
2
3
namespace AlecRabbit\Spinner\Core;
4
5
use AlecRabbit\Accessories\Circular;
6
use AlecRabbit\Accessories\Pretty;
7
use AlecRabbit\ConsoleColour\ConsoleColor;
8
use AlecRabbit\Control\Cursor;
9
use AlecRabbit\Spinner\Contracts\SettingsInterface;
10
use AlecRabbit\Spinner\Contracts\SpinnerInterface;
11
use AlecRabbit\Spinner\Contracts\SpinnerSymbols;
12
use AlecRabbit\Spinner\Contracts\StylesInterface;
13
use function AlecRabbit\typeOf;
14
15
class Spinner implements SpinnerInterface
16
{
17
    protected const ERASING_SHIFT = 1;
18
    protected const INTERVAL = 0.125;
19
    protected const SYMBOLS = SpinnerSymbols::DIAMOND;
20
    protected const NEW_STYLES = [];
21
22
    /** @var string */
23
    protected $messageStr;
24
    /** @var string */
25
    protected $percentStr = '';
26
    /** @var string */
27
    protected $percentPrefix;
28
    /** @var string */
29
    protected $moveBackSequenceStr;
30
    /** @var string */
31
    protected $inlinePaddingStr;
32
    /** @var string */
33
    protected $eraseBySpacesStr;
34
    /** @var Styles */
35
    protected $styles;
36
    /** @var float */
37
    protected $interval;
38
    /** @var int */
39
    protected $erasingShift;
40
    /** @var Circular */
41
    protected $symbols;
42
43
    /**
44
     * AbstractSpinner constructor.
45
     * @param mixed $settings
46
     */
47 10
    public function __construct($settings = null)
48
    {
49 10
        $settings = $this->refineSettings($settings);
50 10
        $this->interval = $settings->getInterval();
51 10
        $this->erasingShift = $settings->getErasingShift();
52 10
        $this->inlinePaddingStr = $settings->getInlinePaddingStr();
53 10
        $this->messageStr = $this->getMessageStr($settings);
54 10
        $this->setFields();
55 10
        $this->symbols = new Circular($settings->getSymbols());
56
        try {
57 10
            $this->styles = new Styles($settings->getStyles());
58
        } catch (\InvalidArgumentException $e) {
59
            throw new \InvalidArgumentException(
60
                '[' . static::class . '] ' . $e->getMessage(),
61
                (int)$e->getCode(),
62
                $e
63
            );
64
        }
65 10
    }
66
67
    /**
68
     * @param mixed $settings
69
     * @return Settings
70
     */
71 10
    protected function refineSettings($settings): Settings
72
    {
73 10
        $this->assertSettings($settings);
74 10
        if (\is_string($settings)) {
75
            return
76 8
                $this->defaultSettings()->setMessage($settings);
77
        }
78
        return
79 2
            $settings ?? $this->defaultSettings();
80
    }
81
82
    /**
83
     * @param mixed $settings
84
     */
85 10
    protected function assertSettings($settings): void
86
    {
87 10
        if (null !== $settings && !\is_string($settings) && !$settings instanceof SettingsInterface) {
88
            throw new \InvalidArgumentException(
89
                'Instance of SettingsInterface or string expected ' . typeOf($settings) . ' given.'
90
            );
91
        }
92 10
    }
93
94
    /**
95
     * @return Settings
96
     */
97 9
    protected function defaultSettings(): Settings
98
    {
99
        return
100 9
            (new Settings())
101 9
                ->setInterval(static::INTERVAL)
102 9
                ->setErasingShift(static::ERASING_SHIFT)
103 9
                ->setSymbols(static::SYMBOLS)
104 9
                ->setStyles(static::NEW_STYLES);
105
    }
106
107
    /**
108
     * @param Settings $settings
109
     * @return string
110
     */
111 10
    protected function getMessageStr(Settings $settings): string
112
    {
113 10
        return $settings->getPrefix() . ucfirst($settings->getMessage()) . $settings->getSuffix();
114
    }
115
116 10
    protected function setFields(): void
117
    {
118 10
        $this->percentPrefix = $this->getPrefix();
119
        $strLen =
120 10
            strlen($this->message()) + strlen($this->percent()) + strlen($this->inlinePaddingStr) + $this->erasingShift;
121 10
        $this->moveBackSequenceStr = ConsoleColor::ESC_CHAR . "[{$strLen}D";
122 10
        $this->eraseBySpacesStr = str_repeat(SettingsInterface::ONE_SPACE_SYMBOL, $strLen);
123 10
    }
124
125
    /**
126
     * @return string
127
     */
128 10
    protected function getPrefix(): string
129
    {
130 10
        if (strpos($this->messageStr, SettingsInterface::DEFAULT_SUFFIX)) {
131 9
            return SettingsInterface::ONE_SPACE_SYMBOL;
132
        }
133 1
        return SettingsInterface::EMPTY;
134
    }
135
136
    /**
137
     * @return string
138
     */
139 10
    protected function message(): string
140
    {
141 10
        return $this->messageStr;
142
    }
143
144
    /**
145
     * @return string
146
     */
147 10
    protected function percent(): string
148
    {
149 10
        return $this->percentStr;
150
    }
151
152 1
    public function interval(): float
153
    {
154 1
        return $this->interval;
155
    }
156
157 2
    public function inline(bool $inline): SpinnerInterface
158
    {
159 2
        $this->inlinePaddingStr = $inline ? SettingsInterface::ONE_SPACE_SYMBOL : SettingsInterface::EMPTY;
160 2
        $this->setFields();
161 2
        return $this;
162
    }
163
164
    /** {@inheritDoc} */
165 9
    public function begin(?float $percent = null): string
166
    {
167 9
        return Cursor::hide() . $this->spin($percent);
168
    }
169
170
    /** {@inheritDoc} */
171 9
    public function spin(?float $percent = null): string
172
    {
173 9
        if (null !== $percent) {
174 1
            $this->updatePercent($percent);
175
        }
176
        return
177 9
            $this->inlinePaddingStr .
178 9
            $this->styles->spinner((string)$this->symbols->value()) .
179 9
            $this->styles->message(
180 9
                $this->message()
181
            ) .
182 9
            $this->styles->percent(
183 9
                $this->percent()
184
            ) .
185 9
            $this->moveBackSequenceStr;
186
    }
187
188
    /**
189
     * @param float $percent
190
     */
191 1
    protected function updatePercent(float $percent): void
192
    {
193 1
        if (0 === (int)($percent * 1000) % 10) {
194 1
            $this->percentStr = Pretty::percent($percent, 0, $this->percentPrefix);
195 1
            $this->setFields();
196
        }
197 1
    }
198
199
    /** {@inheritDoc} */
200 9
    public function end(): string
201
    {
202 9
        return $this->erase() . Cursor::show();
203
    }
204
205
    /** {@inheritDoc} */
206 9
    public function erase(): string
207
    {
208 9
        return $this->eraseBySpacesStr . $this->moveBackSequenceStr;
209
    }
210
}
211