Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
58.62% |
34 / 58 |
|
44.44% |
4 / 9 |
CRAP | |
0.00% |
0 / 1 |
CliVersion | |
58.62% |
34 / 58 |
|
44.44% |
4 / 9 |
93.77 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
tryParseCore | |
92.31% |
24 / 26 |
|
0.00% |
0 / 1 |
11.06 | |||
tryParse | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
parse | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
compare | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
90 | |||
toCompare | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isEquals | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
toString | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__toString | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace PeServer\Core\Version; |
6 | |
7 | use Exception; |
8 | use Stringable; |
9 | use PeServer\Core\Collection\Arr; |
10 | use PeServer\Core\Regex; |
11 | use PeServer\Core\Text; |
12 | use PeServer\Core\Throws\ArgumentException; |
13 | use PeServer\Core\Throws\ParseException; |
14 | use PeServer\Core\Throws\RegexException; |
15 | use PeServer\Core\TypeUtility; |
16 | |
17 | /** |
18 | * .NET のバージョンクラスと同じ扱い。 |
19 | */ |
20 | |
21 | readonly class CliVersion implements Stringable |
22 | { |
23 | #region define |
24 | |
25 | public const IGNORE_REVISION = -1; |
26 | |
27 | #endregion |
28 | |
29 | /** |
30 | * 生成 |
31 | * |
32 | * @param int $major |
33 | * @phpstan-param non-negative-int $major |
34 | * @param int $minor |
35 | * @phpstan-param non-negative-int $minor |
36 | * @param int $build |
37 | * @phpstan-param non-negative-int $build |
38 | * @param int $revision |
39 | * @phpstan-param self::IGNORE_REVISION|non-negative-int $revision |
40 | */ |
41 | public function __construct(int $major, int $minor = 0, int $build = 0, int $revision = self::IGNORE_REVISION) |
42 | { |
43 | $this->major = $major; |
44 | $this->minor = $minor; |
45 | $this->build = $build; |
46 | $this->revision = 0 <= $revision ? $revision : self::IGNORE_REVISION; |
47 | } |
48 | |
49 | #region property |
50 | |
51 | /** |
52 | * [1] メジャー バージョン。 |
53 | * @phpstan-var non-negative-int |
54 | */ |
55 | public int $major; |
56 | /** |
57 | * [2] マイナー バージョン。 |
58 | * @phpstan-var non-negative-int |
59 | */ |
60 | public int $minor; |
61 | /** |
62 | * [3] ビルド バージョン。 |
63 | * @phpstan-var non-negative-int |
64 | */ |
65 | public int $build; |
66 | /** |
67 | * [4] リビジョン バージョン。 |
68 | * @phpstan-var -1|non-negative-int |
69 | */ |
70 | public int $revision; |
71 | |
72 | #endregion |
73 | |
74 | #region function |
75 | |
76 | /** |
77 | * |
78 | * @param null|string $s |
79 | * @param null|CliVersion $result |
80 | * @return bool |
81 | * @phpstan-assert-if-true CliVersion $result |
82 | * @phpstan-assert-if-false null $result |
83 | * @throws ArgumentException |
84 | * @throws RegexException |
85 | */ |
86 | private static function tryParseCore(?string $s, ?CliVersion &$result): bool |
87 | { |
88 | if (Text::isNullOrWhiteSpace($s)) { |
89 | return false; |
90 | } |
91 | |
92 | $regex = new Regex(); |
93 | try { |
94 | $matches = $regex->matches($s, '/^(?<MAJOR>\d+)(\.(?<MINOR>\d+)(\.(?<BUILD>\d+)(\.(?<REVISION>\d+))?)?)?$/'); |
95 | $elementCount = Arr::getCount($matches); |
96 | |
97 | if ($elementCount === 0) { |
98 | return false; |
99 | } |
100 | |
101 | $major = 0; |
102 | $minor = 0; |
103 | $build = 0; |
104 | $revision = self::IGNORE_REVISION; |
105 | |
106 | if (isset($matches['MAJOR'])) { |
107 | $major = TypeUtility::parseUInteger($matches['MAJOR']); |
108 | } |
109 | if (isset($matches['MINOR'])) { |
110 | if (TypeUtility::tryParseUInteger($matches['MINOR'], $value)) { |
111 | $minor = $value; |
112 | } |
113 | } |
114 | if (isset($matches['BUILD'])) { |
115 | if (TypeUtility::tryParseUInteger($matches['BUILD'], $value)) { |
116 | $build = $value; |
117 | } |
118 | } |
119 | if (isset($matches['REVISION'])) { |
120 | if (TypeUtility::tryParseUInteger($matches['REVISION'], $value)) { |
121 | $revision = $value; |
122 | } |
123 | } |
124 | |
125 | $result = new self($major, $minor, $build, $revision); |
126 | |
127 | return true; |
128 | } catch (Exception) { |
129 | return false; |
130 | } |
131 | } |
132 | |
133 | public static function tryParse(?string $s, ?CliVersion &$result): bool |
134 | { |
135 | return self::tryParseCore($s, $result); |
136 | } |
137 | |
138 | public static function parse(?string $s): CliVersion |
139 | { |
140 | if (self::tryParseCore($s, $result)) { |
141 | return $result; |
142 | } |
143 | |
144 | throw new ParseException(); |
145 | } |
146 | |
147 | public static function compare(CliVersion $a, CliVersion $b): int |
148 | { |
149 | if ($a->major != $b->major) { |
150 | if ($a->major > $b->major) { |
151 | return 1; |
152 | } |
153 | return -1; |
154 | } |
155 | |
156 | if ($a->minor != $b->minor) { |
157 | if ($a->minor > $b->minor) { |
158 | return 1; |
159 | } |
160 | return -1; |
161 | } |
162 | |
163 | if ($a->build != $b->build) { |
164 | if ($a->build > $b->build) { |
165 | return 1; |
166 | } |
167 | return -1; |
168 | } |
169 | |
170 | if ($a->revision != $b->revision) { |
171 | if ($a->revision > $b->revision) { |
172 | return 1; |
173 | } |
174 | return -1; |
175 | } |
176 | |
177 | return 0; |
178 | } |
179 | |
180 | public function toCompare(CliVersion $version): int |
181 | { |
182 | return self::compare($this, $version); |
183 | } |
184 | |
185 | public function isEquals(CliVersion $version): bool |
186 | { |
187 | return !self::compare($this, $version); |
188 | } |
189 | |
190 | public function toString(): string |
191 | { |
192 | return $this->__toString(); |
193 | } |
194 | |
195 | #endregion |
196 | |
197 | #region Stringable |
198 | |
199 | public function __toString(): string |
200 | { |
201 | $result = "{$this->major}.{$this->minor}.{$this->build}"; |
202 | if ($this->revision !== self::IGNORE_REVISION) { |
203 | $result .= ".{$this->revision}"; |
204 | } |
205 | |
206 | return $result; |
207 | } |
208 | |
209 | #endregion |
210 | } |