|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* PHP: Nelson Martell Library file |
|
4
|
|
|
* |
|
5
|
|
|
* Content: |
|
6
|
|
|
* - Class definition: [NelsonMartell] Version |
|
7
|
|
|
* |
|
8
|
|
|
* Copyright © 2015-2016 Nelson Martell (http://nelson6e65.github.io) |
|
9
|
|
|
* |
|
10
|
|
|
* Licensed under The MIT License (MIT) |
|
11
|
|
|
* For full copyright and license information, please see the LICENSE |
|
12
|
|
|
* Redistributions of files must retain the above copyright notice. |
|
13
|
|
|
* |
|
14
|
|
|
* @copyright 2015-2016 Nelson Martell |
|
15
|
|
|
* @link http://nelson6e65.github.io/php_nml/ |
|
16
|
|
|
* @since v0.1.1 |
|
17
|
|
|
* @license http://www.opensource.org/licenses/mit-license.php The MIT License (MIT) |
|
18
|
|
|
* */ |
|
19
|
|
|
|
|
20
|
|
|
namespace NelsonMartell; |
|
21
|
|
|
|
|
22
|
|
|
use \InvalidArgumentException; |
|
23
|
|
|
|
|
24
|
|
|
/** |
|
25
|
|
|
* Representa el número de versión de un programa o ensamblado, de la forma "1.2.3.4". Sólo |
|
26
|
|
|
* siendo obligatorios el primer y segundo componente. |
|
27
|
|
|
* No se puede heredar esta clase. |
|
28
|
|
|
* |
|
29
|
|
|
* @author Nelson Martell <[email protected]> |
|
30
|
|
|
* */ |
|
31
|
|
|
final class Version extends Object implements IEquatable, IComparable |
|
32
|
|
|
{ |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* Crea una nueva instancia con los números principal, secundario, de |
|
36
|
|
|
* compilación (opcional) y revisión (opcional). |
|
37
|
|
|
* Para comprobar si la versión es válida, usar el método isValid. |
|
38
|
|
|
* |
|
39
|
|
|
* @param int $major Componente principal |
|
40
|
|
|
* @param int $minor Componente secundario |
|
41
|
|
|
* @param int|string|VersionComponent|null $build Componente de compilación |
|
42
|
|
|
* @param int|string|VersionComponent|null $revision Componente de revisión |
|
43
|
|
|
* |
|
44
|
|
|
* @throws InvalidArgumentException |
|
45
|
|
|
* */ |
|
46
|
33 |
|
public function __construct($major, $minor, $build = null, $revision = null) |
|
47
|
|
|
{ |
|
48
|
33 |
|
parent::__construct(); |
|
49
|
33 |
|
unset($this->Major, $this->Minor, $this->Build, $this->Revision); |
|
50
|
|
|
|
|
51
|
33 |
View Code Duplication |
if (!is_integer($major)) { |
|
|
|
|
|
|
52
|
|
|
$args = [ |
|
53
|
3 |
|
'class' => typeof($this)->Name, |
|
|
|
|
|
|
54
|
3 |
|
'name' => 'major', |
|
55
|
3 |
|
'pos' => 0, |
|
56
|
3 |
|
'expected' => typeof(0), |
|
|
|
|
|
|
57
|
3 |
|
'actual' => typeof($major), |
|
|
|
|
|
|
58
|
3 |
|
]; |
|
59
|
|
|
|
|
60
|
3 |
|
$msg = nml_msg('Invalid argument type.'); |
|
|
|
|
|
|
61
|
3 |
|
$msg .= nml_msg( |
|
|
|
|
|
|
62
|
3 |
|
' "{name}" (position {pos}) must to be an instance of "{expected}"; "{actual}" given.', |
|
63
|
|
|
$args |
|
64
|
3 |
|
); |
|
65
|
3 |
|
$msg .= nml_msg(' Convert value or use the "{class}::parse" (static) method.', $args); |
|
|
|
|
|
|
66
|
|
|
|
|
67
|
3 |
|
throw new InvalidArgumentException($msg); |
|
68
|
|
|
} |
|
69
|
|
|
|
|
70
|
30 |
View Code Duplication |
if (!is_integer($minor)) { |
|
|
|
|
|
|
71
|
|
|
$args = [ |
|
72
|
2 |
|
'class' => typeof($this)->Name, |
|
|
|
|
|
|
73
|
2 |
|
'name' => 'minor', |
|
74
|
2 |
|
'pos' => 1, |
|
75
|
2 |
|
'expected' => typeof(0), |
|
|
|
|
|
|
76
|
2 |
|
'actual' => typeof($minor), |
|
|
|
|
|
|
77
|
2 |
|
]; |
|
78
|
|
|
|
|
79
|
2 |
|
$msg = nml_msg('Invalid argument type.'); |
|
|
|
|
|
|
80
|
2 |
|
$msg .= nml_msg( |
|
|
|
|
|
|
81
|
2 |
|
' "{name}" (position {pos}) must to be an instance of "{expected}"; "{actual}" given.', |
|
82
|
|
|
$args |
|
83
|
2 |
|
); |
|
84
|
2 |
|
$msg .= nml_msg(' Convert value or use the "{class}::parse" (static) method.', $args); |
|
|
|
|
|
|
85
|
|
|
|
|
86
|
2 |
|
throw new InvalidArgumentException($msg); |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
28 |
View Code Duplication |
if ($major < 0) { |
|
|
|
|
|
|
90
|
|
|
$args = [ |
|
91
|
1 |
|
'name' => 'major', |
|
92
|
1 |
|
'pos' => 0, |
|
93
|
1 |
|
'actual' => $major, |
|
94
|
1 |
|
]; |
|
95
|
|
|
|
|
96
|
1 |
|
$msg = nml_msg('Invalid argument value.'); |
|
|
|
|
|
|
97
|
1 |
|
$msg .= nml_msg( |
|
|
|
|
|
|
98
|
1 |
|
' "{name}" (position {pos}) must to be a positive number; "{actual}" given.', |
|
99
|
|
|
$args |
|
100
|
1 |
|
); |
|
101
|
|
|
|
|
102
|
1 |
|
throw new InvalidArgumentException($msg); |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
27 |
View Code Duplication |
if ($minor < 0) { |
|
|
|
|
|
|
106
|
|
|
$args = [ |
|
107
|
1 |
|
'name' => 'minor', |
|
108
|
1 |
|
'pos' => 1, |
|
109
|
1 |
|
'actual' => $minor, |
|
110
|
1 |
|
]; |
|
111
|
|
|
|
|
112
|
1 |
|
$msg = nml_msg('Invalid argument value.'); |
|
|
|
|
|
|
113
|
1 |
|
$msg .= nml_msg( |
|
|
|
|
|
|
114
|
1 |
|
' "{name}" (position {pos}) must to be a positive number; "{actual}" given.', |
|
115
|
21 |
|
$args |
|
116
|
1 |
|
); |
|
117
|
|
|
|
|
118
|
1 |
|
throw new InvalidArgumentException($msg); |
|
119
|
|
|
} |
|
120
|
|
|
|
|
121
|
26 |
|
$this->major = $major; |
|
|
|
|
|
|
122
|
26 |
|
$this->minor = $minor; |
|
|
|
|
|
|
123
|
26 |
|
$this->build = VersionComponent::Parse($build); |
|
|
|
|
|
|
124
|
25 |
|
$this->revision = VersionComponent::Parse($revision); |
|
125
|
23 |
|
} |
|
126
|
|
|
|
|
127
|
|
|
/** |
|
128
|
|
|
* Convierte una cadena a su representación del tipo Version. |
|
129
|
|
|
* |
|
130
|
|
|
* @param Version|string|int|float|array $value Objeto a convertir. |
|
131
|
|
|
* |
|
132
|
|
|
* @return Version Objeto convertido desde $value. |
|
133
|
|
|
* */ |
|
134
|
26 |
|
public static function parse($value) |
|
135
|
|
|
{ |
|
136
|
11 |
|
if ($value instanceof Version) { |
|
137
|
|
|
return $value; |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
11 |
|
$version = []; |
|
141
|
|
|
|
|
142
|
|
|
// Try to convert into an array |
|
143
|
11 |
|
if (is_integer($value)) { |
|
144
|
|
|
// Integer for major value |
|
145
|
|
|
$version = [$value, 0]; |
|
146
|
11 |
|
} elseif (is_float($value)) { |
|
147
|
|
|
// Integer part as major, and decimal part as minor |
|
148
|
|
|
$version = sprintf("%F", $value); |
|
|
|
|
|
|
149
|
|
|
$version = explode('.', $version); |
|
150
|
11 |
|
} elseif (is_array($value)) { |
|
151
|
|
|
// Implode first 4 places for major, minor, build and revision respectivally. |
|
152
|
5 |
|
$version = array_slice($value, 0, 4); |
|
153
|
11 |
|
} elseif (is_string($value)) { |
|
154
|
6 |
|
$version = explode('.', $value); |
|
155
|
6 |
|
} else { |
|
156
|
|
|
$msg = nml_msg('Unable to parse. Argument passed has an invalid type: "{0}".', typeof($value)); |
|
|
|
|
|
|
157
|
|
|
throw new InvalidArgumentException($msg); |
|
158
|
|
|
} |
|
159
|
|
|
|
|
160
|
|
|
// $value ya debería ser un array. |
|
161
|
11 |
|
$c = count($version); |
|
|
|
|
|
|
162
|
|
|
|
|
163
|
26 |
|
if ($c > 4 || $c < 2) { |
|
164
|
4 |
|
$msg = nml_msg('Unable to parse. Argument passed has an invalid format: "{0}".', $value); |
|
|
|
|
|
|
165
|
|
|
//var_dump($version); |
|
166
|
4 |
|
throw new InvalidArgumentException($msg); |
|
167
|
|
|
} |
|
168
|
|
|
|
|
169
|
|
|
|
|
170
|
9 |
|
$major = (int) $version[0]; |
|
|
|
|
|
|
171
|
9 |
|
$minor = (int) $version[1]; |
|
|
|
|
|
|
172
|
9 |
|
$build = null; |
|
|
|
|
|
|
173
|
9 |
|
$revision = null; |
|
174
|
|
|
|
|
175
|
9 |
|
if (count($version) >= 3) { |
|
176
|
7 |
|
$build = VersionComponent::Parse($version[2]); |
|
177
|
|
|
|
|
178
|
7 |
|
if (count($version) == 4) { |
|
179
|
1 |
|
$revision = VersionComponent::Parse($version[3]); |
|
180
|
1 |
|
} |
|
181
|
7 |
|
} |
|
182
|
|
|
|
|
183
|
23 |
|
return new Version($major, $minor, $build, $revision); |
|
184
|
12 |
|
} |
|
185
|
|
|
|
|
186
|
|
|
/** |
|
187
|
|
|
* Obtiene el valor del componente principal del número de versión del |
|
188
|
|
|
* objeto actual. |
|
189
|
|
|
* Esta propiedad es de sólo lectura. |
|
190
|
|
|
* |
|
191
|
|
|
* @var int Componente principal del número de versión. |
|
192
|
|
|
* */ |
|
193
|
|
|
public $Major; |
|
194
|
|
|
private $major; |
|
195
|
|
|
|
|
196
|
|
|
/** |
|
197
|
|
|
* Getter for Major property. |
|
198
|
|
|
* |
|
199
|
|
|
* @return integer |
|
200
|
|
|
* @see Version::Major. |
|
201
|
|
|
*/ |
|
202
|
57 |
|
public function getMajor() |
|
203
|
|
|
{ |
|
204
|
57 |
|
return $this->major; |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
|
|
208
|
|
|
/** |
|
209
|
|
|
* Obtiene el valor del componente secundario del número de versión del |
|
210
|
|
|
* objeto actual. |
|
211
|
|
|
* Esta propiedad es de sólo lectura. |
|
212
|
|
|
* |
|
213
|
|
|
* @var int Componente secundario del número de versión. |
|
214
|
|
|
* */ |
|
215
|
|
|
public $Minor; |
|
216
|
|
|
private $minor; |
|
217
|
|
|
|
|
218
|
|
|
/** |
|
219
|
|
|
* Getter for minor property. |
|
220
|
|
|
* |
|
221
|
|
|
* @return integer |
|
222
|
|
|
* @see Version::Minor. |
|
223
|
|
|
*/ |
|
224
|
35 |
|
public function getMinor() |
|
225
|
|
|
{ |
|
226
|
35 |
|
return $this->minor; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
/** |
|
230
|
|
|
* Obtiene el valor del componente de compilación del número de versión |
|
231
|
|
|
* del objeto actual. |
|
232
|
|
|
* Esta propiedad es de sólo lectura. |
|
233
|
|
|
* |
|
234
|
|
|
* @var VersionComponent Componente de compilación del número de versión. |
|
235
|
|
|
* */ |
|
236
|
|
|
public $Build; |
|
237
|
|
|
private $build; |
|
238
|
|
|
|
|
239
|
|
|
/** |
|
240
|
|
|
* Getter for Build property. |
|
241
|
|
|
* |
|
242
|
|
|
* @return VersionComponent |
|
243
|
|
|
* @see Version::Build |
|
244
|
|
|
*/ |
|
245
|
47 |
|
public function getBuild() |
|
246
|
|
|
{ |
|
247
|
47 |
|
return $this->build; |
|
248
|
|
|
} |
|
249
|
|
|
|
|
250
|
|
|
/** |
|
251
|
|
|
* Obtiene el valor del componente de revisión del número de versión del |
|
252
|
|
|
* objeto actual. |
|
253
|
|
|
* Esta propiedad es de sólo lectura. |
|
254
|
|
|
* |
|
255
|
|
|
* @var VersionComponent Componente de revisión del número de versión. |
|
256
|
|
|
* */ |
|
257
|
|
|
public $Revision; |
|
258
|
|
|
private $revision; |
|
259
|
|
|
|
|
260
|
|
|
/** |
|
261
|
|
|
* Getter for Revision property. |
|
262
|
|
|
* |
|
263
|
|
|
* @return VersionComponent |
|
264
|
|
|
* @see Version::Revision |
|
265
|
|
|
*/ |
|
266
|
42 |
|
public function getRevision() |
|
267
|
|
|
{ |
|
268
|
42 |
|
return $this->revision; |
|
269
|
|
|
} |
|
270
|
|
|
|
|
271
|
|
|
|
|
272
|
|
|
/** |
|
273
|
|
|
* Convierte la instancia actual en su representación en cadena. |
|
274
|
|
|
* Por defecto, si no están definidos los componentes de compilación y |
|
275
|
|
|
* revisión, no se incluyen en la salida. |
|
276
|
|
|
* Use el método isValid si quiere determinar si la versión es válida |
|
277
|
|
|
* antes de devolver esta cadena. |
|
278
|
|
|
* |
|
279
|
|
|
* @return string Representación de la versión en forma de cadena: |
|
280
|
|
|
* 'major.minor[.build[.revision]]' |
|
281
|
|
|
* @see VersionComponent::isNull |
|
282
|
|
|
* @see Version::isValid |
|
283
|
|
|
* */ |
|
284
|
17 |
|
public function toString() |
|
285
|
|
|
{ |
|
286
|
16 |
|
$s[0] = $this->Major; |
|
|
|
|
|
|
287
|
16 |
|
$s[1] = $this->Minor; |
|
288
|
|
|
|
|
289
|
16 |
|
if ($this->Revision->IsNotNull()) { |
|
290
|
6 |
|
$s[2] = $this->Build; |
|
291
|
6 |
|
$s[3] = $this->Revision; |
|
292
|
6 |
|
} else { |
|
293
|
10 |
|
if ($this->Build->IsNotNull()) { |
|
294
|
6 |
|
$s[2] = $this->Build; |
|
295
|
6 |
|
} |
|
296
|
17 |
|
} |
|
297
|
16 |
|
$v = implode('.', $s); |
|
|
|
|
|
|
298
|
|
|
|
|
299
|
16 |
|
return $v; |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
/** |
|
303
|
|
|
* Indica si la instancia actual es un número de versión válido. |
|
304
|
|
|
* |
|
305
|
|
|
* Se considera válido si: |
|
306
|
|
|
* 1. Major o Minor es mayor a cero (0). No puede ser '0.0'. |
|
307
|
|
|
* 2. Build y Revision son nulos (no están definidos). |
|
308
|
|
|
* 3. Build está definido pero Revision no. |
|
309
|
|
|
* 4. Ambos están definidos, pero no poseen la parte de la cadena. |
|
310
|
|
|
* 5. Ambos están definidos, pero Build no posee la parte de cadena. |
|
311
|
|
|
* 6. Build está definido y tiene la cadena, pero Revision no está definido. |
|
312
|
|
|
* 7. Revision posee cadena, pero Build no. |
|
313
|
|
|
* |
|
314
|
|
|
* @return boolean Un valor que indica si la instancia actual es válida. |
|
315
|
|
|
* */ |
|
316
|
16 |
|
public function isValid() |
|
317
|
|
|
{ |
|
318
|
|
|
// Validación de Major y Minor: |
|
319
|
16 |
|
$r = ($this->Major > 0 or $this->Minor > 0); //#1 |
|
|
|
|
|
|
320
|
|
|
|
|
321
|
|
|
// Validación de Build y Revision: |
|
322
|
16 |
|
if ($r) { |
|
323
|
15 |
|
$r = ($this->Build->IsNull() and $this->Revision->IsNull()); // #2 |
|
|
|
|
|
|
324
|
|
|
|
|
325
|
15 |
|
if (!$r) { |
|
326
|
13 |
|
if ($this->Build->IsNotNull() and $this->Revision->IsNotNull()) { |
|
|
|
|
|
|
327
|
|
|
// Si ambos están definidos... |
|
328
|
|
|
|
|
329
|
9 |
|
$r = (bool) ($this->Build->StringValue == ''); //#5 |
|
330
|
|
|
|
|
331
|
9 |
|
if (!$r) { |
|
332
|
|
|
//#4 |
|
333
|
6 |
|
$r = (bool) (($this->Build->StringValue == '') and ($this->Revision->StringValue == '')); |
|
|
|
|
|
|
334
|
|
|
|
|
335
|
6 |
|
if (!$r) { |
|
336
|
6 |
|
if ($this->Build->StringValue != '') { |
|
337
|
6 |
|
$r = $this->Revision->IsNull(); #6 |
|
|
|
|
|
|
338
|
6 |
|
} |
|
339
|
|
|
|
|
340
|
6 |
|
if ($this->Revision->StringValue != '') { |
|
341
|
3 |
|
$r = ($this->Build->StringValue == ''); #7 |
|
|
|
|
|
|
342
|
3 |
|
} |
|
343
|
6 |
|
} |
|
344
|
6 |
|
} |
|
345
|
9 |
|
} else { |
|
346
|
4 |
|
$r = ($this->Build->IsNotNull() and $this->Revision->IsNull()); //#3 |
|
|
|
|
|
|
347
|
|
|
} |
|
348
|
13 |
|
} |
|
349
|
15 |
|
} |
|
350
|
|
|
|
|
351
|
16 |
|
return (bool) $r; |
|
352
|
|
|
} |
|
353
|
|
|
|
|
354
|
|
|
/** |
|
355
|
|
|
* Determina si el objeto $other especificado es igual a la instancia actual. |
|
356
|
|
|
* |
|
357
|
|
|
* @param Version $other El otro objeto a comparar. |
|
358
|
|
|
* |
|
359
|
|
|
* @return bool `true` si $other es igual esta instancia; caso contrario, |
|
360
|
|
|
* `false`. |
|
361
|
|
|
* */ |
|
362
|
32 |
|
public function equals($other) |
|
363
|
|
|
{ |
|
364
|
32 |
|
if ($other instanceof Version) { |
|
365
|
25 |
|
if ($this->Major == $other->Major && $this->Minor == $other->Minor) { |
|
366
|
16 |
|
if ($this->Build->equals($other->Build)) { |
|
367
|
11 |
|
if ($this->Revision->equals($other->Revision)) { |
|
368
|
10 |
|
return true; |
|
369
|
|
|
} |
|
370
|
1 |
|
} |
|
371
|
7 |
|
} |
|
372
|
17 |
|
} |
|
373
|
|
|
|
|
374
|
29 |
|
return false; |
|
375
|
|
|
} |
|
376
|
|
|
|
|
377
|
|
|
|
|
378
|
|
|
#region IComparable |
|
|
|
|
|
|
379
|
|
|
|
|
380
|
|
|
/** |
|
381
|
|
|
* Determina la posición relativa de esta instancia con respecto al objeto especificado. |
|
382
|
|
|
* |
|
383
|
|
|
* For types different than ``Version``: |
|
384
|
|
|
* - ``integer`` and ``null`` are always < 0; |
|
385
|
|
|
* - ``string`` and ``array`` are parsed and then evaluated (if is not parseable, always > 0); |
|
386
|
|
|
* - other types are always > 0 |
|
387
|
|
|
* |
|
388
|
|
|
* @param Version|int|string|mixed $other |
|
389
|
|
|
* The other object to compare with. |
|
390
|
|
|
* |
|
391
|
|
|
* @return integer|null |
|
392
|
|
|
* Returns: |
|
393
|
|
|
* - ``= 0`` if this instance is considered equivalent to $other; |
|
394
|
|
|
* - ``> 0`` si esta instancia se considera mayor a $other; |
|
395
|
|
|
* - ``< 0`` si esta instancia se considera menor a $other. |
|
396
|
|
|
* - ``null`` if this instance can't be compared against $other . |
|
397
|
|
|
* @see Object::compare() |
|
398
|
|
|
* */ |
|
399
|
24 |
|
public function compareTo($other) |
|
400
|
|
|
{ |
|
401
|
24 |
|
$r = $this->equals($other) ? 0 : 9999; |
|
|
|
|
|
|
402
|
|
|
|
|
403
|
24 |
|
if (!($other instanceof Version)) { |
|
404
|
17 |
|
switch (typeof($other)->toString()) { |
|
|
|
|
|
|
405
|
17 |
|
case 'integer': |
|
406
|
17 |
|
case 'float': |
|
407
|
17 |
|
case 'double': |
|
408
|
17 |
|
case 'null': |
|
409
|
17 |
|
case 'NULL': |
|
410
|
4 |
|
$r = 1; // Siempre es mayor a cualquier número o null |
|
411
|
4 |
|
break; |
|
412
|
|
|
|
|
413
|
13 |
|
case 'string': |
|
414
|
13 |
|
case 'array': |
|
415
|
|
|
// Se tratan de convertir las cadenas y arrays |
|
416
|
|
|
try { |
|
417
|
11 |
|
$tmp = Version::parse($other); |
|
418
|
9 |
|
$r = $this->compareTo($tmp); |
|
|
|
|
|
|
419
|
11 |
|
} catch (InvalidArgumentException $e) { |
|
420
|
|
|
// Siempre es mayor a strings o arrays que no se puedan convertir |
|
421
|
4 |
|
$r = 1; |
|
422
|
|
|
} |
|
423
|
11 |
|
break; |
|
424
|
|
|
|
|
425
|
2 |
|
default: |
|
426
|
|
|
// No se puede determinar comparando a otros objetos. |
|
427
|
2 |
|
$r = null; |
|
428
|
17 |
|
} |
|
429
|
|
|
|
|
430
|
17 |
|
return $r; |
|
431
|
|
|
} |
|
432
|
|
|
|
|
433
|
17 |
|
if ($r != 0) { |
|
434
|
15 |
|
$r = $this->Major - $other->Major; |
|
435
|
|
|
|
|
436
|
15 |
|
if ($r == 0) { |
|
437
|
7 |
|
$r = $this->Minor - $other->Minor; |
|
438
|
|
|
|
|
439
|
7 |
|
if ($r == 0) { |
|
440
|
6 |
|
$r = $this->Build->compareTo($other->Build); |
|
441
|
|
|
|
|
442
|
6 |
|
if ($r == 0) { |
|
|
|
|
|
|
443
|
1 |
|
$r = $this->Revision->compareTo($other->Revision); |
|
444
|
1 |
|
} |
|
445
|
6 |
|
} |
|
446
|
7 |
|
} |
|
447
|
15 |
|
} |
|
448
|
|
|
|
|
449
|
17 |
|
return $r; |
|
450
|
|
|
} |
|
451
|
|
|
|
|
452
|
|
|
#endregion |
|
|
|
|
|
|
453
|
|
|
} |
|
|
|
|
|
|
454
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.