From e82cd4427b3683241b2f21321a2e7998543eb70f Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Sun, 10 May 2026 18:54:25 +0200 Subject: [PATCH] Extract string limiting logic from CodeQuoter into LimiterQuoter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeQuoter was handling two distinct responsibilities: limiting string length (including truncation and context-aware placeholder selection) and wrapping content in backtick quotes. Separating these concerns gives each class a single, clear job — LimiterQuoter handles the length cap and truncation strategy, while CodeQuoter focuses on depth-checking and backtick formatting. This also makes each concern independently testable. Assisted-by: Claude Code (claude-sonnet-4-6) --- src/Quoters/CodeQuoter.php | 37 ++--------------- src/Quoters/LimiterQuoter.php | 52 ++++++++++++++++++++++++ tests/unit/Quoters/LimiterQuoterTest.php | 49 ++++++++++++++++++++++ 3 files changed, 105 insertions(+), 33 deletions(-) create mode 100644 src/Quoters/LimiterQuoter.php create mode 100644 tests/unit/Quoters/LimiterQuoterTest.php diff --git a/src/Quoters/CodeQuoter.php b/src/Quoters/CodeQuoter.php index 0e8b3a6..550c545 100644 --- a/src/Quoters/CodeQuoter.php +++ b/src/Quoters/CodeQuoter.php @@ -12,20 +12,15 @@ use Respect\Stringifier\Quoter; -use function mb_strlen; -use function mb_substr; use function sprintf; -use function str_contains; -use function strpos; final class CodeQuoter implements Quoter { - private const string OBJECT_PLACEHOLDER = ' ... }'; - private const string ARRAY_PLACEHOLDER = ' ... ]'; - private const string GENERIC_PLACEHOLDER = ' ...'; + private readonly LimiterQuoter $limiter; - public function __construct(private readonly int $maximumLength) + public function __construct(int $maximumLength) { + $this->limiter = new LimiterQuoter($maximumLength - 2); } public function quote(string $string, int $depth): string @@ -34,30 +29,6 @@ public function quote(string $string, int $depth): string return $string; } - $limitWithQuotes = $this->maximumLength - 2; - if (mb_strlen($string) <= $limitWithQuotes) { - return $this->code($string); - } - - $filtered = mb_substr($string, 0, $limitWithQuotes); - if (strpos($filtered, '[') === 0) { - return $this->placeholder($filtered, self::ARRAY_PLACEHOLDER); - } - - if (str_contains($filtered, '{')) { - return $this->placeholder($filtered, self::OBJECT_PLACEHOLDER); - } - - return $this->placeholder($filtered, self::GENERIC_PLACEHOLDER); - } - - private function code(string $string): string - { - return sprintf('`%s`', $string); - } - - private function placeholder(string $string, string $placeholder): string - { - return $this->code(mb_substr($string, 0, -1 * mb_strlen($placeholder)) . $placeholder); + return sprintf('`%s`', $this->limiter->quote($string, $depth)); } } diff --git a/src/Quoters/LimiterQuoter.php b/src/Quoters/LimiterQuoter.php new file mode 100644 index 0000000..091499e --- /dev/null +++ b/src/Quoters/LimiterQuoter.php @@ -0,0 +1,52 @@ + + * SPDX-License-Identifier: MIT + */ + +declare(strict_types=1); + +namespace Respect\Stringifier\Quoters; + +use Respect\Stringifier\Quoter; + +use function mb_strlen; +use function mb_substr; +use function str_contains; +use function strpos; + +final class LimiterQuoter implements Quoter +{ + private const string OBJECT_PLACEHOLDER = ' ... }'; + private const string ARRAY_PLACEHOLDER = ' ... ]'; + private const string GENERIC_PLACEHOLDER = ' ...'; + + public function __construct(private readonly int $maximumLength) + { + } + + public function quote(string $string, int $depth): string + { + if (mb_strlen($string) <= $this->maximumLength) { + return $string; + } + + $filtered = mb_substr($string, 0, $this->maximumLength); + if (strpos($filtered, '[') === 0) { + return $this->truncate($filtered, self::ARRAY_PLACEHOLDER); + } + + if (str_contains($filtered, '{')) { + return $this->truncate($filtered, self::OBJECT_PLACEHOLDER); + } + + return $this->truncate($filtered, self::GENERIC_PLACEHOLDER); + } + + private function truncate(string $string, string $placeholder): string + { + return mb_substr($string, 0, -1 * mb_strlen($placeholder)) . $placeholder; + } +} diff --git a/tests/unit/Quoters/LimiterQuoterTest.php b/tests/unit/Quoters/LimiterQuoterTest.php new file mode 100644 index 0000000..7ed325d --- /dev/null +++ b/tests/unit/Quoters/LimiterQuoterTest.php @@ -0,0 +1,49 @@ + + * SPDX-License-Identifier: MIT + */ + +declare(strict_types=1); + +namespace Respect\Stringifier\Test\Unit\Quoters; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; +use Respect\Stringifier\Quoters\LimiterQuoter; + +use function mb_strlen; + +#[CoversClass(LimiterQuoter::class)] +final class LimiterQuoterTest extends TestCase +{ + private const int LIMIT = 18; + + #[Test] + #[DataProvider('provideData')] + public function itShouldLimitString(string $string, string $expected): void + { + $sut = new LimiterQuoter(self::LIMIT); + + $actual = $sut->quote($string, 0); + + self::assertSame($expected, $actual); + self::assertLessThanOrEqual(self::LIMIT, mb_strlen($actual)); + } + + /** @return array> */ + public static function provideData(): array + { + return [ + ['short string', 'short string'], + ['1234567890ABCDEFGH', '1234567890ABCDEFGH'], + ['1234567890ABCDEFGHI', '1234567890ABCD ...'], + ['class { 90ABCDEFGH }', 'class { 90AB ... }'], + ['[2, 5, 7, A, D, G, H]', '[2, 5, 7, A, ... ]'], + ]; + } +}