From a1d030c327a97891b689c9effbfea8bd8212dceb Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 3 Oct 2020 18:56:55 +0100 Subject: [PATCH] [Str] add grarpheme support --- .github/workflows/security-analysis.yml | 2 +- .github/workflows/static-analysis.yml | 2 +- composer.json | 3 +- src/Psl/Internal/Loader.php | 14 ++++ src/Psl/Str/Grapheme/contains.php | 30 +++++++++ src/Psl/Str/Grapheme/contains_ci.php | 30 +++++++++ src/Psl/Str/Grapheme/ends_with.php | 33 ++++++++++ src/Psl/Str/Grapheme/ends_with_ci.php | 33 ++++++++++ src/Psl/Str/Grapheme/length.php | 17 +++++ src/Psl/Str/Grapheme/search.php | 34 ++++++++++ src/Psl/Str/Grapheme/search_ci.php | 34 ++++++++++ src/Psl/Str/Grapheme/search_last.php | 35 ++++++++++ src/Psl/Str/Grapheme/search_last_ci.php | 35 ++++++++++ src/Psl/Str/Grapheme/slice.php | 39 +++++++++++ src/Psl/Str/Grapheme/starts_with.php | 18 ++++++ src/Psl/Str/Grapheme/starts_with_ci.php | 18 ++++++ src/Psl/Str/Grapheme/strip_prefix.php | 23 +++++++ src/Psl/Str/Grapheme/strip_suffix.php | 23 +++++++ tests/Psl/Str/Grapheme/ContainsCiTest.php | 32 +++++++++ tests/Psl/Str/Grapheme/ContainsTest.php | 72 +++++++++++++++++++++ tests/Psl/Str/Grapheme/EndsWithCiTest.php | 35 ++++++++++ tests/Psl/Str/Grapheme/EndsWithTest.php | 34 ++++++++++ tests/Psl/Str/Grapheme/LengthTest.php | 33 ++++++++++ tests/Psl/Str/Grapheme/SearchCiTest.php | 33 ++++++++++ tests/Psl/Str/Grapheme/SearchLastCiTest.php | 33 ++++++++++ tests/Psl/Str/Grapheme/SearchLastTest.php | 33 ++++++++++ tests/Psl/Str/Grapheme/SearchTest.php | 33 ++++++++++ tests/Psl/Str/Grapheme/SliceTest.php | 62 ++++++++++++++++++ tests/Psl/Str/Grapheme/StartsWithCiTest.php | 41 ++++++++++++ tests/Psl/Str/Grapheme/StartsWithTest.php | 41 ++++++++++++ tests/Psl/Str/Grapheme/StripPrefixTest.php | 41 ++++++++++++ tests/Psl/Str/Grapheme/StripSuffixTest.php | 48 ++++++++++++++ 32 files changed, 991 insertions(+), 3 deletions(-) create mode 100644 src/Psl/Str/Grapheme/contains.php create mode 100644 src/Psl/Str/Grapheme/contains_ci.php create mode 100644 src/Psl/Str/Grapheme/ends_with.php create mode 100644 src/Psl/Str/Grapheme/ends_with_ci.php create mode 100644 src/Psl/Str/Grapheme/length.php create mode 100644 src/Psl/Str/Grapheme/search.php create mode 100644 src/Psl/Str/Grapheme/search_ci.php create mode 100644 src/Psl/Str/Grapheme/search_last.php create mode 100644 src/Psl/Str/Grapheme/search_last_ci.php create mode 100644 src/Psl/Str/Grapheme/slice.php create mode 100644 src/Psl/Str/Grapheme/starts_with.php create mode 100644 src/Psl/Str/Grapheme/starts_with_ci.php create mode 100644 src/Psl/Str/Grapheme/strip_prefix.php create mode 100644 src/Psl/Str/Grapheme/strip_suffix.php create mode 100644 tests/Psl/Str/Grapheme/ContainsCiTest.php create mode 100644 tests/Psl/Str/Grapheme/ContainsTest.php create mode 100644 tests/Psl/Str/Grapheme/EndsWithCiTest.php create mode 100644 tests/Psl/Str/Grapheme/EndsWithTest.php create mode 100644 tests/Psl/Str/Grapheme/LengthTest.php create mode 100644 tests/Psl/Str/Grapheme/SearchCiTest.php create mode 100644 tests/Psl/Str/Grapheme/SearchLastCiTest.php create mode 100644 tests/Psl/Str/Grapheme/SearchLastTest.php create mode 100644 tests/Psl/Str/Grapheme/SearchTest.php create mode 100644 tests/Psl/Str/Grapheme/SliceTest.php create mode 100644 tests/Psl/Str/Grapheme/StartsWithCiTest.php create mode 100644 tests/Psl/Str/Grapheme/StartsWithTest.php create mode 100644 tests/Psl/Str/Grapheme/StripPrefixTest.php create mode 100644 tests/Psl/Str/Grapheme/StripSuffixTest.php diff --git a/.github/workflows/security-analysis.yml b/.github/workflows/security-analysis.yml index f83d1c872..3e4a23df3 100644 --- a/.github/workflows/security-analysis.yml +++ b/.github/workflows/security-analysis.yml @@ -4,7 +4,7 @@ on: ["pull_request", "push"] jobs: security-analysis: - name: "security anaylsis" + name: "security analysis" runs-on: "ubuntu-latest" steps: - name: "checkout" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 857c9c2de..f3ac2ad03 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -4,7 +4,7 @@ on: ["pull_request", "push"] jobs: static-analysis: - name: "static anaylsis" + name: "static analysis" runs-on: "ubuntu-latest" steps: - name: "checkout" diff --git a/composer.json b/composer.json index 52237244f..be00ae12c 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ "ext-bcmath": "*", "ext-mbstring": "*", "ext-json": "*", - "ext-sodium": "*" + "ext-sodium": "*", + "ext-intl": "*" }, "require-dev": { "vimeo/psalm": "dev-master", diff --git a/src/Psl/Internal/Loader.php b/src/Psl/Internal/Loader.php index 99247d888..eb12b57cb 100644 --- a/src/Psl/Internal/Loader.php +++ b/src/Psl/Internal/Loader.php @@ -325,6 +325,20 @@ final class Loader 'Psl\Password\hash', 'Psl\Password\needs_rehash', 'Psl\Password\verify', + 'Psl\Str\Grapheme\contains', + 'Psl\Str\Grapheme\contains_ci', + 'Psl\Str\Grapheme\ends_with', + 'Psl\Str\Grapheme\ends_with_ci', + 'Psl\Str\Grapheme\length', + 'Psl\Str\Grapheme\search', + 'Psl\Str\Grapheme\search_ci', + 'Psl\Str\Grapheme\search_last', + 'Psl\Str\Grapheme\search_last_ci', + 'Psl\Str\Grapheme\slice', + 'Psl\Str\Grapheme\starts_with', + 'Psl\Str\Grapheme\starts_with_ci', + 'Psl\Str\Grapheme\strip_prefix', + 'Psl\Str\Grapheme\strip_suffix', ]; public const INTERFACES = [ diff --git a/src/Psl/Str/Grapheme/contains.php b/src/Psl/Str/Grapheme/contains.php new file mode 100644 index 000000000..daf207d14 --- /dev/null +++ b/src/Psl/Str/Grapheme/contains.php @@ -0,0 +1,30 @@ + $total_length) { + return false; + } + + /** @psalm-suppress MissingThrowsDocblock */ + $position = search_last($string, $suffix); + if (null === $position) { + return false; + } + + return $position + $suffix_length === $total_length; +} diff --git a/src/Psl/Str/Grapheme/ends_with_ci.php b/src/Psl/Str/Grapheme/ends_with_ci.php new file mode 100644 index 000000000..9779e2ed2 --- /dev/null +++ b/src/Psl/Str/Grapheme/ends_with_ci.php @@ -0,0 +1,33 @@ + $total_length) { + return false; + } + + /** @psalm-suppress MissingThrowsDocblock */ + $position = search_last_ci($string, $suffix); + if (null === $position) { + return false; + } + + return $position + $suffix_length === $total_length; +} diff --git a/src/Psl/Str/Grapheme/length.php b/src/Psl/Str/Grapheme/length.php new file mode 100644 index 000000000..ee823dddc --- /dev/null +++ b/src/Psl/Str/Grapheme/length.php @@ -0,0 +1,17 @@ += -$haystack_length && $offset <= $haystack_length, 'Offset is out-of-bounds.'); + + return false === ($pos = grapheme_strrpos($haystack, $needle, $offset)) ? + null : + $pos; +} diff --git a/src/Psl/Str/Grapheme/search_last_ci.php b/src/Psl/Str/Grapheme/search_last_ci.php new file mode 100644 index 000000000..d1295e474 --- /dev/null +++ b/src/Psl/Str/Grapheme/search_last_ci.php @@ -0,0 +1,35 @@ += -$haystack_length && $offset <= $haystack_length, 'Offset is out-of-bounds.'); + + return false === ($pos = grapheme_strripos($haystack, $needle, $offset)) ? + null : + $pos; +} diff --git a/src/Psl/Str/Grapheme/slice.php b/src/Psl/Str/Grapheme/slice.php new file mode 100644 index 000000000..380594582 --- /dev/null +++ b/src/Psl/Str/Grapheme/slice.php @@ -0,0 +1,39 @@ += 0, 'Expected a non-negative length.'); + $string_length = length($string); + $offset = Psl\Internal\validate_offset($offset, $string_length); + + if (0 === $offset && (null === $length || $string_length <= $length)) { + return $string; + } + + if (null === $length) { + return (string) grapheme_substr($string, $offset); + } + + return (string) grapheme_substr($string, $offset, $length); +} diff --git a/src/Psl/Str/Grapheme/starts_with.php b/src/Psl/Str/Grapheme/starts_with.php new file mode 100644 index 000000000..f1cfd09ad --- /dev/null +++ b/src/Psl/Str/Grapheme/starts_with.php @@ -0,0 +1,18 @@ +expectException(Exception\InvariantViolationException::class); + + Grapheme\slice('Hello', 0, -1); + } + + public function testSliceThrowsForOutOfBoundOffset(): void + { + $this->expectException(Exception\InvariantViolationException::class); + + Grapheme\slice('Hello', 10); + } + + public function testSliceThrowsForNegativeOutOfBoundOffset(): void + { + $this->expectException(Exception\InvariantViolationException::class); + + Grapheme\slice('hello', -6); + } +} diff --git a/tests/Psl/Str/Grapheme/StartsWithCiTest.php b/tests/Psl/Str/Grapheme/StartsWithCiTest.php new file mode 100644 index 000000000..3703a6be1 --- /dev/null +++ b/tests/Psl/Str/Grapheme/StartsWithCiTest.php @@ -0,0 +1,41 @@ +