Passed
Push — master ( 78d144...82c48c )
by Alec
02:16
created

Spinner::refineSettings()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 9
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 10
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\Cli\Tools\Cursor;
8
use AlecRabbit\Spinner\Core\Adapters\EchoOutputAdapter;
9
use AlecRabbit\Spinner\Core\Contracts\SettingsInterface;
10
use AlecRabbit\Spinner\Core\Contracts\SpinnerInterface;
11
use AlecRabbit\Spinner\Core\Contracts\SpinnerOutputInterface;
12
use AlecRabbit\Spinner\Core\Contracts\SpinnerSymbols;
13
use function AlecRabbit\typeOf;
14
use const AlecRabbit\ESC;
15
16
abstract class Spinner implements SpinnerInterface
17
{
18
    protected const ERASING_SHIFT = SettingsInterface::DEFAULT_ERASING_SHIFT;
19
    protected const INTERVAL = SettingsInterface::DEFAULT_INTERVAL;
20
    protected const SYMBOLS = SpinnerSymbols::DIAMOND;
21
    protected const STYLES = [];
22
23
    /** @var string */
24
    protected $messageStr;
25
    /** @var string */
26
    protected $percentStr = '';
27
    /** @var string */
28
    protected $percentPrefix;
29
    /** @var string */
30
    protected $moveBackSequenceStr;
31
    /** @var string */
32
    protected $inlinePaddingStr;
33
    /** @var string */
34
    protected $eraseBySpacesStr;
35
    /** @var Style */
36
    protected $style;
37
    /** @var float */
38
    protected $interval;
39
    /** @var int */
40
    protected $erasingShift;
41
    /** @var Circular */
42
    protected $symbols;
43
    /** @var null|SpinnerOutputInterface */
44
    protected $output;
45
46
    /**
47
     * AbstractSpinner constructor.
48
     * @param mixed $settings
49
     * @param null|bool|SpinnerOutputInterface $output
50
     * @param mixed $color
51
     */
52 19
    public function __construct($settings = null, $output = false, $color = null)
53
    {
54 19
        $this->output = $this->refineOutput($output);
55 19
        $settings = $this->refineSettings($settings);
56 18
        $this->interval = $settings->getInterval();
57 18
        $this->erasingShift = $settings->getErasingShift();
58 18
        $this->inlinePaddingStr = $settings->getInlinePaddingStr();
59 18
        $this->messageStr = $this->getMessageStr($settings);
60 18
        $this->setFields();
61 18
        $this->symbols = new Circular($settings->getSymbols());
62
        try {
63 18
            $this->style = new Style($settings->getStyles(), $color);
64 1
        } catch (\Throwable $e) {
65 1
            throw new \InvalidArgumentException(
66 1
                '[' . static::class . '] ' . $e->getMessage(),
67 1
                (int)$e->getCode(),
68 1
                $e
69
            );
70
        }
71 17
    }
72
73
    /**
74
     * @param null|bool|SpinnerOutputInterface $output
75
     * @return null|SpinnerOutputInterface
76
     */
77 19
    protected function refineOutput($output): ?SpinnerOutputInterface
78
    {
79 19
        $this->assertOutput($output);
80 19
        if (false === $output) {
81 16
            return null;
82
        }
83 3
        return $output ?? new EchoOutputAdapter();
84
    }
85
86
    /**
87
     * @param null|bool|SpinnerOutputInterface $output
88
     */
89 19
    protected function assertOutput($output): void
90
    {
91 19
        if (null !== $output && false !== $output && !$output instanceof SpinnerOutputInterface) {
92
            dump($output);
93
            throw new \InvalidArgumentException(
94
                'Incorrect $output param null|false|SpinnerOutputInterface expected "' . typeOf($output) . '" given'
95
            );
96
        }
97 19
    }
98
99
    /**
100
     * @param mixed $settings
101
     * @return SettingsInterface
102
     */
103 19
    protected function refineSettings($settings): SettingsInterface
104
    {
105 19
        $this->assertSettings($settings);
106 18
        if (\is_string($settings)) {
107
            return
108 13
                $this->defaultSettings()->setMessage($settings);
109
        }
110
        return
111 5
            $settings ?? $this->defaultSettings();
112
    }
113
114
    /**
115
     * @param mixed $settings
116
     */
117 19
    protected function assertSettings($settings): void
118
    {
119 19
        if (null !== $settings && !\is_string($settings) && !$settings instanceof SettingsInterface) {
120 1
            throw new \InvalidArgumentException(
121 1
                'Instance of SettingsInterface or string expected ' . typeOf($settings) . ' given.'
122
            );
123
        }
124 18
    }
125
126
    /**
127
     * @return SettingsInterface
128
     */
129 15
    protected function defaultSettings(): SettingsInterface
130
    {
131
        return
132 15
            (new Settings())
133 15
                ->setInterval(static::INTERVAL)
134 15
                ->setErasingShift(static::ERASING_SHIFT)
135 15
                ->setSymbols(static::SYMBOLS)
136 15
                ->setStyles(static::STYLES);
137
    }
138
139
    /**
140
     * @param SettingsInterface $settings
141
     * @return string
142
     */
143 18
    protected function getMessageStr(SettingsInterface $settings): string
144
    {
145 18
        return $settings->getPrefix() . ucfirst($settings->getMessage()) . $settings->getSuffix();
146
    }
147
148 18
    protected function setFields(): void
149
    {
150 18
        $this->percentPrefix = $this->getPercentPrefix();
151
        $strLen =
152 18
            strlen($this->message()) + strlen($this->percent()) + strlen($this->inlinePaddingStr) + $this->erasingShift;
153 18
        $this->moveBackSequenceStr = ESC . "[{$strLen}D";
154 18
        $this->eraseBySpacesStr = str_repeat(SettingsInterface::ONE_SPACE_SYMBOL, $strLen);
155 18
    }
156
157
    /**
158
     * @return string
159
     */
160 18
    protected function getPercentPrefix(): string
161
    {
162 18
        if (strpos($this->messageStr, SettingsInterface::DEFAULT_SUFFIX)) {
163 15
            return SettingsInterface::ONE_SPACE_SYMBOL;
164
        }
165 3
        return SettingsInterface::EMPTY;
166
    }
167
168
    /**
169
     * @return string
170
     */
171 18
    protected function message(): string
172
    {
173 18
        return $this->messageStr;
174
    }
175
176
    /**
177
     * @return string
178
     */
179 18
    protected function percent(): string
180
    {
181 18
        return $this->percentStr;
182
    }
183
184 2
    public function interval(): float
185
    {
186 2
        return $this->interval;
187
    }
188
189 4
    public function inline(bool $inline): SpinnerInterface
190
    {
191 4
        $this->inlinePaddingStr = $inline ? SettingsInterface::ONE_SPACE_SYMBOL : SettingsInterface::EMPTY;
192 4
        $this->setFields();
193 4
        return $this;
194
    }
195
196
    /** {@inheritDoc} */
197 14
    public function begin(?float $percent = null): string
198
    {
199 14
        if ($this->output) {
200 3
            $this->output->write(Cursor::hide());
201 3
            $this->spin($percent);
202 3
            return '';
203
        }
204 11
        return Cursor::hide() . $this->spin($percent);
205
    }
206
207
    /** {@inheritDoc} */
208 14
    public function spin(?float $percent = null): string
209
    {
210 14
        if (null !== $percent) {
211 4
            $this->updatePercent($percent);
212
        }
213 14
        $str = $this->inlinePaddingStr .
214 14
            $this->style->spinner((string)$this->symbols->value()) .
215 14
            $this->style->message(
216 14
                $this->message()
217
            ) .
218 14
            $this->style->percent(
219 14
                $this->percent()
220
            ) .
221 14
            $this->moveBackSequenceStr;
222 14
        if ($this->output) {
223 3
            $this->output->write($str);
224 3
            return '';
225
        }
226
        return
227 11
            $str;
228
    }
229
230
    /**
231
     * @param float $percent
232
     */
233 4
    protected function updatePercent(float $percent): void
234
    {
235 4
        if (0 === (int)($percent * 1000) % 10) {
236 4
            $this->percentStr = Pretty::percent($percent, 0, $this->percentPrefix);
237 4
            $this->setFields();
238
        }
239 4
    }
240
241
    /** {@inheritDoc} */
242 14
    public function end(): string
243
    {
244 14
        if ($this->output) {
245 3
            $this->erase();
246 3
            $this->output->write(Cursor::show());
247 3
            return '';
248
        }
249 11
        return $this->erase() . Cursor::show();
250
    }
251
252
    /** {@inheritDoc} */
253 14
    public function erase(): string
254
    {
255 14
        $str = $this->eraseBySpacesStr . $this->moveBackSequenceStr;
256 14
        if ($this->output) {
257 3
            $this->output->write($str);
258 3
            return '';
259
        }
260 11
        return $str;
261
    }
262
}
263