Skip to content

Commit 7a4662e

Browse files
committed
Merge branch 'cleanup'
2 parents 5da66b8 + d4813bb commit 7a4662e

File tree

9 files changed

+1083
-735
lines changed

9 files changed

+1083
-735
lines changed

src/Db/DbConnector.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
use Lkrms\Concern\TFullyReadable;
66
use Lkrms\Contract\IReadable;
77
use Lkrms\Exception\UnexpectedValueException;
8-
use Lkrms\Utility\Convert;
98
use Lkrms\Utility\Env;
109
use Lkrms\Utility\Format;
10+
use Lkrms\Utility\Get;
1111
use ADOConnection;
1212

1313
/**
@@ -96,7 +96,7 @@ final class DbConnector implements IReadable
9696
public function __construct(string $name, int $driver = null)
9797
{
9898
$driver = $driver === null
99-
? Convert::toValue(Env::get("{$name}_driver"), false, false)
99+
? Get::apparent(Env::get("{$name}_driver"), false, false)
100100
: $driver;
101101

102102
$this->Name = $name;

src/Utility/Convert.php

Lines changed: 0 additions & 328 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Lkrms\Support\Date\DateFormatter;
88
use Lkrms\Support\Date\DateFormatterInterface;
99
use DateTimeInterface;
10-
use LogicException;
1110
use Stringable;
1211

1312
/**
@@ -21,162 +20,6 @@
2120
*/
2221
final class Convert extends Utility
2322
{
24-
/**
25-
* Convert a scalar to the type it appears to be
26-
*
27-
* @param mixed $value
28-
* @param bool $toFloat If `true` (the default), convert float strings to
29-
* `float`s.
30-
* @param bool $toBool If `true` (the default), convert boolean strings to
31-
* `bool`s.
32-
* @return int|float|string|bool|null
33-
*/
34-
public static function toValue($value, bool $toFloat = true, bool $toBool = true)
35-
{
36-
if ($value === null || is_bool($value) || is_int($value) || is_float($value)) {
37-
return $value;
38-
}
39-
if (!is_string($value)) {
40-
throw new LogicException('$value must be a scalar');
41-
}
42-
if (Pcre::match('/^' . Regex::INTEGER_STRING . '$/', $value)) {
43-
return (int) $value;
44-
}
45-
if ($toFloat && is_numeric($value)) {
46-
return (float) $value;
47-
}
48-
if ($toBool && Pcre::match(
49-
'/^' . Regex::BOOLEAN_STRING . '$/',
50-
$value,
51-
$match,
52-
\PREG_UNMATCHED_AS_NULL
53-
)) {
54-
return $match['true'] !== null;
55-
}
56-
return $value;
57-
}
58-
59-
/**
60-
* Convert a value to an integer, preserving null
61-
*
62-
* @param mixed $value
63-
*/
64-
public static function toInt($value): ?int
65-
{
66-
if ($value === null) {
67-
return null;
68-
}
69-
return (int) $value;
70-
}
71-
72-
/**
73-
* Expand tabs to spaces
74-
*/
75-
public static function expandTabs(
76-
string $text,
77-
int $tabSize = 8,
78-
int $column = 1
79-
): string {
80-
if (strpos($text, "\t") === false) {
81-
return $text;
82-
}
83-
$eol = Get::eol($text) ?: "\n";
84-
$expanded = '';
85-
foreach (explode($eol, $text) as $i => $line) {
86-
!$i || $expanded .= $eol;
87-
$parts = explode("\t", $line);
88-
$last = array_key_last($parts);
89-
foreach ($parts as $p => $part) {
90-
$expanded .= $part;
91-
if ($p === $last) {
92-
break;
93-
}
94-
$column += mb_strlen($part);
95-
// e.g. with $tabSize 4, a tab at $column 2 occupies 3 spaces
96-
$spaces = $tabSize - (($column - 1) % $tabSize);
97-
$expanded .= str_repeat(' ', $spaces);
98-
$column += $spaces;
99-
}
100-
$column = 1;
101-
}
102-
return $expanded;
103-
}
104-
105-
/**
106-
* Expand leading tabs to spaces
107-
*/
108-
public static function expandLeadingTabs(
109-
string $text,
110-
int $tabSize = 8,
111-
bool $preserveLine1 = false,
112-
int $column = 1
113-
): string {
114-
if (strpos($text, "\t") === false) {
115-
return $text;
116-
}
117-
$eol = Get::eol($text) ?: "\n";
118-
$softTab = str_repeat(' ', $tabSize);
119-
$expanded = '';
120-
foreach (explode($eol, $text) as $i => $line) {
121-
!$i || $expanded .= $eol;
122-
if ($i || (!$preserveLine1 && $column === 1)) {
123-
$expanded .= Pcre::replace('/(?<=\n|\G)\t/', $softTab, $line);
124-
continue;
125-
}
126-
if ($preserveLine1) {
127-
$expanded .= $line;
128-
continue;
129-
}
130-
$parts = explode("\t", $line);
131-
while (($part = array_shift($parts)) !== null) {
132-
$expanded .= $part;
133-
if (!$parts) {
134-
break;
135-
}
136-
if ($part) {
137-
$expanded .= "\t" . implode("\t", $parts);
138-
break;
139-
}
140-
$column += mb_strlen($part);
141-
$spaces = $tabSize - (($column - 1) % $tabSize);
142-
$expanded .= str_repeat(' ', $spaces);
143-
$column += $spaces;
144-
}
145-
}
146-
return $expanded;
147-
}
148-
149-
/**
150-
* Replace the end of a multi-byte string with an ellipsis ("...") if its
151-
* length exceeds a limit
152-
*/
153-
public static function ellipsize(string $value, int $length): string
154-
{
155-
if (mb_strlen($value) > $length) {
156-
return rtrim(mb_substr($value, 0, $length - 3)) . '...';
157-
}
158-
159-
return $value;
160-
}
161-
162-
/**
163-
* Get a phrase like "between lines 3 and 11" or "on platform 23"
164-
*
165-
* @param string|null $plural `"{$singular}s"` is used if `$plural` is
166-
* `null`.
167-
*/
168-
public static function pluralRange(
169-
int $from,
170-
int $to,
171-
string $singular,
172-
?string $plural = null,
173-
string $preposition = 'on'
174-
): string {
175-
return $to - $from
176-
? sprintf('between %s %d and %d', $plural === null ? $singular . 's' : $plural, $from, $to)
177-
: sprintf('%s %s %d', $preposition, $singular, $from);
178-
}
179-
18023
/**
18124
* Convert a list of "key=value" strings to an array like ["key" => "value"]
18225
*
@@ -201,177 +44,6 @@ public static function queryToData(array $query): array
20144
);
20245
}
20346

204-
/**
205-
* Remove duplicates in a string where top-level lines ("sections") are
206-
* grouped with "list items" below
207-
*
208-
* Lines that match `$regex` are regarded as list items, and other lines are
209-
* used as the section name for subsequent list items. If `$loose` is
210-
* `false` (the default), blank lines between list items clear the current
211-
* section name.
212-
*
213-
* Top-level lines with no children, including any list items orphaned by
214-
* blank lines above them, are returned before sections with children.
215-
*
216-
* If a named subpattern in `$regex` called `indent` matches a non-empty
217-
* string, subsequent lines with the same number of spaces for indentation
218-
* as there are characters in the match are treated as part of the item,
219-
* including any blank lines.
220-
*
221-
* Line endings used in `$text` may be any combination of LF, CRLF and CR,
222-
* but LF (`"\n"`) line endings are used in the return value.
223-
*
224-
* @param string $separator Used between top-level lines and sections. Has
225-
* no effect on the end-of-line sequence used between items, which is always
226-
* LF (`"\n"`).
227-
* @param string|null $marker Added before each section name. Nested list
228-
* items are indented by the equivalent number of spaces. To add a leading
229-
* `"- "` to top-level lines and indent others with two spaces, set
230-
* `$marker` to `"-"`.
231-
* @param bool $clean If `true`, the first match of `$regex` in each section
232-
* name is removed.
233-
* @param bool $loose If `true`, blank lines between list items are ignored.
234-
*/
235-
public static function linesToLists(
236-
string $text,
237-
string $separator = "\n",
238-
?string $marker = null,
239-
string $regex = '/^(?<indent>\h*[-*] )/',
240-
bool $clean = false,
241-
bool $loose = false
242-
): string {
243-
$marker = (string) $marker !== '' ? $marker . ' ' : null;
244-
$indent = $marker !== null ? str_repeat(' ', mb_strlen($marker)) : '';
245-
$markerIsItem = $marker !== null && Pcre::match($regex, $marker);
246-
247-
/** @var array<string,string[]> */
248-
$sections = [];
249-
$lastWasItem = false;
250-
$lines = Pcre::split('/\r\n|\n|\r/', $text);
251-
for ($i = 0; $i < count($lines); $i++) {
252-
$line = $lines[$i];
253-
254-
// Remove pre-existing markers early to ensure sections with the
255-
// same name are combined
256-
if ($marker !== null && !$markerIsItem && strpos($line, $marker) === 0) {
257-
$line = substr($line, strlen($marker));
258-
}
259-
260-
// Treat blank lines between items as section breaks
261-
if (trim($line) === '') {
262-
if (!$loose && $lastWasItem) {
263-
unset($section);
264-
}
265-
continue;
266-
}
267-
268-
// Collect any subsequent indented lines
269-
if (Pcre::match($regex, $line, $matches)) {
270-
$matchIndent = $matches['indent'] ?? '';
271-
if ($matchIndent !== '') {
272-
$matchIndent = str_repeat(' ', mb_strlen($matchIndent));
273-
$pendingWhitespace = '';
274-
$backtrack = 0;
275-
while ($i < count($lines) - 1) {
276-
$nextLine = $lines[$i + 1];
277-
if (trim($nextLine) === '') {
278-
$pendingWhitespace .= $nextLine . "\n";
279-
$backtrack++;
280-
} elseif (substr($nextLine, 0, strlen($matchIndent)) === $matchIndent) {
281-
$line .= "\n" . $pendingWhitespace . $nextLine;
282-
$pendingWhitespace = '';
283-
$backtrack = 0;
284-
} else {
285-
$i -= $backtrack;
286-
break;
287-
}
288-
$i++;
289-
}
290-
}
291-
} else {
292-
$section = $line;
293-
}
294-
295-
$key = $section ?? $line;
296-
297-
if (!array_key_exists($key, $sections)) {
298-
$sections[$key] = [];
299-
}
300-
301-
if ($key !== $line) {
302-
if (!in_array($line, $sections[$key])) {
303-
$sections[$key][] = $line;
304-
}
305-
$lastWasItem = true;
306-
} else {
307-
$lastWasItem = false;
308-
}
309-
}
310-
311-
// Move lines with no associated list to the top
312-
/** @var array<string,string[]> */
313-
$top = [];
314-
$last = null;
315-
foreach ($sections as $section => $lines) {
316-
if (count($lines)) {
317-
continue;
318-
}
319-
320-
unset($sections[$section]);
321-
322-
if ($clean) {
323-
$top[$section] = [];
324-
continue;
325-
}
326-
327-
// Collect second and subsequent consecutive top-level list items
328-
// under the first so they don't form a loose list
329-
if (Pcre::match($regex, $section)) {
330-
if ($last !== null) {
331-
$top[$last][] = $section;
332-
continue;
333-
}
334-
$last = $section;
335-
} else {
336-
$last = null;
337-
}
338-
$top[$section] = [];
339-
}
340-
/** @var array<string,string[]> */
341-
$sections = array_merge($top, $sections);
342-
343-
$groups = [];
344-
foreach ($sections as $section => $lines) {
345-
if ($clean) {
346-
$section = Pcre::replace($regex, '', $section, 1);
347-
}
348-
349-
$marked = false;
350-
if ($marker !== null &&
351-
!($markerIsItem && strpos($section, $marker) === 0) &&
352-
!Pcre::match($regex, $section)) {
353-
$section = $marker . $section;
354-
$marked = true;
355-
}
356-
357-
if (!$lines) {
358-
$groups[] = $section;
359-
continue;
360-
}
361-
362-
// Don't separate or indent top-level list items collected above
363-
if (!$marked && Pcre::match($regex, $section)) {
364-
$groups[] = implode("\n", [$section, ...$lines]);
365-
continue;
366-
}
367-
368-
$groups[] = $section;
369-
$groups[] = $indent . implode("\n" . $indent, $lines);
370-
}
371-
372-
return implode($separator, $groups);
373-
}
374-
37547
/**
37648
* Undo wordwrap(), preserving Markdown-style paragraphs and lists
37749
*

0 commit comments

Comments
 (0)