From 58d9ec29efae9737cf6fecd8c3eadfc62a0a7bdf Mon Sep 17 00:00:00 2001 From: mhmdanas <6daf084a-8eaf-40fb-86c7-8500077c3b69@anonaddy.me> Date: Wed, 10 Mar 2021 13:31:24 +0300 Subject: [PATCH 1/7] Add startsWith and endsWith --- src/Data/String/CodeUnits.js | 12 ++++++++++++ src/Data/String/CodeUnits.purs | 18 ++++++++++++++++++ test/Test/Data/String/CodeUnits.purs | 14 ++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/Data/String/CodeUnits.js b/src/Data/String/CodeUnits.js index 6017fd3..e42bfa1 100644 --- a/src/Data/String/CodeUnits.js +++ b/src/Data/String/CodeUnits.js @@ -116,3 +116,15 @@ exports.splitAt = function (i) { return { before: s.substring(0, i), after: s.substring(i) }; }; }; + +exports.startsWith = function (pattern) { + return function (s) { + return s.startsWith(pattern); + } +} + +exports.endsWith = function (pattern) { + return function (s) { + return s.endsWith(pattern); + } +} diff --git a/src/Data/String/CodeUnits.purs b/src/Data/String/CodeUnits.purs index dfa0482..3a87ad2 100644 --- a/src/Data/String/CodeUnits.purs +++ b/src/Data/String/CodeUnits.purs @@ -22,6 +22,8 @@ module Data.String.CodeUnits , dropWhile , slice , splitAt + , startsWith + , endsWith ) where import Prelude @@ -343,3 +345,19 @@ foreign import _slice :: Int -> Int -> String -> String -- | splitAt i s == {before: take i s, after: drop i s} -- | ``` foreign import splitAt :: Int -> String -> { before :: String, after :: String } + +-- | Checks whether the given string starts with the pattern. +-- | +-- | ```purescript +-- | startsWith (Pattern "foo") "foobar" == true +-- | startsWith (Pattern "bar") "foobar" == false +-- | ``` +foreign import startsWith :: Pattern -> String -> Boolean + +-- | Checks whether the given string ends with the pattern. +-- | +-- | ```purescript +-- | endsWith (Pattern "bar") "foobar" == true +-- | endsWith (Pattern "foo") "foobar" == false +-- | ``` +foreign import endsWith :: Pattern -> String -> Boolean diff --git a/test/Test/Data/String/CodeUnits.purs b/test/Test/Data/String/CodeUnits.purs index 9cf010b..bbebb0b 100644 --- a/test/Test/Data/String/CodeUnits.purs +++ b/test/Test/Data/String/CodeUnits.purs @@ -510,3 +510,17 @@ testStringCodeUnits = do { actual: SCU.slice 3 1000 "purescript" , expected: Nothing -- e > l } + + log "startsWith" + assert $ SCU.startsWith (Pattern "foo") "foobar" + assert $ SCU.startsWith (Pattern "foo") "foo" + assert $ SCU.startsWith (Pattern "") "" + assert $ SCU.startsWith (Pattern "") "foo" + assert $ not $ SCU.startsWith (Pattern "foo") "" + + log "endsWith" + assert $ SCU.endsWith (Pattern "bar") "foobar" + assert $ SCU.endsWith (Pattern "bar") "bar" + assert $ SCU.endsWith (Pattern "") "" + assert $ SCU.endsWith (Pattern "") "bar" + assert $ not $ SCU.endsWith (Pattern "bar") "" From 695e414cd1c28c7dc70d4b50789a7c8079de823a Mon Sep 17 00:00:00 2001 From: mhmdanas <6daf084a-8eaf-40fb-86c7-8500077c3b69@anonaddy.me> Date: Wed, 10 Mar 2021 13:36:13 +0300 Subject: [PATCH 2/7] Add missing semicolons to FFI functions --- src/Data/String/CodeUnits.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Data/String/CodeUnits.js b/src/Data/String/CodeUnits.js index e42bfa1..a9e4795 100644 --- a/src/Data/String/CodeUnits.js +++ b/src/Data/String/CodeUnits.js @@ -120,11 +120,11 @@ exports.splitAt = function (i) { exports.startsWith = function (pattern) { return function (s) { return s.startsWith(pattern); - } -} + }; +}; exports.endsWith = function (pattern) { return function (s) { return s.endsWith(pattern); - } -} + }; +}; From 84487d52f91ba25f8f3c15f9819fa4e7c779e06a Mon Sep 17 00:00:00 2001 From: mhmdanas <32234660+mhmdanas@users.noreply.github.com> Date: Sun, 11 Apr 2021 15:47:57 +0300 Subject: [PATCH 3/7] Define `startsWith` and `endsWith` in PS --- src/Data/String/CodeUnits.js | 12 ------------ src/Data/String/CodeUnits.purs | 6 ++++-- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/Data/String/CodeUnits.js b/src/Data/String/CodeUnits.js index a9e4795..6017fd3 100644 --- a/src/Data/String/CodeUnits.js +++ b/src/Data/String/CodeUnits.js @@ -116,15 +116,3 @@ exports.splitAt = function (i) { return { before: s.substring(0, i), after: s.substring(i) }; }; }; - -exports.startsWith = function (pattern) { - return function (s) { - return s.startsWith(pattern); - }; -}; - -exports.endsWith = function (pattern) { - return function (s) { - return s.endsWith(pattern); - }; -}; diff --git a/src/Data/String/CodeUnits.purs b/src/Data/String/CodeUnits.purs index 3a87ad2..bcc8660 100644 --- a/src/Data/String/CodeUnits.purs +++ b/src/Data/String/CodeUnits.purs @@ -352,7 +352,8 @@ foreign import splitAt :: Int -> String -> { before :: String, after :: String } -- | startsWith (Pattern "foo") "foobar" == true -- | startsWith (Pattern "bar") "foobar" == false -- | ``` -foreign import startsWith :: Pattern -> String -> Boolean +startsWith :: Pattern -> String -> Boolean +startsWith pat = isJust <<< stripPrefix pat -- | Checks whether the given string ends with the pattern. -- | @@ -360,4 +361,5 @@ foreign import startsWith :: Pattern -> String -> Boolean -- | endsWith (Pattern "bar") "foobar" == true -- | endsWith (Pattern "foo") "foobar" == false -- | ``` -foreign import endsWith :: Pattern -> String -> Boolean +endsWith :: Pattern -> String -> Boolean +endsWith pat = isJust <<< stripSuffix pat From 66fa11b2130017509a437351c6d3d56aecbec6f6 Mon Sep 17 00:00:00 2001 From: mhmdanas <32234660+mhmdanas@users.noreply.github.com> Date: Sun, 11 Apr 2021 15:57:30 +0300 Subject: [PATCH 4/7] Add notes about `stripPrefix` and `stripSuffix` --- src/Data/String/CodeUnits.purs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Data/String/CodeUnits.purs b/src/Data/String/CodeUnits.purs index bcc8660..ace1041 100644 --- a/src/Data/String/CodeUnits.purs +++ b/src/Data/String/CodeUnits.purs @@ -348,6 +348,9 @@ foreign import splitAt :: Int -> String -> { before :: String, after :: String } -- | Checks whether the given string starts with the pattern. -- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripPrefix`. +-- | -- | ```purescript -- | startsWith (Pattern "foo") "foobar" == true -- | startsWith (Pattern "bar") "foobar" == false @@ -357,6 +360,9 @@ startsWith pat = isJust <<< stripPrefix pat -- | Checks whether the given string ends with the pattern. -- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripSuffix`. +-- | -- | ```purescript -- | endsWith (Pattern "bar") "foobar" == true -- | endsWith (Pattern "foo") "foobar" == false From 98f0f5b8e4ecaa05a0887c7c229a22518dd7ef92 Mon Sep 17 00:00:00 2001 From: mhmdanas <32234660+mhmdanas@users.noreply.github.com> Date: Sun, 11 Apr 2021 16:00:03 +0300 Subject: [PATCH 5/7] Add changes to `Unreleased` section of changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 311b72b..f3110f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Notable changes to this project are documented in this file. The format is based Breaking changes: New features: +- Added `startsWith` and `endsWith` (#147) Bugfixes: From b9054ecc8b269a8299f584958356e9085527de12 Mon Sep 17 00:00:00 2001 From: mhmdanas <32234660+mhmdanas@users.noreply.github.com> Date: Sat, 3 Jul 2021 22:06:16 +0300 Subject: [PATCH 6/7] Move `startsWith` and `endsWith` up This is because like `stripPrefix` and `stripSuffix`, these functions are CodeUnit/CodePoint-agnostic. The same was also done for tests. --- src/Data/String/CodeUnits.purs | 55 ++++++++++++++-------------- test/Test/Data/String/CodeUnits.purs | 28 +++++++------- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/Data/String/CodeUnits.purs b/src/Data/String/CodeUnits.purs index f64aa1f..ec277ce 100644 --- a/src/Data/String/CodeUnits.purs +++ b/src/Data/String/CodeUnits.purs @@ -33,9 +33,10 @@ import Data.String.Pattern (Pattern(..)) import Data.String.Unsafe as U ------------------------------------------------------------------------------- --- `stripPrefix`, `stripSuffix`, and `contains` are CodeUnit/CodePoint agnostic --- as they are based on patterns rather than lengths/indices, but they need to --- be defined in here to avoid a circular module dependency +-- `stripPrefix`, `stripSuffix`, `startsWith`, `endsWith`, and `contains` are +-- CodeUnit/CodePoint agnostic as they are based on patterns rather than +-- lengths/indices, but they need to be defined in here to avoid a circular +-- module dependency ------------------------------------------------------------------------------- -- | If the string starts with the given prefix, return the portion of the @@ -63,6 +64,30 @@ stripSuffix (Pattern suffix) str = let { before, after } = splitAt (length str - length suffix) str in if after == suffix then Just before else Nothing +-- | Checks whether the given string starts with the pattern. +-- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripPrefix`. +-- | +-- | ```purescript +-- | startsWith (Pattern "foo") "foobar" == true +-- | startsWith (Pattern "bar") "foobar" == false +-- | ``` +startsWith :: Pattern -> String -> Boolean +startsWith pat = isJust <<< stripPrefix pat + +-- | Checks whether the given string ends with the pattern. +-- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripSuffix`. +-- | +-- | ```purescript +-- | endsWith (Pattern "bar") "foobar" == true +-- | endsWith (Pattern "foo") "foobar" == false +-- | ``` +endsWith :: Pattern -> String -> Boolean +endsWith pat = isJust <<< stripSuffix pat + -- | Checks whether the pattern appears in the given string. -- | -- | ```purescript @@ -345,27 +370,3 @@ foreign import _slice :: Int -> Int -> String -> String -- | splitAt i s == {before: take i s, after: drop i s} -- | ``` foreign import splitAt :: Int -> String -> { before :: String, after :: String } - --- | Checks whether the given string starts with the pattern. --- | --- | **NOTE**: if you also want to get the string stripped of the pattern, see --- | `stripPrefix`. --- | --- | ```purescript --- | startsWith (Pattern "foo") "foobar" == true --- | startsWith (Pattern "bar") "foobar" == false --- | ``` -startsWith :: Pattern -> String -> Boolean -startsWith pat = isJust <<< stripPrefix pat - --- | Checks whether the given string ends with the pattern. --- | --- | **NOTE**: if you also want to get the string stripped of the pattern, see --- | `stripSuffix`. --- | --- | ```purescript --- | endsWith (Pattern "bar") "foobar" == true --- | endsWith (Pattern "foo") "foobar" == false --- | ``` -endsWith :: Pattern -> String -> Boolean -endsWith pat = isJust <<< stripSuffix pat diff --git a/test/Test/Data/String/CodeUnits.purs b/test/Test/Data/String/CodeUnits.purs index bbebb0b..8472f20 100644 --- a/test/Test/Data/String/CodeUnits.purs +++ b/test/Test/Data/String/CodeUnits.purs @@ -64,6 +64,20 @@ testStringCodeUnits = do , expected: Just "" } + log "startsWith" + assert $ SCU.startsWith (Pattern "foo") "foobar" + assert $ SCU.startsWith (Pattern "foo") "foo" + assert $ SCU.startsWith (Pattern "") "" + assert $ SCU.startsWith (Pattern "") "foo" + assert $ not $ SCU.startsWith (Pattern "foo") "" + + log "endsWith" + assert $ SCU.endsWith (Pattern "bar") "foobar" + assert $ SCU.endsWith (Pattern "bar") "bar" + assert $ SCU.endsWith (Pattern "") "" + assert $ SCU.endsWith (Pattern "") "bar" + assert $ not $ SCU.endsWith (Pattern "bar") "" + log "charAt" assertEqual { actual: SCU.charAt 0 "" @@ -510,17 +524,3 @@ testStringCodeUnits = do { actual: SCU.slice 3 1000 "purescript" , expected: Nothing -- e > l } - - log "startsWith" - assert $ SCU.startsWith (Pattern "foo") "foobar" - assert $ SCU.startsWith (Pattern "foo") "foo" - assert $ SCU.startsWith (Pattern "") "" - assert $ SCU.startsWith (Pattern "") "foo" - assert $ not $ SCU.startsWith (Pattern "foo") "" - - log "endsWith" - assert $ SCU.endsWith (Pattern "bar") "foobar" - assert $ SCU.endsWith (Pattern "bar") "bar" - assert $ SCU.endsWith (Pattern "") "" - assert $ SCU.endsWith (Pattern "") "bar" - assert $ not $ SCU.endsWith (Pattern "bar") "" From d6adb7fe23525ade5981bcead0a1a6fa0d936c50 Mon Sep 17 00:00:00 2001 From: mhmdanas <32234660+mhmdanas@users.noreply.github.com> Date: Sat, 3 Jul 2021 22:07:50 +0300 Subject: [PATCH 7/7] Add startsWith and endsWith for NonEmptyString --- src/Data/String/CodePoints.purs | 2 +- src/Data/String/NonEmpty.purs | 2 +- src/Data/String/NonEmpty/Internal.purs | 25 +++++++++++++++++++++++++ test/Test/Data/String/NonEmpty.purs | 13 +++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Data/String/CodePoints.purs b/src/Data/String/CodePoints.purs index 65e0b55..bd962f3 100644 --- a/src/Data/String/CodePoints.purs +++ b/src/Data/String/CodePoints.purs @@ -34,7 +34,7 @@ import Data.Array as Array import Data.Enum (class BoundedEnum, class Enum, Cardinality(..), defaultPred, defaultSucc, fromEnum, toEnum, toEnumWithDefaults) import Data.Int (hexadecimal, toStringAs) import Data.Maybe (Maybe(..)) -import Data.String.CodeUnits (contains, stripPrefix, stripSuffix) as Exports +import Data.String.CodeUnits (contains, stripPrefix, stripSuffix, startsWith, endsWith) as Exports import Data.String.CodeUnits as CU import Data.String.Common (toUpper) import Data.String.Pattern (Pattern) diff --git a/src/Data/String/NonEmpty.purs b/src/Data/String/NonEmpty.purs index 6b6210c..72e10b3 100644 --- a/src/Data/String/NonEmpty.purs +++ b/src/Data/String/NonEmpty.purs @@ -4,6 +4,6 @@ module Data.String.NonEmpty , module Data.String.NonEmpty.CodePoints ) where -import Data.String.NonEmpty.Internal (NonEmptyString, class MakeNonEmpty, NonEmptyReplacement(..), appendString, contains, fromString, join1With, joinWith, joinWith1, localeCompare, nes, prependString, replace, replaceAll, stripPrefix, stripSuffix, toLower, toString, toUpper, trim, unsafeFromString) +import Data.String.NonEmpty.Internal (NonEmptyString, class MakeNonEmpty, NonEmptyReplacement(..), appendString, contains, fromString, join1With, joinWith, joinWith1, localeCompare, nes, prependString, replace, replaceAll, stripPrefix, stripSuffix, startsWith, endsWith, toLower, toString, toUpper, trim, unsafeFromString) import Data.String.Pattern (Pattern(..)) import Data.String.NonEmpty.CodePoints diff --git a/src/Data/String/NonEmpty/Internal.purs b/src/Data/String/NonEmpty/Internal.purs index 707b779..f08869c 100644 --- a/src/Data/String/NonEmpty/Internal.purs +++ b/src/Data/String/NonEmpty/Internal.purs @@ -123,6 +123,31 @@ stripPrefix pat = fromString <=< liftS (String.stripPrefix pat) stripSuffix :: Pattern -> NonEmptyString -> Maybe NonEmptyString stripSuffix pat = fromString <=< liftS (String.stripSuffix pat) + +-- | Checks whether the given string starts with the pattern. +-- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripPrefix`. +-- | +-- | ```purescript +-- | startsWith (Pattern "foo") (NonEmptyString "foobar") == true +-- | startsWith (Pattern "bar") (NonEmptyString "foobar") == false +-- | ``` +startsWith :: Pattern -> NonEmptyString -> Boolean +startsWith = liftS <<< String.startsWith + +-- | Checks whether the given string ends with the pattern. +-- | +-- | **NOTE**: if you also want to get the string stripped of the pattern, see +-- | `stripSuffix`. +-- | +-- | ```purescript +-- | endsWith (Pattern "bar") (NonEmptyString "foobar") == true +-- | endsWith (Pattern "foo") (NonEmptyString "foobar") == false +-- | ``` +endsWith :: Pattern -> NonEmptyString -> Boolean +endsWith = liftS <<< String.endsWith + -- | Checks whether the pattern appears in the given string. -- | -- | ```purescript diff --git a/test/Test/Data/String/NonEmpty.purs b/test/Test/Data/String/NonEmpty.purs index a4103ec..46f2cd0 100644 --- a/test/Test/Data/String/NonEmpty.purs +++ b/test/Test/Data/String/NonEmpty.purs @@ -144,6 +144,19 @@ testNonEmptyString = do , expected: Nothing } + log "startsWith" + assert $ NES.startsWith (Pattern "foo") (nes (Proxy :: Proxy "foobar")) + assert $ NES.startsWith (Pattern "foo") (nes (Proxy :: Proxy "foo")) + assert $ NES.startsWith (Pattern "") (nes (Proxy :: Proxy "foo")) + assert $ not $ NES.startsWith (Pattern "foo") (nes (Proxy :: Proxy "f")) + + log "endsWith" + assert $ NES.endsWith (Pattern "bar") (nes (Proxy :: Proxy "foobar")) + assert $ NES.endsWith (Pattern "bar") (nes (Proxy :: Proxy "bar")) + assert $ NES.endsWith (Pattern "") (nes (Proxy :: Proxy "f")) + assert $ NES.endsWith (Pattern "") (nes (Proxy :: Proxy "bar")) + assert $ not $ NES.endsWith (Pattern "bar") (nes (Proxy :: Proxy "b")) + log "toLower" assertEqual { actual: NES.toLower (nes (Proxy :: Proxy "bAtMaN"))