ascii-case 1.0.0.4 → 1.0.0.6
raw patch · 5 files changed
+175/−116 lines, 5 filesdep +ascii-casedep ~ascii-chardep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: ascii-case
Dependency ranges changed: ascii-char, base
API changes (from Hackage documentation)
Files
- ASCII/Case.hs +0/−113
- ascii-case.cabal +13/−3
- changelog.txt +1/−0
- library/ASCII/Case.hs +107/−0
- test/test.hs +54/−0
− ASCII/Case.hs
@@ -1,113 +0,0 @@-{- |--/Case/ is a property of letters. /A-Z/ are /upper case/ letters, and /a-z/ are /lower case/ letters. No other ASCII characters have case.---}--module ASCII.Case ( Case (..), letterCase, isCase, toCase ) where--import ASCII.Char ( Char (..) )-import Data.Bool ( Bool, otherwise )-import Data.Data ( Data )-import Data.Eq ( Eq )-import Data.Function ( (.), ($) )-import Data.Hashable ( Hashable )-import Data.Ord ( Ord, (<=), (>=) )-import GHC.Generics ( Generic )-import Prelude ( Enum, Bounded, Int, (+), (-) )-import Text.Show ( Show )-import Data.Maybe ( Maybe (..) )--import qualified ASCII.Char as Char-import qualified Data.Bool as Bool--{- $setup-->>> import Prelude---}--data Case =- UpperCase -- ^ The letters from 'CapitalLetterA' to 'CapitalLetterZ'.- | LowerCase -- ^ The letters from 'SmallLetterA' to 'SmallLetterZ'.--deriving stock instance Eq Case--deriving stock instance Ord Case--deriving stock instance Enum Case--deriving stock instance Bounded Case--deriving stock instance Show Case--deriving stock instance Data Case--deriving stock instance Generic Case--deriving anyclass instance Hashable Case--{- | Determines whether a character is a letter, and if so, whether it is upper or lower case.-->>> map letterCase [CapitalLetterR, SmallLetterR, DollarSign]-[Just UpperCase,Just LowerCase,Nothing]---}--letterCase :: Char -> Maybe Case-letterCase x | isCase UpperCase x = Just UpperCase- | isCase LowerCase x = Just LowerCase- | otherwise = Nothing--{- | Determines whether a character is a letter of a particular case.-->>> map (isCase UpperCase) [CapitalLetterR,SmallLetterR,DollarSign]-[True,False,False]---}--isCase :: Case -> Char -> Bool-isCase c x = (Bool.&&) ( x >= a ) ( x <= z ) where (a, z) = az c--az :: Case -> (Char, Char)-az UpperCase = (CapitalLetterA, CapitalLetterZ)-az LowerCase = (SmallLetterA, SmallLetterZ)--{- | Maps a letter character to its upper/lower case equivalent.-->>> toCase UpperCase SmallLetterX-CapitalLetterX-->>> toCase LowerCase CapitalLetterF-SmallLetterF--Characters that are already in the requested case are unmodified by this transformation.-->>> toCase UpperCase CapitalLetterA-CapitalLetterA--Characters that are not letters, such as exclamation mark, are unmodified by this transformation.-->>> toCase UpperCase ExclamationMark-ExclamationMark---}--toCase :: Case -> Char -> Char-toCase c x = if isCase (opposite c) x then changeCaseUnsafe c x else x---- | Change a letter to the given case, assuming that the input character is a letter of the opposite case.--changeCaseUnsafe :: Case -> Char -> Char-changeCaseUnsafe c = charAsIntUnsafe (changeCaseInt c)--changeCaseInt :: Case -> Int -> Int-changeCaseInt LowerCase i = i + 32-changeCaseInt UpperCase i = i - 32--opposite :: Case -> Case-opposite UpperCase = LowerCase-opposite LowerCase = UpperCase--charAsIntUnsafe :: (Int -> Int) -> (Char -> Char)-charAsIntUnsafe f = Char.fromIntUnsafe . f . Char.toInt
ascii-case.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.0 name: ascii-case-version: 1.0.0.4+version: 1.0.0.6 synopsis: ASCII letter case category: Data, Text @@ -18,8 +18,6 @@ build-type: Simple -tested-with: GHC == 9.0.1, GHC == 8.10.1, GHC == 8.8.1, GHC == 8.6.5, GHC == 8.4.3- extra-source-files: changelog.txt source-repository head@@ -35,6 +33,7 @@ default-extensions: DeriveDataTypeable default-extensions: DeriveGeneric ghc-options: -Wall+ hs-source-dirs: library build-depends: ascii-char ^>= 1.0 @@ -42,3 +41,14 @@ build-depends: hashable >= 1.2 && < 1.4 exposed-modules: ASCII.Case++test-suite test+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ default-extensions: NoImplicitPrelude+ default-extensions: OverloadedStrings+ default-extensions: QuasiQuotes+ ghc-options: -Wall+ hs-source-dirs: test+ main-is: test.hs+ build-depends: ascii-case, ascii-char, base
changelog.txt view
@@ -1,3 +1,4 @@ 1.0.0.0 - 2020-05-05 - Initial release 1.0.0.2 - 2020-05-18 - Support GHC 8.10 1.0.0.4 - 2021-02-10 - Support GHC 9.0+1.0.0.6 - 2021-09-26 - Add a test suite
+ library/ASCII/Case.hs view
@@ -0,0 +1,107 @@+{- |++/Case/ is a property of letters. /A-Z/ are /upper case/ letters, and /a-z/ are /lower case/ letters. No other ASCII characters have case.++-}++module ASCII.Case ( Case (..), letterCase, isCase, toCase ) where++import ASCII.Char ( Char (..) )+import Data.Bool ( Bool, otherwise )+import Data.Data ( Data )+import Data.Eq ( Eq )+import Data.Function ( (.) )+import Data.Hashable ( Hashable )+import Data.Ord ( Ord, (<=), (>=) )+import GHC.Generics ( Generic )+import Prelude ( Enum, Bounded, Int, (+), (-) )+import Text.Show ( Show )+import Data.Maybe ( Maybe (..) )++import qualified ASCII.Char as Char+import qualified Data.Bool as Bool++data Case =+ UpperCase -- ^ The letters from 'CapitalLetterA' to 'CapitalLetterZ'.+ | LowerCase -- ^ The letters from 'SmallLetterA' to 'SmallLetterZ'.++deriving stock instance Eq Case++deriving stock instance Ord Case++deriving stock instance Enum Case++deriving stock instance Bounded Case++deriving stock instance Show Case++deriving stock instance Data Case++deriving stock instance Generic Case++deriving anyclass instance Hashable Case++{- | Determines whether a character is a letter, and if so, whether it is upper or lower case.++>>> map letterCase [CapitalLetterR, SmallLetterR, DollarSign]+[Just UpperCase,Just LowerCase,Nothing]++-}++letterCase :: Char -> Maybe Case+letterCase x | isCase UpperCase x = Just UpperCase+ | isCase LowerCase x = Just LowerCase+ | otherwise = Nothing++{- | Determines whether a character is a letter of a particular case.++>>> map (isCase UpperCase) [CapitalLetterR,SmallLetterR,DollarSign]+[True,False,False]++-}++isCase :: Case -> Char -> Bool+isCase c x = (Bool.&&) ( x >= a ) ( x <= z ) where (a, z) = az c++az :: Case -> (Char, Char)+az UpperCase = (CapitalLetterA, CapitalLetterZ)+az LowerCase = (SmallLetterA, SmallLetterZ)++{- | Maps a letter character to its upper/lower case equivalent.++>>> toCase UpperCase SmallLetterX+CapitalLetterX++>>> toCase LowerCase CapitalLetterF+SmallLetterF++Characters that are already in the requested case are unmodified by this transformation.++>>> toCase UpperCase CapitalLetterA+CapitalLetterA++Characters that are not letters, such as exclamation mark, are unmodified by this transformation.++>>> toCase UpperCase ExclamationMark+ExclamationMark++-}++toCase :: Case -> Char -> Char+toCase c x = if isCase (opposite c) x then changeCaseUnsafe c x else x++-- | Change a letter to the given case, assuming that the input character is a letter of the opposite case.++changeCaseUnsafe :: Case -> Char -> Char+changeCaseUnsafe c = charAsIntUnsafe (changeCaseInt c)++changeCaseInt :: Case -> Int -> Int+changeCaseInt LowerCase i = i + 32+changeCaseInt UpperCase i = i - 32++opposite :: Case -> Case+opposite UpperCase = LowerCase+opposite LowerCase = UpperCase++charAsIntUnsafe :: (Int -> Int) -> (Char -> Char)+charAsIntUnsafe f = Char.fromIntUnsafe . f . Char.toInt
+ test/test.hs view
@@ -0,0 +1,54 @@+module Main where++import ASCII.Case++import ASCII.Char (Char (..))++import Control.Applicative (Applicative (..))+import Control.Monad (Monad (..))+import Data.Bool (Bool (..))+import Data.Eq (Eq ((==)))+import Data.Function ((.), ($))+import Data.Functor (Functor (..))+import Data.List (intercalate, map, null)+import Data.Maybe (Maybe (..))+import Data.Semigroup ((<>))+import Numeric.Natural (Natural)+import System.Exit (die)+import System.IO (IO, putStrLn)+import Text.Show (show)++main :: IO ()+main = dieIfFailures $ do+ test 1 $ map letterCase [CapitalLetterR, SmallLetterR, DollarSign] == [Just UpperCase, Just LowerCase,Nothing]+ test 2 $ map (isCase UpperCase) [CapitalLetterR, SmallLetterR, DollarSign] == [True, False, False]+ test 3 $ toCase UpperCase SmallLetterX == CapitalLetterX+ test 4 $ toCase LowerCase CapitalLetterF == SmallLetterF+ test 5 $ toCase UpperCase CapitalLetterA == CapitalLetterA+ test 6 $ toCase UpperCase ExclamationMark == ExclamationMark++dieIfFailures :: Failures a -> IO a+dieIfFailures (Failures fs x) =+ if null fs+ then do putStrLn "💯"; return x+ else die $ intercalate " " (map (("🔥" <> ) . show) fs)++type TestNumber = Natural++test :: TestNumber -> Bool -> Failures ()+test n t = Failures (if t then [] else [n]) ()++data Failures a = Failures [TestNumber] a++instance Functor Failures+ where+ fmap f (Failures a x) = Failures a (f x)++instance Applicative Failures+ where+ pure x = Failures [] x+ Failures a f <*> Failures b x = Failures (a <> b) (f x)++instance Monad Failures+ where+ Failures a x >>= f = let Failures b y = f x in Failures (a <> b) y