packages feed

ascii-superset 1.1.1.0 → 1.2.0.0

raw patch · 7 files changed

+136/−17 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ ASCII.CaseRefinement: refineCharToCase :: forall letterCase char. KnownCase letterCase => CharSuperset char => ASCII char -> ASCII'case letterCase char
+ ASCII.CaseRefinement: refineStringToCase :: forall letterCase char. KnownCase letterCase => StringSuperset char => ASCII char -> ASCII'case letterCase char
+ ASCII.Superset: toCaseChar :: CharSuperset char => Case -> char -> char
+ ASCII.Superset: toCaseString :: StringSuperset string => Case -> string -> string

Files

ascii-superset.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0  name: ascii-superset-version: 1.1.1.0+version: 1.2.0.0 synopsis: Representing ASCII with refined supersets category: Data, Text 
changelog.md view
@@ -1,3 +1,31 @@+### 1.2.0.0 (2023-01-03)++Add to the `CharSuperset` class a new method:++```haskell+toCaseChar :: Case -> char -> char+```++Add to the `StringSuperset` class a new method:++```haskell+toCaseString :: Case -> string -> string+```++Add to the `ASCII.CaseRefinement` module:++```haskell+refineCharToCase :: forall letterCase char.+    KnownCase letterCase => CharSuperset char =>+    ASCII char -> ASCII'case letterCase char+```++```haskell+refineStringToCase :: forall letterCase char.+    KnownCase letterCase => StringSuperset char =>+    ASCII char -> ASCII'case letterCase char+```+ ### 1.1.1.0 (2023-01-03)  Add to `ASCII.CaseRefinement` the `KnownCase` class.
library/ASCII/CaseRefinement.hs view
@@ -3,21 +3,23 @@     {- * ASCII'case type constructor -} ASCII'case, lift, asciiCaseUnsafe,     {- ** Aliases -} {- $aliases -} ASCII'upper, ASCII'lower,     {- * Character functions -} validateChar, fromCaselessChar,-          toCaselessChar, substituteChar, asCaselessChar,+          toCaselessChar, substituteChar, asCaselessChar, refineCharToCase,     {- * String functions -} validateString, fromCaselessCharList,-          toCaselessCharList, substituteString, mapChars,+          toCaselessCharList, substituteString, mapChars, refineStringToCase,     {- * KnownCase -} KnownCase (..),   )   where  import ASCII.Case (Case (..)) import ASCII.Caseless (CaselessChar)+import {-# source #-} ASCII.Refinement (ASCII) import ASCII.Superset (CharSuperset, StringSuperset)  import qualified ASCII.Case as Case import qualified ASCII.Caseless as Caseless import qualified ASCII.Char as ASCII import qualified ASCII.Superset as Superset+import {-# source #-} qualified ASCII.Refinement as Refinement  import Control.Monad (guard) import Data.Bool (Bool (..))@@ -145,7 +147,7 @@     ASCII'case letterCase superset {- ^ Character that is known to be ASCII, and                                         in the particular case if it is a letter -}     -> CaselessChar-toCaselessChar =  Caseless.disregardCase . Superset.toCharUnsafe . lift+toCaselessChar = Caseless.disregardCase . Superset.toCharUnsafe . lift  {-| Given a character from a larger set that is known to represent an ASCII character, manipulate it as if it were an ASCII character -}@@ -158,6 +160,12 @@   where     g = Caseless.toCase (theCase @letterCase) . f . Caseless.assumeCaseUnsafe (theCase @letterCase) +{-| Given an ASCII superset character that is known to be valid ASCII,+refine it further by converting it to a particular letter case -}+refineCharToCase :: forall letterCase char. KnownCase letterCase => CharSuperset char =>+    ASCII char -> ASCII'case letterCase char+refineCharToCase = asciiCaseUnsafe . Superset.toCaseChar (theCase @letterCase) . Refinement.lift+ ---  {-| Return 'Just' an 'ASCII'case' string if the input consists entirely of ASCII@@ -206,3 +214,9 @@ mapChars f = asciiCaseUnsafe . Superset.mapCharsUnsafe g . lift   where     g = Caseless.toCase (theCase @letterCase) . f . Caseless.assumeCaseUnsafe (theCase @letterCase)++{-| Given an ASCII superset string that is known to be valid ASCII,+refine it further by converting it to a particular letter case -}+refineStringToCase :: forall letterCase char. KnownCase letterCase => StringSuperset char =>+    ASCII char -> ASCII'case letterCase char+refineStringToCase = asciiCaseUnsafe . Superset.toCaseString (theCase @letterCase) . Refinement.lift
library/ASCII/Refinement.hs view
@@ -10,6 +10,7 @@ import qualified ASCII.Isomorphism as I import qualified ASCII.Superset as S +import ASCII.CaseRefinement (KnownCase (..), ASCII'case, ASCII'upper, ASCII'lower) import Data.Data (Data) import Data.Eq (Eq) import Data.Function (id, ($), (.))@@ -66,7 +67,8 @@ instance S.CharSuperset char => S.FromChar (ASCII char) where     fromChar = asciiUnsafe . S.fromChar -instance S.CharSuperset char => S.CharSuperset (ASCII char)+instance S.CharSuperset char => S.CharSuperset (ASCII char) where+    toCaseChar c = asciiUnsafe . S.toCaseChar c . lift  instance S.CharSuperset char => I.CharIso (ASCII char) where     toChar = S.toCharUnsafe@@ -86,6 +88,7 @@  instance S.StringSuperset string => S.StringSuperset (ASCII string) where     substituteString = id+    toCaseString c = asciiUnsafe . S.toCaseString c . lift  instance S.StringSuperset string => I.StringIso (ASCII string) where     toCharList = S.toCharListUnsafe
+ library/ASCII/Refinement.hs-boot view
@@ -0,0 +1,5 @@+module ASCII.Refinement where++data ASCII superset++lift :: ASCII superset -> superset
library/ASCII/Superset.hs view
@@ -1,7 +1,7 @@ module ASCII.Superset   (     {- * Characters -}-    {- ** Class -} ToCaselessChar (..), ToChar (..), FromChar (..), CharSuperset,+    {- ** Class -} ToCaselessChar (..), ToChar (..), FromChar (..), CharSuperset (..),     {- ** Functions -} asCharUnsafe, toCharMaybe, toCaselessCharMaybe, toCharOrFail, toCaselessCharOrFail,         toCharSub, toCaselessCharSub, substituteChar, convertCharMaybe, convertCharOrFail, @@ -12,6 +12,7 @@   )   where +import ASCII.Case (Case (..)) import ASCII.Caseless (CaselessChar) import Control.Monad (return) import Control.Monad.Fail (MonadFail (fail))@@ -20,7 +21,9 @@ import Data.Functor (fmap) import Data.Maybe (Maybe (..)) import Data.Ord ((<=), (>=))+import Prelude ((+), (-)) +import qualified ASCII.Case as Case import qualified ASCII.Caseless as Caseless import qualified ASCII.Char as ASCII import qualified Data.Bool as Bool@@ -82,8 +85,13 @@  - a total conversion from ASCII; and - a partial conversion to ASCII -}-class (ToChar char, FromChar char) => CharSuperset char+class (ToChar char, FromChar char) => CharSuperset char where +    {- | Convert a character in the superset to the designated case,+    if it is an ASCII letter of the opposite case. Otherwise, return+    the argument unmodified. -}+    toCaseChar :: Case -> char -> char+ {-| Manipulate a character as if it were an ASCII 'ASCII.Char', assuming that it is  Defined only where 'isAsciiChar' is satisfied. -}@@ -194,6 +202,10 @@     mapCharsUnsafe :: (ASCII.Char -> ASCII.Char) -> string -> string     mapCharsUnsafe f = fromCharList  . List.map f . toCharListUnsafe +    {- | Convert each character in the superset to the designated case, if it is+    an ASCII letter of the opposite case. Leaves other characters unchanged. -}+    toCaseString :: Case -> string -> string+ toCharListMaybe :: ToString string => string -> Maybe [ASCII.Char] toCharListMaybe = toCharListOrFail @@ -229,7 +241,7 @@  ---  Instances  --- --- | 'CaselessChar' is trivially convertible to itself. (This instance is uninteresting.)+-- | 'CaselessChar' is trivially convertible to itself. instance ToCaselessChar CaselessChar where     isAsciiCaselessChar _ = Bool.True     toCaselessCharUnsafe = id@@ -247,8 +259,9 @@ instance FromChar ASCII.Char where     fromChar = id --- | 'ASCII.Char' is trivially a superset of itself. (This instance is uninteresting.)-instance CharSuperset ASCII.Char+-- | 'ASCII.Char' is trivially a superset of itself.+instance CharSuperset ASCII.Char where+    toCaseChar = Case.toCase  --- @@ -263,7 +276,10 @@ instance FromChar Unicode.Char where     fromChar = Unicode.chr . ASCII.toInt -instance CharSuperset Unicode.Char+instance CharSuperset Unicode.Char where+    toCaseChar UpperCase x | x >= 'a' && x <= 'z' = Unicode.chr (Unicode.ord x - 32)+    toCaseChar LowerCase x | x >= 'A' && x <= 'Z' = Unicode.chr (Unicode.ord x + 32)+    toCaseChar _ x = x  --- @@ -278,7 +294,10 @@ instance FromChar Nat.Natural where     fromChar = Prelude.fromIntegral . ASCII.toInt -instance CharSuperset Nat.Natural+instance CharSuperset Nat.Natural where+    toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32+    toCaseChar LowerCase x | x >= 65 && x <= 90  = x + 32+    toCaseChar _ x = x  --- @@ -293,7 +312,10 @@ instance FromChar Int.Int where     fromChar = ASCII.toInt -instance CharSuperset Int.Int+instance CharSuperset Int.Int where+    toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32+    toCaseChar LowerCase x | x >= 65 && x <= 90  = x + 32+    toCaseChar _ x = x  --- @@ -308,7 +330,10 @@ instance FromChar Word.Word8 where     fromChar = Prelude.fromIntegral . ASCII.toInt -instance CharSuperset Word.Word8+instance CharSuperset Word.Word8 where+    toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32+    toCaseChar LowerCase x | x >= 65 && x <= 90  = x + 32+    toCaseChar _ x = x  --- @@ -327,6 +352,7 @@  instance CharSuperset char => StringSuperset [char] where     substituteString = List.map substituteChar+    toCaseString c = List.map (toCaseChar c)  --- @@ -346,6 +372,7 @@ instance StringSuperset T.Text where     substituteString = T.map substituteChar     mapCharsUnsafe f = T.map (asCharUnsafe f)+    toCaseString c   = T.map (toCaseChar c)  --- @@ -365,6 +392,7 @@ instance StringSuperset LT.Text where     substituteString = LT.map substituteChar     mapCharsUnsafe f = LT.map (asCharUnsafe f)+    toCaseString c   = LT.map (toCaseChar c)  --- @@ -384,6 +412,7 @@ instance StringSuperset TB.Builder where     substituteString = TB.fromLazyText . substituteString . TB.toLazyText     mapCharsUnsafe f = TB.fromLazyText . mapCharsUnsafe f . TB.toLazyText+    toCaseString c   = TB.fromLazyText . toCaseString c   . TB.toLazyText  --- @@ -403,6 +432,7 @@ instance StringSuperset BS.ByteString where     substituteString = BS.map substituteChar     mapCharsUnsafe f = BS.map (asCharUnsafe f)+    toCaseString c   = BS.map (toCaseChar c)  --- @@ -422,6 +452,7 @@ instance StringSuperset LBS.ByteString where     substituteString = LBS.map substituteChar     mapCharsUnsafe f = LBS.map (asCharUnsafe f)+    toCaseString c   = LBS.map (toCaseChar c)  --- @@ -441,3 +472,4 @@ instance StringSuperset BSB.Builder where     substituteString = BSB.lazyByteString . substituteString . BSB.toLazyByteString     mapCharsUnsafe f = BSB.lazyByteString . mapCharsUnsafe f . BSB.toLazyByteString+    toCaseString c   = BSB.lazyByteString . toCaseString c   . BSB.toLazyByteString
test/Main.hs view
@@ -2,20 +2,29 @@  import Test.Hspec -import ASCII.Refinement (ASCII, asciiUnsafe)+import ASCII.Case (Case (..)) import ASCII.CaseRefinement (ASCII'lower, ASCII'upper, asciiCaseUnsafe)+import ASCII.Char (Char (..))+import ASCII.Refinement (ASCII, asciiUnsafe) +import qualified ASCII.Case as Case+import qualified ASCII.Caseless as CC import qualified ASCII.CaseRefinement as CaseRefinement+import qualified ASCII.Char as ASCII import qualified ASCII.Lift as Lift import qualified ASCII.Refinement as Refinement+import qualified ASCII.Superset as Superset -import ASCII.Char (Char (..))-import qualified ASCII.Caseless as CC+import qualified Data.Foldable as Foldable +import Data.Function ((&)) import Data.Text (Text) import Data.Word (Word8)+import Numeric.Natural (Natural) import Prelude +import qualified Data.Char as Unicode+ main :: IO () main = hspec $ do @@ -116,3 +125,31 @@                 let f x = CaseRefinement.validateString x :: Maybe (ASCII'upper Text)                 f "HELLO" `shouldBe` Just (asciiCaseUnsafe "HELLO")                 f "Hello" `shouldBe` Nothing++    describe "case conversion" $ do++        describe "toCaseChar" $ do+            let check :: forall a. Eq a => Superset.CharSuperset a => Expectation+                check =+                    ([UpperCase, LowerCase] & Foldable.all (\c ->+                        ASCII.allCharacters & Foldable.all (\x ->+                            Superset.toCaseChar c (Superset.fromChar @a x)+                                == Superset.fromChar @a (Case.toCase c x)+                    ))) `shouldBe` True+            it "ASCII.Char" $ check @ASCII.Char+            it "Unicode.Char" $ check @Unicode.Char+            it "Natural" $ check @Natural+            it "Int" $ check @Int+            it "Word8" $ check @Word8++        describe "toCaseString" $ do+            it "Text" $ do+                let x = "012 abc DEF ﬓ" :: Text+                Superset.toCaseString UpperCase x `shouldBe` "012 ABC DEF ﬓ"+                Superset.toCaseString LowerCase x `shouldBe` "012 abc def ﬓ"++        describe "refineStringToCase" $ do+            it "Text" $ do+                let x = asciiUnsafe "Hi!" :: ASCII Text+                CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "HI!" :: ASCII'upper Text)+                CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "hi!" :: ASCII'lower Text)