Skip to content

Commit f5b4de7

Browse files
committed
Add StringNonBlank type with tryFromString and comprehensive tests
- Implemented `StringNonBlank` class to represent non-blank strings (not empty or whitespace-only). - Added `fromString` and `tryFromString` methods to validate input, returning `Undefined` for invalid cases. - Updated `Usage` examples to demonstrate `StringNonBlank` behavior. - Included thorough unit tests to validate creation, exception handling, and `Undefined` behavior for blank inputs.
1 parent 253f7d5 commit f5b4de7

File tree

4 files changed

+111
-0
lines changed

4 files changed

+111
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
.idea
12
/vendor/

src/String/StringNonBlank.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpTypedValues\String;
6+
7+
use PhpTypedValues\Abstract\String\StrType;
8+
use PhpTypedValues\Exception\StringTypeException;
9+
use PhpTypedValues\Exception\TypeException;
10+
use PhpTypedValues\Undefined\Alias\Undefined;
11+
12+
use function sprintf;
13+
use function trim;
14+
15+
/**
16+
* Non-blank string value (not empty and not only whitespace).
17+
*
18+
* Example "hello" or " hi ".
19+
*
20+
* @psalm-immutable
21+
*/
22+
readonly class StringNonBlank extends StrType
23+
{
24+
/** @var non-empty-string */
25+
protected string $value;
26+
27+
/**
28+
* @throws StringTypeException
29+
*/
30+
public function __construct(string $value)
31+
{
32+
if (trim($value) === '') {
33+
throw new StringTypeException(sprintf('Expected non-blank string, got "%s"', $value));
34+
}
35+
36+
/** @var non-empty-string $value */
37+
$this->value = $value;
38+
}
39+
40+
public static function tryFromString(string $value): static|Undefined
41+
{
42+
try {
43+
return static::fromString($value);
44+
} catch (TypeException) {
45+
return Undefined::create();
46+
}
47+
}
48+
49+
/**
50+
* @throws StringTypeException
51+
*/
52+
public static function fromString(string $value): static
53+
{
54+
return new static($value);
55+
}
56+
57+
/** @return non-empty-string */
58+
public function value(): string
59+
{
60+
return $this->value;
61+
}
62+
}

src/Usage/String.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
use PhpTypedValues\String\Alias\StrType;
77
use PhpTypedValues\String\Json;
88
use PhpTypedValues\String\MariaDb\StringVarChar255;
9+
use PhpTypedValues\String\StringNonBlank;
910
use PhpTypedValues\String\StringNonEmpty;
1011
use PhpTypedValues\String\StringStandard;
1112
use PhpTypedValues\String\StringUuidV4;
1213
use PhpTypedValues\String\StringUuidV7;
14+
use PhpTypedValues\Undefined\Alias\Undefined;
1315

1416
/**
1517
* String.
@@ -23,6 +25,12 @@
2325
echo Str::fromString('hi')->toString() . \PHP_EOL;
2426
echo StringNonEmpty::tryFromString('hi')->toString() . \PHP_EOL;
2527
echo StringStandard::tryFromString('hi')->toString() . \PHP_EOL;
28+
// NonBlank usage (valid and try*)
29+
echo StringNonBlank::fromString(' hi ')->toString() . \PHP_EOL;
30+
$nb = StringNonBlank::tryFromString(' ');
31+
if (!($nb instanceof Undefined)) {
32+
echo $nb->toString() . \PHP_EOL;
33+
}
2634
echo StringUuidV4::tryFromString('550e8400-e29b-41d4-a716-446655440000')->toString() . \PHP_EOL;
2735
echo StringUuidV7::tryFromString('01890f2a-5bcd-7def-8abc-1234567890ab')->toString() . \PHP_EOL;
2836
echo StringVarChar255::tryFromString('hi')->toString() . \PHP_EOL;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use PhpTypedValues\Exception\StringTypeException;
6+
use PhpTypedValues\String\StringNonBlank;
7+
use PhpTypedValues\Undefined\Alias\Undefined;
8+
9+
it('StringNonBlank accepts non-blank strings and preserves value/toString', function (): void {
10+
$v = new StringNonBlank(' hi ');
11+
12+
expect($v->value())->toBe(' hi ')
13+
->and($v->toString())->toBe(' hi ')
14+
->and((string) $v)->toBe(' hi ');
15+
});
16+
17+
it('StringNonBlank throws on empty or whitespace-only strings', function (): void {
18+
expect(fn() => new StringNonBlank(''))
19+
->toThrow(StringTypeException::class, 'Expected non-blank string, got ""')
20+
->and(fn() => StringNonBlank::fromString(" \t "))
21+
// Do not assert exact whitespace count (tabs vs spaces may render differently across environments)
22+
->toThrow(StringTypeException::class, 'Expected non-blank string, got "');
23+
});
24+
25+
it('StringNonBlank::tryFromString returns value for non-blank and Undefined for blank', function (): void {
26+
$ok = StringNonBlank::tryFromString('x');
27+
$bad = StringNonBlank::tryFromString(' ');
28+
29+
expect($ok)->toBeInstanceOf(StringNonBlank::class)
30+
->and($ok->value())->toBe('x')
31+
->and($bad)->toBeInstanceOf(Undefined::class);
32+
});
33+
34+
it('StringNonBlank for an empty string', function (): void {
35+
expect(StringNonBlank::tryFromString(''))
36+
->toBeInstanceOf(Undefined::class);
37+
38+
expect(fn() => StringNonBlank::fromString(''))
39+
->toThrow(StringTypeException::class, 'Expected non-blank string, got ""');
40+
});

0 commit comments

Comments
 (0)