text-manipulate 0.2.0.1 → 0.3.0.0
raw patch · 8 files changed
+544/−504 lines, 8 filesdep ~basesetup-changedPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
Files
- Setup.hs +1/−0
- bench/Main.hs +35/−32
- src/Data/Text/Lazy/Manipulate.hs +57/−52
- src/Data/Text/Manipulate.hs +58/−53
- src/Data/Text/Manipulate/Internal/Fusion.hs +90/−74
- src/Data/Text/Manipulate/Internal/Types.hs +22/−21
- test/Main.hs +220/−209
- text-manipulate.cabal +61/−63
Setup.hs view
@@ -1,2 +1,3 @@ import Distribution.Simple+ main = defaultMain
bench/Main.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE OverloadedStrings #-} -- Module : Main--- Copyright : (c) 2014-2015 Brendan Hay <brendan.g.hay@gmail.com>+-- Copyright : (c) 2014-2020 Brendan Hay <brendan.g.hay@gmail.com> -- License : This Source Code Form is subject to the terms of -- the Mozilla Public License, v. 2.0. -- A copy of the MPL can be found in the LICENSE file or@@ -12,38 +12,40 @@ module Main (main) where -import Criterion-import Criterion.Main-import Data.List (intersperse)-import Data.Monoid-import Data.Text (Text)-import qualified Data.Text as Text-import Data.Text.Manipulate+import Criterion+import Criterion.Main+import Data.List (intersperse)+import Data.Monoid+import Data.Text (Text)+import qualified Data.Text as Text+import Data.Text.Manipulate main :: IO ()-main = defaultMain- [ bgroup "Data.Text"- [ bench "takeWord"- $ whnf (Text.takeWhile (not . isWordBoundary)) phrase- , bench "toCamel"- $ whnf (lowerHead . mconcat . group Text.toTitle) phrase- , bench "toPascal"- $ whnf (upperHead . mconcat . group Text.toTitle) phrase- , bench "toSnake"- $ whnf (mconcat . intersperse "_" . group Text.toLower) phrase- , bench "toSpinal"- $ whnf (mconcat . intersperse "-" . group Text.toLower) phrase- , bench "toTrain"- $ whnf (mconcat . intersperse "-" . group Text.toTitle) phrase- ]-- , bgroup "Data.Text.Case"- [ bench "takeWord" $ whnf takeWord phrase- , bench "toCamel" $ whnf toCamel phrase- , bench "toPacal" $ whnf toPascal phrase- , bench "toSnake" $ whnf toSnake phrase- , bench "toSpinal" $ whnf toSpinal phrase- , bench "toTrain" $ whnf toTrain phrase+main =+ defaultMain+ [ bgroup+ "Data.Text"+ [ bench "takeWord" $+ whnf (Text.takeWhile (not . isWordBoundary)) phrase,+ bench "toCamel" $+ whnf (lowerHead . mconcat . group Text.toTitle) phrase,+ bench "toPascal" $+ whnf (upperHead . mconcat . group Text.toTitle) phrase,+ bench "toSnake" $+ whnf (mconcat . intersperse "_" . group Text.toLower) phrase,+ bench "toSpinal" $+ whnf (mconcat . intersperse "-" . group Text.toLower) phrase,+ bench "toTrain" $+ whnf (mconcat . intersperse "-" . group Text.toTitle) phrase+ ],+ bgroup+ "Data.Text.Case"+ [ bench "takeWord" $ whnf takeWord phrase,+ bench "toCamel" $ whnf toCamel phrase,+ bench "toPacal" $ whnf toPascal phrase,+ bench "toSnake" $ whnf toSnake phrase,+ bench "toSpinal" $ whnf toSpinal phrase,+ bench "toTrain" $ whnf toTrain phrase ] ] @@ -51,5 +53,6 @@ phrase = "Supercalifragilistic, world! This-is A multipleDelimiter_String" group :: (Text -> Text) -> Text -> [Text]-group f = map (f . Text.dropWhile isBoundary)+group f =+ map (f . Text.dropWhile isBoundary) . Text.groupBy (const (not . isWordBoundary))
src/Data/Text/Lazy/Manipulate.hs view
@@ -1,8 +1,8 @@ {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ViewPatterns #-} -- Module : Data.Text.Lazy.Manipulate--- Copyright : (c) 2014-2015 Brendan Hay <brendan.g.hay@gmail.com>+-- Copyright : (c) 2014-2020 Brendan Hay <brendan.g.hay@gmail.com> -- License : This Source Code Form is subject to the terms of -- the Mozilla Public License, v. 2.0. -- A copy of the MPL can be found in the LICENSE file or@@ -19,8 +19,7 @@ -- in predominantely English text, please see individual function documentation -- for further details and behaviour. module Data.Text.Lazy.Manipulate- (- -- * Strict vs lazy types+ ( -- * Strict vs lazy types -- $strict -- * Unicode@@ -30,56 +29,58 @@ -- $fusion -- * Subwords+ -- ** Removing words- takeWord- , dropWord- , stripWord+ takeWord,+ dropWord,+ stripWord,+ -- ** Breaking on words- , breakWord- , splitWords+ breakWord,+ splitWords, -- * Character manipulation- , lowerHead- , upperHead- , mapHead+ lowerHead,+ upperHead,+ mapHead, -- * Line manipulation- , indentLines- , prependLines+ indentLines,+ prependLines, -- * Ellipsis- , toEllipsis- , toEllipsisWith+ toEllipsis,+ toEllipsisWith, -- * Acronyms- , toAcronym+ toAcronym, -- * Ordinals- , toOrdinal+ toOrdinal, -- * Casing- , toTitle- , toCamel- , toPascal- , toSnake- , toSpinal- , toTrain+ toTitle,+ toCamel,+ toPascal,+ toSnake,+ toSpinal,+ toTrain, -- * Boundary predicates- , isBoundary- , isWordBoundary- ) where+ isBoundary,+ isWordBoundary,+ )+where -import qualified Data.Char as Char-import Data.Int-import Data.List (intersperse)-import Data.Monoid-import Data.Text.Lazy (Text)-import qualified Data.Text.Lazy as LText-import Data.Text.Lazy.Builder (toLazyText)-import Data.Text.Manipulate.Internal.Fusion (lazy)+import qualified Data.Char as Char+import Data.Int+import Data.List (intersperse)+import Data.Text.Lazy (Text)+import qualified Data.Text.Lazy as LText+import Data.Text.Lazy.Builder (toLazyText)+import Data.Text.Manipulate.Internal.Fusion (lazy) import qualified Data.Text.Manipulate.Internal.Fusion as Fusion-import Data.Text.Manipulate.Internal.Types+import Data.Text.Manipulate.Internal.Types -- $strict -- This library provides functions for manipulating both strict and lazy Text types.@@ -116,9 +117,9 @@ -- | Apply a function to the first character of a piece of text. mapHead :: (Char -> Char) -> Text -> Text mapHead f x =- case LText.uncons x of- Just (c, cs) -> LText.singleton (f c) <> cs- Nothing -> x+ case LText.uncons x of+ Just (c, cs) -> LText.singleton (f c) <> cs+ Nothing -> x -- | Indent newlines by the given number of spaces. indentLines :: Int -> Text -> Text@@ -137,13 +138,16 @@ -- | O(n) Truncate text to a specific length. -- If the text was truncated the given ellipsis sign will be appended.-toEllipsisWith :: Int64 -- ^ Length.- -> Text -- ^ Ellipsis.- -> Text- -> Text+toEllipsisWith ::+ -- | Length.+ Int64 ->+ -- | Ellipsis.+ Text ->+ Text ->+ Text toEllipsisWith n suf x- | LText.length x > n = LText.take n x <> suf- | otherwise = x+ | LText.length x > n = LText.take n x <> suf+ | otherwise = x -- | O(n) Returns the first word, or the original text if no word -- boundary is encountered. /Subject to fusion./@@ -175,8 +179,8 @@ -- Nothing stripWord :: Text -> Maybe Text stripWord x- | LText.length y < LText.length x = Just y- | otherwise = Nothing+ | LText.length y < LText.length x = Just y+ | otherwise = Nothing where y = dropWord x @@ -188,9 +192,10 @@ splitWords = go where go x = case breakWord x of- (h, t) | LText.null h -> go t- | LText.null t -> [h]- | otherwise -> h : go t+ (h, t)+ | LText.null h -> go t+ | LText.null t -> [h]+ | otherwise -> h : go t -- | O(n) Create an adhoc acronym from a piece of cased text. --@@ -204,8 +209,8 @@ -- Nothing toAcronym :: Text -> Maybe Text toAcronym (LText.filter Char.isUpper -> x)- | LText.length x > 1 = Just x- | otherwise = Nothing+ | LText.length x > 1 = Just x+ | otherwise = Nothing -- | Render an ordinal used to denote the position in an ordered sequence. --
src/Data/Text/Manipulate.hs view
@@ -1,8 +1,8 @@ {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ViewPatterns #-} -- Module : Data.Text.Manipulate--- Copyright : (c) 2014-2015 Brendan Hay <brendan.g.hay@gmail.com>+-- Copyright : (c) 2014-2020 Brendan Hay <brendan.g.hay@gmail.com> -- License : This Source Code Form is subject to the terms of -- the Mozilla Public License, v. 2.0. -- A copy of the MPL can be found in the LICENSE file or@@ -18,9 +18,8 @@ -- Assumptions have been made about word boundary characteristics inherint -- in predominantely English text, please see individual function documentation -- for further details and behaviour.- module Data.Text.Manipulate- (- -- * Strict vs lazy types+module Data.Text.Manipulate+ ( -- * Strict vs lazy types -- $strict -- * Unicode@@ -30,56 +29,58 @@ -- $fusion -- * Subwords+ -- ** Removing words- takeWord- , dropWord- , stripWord+ takeWord,+ dropWord,+ stripWord,+ -- ** Breaking on words- , breakWord- , splitWords+ breakWord,+ splitWords, -- * Character manipulation- , lowerHead- , upperHead- , mapHead+ lowerHead,+ upperHead,+ mapHead, -- * Line manipulation- , indentLines- , prependLines+ indentLines,+ prependLines, -- * Ellipsis- , toEllipsis- , toEllipsisWith+ toEllipsis,+ toEllipsisWith, -- * Acronyms- , toAcronym+ toAcronym, -- * Ordinals- , toOrdinal+ toOrdinal, -- * Casing- , toTitle- , toCamel- , toPascal- , toSnake- , toSpinal- , toTrain+ toTitle,+ toCamel,+ toPascal,+ toSnake,+ toSpinal,+ toTrain, -- * Boundary predicates- , isBoundary- , isWordBoundary- ) where+ isBoundary,+ isWordBoundary,+ )+where -import qualified Data.Char as Char-import Data.List (intersperse)-import Data.Monoid-import Data.Text (Text)-import qualified Data.Text as Text-import qualified Data.Text.Lazy as LText-import qualified Data.Text.Lazy.Manipulate as LMan-import Data.Text.Manipulate.Internal.Fusion (strict)+import qualified Data.Char as Char+import Data.List (intersperse)+import Data.Text (Text)+import qualified Data.Text as Text+import qualified Data.Text.Lazy as LText+import qualified Data.Text.Lazy.Manipulate as LMan+import Data.Text.Manipulate.Internal.Fusion (strict) import qualified Data.Text.Manipulate.Internal.Fusion as Fusion-import Data.Text.Manipulate.Internal.Types+import Data.Text.Manipulate.Internal.Types -- $strict -- This library provides functions for manipulating both strict and lazy Text types.@@ -124,9 +125,9 @@ -- | Apply a function to the first character of a piece of text. mapHead :: (Char -> Char) -> Text -> Text mapHead f x =- case Text.uncons x of- Just (c, cs) -> Text.singleton (f c) <> cs- Nothing -> x+ case Text.uncons x of+ Just (c, cs) -> Text.singleton (f c) <> cs+ Nothing -> x -- | Indent newlines by the given number of spaces. --@@ -147,13 +148,16 @@ -- | O(n) Truncate text to a specific length. -- If the text was truncated the given ellipsis sign will be appended.-toEllipsisWith :: Int -- ^ Length.- -> Text -- ^ Ellipsis.- -> Text- -> Text+toEllipsisWith ::+ -- | Length.+ Int ->+ -- | Ellipsis.+ Text ->+ Text ->+ Text toEllipsisWith n suf x- | Text.length x > n = Text.take n x <> suf- | otherwise = x+ | Text.length x > n = Text.take n x <> suf+ | otherwise = x -- | O(n) Returns the first word, or the original text if no word -- boundary is encountered. /Subject to fusion./@@ -185,8 +189,8 @@ -- Nothing stripWord :: Text -> Maybe Text stripWord x- | Text.length y < Text.length x = Just y- | otherwise = Nothing+ | Text.length y < Text.length x = Just y+ | otherwise = Nothing where y = dropWord x @@ -198,9 +202,10 @@ splitWords = go where go x = case breakWord x of- (h, t) | Text.null h -> go t- | Text.null t -> [h]- | otherwise -> h : go t+ (h, t)+ | Text.null h -> go t+ | Text.null t -> [h]+ | otherwise -> h : go t -- | O(n) Create an adhoc acronym from a piece of cased text. --@@ -214,8 +219,8 @@ -- Nothing toAcronym :: Text -> Maybe Text toAcronym (Text.filter Char.isUpper -> x)- | Text.length x > 1 = Just x- | otherwise = Nothing+ | Text.length x > 1 = Just x+ | otherwise = Nothing -- | Render an ordinal used to denote the position in an ordered sequence. --
src/Data/Text/Manipulate/Internal/Fusion.hs view
@@ -1,9 +1,9 @@ {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE RankNTypes #-} -- Module : Data.Text.Manipulate.Internal.Fusion--- Copyright : (c) 2014-2015 Brendan Hay <brendan.g.hay@gmail.com>+-- Copyright : (c) 2014-2020 Brendan Hay <brendan.g.hay@gmail.com> -- License : This Source Code Form is subject to the terms of -- the Mozilla Public License, v. 2.0. -- A copy of the MPL can be found in the LICENSE file or@@ -14,15 +14,15 @@ module Data.Text.Manipulate.Internal.Fusion where -import qualified Data.Char as Char-import Data.Text (Text)-import qualified Data.Text.Internal.Fusion as Fusion-import Data.Text.Internal.Fusion.CaseMapping (upperMapping, lowerMapping)-import Data.Text.Internal.Fusion.Common-import Data.Text.Internal.Fusion.Types-import qualified Data.Text.Internal.Lazy.Fusion as LFusion-import qualified Data.Text.Lazy as LText-import Data.Text.Manipulate.Internal.Types+import qualified Data.Char as Char+import Data.Text (Text)+import qualified Data.Text.Internal.Fusion as Fusion+import Data.Text.Internal.Fusion.CaseMapping (lowerMapping, upperMapping)+import Data.Text.Internal.Fusion.Common+import Data.Text.Internal.Fusion.Types+import qualified Data.Text.Internal.Lazy.Fusion as LFusion+import qualified Data.Text.Lazy as LText+import Data.Text.Manipulate.Internal.Types takeWord :: Stream Char -> Stream Char takeWord = transform (const Done) yield . tokenise@@ -32,17 +32,17 @@ dropWord (tokenise -> Stream next0 s0 len) = Stream next (True :*: s0) len where next (skip :*: s) =- case next0 s of- Done -> Done- Skip s' -> Skip (skip :*: s')- Yield t s' ->- case t of- B '\0' -> Skip (False :*: s')- B _ | skip -> Skip (False :*: s')- B c -> Yield c (False :*: s')- _ | skip -> Skip (skip :*: s')- U c -> Yield c (skip :*: s')- L c -> Yield c (skip :*: s')+ case next0 s of+ Done -> Done+ Skip s' -> Skip (skip :*: s')+ Yield t s' ->+ case t of+ B '\0' -> Skip (False :*: s')+ B _ | skip -> Skip (False :*: s')+ B c -> Yield c (False :*: s')+ _ | skip -> Skip (skip :*: s')+ U c -> Yield c (skip :*: s')+ L c -> Yield c (skip :*: s') {-# INLINE [0] dropWord #-} toTitle :: Stream Char -> Stream Char@@ -89,86 +89,102 @@ -- both subsequent uppercase and lowercase characters uniformly. -- -- /See:/ 'transformWith'-transform :: (forall s. s -> Step (CC s) Char) -- ^ Boundary action.- -> (forall s. Char -> s -> Step (CC s) Char) -- ^ Character mapping.- -> Stream Token -- ^ Input stream.- -> Stream Char+transform ::+ -- | Boundary action.+ (forall s. s -> Step (CC s) Char) ->+ -- | Character mapping.+ (forall s. Char -> s -> Step (CC s) Char) ->+ -- | Input stream.+ Stream Token ->+ Stream Char transform s m = transformWith s m m {-# INLINE [0] transform #-} -- | Step across word boundaries using a custom action, and transform -- subsequent characters after the word boundary is encountered with a mapping -- depending on case.-transformWith :: (forall s. s -> Step (CC s) Char) -- ^ Boundary action.- -> (forall s. Char -> s -> Step (CC s) Char) -- ^ Boundary mapping.- -> (forall s. Char -> s -> Step (CC s) Char) -- ^ Subsequent character mapping.- -> Stream Token -- ^ Input stream.- -> Stream Char+transformWith ::+ -- | Boundary action.+ (forall s. s -> Step (CC s) Char) ->+ -- | Boundary mapping.+ (forall s. Char -> s -> Step (CC s) Char) ->+ -- | Subsequent character mapping.+ (forall s. Char -> s -> Step (CC s) Char) ->+ -- | Input stream.+ Stream Token ->+ Stream Char transformWith md mu mc (Stream next0 s0 len) =- -- HINT: len incorrect when the boundary replacement yields a char.- Stream next (CC (False :*: False :*: s0) '\0' '\0') len+ -- HINT: len incorrect when the boundary replacement yields a char.+ Stream next (CC (False :*: False :*: s0) '\0' '\0') len where next (CC (up :*: prev :*: s) '\0' _) =- case next0 s of- Done -> Done- Skip s' -> Skip (CC (up :*: prev :*: s') '\0' '\0')- Yield t s' ->- case t of- B _ -> md (False :*: True :*: s')- U c | prev -> mu c (True :*: False :*: s')- L c | prev -> mu c (False :*: False :*: s')- U c | up -> mu c (True :*: False :*: s')- U c -> mc c (True :*: False :*: s')- L c -> mc c (False :*: False :*: s')-+ case next0 s of+ Done -> Done+ Skip s' -> Skip (CC (up :*: prev :*: s') '\0' '\0')+ Yield t s' ->+ case t of+ B _ -> md (False :*: True :*: s')+ U c | prev -> mu c (True :*: False :*: s')+ L c | prev -> mu c (False :*: False :*: s')+ U c | up -> mu c (True :*: False :*: s')+ U c -> mc c (True :*: False :*: s')+ L c -> mc c (False :*: False :*: s') next (CC s a b) = Yield a (CC s b '\0') {-# INLINE [0] transformWith #-} -- | A token representing characters and boundaries in a stream. data Token- = B {-# UNPACK #-} !Char -- ^ Word boundary.- | U {-# UNPACK #-} !Char -- ^ Upper case character.- | L {-# UNPACK #-} !Char -- ^ Lower case character.- deriving (Show)+ = -- | Word boundary.+ B {-# UNPACK #-} !Char+ | -- | Upper case character.+ U {-# UNPACK #-} !Char+ | -- | Lower case character.+ L {-# UNPACK #-} !Char+ deriving (Show) -- | Tokenise a character stream using the default 'isBoundary' predicate. -- -- /See:/ 'tokeniseWith'-tokenise :: Stream Char -- ^ Input stream.- -> Stream Token+tokenise ::+ -- | Input stream.+ Stream Char ->+ Stream Token tokenise = tokeniseWith isBoundary {-# INLINE [0] tokenise #-} -- | Tokenise a character stream using a custom boundary predicate.-tokeniseWith :: (Char -> Bool) -- ^ Boundary predicate.- -> Stream Char -- ^ Input stream.- -> Stream Token+tokeniseWith ::+ -- | Boundary predicate.+ (Char -> Bool) ->+ -- | Input stream.+ Stream Char ->+ Stream Token tokeniseWith f (Stream next0 s0 len) =- -- HINT: len incorrect if there are adjacent boundaries, which are skipped.- Stream next (CC (True :*: False :*: False :*: s0) '\0' '\0') len+ -- HINT: len incorrect if there are adjacent boundaries, which are skipped.+ Stream next (CC (True :*: False :*: False :*: s0) '\0' '\0') len where next (CC (start :*: up :*: prev :*: s) '\0' _) =- case next0 s of- Done -> Done- Skip s' -> Skip (CC (start :*: up :*: prev :*: s') '\0' '\0')- Yield c s'- | not b, start -> push- | up -> push- | b, prev -> Skip (step start)- | otherwise -> push- where- push | b = Yield (B c) (step False)- | u, skip = Yield (U c) (step False)- | u = Yield (B '\0') (CC (False :*: u :*: b :*: s') c '\0')- | otherwise = Yield (L c) (step False)-- step p = CC (p :*: u :*: b :*: s') '\0' '\0'+ case next0 s of+ Done -> Done+ Skip s' -> Skip (CC (start :*: up :*: prev :*: s') '\0' '\0')+ Yield c s'+ | not b, start -> push+ | up -> push+ | b, prev -> Skip (step start)+ | otherwise -> push+ where+ push+ | b = Yield (B c) (step False)+ | u, skip = Yield (U c) (step False)+ | u = Yield (B '\0') (CC (False :*: u :*: b :*: s') c '\0')+ | otherwise = Yield (L c) (step False) - skip = up || start || prev+ step p = CC (p :*: u :*: b :*: s') '\0' '\0' - b = f c- u = Char.isUpper c+ skip = up || start || prev + b = f c+ u = Char.isUpper c next (CC s a b) = Yield (U a) (CC s b '\0') {-# INLINE [0] tokeniseWith #-}
src/Data/Text/Manipulate/Internal/Types.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MagicHash #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE ViewPatterns #-} -- Module : Data.Text.Manipulate.Internal.Types--- Copyright : (c) 2014-2015 Brendan Hay <brendan.g.hay@gmail.com>+-- Copyright : (c) 2014-2020 Brendan Hay <brendan.g.hay@gmail.com> -- License : This Source Code Form is subject to the terms of -- the Mozilla Public License, v. 2.0. -- A copy of the MPL can be found in the LICENSE file or@@ -14,11 +14,10 @@ module Data.Text.Manipulate.Internal.Types where -import Control.Monad-import qualified Data.Char as Char-import Data.Monoid-import Data.Text.Lazy.Builder (Builder, singleton)-import GHC.Base+import Control.Monad+import qualified Data.Char as Char+import Data.Text.Lazy.Builder (Builder, singleton)+import GHC.Base -- | Returns 'True' for any boundary or uppercase character. isWordBoundary :: Char -> Bool@@ -30,25 +29,27 @@ ordinal :: Integral a => a -> Builder ordinal (toInteger -> n) = decimal n <> suf- where- suf | x `elem` [11..13] = "th"- | y == 1 = "st"- | y == 2 = "nd"- | y == 3 = "rd"- | otherwise = "th"+ where+ suf+ | x `elem` [11 .. 13] = "th"+ | y == 1 = "st"+ | y == 2 = "nd"+ | y == 3 = "rd"+ | otherwise = "th" - (flip mod 100 -> x, flip mod 10 -> y) = join (,) (abs n)-{-# NOINLINE[0] ordinal #-}+ (flip mod 100 -> x, flip mod 10 -> y) = join (,) (abs n)+{-# NOINLINE [0] ordinal #-} decimal :: Integral a => a -> Builder {-# SPECIALIZE decimal :: Int -> Builder #-} decimal i- | i < 0 = singleton '-' <> go (-i)- | otherwise = go i+ | i < 0 = singleton '-' <> go (- i)+ | otherwise = go i where- go n | n < 10 = digit n- | otherwise = go (n `quot` 10) <> digit (n `rem` 10)-{-# NOINLINE[0] decimal #-}+ go n+ | n < 10 = digit n+ | otherwise = go (n `quot` 10) <> digit (n `rem` 10)+{-# NOINLINE [0] decimal #-} digit :: Integral a => a -> Builder digit n = singleton $! i2d (fromIntegral n)
test/Main.hs view
@@ -1,9 +1,8 @@ {-# LANGUAGE OverloadedStrings #-}- {-# OPTIONS_GHC -fno-warn-type-defaults #-} -- Module : Main--- Copyright : (c) 2014-2015 Brendan Hay <brendan.g.hay@gmail.com>+-- Copyright : (c) 2014-2020 Brendan Hay <brendan.g.hay@gmail.com> -- License : This Source Code Form is subject to the terms of -- the Mozilla Public License, v. 2.0. -- A copy of the MPL can be found in the LICENSE file or@@ -14,202 +13,214 @@ module Main (main) where -import Data.Text (Text)-import Data.Text.Manipulate-import Test.Tasty-import Test.Tasty.HUnit+import Data.Text (Text)+import Data.Text.Manipulate+import Test.Tasty+import Test.Tasty.HUnit main :: IO ()-main = defaultMain $ testGroup "tests"- [ exampleGroup "lowerHead" lowerHead- [ ""- , "title cased phrase"- , "camelCasedPhrase"- , "pascalCasedPhrase"- , "snake_cased_phrase"- , "spinal-cased-phrase"- , "train-Cased-Phrase"- , "1-Mixed_string AOK"- , "a double--stop__phrase"- , "hTML5"- , "είναιΥπάρχουν πολλές-Αντίθετα"- , "je_obecněÚvodní-Španěl"- ]-- , exampleGroup "upperHead" upperHead- [ ""- , "Title cased phrase"- , "CamelCasedPhrase"- , "PascalCasedPhrase"- , "Snake_cased_phrase"- , "Spinal-cased-phrase"- , "Train-Cased-Phrase"- , "1-Mixed_string AOK"- , "A double--stop__phrase"- , "HTML5"- , "ΕίναιΥπάρχουν πολλές-Αντίθετα"- , "Je_obecněÚvodní-Španěl"- ]-- , exampleGroup "takeWord" takeWord- [ ""- , "Title"- , "camel"- , "Pascal"- , "snake"- , "spinal"- , "Train"- , "1"- , "a"- , "HTML5"- , "Είναι"- , "Je"- ]-- , exampleGroup "dropWord" dropWord- [ ""- , "cased phrase"- , "CasedPhrase"- , "CasedPhrase"- , "cased_phrase"- , "cased-phrase"- , "Cased-Phrase"- , "Mixed_string AOK"- , "double-stop_phrase"- , ""- , "Υπάρχουν πολλές-Αντίθετα"- , "obecněÚvodní-Španěl"- ]-- , exampleGroup "stripWord" stripWord- [ Nothing- , Just "cased phrase"- , Just "CasedPhrase"- , Just "CasedPhrase"- , Just "cased_phrase"- , Just "cased-phrase"- , Just "Cased-Phrase"- , Just "Mixed_string AOK"- , Just "double-stop_phrase"- , Just ""- , Just "Υπάρχουν πολλές-Αντίθετα"- , Just "obecněÚvodní-Španěl"- ]-- , testGroup "splitWords"- [- ]-- , testGroup "indentLines"- [- ]-- , testGroup "toAcronym"- [- ]-- , testGroup "toOrdinal"- [ testCase "1st" ("1st" @=? toOrdinal 1)- , testCase "2nd" ("2nd" @=? toOrdinal 2)- , testCase "3rd" ("3rd" @=? toOrdinal 3)- , testCase "4th" ("4th" @=? toOrdinal 4)- , testCase "5th" ("5th" @=? toOrdinal 5)- , testCase "21st" ("21st" @=? toOrdinal 21)- , testCase "33rd" ("33rd" @=? toOrdinal 33)- , testCase "102nd" ("102nd" @=? toOrdinal 102)- , testCase "203rd" ("203rd" @=? toOrdinal 203)- ]-- , exampleGroup "toCamel" toCamel- [ ""- , "titleCasedPhrase"- , "camelCasedPhrase"- , "pascalCasedPhrase"- , "snakeCasedPhrase"- , "spinalCasedPhrase"- , "trainCasedPhrase"- , "1MixedStringAOK"- , "aDoubleStopPhrase"- , "hTML5"- , "είναιΥπάρχουνΠολλέςΑντίθετα"- , "jeObecněÚvodníŠpaněl"- ]-- , exampleGroup "toPascal" toPascal- [ ""- , "TitleCasedPhrase"- , "CamelCasedPhrase"- , "PascalCasedPhrase"- , "SnakeCasedPhrase"- , "SpinalCasedPhrase"- , "TrainCasedPhrase"- , "1MixedStringAOK"- , "ADoubleStopPhrase"- , "HTML5"- , "ΕίναιΥπάρχουνΠολλέςΑντίθετα"- , "JeObecněÚvodníŠpaněl"- ]-- , exampleGroup "toSnake" toSnake- [ ""- , "title_cased_phrase"- , "camel_cased_phrase"- , "pascal_cased_phrase"- , "snake_cased_phrase"- , "spinal_cased_phrase"- , "train_cased_phrase"- , "1_mixed_string_aok"- , "a_double_stop_phrase"- , "html5"- , "είναι_υπάρχουν_πολλές_αντίθετα"- , "je_obecně_úvodní_španěl"- ]-- , exampleGroup "toSpinal" toSpinal- [ ""- , "title-cased-phrase"- , "camel-cased-phrase"- , "pascal-cased-phrase"- , "snake-cased-phrase"- , "spinal-cased-phrase"- , "train-cased-phrase"- , "1-mixed-string-aok"- , "a-double-stop-phrase"- , "html5"- , "είναι-υπάρχουν-πολλές-αντίθετα"- , "je-obecně-úvodní-španěl"- ]-- , exampleGroup "toTrain" toTrain- [ ""- , "Title-Cased-Phrase"- , "Camel-Cased-Phrase"- , "Pascal-Cased-Phrase"- , "Snake-Cased-Phrase"- , "Spinal-Cased-Phrase"- , "Train-Cased-Phrase"- , "1-Mixed-String-AOK"- , "A-Double-Stop-Phrase"- , "HTML5"- , "Είναι-Υπάρχουν-Πολλές-Αντίθετα"- , "Je-Obecně-Úvodní-Španěl"- ]-- , exampleGroup "toTitle" toTitle- [ ""- , "Title Cased Phrase"- , "Camel Cased Phrase"- , "Pascal Cased Phrase"- , "Snake Cased Phrase"- , "Spinal Cased Phrase"- , "Train Cased Phrase"- , "1 Mixed String AOK"- , "A Double Stop Phrase"- , "HTML5"- , "Είναι Υπάρχουν Πολλές Αντίθετα"- , "Je Obecně Úvodní Španěl"- ]- ]+main =+ defaultMain $+ testGroup+ "tests"+ [ exampleGroup+ "lowerHead"+ lowerHead+ [ "",+ "title cased phrase",+ "camelCasedPhrase",+ "pascalCasedPhrase",+ "snake_cased_phrase",+ "spinal-cased-phrase",+ "train-Cased-Phrase",+ "1-Mixed_string AOK",+ "a double--stop__phrase",+ "hTML5",+ "είναιΥπάρχουν πολλές-Αντίθετα",+ "je_obecněÚvodní-Španěl"+ ],+ exampleGroup+ "upperHead"+ upperHead+ [ "",+ "Title cased phrase",+ "CamelCasedPhrase",+ "PascalCasedPhrase",+ "Snake_cased_phrase",+ "Spinal-cased-phrase",+ "Train-Cased-Phrase",+ "1-Mixed_string AOK",+ "A double--stop__phrase",+ "HTML5",+ "ΕίναιΥπάρχουν πολλές-Αντίθετα",+ "Je_obecněÚvodní-Španěl"+ ],+ exampleGroup+ "takeWord"+ takeWord+ [ "",+ "Title",+ "camel",+ "Pascal",+ "snake",+ "spinal",+ "Train",+ "1",+ "a",+ "HTML5",+ "Είναι",+ "Je"+ ],+ exampleGroup+ "dropWord"+ dropWord+ [ "",+ "cased phrase",+ "CasedPhrase",+ "CasedPhrase",+ "cased_phrase",+ "cased-phrase",+ "Cased-Phrase",+ "Mixed_string AOK",+ "double-stop_phrase",+ "",+ "Υπάρχουν πολλές-Αντίθετα",+ "obecněÚvodní-Španěl"+ ],+ exampleGroup+ "stripWord"+ stripWord+ [ Nothing,+ Just "cased phrase",+ Just "CasedPhrase",+ Just "CasedPhrase",+ Just "cased_phrase",+ Just "cased-phrase",+ Just "Cased-Phrase",+ Just "Mixed_string AOK",+ Just "double-stop_phrase",+ Just "",+ Just "Υπάρχουν πολλές-Αντίθετα",+ Just "obecněÚvodní-Španěl"+ ],+ testGroup+ "splitWords"+ [],+ testGroup+ "indentLines"+ [],+ testGroup+ "toAcronym"+ [],+ testGroup+ "toOrdinal"+ [ testCase "1st" ("1st" @=? toOrdinal 1),+ testCase "2nd" ("2nd" @=? toOrdinal 2),+ testCase "3rd" ("3rd" @=? toOrdinal 3),+ testCase "4th" ("4th" @=? toOrdinal 4),+ testCase "5th" ("5th" @=? toOrdinal 5),+ testCase "21st" ("21st" @=? toOrdinal 21),+ testCase "33rd" ("33rd" @=? toOrdinal 33),+ testCase "102nd" ("102nd" @=? toOrdinal 102),+ testCase "203rd" ("203rd" @=? toOrdinal 203)+ ],+ exampleGroup+ "toCamel"+ toCamel+ [ "",+ "titleCasedPhrase",+ "camelCasedPhrase",+ "pascalCasedPhrase",+ "snakeCasedPhrase",+ "spinalCasedPhrase",+ "trainCasedPhrase",+ "1MixedStringAOK",+ "aDoubleStopPhrase",+ "hTML5",+ "είναιΥπάρχουνΠολλέςΑντίθετα",+ "jeObecněÚvodníŠpaněl"+ ],+ exampleGroup+ "toPascal"+ toPascal+ [ "",+ "TitleCasedPhrase",+ "CamelCasedPhrase",+ "PascalCasedPhrase",+ "SnakeCasedPhrase",+ "SpinalCasedPhrase",+ "TrainCasedPhrase",+ "1MixedStringAOK",+ "ADoubleStopPhrase",+ "HTML5",+ "ΕίναιΥπάρχουνΠολλέςΑντίθετα",+ "JeObecněÚvodníŠpaněl"+ ],+ exampleGroup+ "toSnake"+ toSnake+ [ "",+ "title_cased_phrase",+ "camel_cased_phrase",+ "pascal_cased_phrase",+ "snake_cased_phrase",+ "spinal_cased_phrase",+ "train_cased_phrase",+ "1_mixed_string_aok",+ "a_double_stop_phrase",+ "html5",+ "είναι_υπάρχουν_πολλές_αντίθετα",+ "je_obecně_úvodní_španěl"+ ],+ exampleGroup+ "toSpinal"+ toSpinal+ [ "",+ "title-cased-phrase",+ "camel-cased-phrase",+ "pascal-cased-phrase",+ "snake-cased-phrase",+ "spinal-cased-phrase",+ "train-cased-phrase",+ "1-mixed-string-aok",+ "a-double-stop-phrase",+ "html5",+ "είναι-υπάρχουν-πολλές-αντίθετα",+ "je-obecně-úvodní-španěl"+ ],+ exampleGroup+ "toTrain"+ toTrain+ [ "",+ "Title-Cased-Phrase",+ "Camel-Cased-Phrase",+ "Pascal-Cased-Phrase",+ "Snake-Cased-Phrase",+ "Spinal-Cased-Phrase",+ "Train-Cased-Phrase",+ "1-Mixed-String-AOK",+ "A-Double-Stop-Phrase",+ "HTML5",+ "Είναι-Υπάρχουν-Πολλές-Αντίθετα",+ "Je-Obecně-Úvodní-Španěl"+ ],+ exampleGroup+ "toTitle"+ toTitle+ [ "",+ "Title Cased Phrase",+ "Camel Cased Phrase",+ "Pascal Cased Phrase",+ "Snake Cased Phrase",+ "Spinal Cased Phrase",+ "Train Cased Phrase",+ "1 Mixed String AOK",+ "A Double Stop Phrase",+ "HTML5",+ "Είναι Υπάρχουν Πολλές Αντίθετα",+ "Je Obecně Úvodní Španěl"+ ]+ ] exampleGroup :: (Show a, Eq a) => TestName -> (Text -> a) -> [a] -> TestTree exampleGroup n f = testGroup n . zipWith run reference@@ -217,16 +228,16 @@ run (c, x) y = testCase c (f x @=? y) reference =- [ ("Empty", "")- , ("Title", "Title cased phrase")- , ("Camel", "camelCasedPhrase")- , ("Pascal", "PascalCasedPhrase")- , ("Snake", "snake_cased_phrase")- , ("Spinal", "spinal-cased-phrase")- , ("Train", "Train-Cased-Phrase")- , ("Mixed", "1-Mixed_string AOK")- , ("Double Stop", "a double--stop__phrase")- , ("Acronym", "HTML5")- , ("Greek", "ΕίναιΥπάρχουν πολλές-Αντίθετα")- , ("Czech", "Je_obecněÚvodní-Španěl")- ]+ [ ("Empty", ""),+ ("Title", "Title cased phrase"),+ ("Camel", "camelCasedPhrase"),+ ("Pascal", "PascalCasedPhrase"),+ ("Snake", "snake_cased_phrase"),+ ("Spinal", "spinal-cased-phrase"),+ ("Train", "Train-Cased-Phrase"),+ ("Mixed", "1-Mixed_string AOK"),+ ("Double Stop", "a double--stop__phrase"),+ ("Acronym", "HTML5"),+ ("Greek", "ΕίναιΥπάρχουν πολλές-Αντίθετα"),+ ("Czech", "Je_obecněÚvodní-Španěl")+ ]
text-manipulate.cabal view
@@ -1,75 +1,73 @@-name: text-manipulate-version: 0.2.0.1-synopsis: Case conversion, word boundary manipulation, and textual subjugation.-homepage: https://github.com/brendanhay/text-manipulate-license: OtherLicense-license-file: LICENSE-author: Brendan Hay-maintainer: Brendan Hay <brendan.g.hay@gmail.com>-copyright: Copyright (c) 2014-2015 Brendan Hay-category: Data, Text-build-type: Simple-extra-source-files: README.md-cabal-version: >= 1.10+name: text-manipulate+version: 0.3.0.0+synopsis:+ Case conversion, word boundary manipulation, and textual subjugation. +homepage: https://github.com/brendanhay/text-manipulate+license: MPL-2.0+license-file: LICENSE+author: Brendan Hay+maintainer: Brendan Hay <brendan.g.hay@gmail.com>+copyright: Copyright (c) 2014-2020 Brendan Hay+category: Data, Text+build-type: Simple+extra-source-files: README.md+cabal-version: >=2.0 description:- Manipulate identifiers and structurally non-complex pieces- of text by delimiting word boundaries via a combination of whitespace,- control-characters, and case-sensitivity.- .- Has support for common idioms like casing of programmatic variable names,- taking, dropping, and splitting by word, and modifying the first character- of a piece of text.- .- /Caution:/ this library makes heavy use of the <http://hackage.haskell.org/package/text text>- library's internal loop optimisation framework. Since internal modules are not- guaranteed to have a stable API there is potential for build breakage when- the text dependency is upgraded. Consider yourself warned!+ Manipulate identifiers and structurally non-complex pieces+ of text by delimiting word boundaries via a combination of whitespace,+ control-characters, and case-sensitivity.+ .+ Has support for common idioms like casing of programmatic variable names,+ taking, dropping, and splitting by word, and modifying the first character+ of a piece of text.+ .+ /Caution:/ this library makes heavy use of the <http://hackage.haskell.org/package/text text>+ library's internal loop optimisation framework. Since internal modules are not+ guaranteed to have a stable API there is potential for build breakage when+ the text dependency is upgraded. Consider yourself warned! source-repository head- type: git- location: git://github.com/brendanhay/text-manipulate.git+ type: git+ location: git://github.com/brendanhay/text-manipulate.git library- default-language: Haskell2010- hs-source-dirs: src- ghc-options: -Wall-- exposed-modules:- Data.Text.Manipulate- , Data.Text.Lazy.Manipulate+ default-language: Haskell2010+ hs-source-dirs: src+ ghc-options: -Wall+ exposed-modules:+ Data.Text.Lazy.Manipulate+ Data.Text.Manipulate - other-modules:- Data.Text.Manipulate.Internal.Fusion- , Data.Text.Manipulate.Internal.Types+ other-modules:+ Data.Text.Manipulate.Internal.Fusion+ Data.Text.Manipulate.Internal.Types - build-depends:- base >= 4.5 && < 5- , text >= 1.1+ build-depends:+ base >=4.12 && <5+ , text >=1.1 benchmark benchmarks- type: exitcode-stdio-1.0- default-language: Haskell2010- main-is: Main.hs- hs-source-dirs: bench- ghc-options: -Wall -O2 -threaded -with-rtsopts=-T-- build-depends:- base- , criterion >= 1.0.0.2- , text-manipulate- , text+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ main-is: Main.hs+ hs-source-dirs: bench+ ghc-options: -Wall -O2 -threaded -with-rtsopts=-T+ build-depends:+ base >=4.12 && <5+ , criterion >=1.0.0.2+ , text+ , text-manipulate test-suite tests- type: exitcode-stdio-1.0- default-language: Haskell2010- hs-source-dirs: test- main-is: Main.hs- ghc-options: -Wall -threaded-- build-depends:- base- , text-manipulate- , tasty >= 0.8- , tasty-hunit >= 0.8- , text+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ hs-source-dirs: test+ main-is: Main.hs+ ghc-options: -Wall -threaded+ build-depends:+ base >=4.12 && <5+ , tasty >=0.8+ , tasty-hunit >=0.8+ , text+ , text-manipulate