ascii 1.4.1.0 → 1.4.1.1
raw patch · 4 files changed
+309/−393 lines, 4 filesdep +hspecdep −hedgehogPVP ok
version bump matches the API change (PVP)
Dependencies added: hspec
Dependencies removed: hedgehog
API changes (from Hackage documentation)
Files
- ascii.cabal +6/−6
- changelog.md +4/−0
- library/ASCII.hs +194/−307
- test/Main.hs +105/−80
ascii.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0 name: ascii-version: 1.4.1.0+version: 1.4.1.1 synopsis: The ASCII character set and encoding category: Data, Text @@ -28,7 +28,7 @@ ghc-options: -Wall default-extensions: NoImplicitPrelude build-depends:- ascii-caseless == 0.0.0.*+ , ascii-caseless == 0.0.0.* , ascii-char == 1.0.1.* , ascii-group == 1.0.0.* , ascii-case == 1.0.1.*@@ -46,7 +46,7 @@ default-extensions: RankNTypes ScopedTypeVariables TypeApplications exposed-modules: ASCII reexported-modules:- ASCII.Case+ , ASCII.Case , ASCII.Caseless , ASCII.CaseRefinement , ASCII.Char@@ -69,7 +69,7 @@ type: exitcode-stdio-1.0 hs-source-dirs: test main-is: Main.hs- default-extensions: OverloadedStrings QuasiQuotes TemplateHaskell+ default-extensions: OverloadedStrings QuasiQuotes build-depends:- ascii- , hedgehog ^>= 1.0.5 || ^>= 1.1 || ^>= 1.2+ , ascii+ , hspec ^>= 2.8.5 || ^>= 2.9 || ^>= 2.10
changelog.md view
@@ -1,3 +1,7 @@+### 1.4.1.1 (2023-01-05)++Change test suite from `hedgehog` to `hspec`+ ### 1.4.1.0 (2023-01-05) Raise `ascii-char` version to `1.0.1`. This adds `Word8` conversions to the
library/ASCII.hs view
@@ -35,16 +35,16 @@ {- * Character classifications -} {- ** Print/control groups -} {- $groups -}- Group (..), charGroup, inGroup,+ Group (..), charGroup, inGroup, {- ** Upper/lower case -} {- $case -} Case (..), letterCase, isCase, toCaseChar, toCaseString, disregardCase, refineCharToCase, refineStringToCase,- {- ** Letters -} isLetter,- {- ** Letters and numbers -} isAlphaNum,+ {- ** Letters -} isLetter,+ {- ** Letters and numbers -} isAlphaNum, {- ** Decimal digits -} {- $digit -} isDigit, Digit, {- ** Hexadecimal digits -} {- $hexchar -} isHexDigit, HexChar, {- ** Octal digits -} isOctDigit,- {- ** Spaces and symbols -} isSpace, isPunctuation, isSymbol, isVisible,+ {- ** Spaces and symbols -} isSpace, isPunctuation, isSymbol, isVisible, {- * Monomorphic character conversions -} {- $monomorphicConversions -} {- ** @ASCII.Char@ ↔ @Int@ -} {- $intConversions -}@@ -158,145 +158,127 @@ {- $char -See also: "ASCII.Char"---}+See also: "ASCII.Char" -} {- $caselessChar -See also: "ASCII.Caseless"+See also: "ASCII.Caseless" -} --}+{-| A character in the full range of Unicode --- | A character in the full range of Unicode------ ASCII 'Char' is a subset of this type. Convert using 'charToUnicode' and 'unicodeToCharMaybe'.+ASCII 'Char' is a subset of this type. Convert using 'charToUnicode' and+'unicodeToCharMaybe'. -} type UnicodeChar = Unicode.Char {- $groups -ASCII characters are broadly categorized into two groups: /control codes/ and /printable characters/.--See also: "ASCII.Group"---}-+ASCII characters are broadly categorized into two groups: /control codes/ and+/printable characters/. -{- | Determine which group a particular character belongs to.+See also: "ASCII.Group" -} ->>> map charGroup [CapitalLetterA,EndOfTransmission]-[Printable,Control]+{-| Determine which group a particular character belongs to --}+@+charGroup CapitalLetterA == Printable +charGroup EndOfTransmission == Control+@ -} charGroup :: CharIso char => char -> Group charGroup = ASCII.Group.charGroup . ASCII.Isomorphism.toChar -{- | Test whether a character belongs to a particular ASCII group.-->>> inGroup Printable EndOfTransmission-False-->>> inGroup Control EndOfTransmission-True+{-| Test whether a character belongs to a particular ASCII group ->>> map (inGroup Printable) ( [-1, 5, 65, 97, 127, 130] :: [Int] )-[False,False,True,True,False,False]+@+not (inGroup Printable EndOfTransmission) --}+inGroup Control EndOfTransmission +map (inGroup Printable) ([-1, 5, 65, 97, 127, 130] :: [Int])+ == [False, False, True, True, False, False]+@ -} inGroup :: CharSuperset char => Group -> char -> Bool inGroup g = maybe False (ASCII.Group.inGroup g) . ASCII.Superset.toCharMaybe {- $case -/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.--See also: "ASCII.Case"---}--{- | Determines whether a character is an ASCII letter, and if so, whether it is upper or lower case.+/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. ->>> map letterCase [SmallLetterA, CapitalLetterA, ExclamationMark]-[Just LowerCase,Just UpperCase,Nothing]+See also: "ASCII.Case" -} ->>> map letterCase ( [string|Hey!|] :: [ASCII Word8] )-[Just UpperCase,Just LowerCase,Just LowerCase,Nothing]+{-| Determines whether a character is an ASCII letter, and if so, whether it is+ upper or lower case --}+@+map letterCase [SmallLetterA, CapitalLetterA, ExclamationMark]+ == [Just LowerCase, Just UpperCase, Nothing] +map letterCase ([string|Hey!|] :: [ASCII Word8])+ == [Just UpperCase, Just LowerCase, Just LowerCase, Nothing]+@ -} letterCase :: CharSuperset char => char -> Maybe Case letterCase = ASCII.Superset.toCharMaybe >=> ASCII.Case.letterCase -{- | Determines whether a character is an ASCII letter of a particular case.-->>> map (isCase UpperCase) [SmallLetterA, CapitalLetterA, ExclamationMark]-[False,True,False]-->>> map (isCase UpperCase) ( [string|Hey!|] :: [ASCII Word8] )-[True,False,False,False]+{-| Determines whether a character is an ASCII letter of a particular case ->>> map (isCase UpperCase) ( [-1, 65, 97, 150] :: [Int] )-[False,True,False,False]+@+map (isCase UpperCase) [SmallLetterA, CapitalLetterA, ExclamationMark]+ == [False, True, False] --}+map (isCase UpperCase) ([string|Hey!|] :: [ASCII Word8])+ == [True, False, False, False] +map (isCase UpperCase) ([-1, 65, 97, 150] :: [Int])+ == [False, True, False, False]+@ -} isCase :: CharSuperset char => Case -> char -> Bool isCase c = maybe False (ASCII.Case.isCase c) . ASCII.Superset.toCharMaybe -{- | Maps a letter character to its upper/lower case equivalent.-->>> toCaseChar UpperCase SmallLetterA-CapitalLetterA-->>> ([char|a|] :: ASCII Word8, toCaseChar UpperCase [char|a|] :: ASCII Word8)-(asciiUnsafe 97,asciiUnsafe 65)+{-| Maps a letter character to its upper/lower case equivalent --}+@+toCaseChar UpperCase SmallLetterA == CapitalLetterA +( [char|a|] :: ASCII Word8) == asciiUnsafe 97+(toCaseChar UpperCase [char|a|] :: ASCII Word8) == asciiUnsafe 65+@ -} toCaseChar :: CharSuperset char => Case -> char -> char toCaseChar = ASCII.Superset.toCaseChar -{- | Maps each of the characters in a string to its upper/lower case equivalent.-->>> toCaseString UpperCase [CapitalLetterH,SmallLetterE,SmallLetterY,ExclamationMark]-[CapitalLetterH,CapitalLetterE,CapitalLetterY,ExclamationMark]-->>> toCaseString UpperCase [string|Hey!|] :: ASCII Text-asciiUnsafe "HEY!"+{-| Maps each of the characters in a string to its upper/lower case equivalent --}+@+toCaseString UpperCase [CapitalLetterH, SmallLetterE, SmallLetterY, ExclamationMark]+ == [CapitalLetterH, CapitalLetterE, CapitalLetterY, ExclamationMark] +(toCaseString UpperCase [string|Hey!|] :: ASCII Text) == asciiUnsafe "HEY!"+@ -} toCaseString :: StringSuperset string => Case -> string -> string toCaseString = ASCII.Superset.toCaseString {-| Convert from ASCII character to caseless ASCII character, discarding the-case if the character is a letter -}+ case if the character is a letter -} disregardCase :: Char -> CaselessChar disregardCase = ASCII.Caseless.disregardCase {- $monomorphicConversions -These are a few simple monomorphic functions to convert between ASCII and types representing some other character set.--This is not intended to be an exhaustive list of all possible conversions. For more options, see "ASCII.Superset".+These are a few simple monomorphic functions to convert between ASCII and types+representing some other character set. --}+This is not intended to be an exhaustive list of all possible conversions. For+more options, see "ASCII.Superset". -} {- $intConversions -These functions convert between the ASCII 'Char' type and 'Int'.---}--{- |-->>> map charToInt [Null, CapitalLetterA, SmallLetterA, Delete]-[0,65,97,127]+These functions convert between the ASCII 'Char' type and 'Int'. -} --}+{-| +@+map charToInt [Null, CapitalLetterA, SmallLetterA, Delete] == [0, 65, 97, 127]+@ -} charToInt :: Char -> Int charToInt = ASCII.Superset.fromChar @@ -308,17 +290,13 @@ {- $word8Conversions -These functions convert between the ASCII 'Char' type and 'Word8'.---}--{- |-->>> map charToWord8 [Null, CapitalLetterA, SmallLetterA, Delete]-[0,65,97,127]+These functions convert between the ASCII 'Char' type and 'Word8'. -} --}+{-| +@+map charToWord8 [Null, CapitalLetterA, SmallLetterA, Delete] == [0, 65, 97, 127]+@ -} charToWord8 :: Char -> Word8 charToWord8 = ASCII.Superset.fromChar @@ -330,9 +308,8 @@ {- $unicodeCharConversions -These functions convert between the ASCII 'Char' type and the 'UnicodeChar' type.---}+These functions convert between the ASCII 'Char' type and the 'UnicodeChar'+type. -} charToUnicode :: Char -> UnicodeChar charToUnicode = ASCII.Superset.fromChar@@ -345,11 +322,11 @@ {- $digitWord8Conversions -These functions convert between the ASCII 'Digit' type and ASCII digits in their byte encoding.--These conversions do /not/ correspond to the numeric interpretations of 'Digit' and 'Word8'. For example, 'digitToWord8' 'ASCII.Decimal.Digit0' is 48, not 0.+These functions convert between the ASCII 'Digit' type and ASCII digits in their+byte encoding. --}+These conversions do /not/ correspond to the numeric interpretations of 'Digit'+and 'Word8'. For example, 'digitToWord8' 'ASCII.Decimal.Digit0' is 48, not 0. -} digitToWord8 :: Digit -> Word8 digitToWord8 = ASCII.Decimal.fromDigit@@ -362,9 +339,8 @@ {- $digitCharConversions -These functions convert between the ASCII 'Digit' type and the ASCII 'Char' type.---}+These functions convert between the ASCII 'Digit' type and the ASCII 'Char'+type. -} digitToChar :: Digit -> Char digitToChar = ASCII.Decimal.fromDigit@@ -377,9 +353,8 @@ {- $digitUnicodeConversions -These functions convert between the ASCII 'Digit' type and the 'UnicodeChar' type.---}+These functions convert between the ASCII 'Digit' type and the 'UnicodeChar'+type. -} digitToUnicode :: Digit -> UnicodeChar digitToUnicode = ASCII.Decimal.fromDigit@@ -393,11 +368,12 @@ {- $hexCharWord8Conversions -These functions convert between the ASCII 'HexChar' type and ASCII characters in their byte encoding.--These conversions do /not/ correspond to the numeric interpretations of 'HexChar' and 'Word8'. For example, 'hexCharToWord8' 'ASCII.Hexadecimal.CapitalLetterA' is 65, not 10.+These functions convert between the ASCII 'HexChar' type and ASCII characters in+their byte encoding. --}+These conversions do /not/ correspond to the numeric interpretations of+'HexChar' and 'Word8'. For example, 'hexCharToWord8'+'ASCII.Hexadecimal.CapitalLetterA' is 65, not 10. -} hexCharToWord8 :: HexChar -> Word8 hexCharToWord8 = ASCII.Hexadecimal.fromHexChar@@ -410,9 +386,8 @@ {- $hexCharCharConversions -These functions convert between the ASCII 'HexChar' type and the ASCII 'Char' type.---}+These functions convert between the ASCII 'HexChar' type and the ASCII 'Char'+type. -} hexCharToChar :: HexChar -> Char hexCharToChar = ASCII.Hexadecimal.fromHexChar@@ -425,9 +400,8 @@ {- $hexCharUnicodeConversions -These functions convert between the ASCII 'HexChar' type and the 'UnicodeChar' type.---}+These functions convert between the ASCII 'HexChar' type and the 'UnicodeChar'+type. -} hexCharToUnicode :: HexChar -> UnicodeChar hexCharToUnicode = ASCII.Hexadecimal.fromHexChar@@ -440,9 +414,8 @@ {- $unicodeStringConversions -These functions convert between @['Char']@ (a list of ASCII characters) and 'Unicode.String' (a list of Unicode characters).---}+These functions convert between @['Char']@ (a list of ASCII characters) and+'Unicode.String' (a list of Unicode characters). -} charListToUnicodeString :: [Char] -> Unicode.String charListToUnicodeString = ASCII.Superset.fromCharList@@ -455,17 +428,13 @@ {- $textConversions -These functions convert between @['Char']@ and 'Text.Text'.---}--{- |-->>> charListToText [CapitalLetterH,SmallLetterI,ExclamationMark]-"Hi!"+These functions convert between @['Char']@ and 'Text.Text'. -} --}+{-| +@+charListToText [CapitalLetterH, SmallLetterI, ExclamationMark] == "Hi!"+@ -} charListToText :: [Char] -> Text.Text charListToText = ASCII.Superset.fromCharList @@ -477,9 +446,7 @@ {- $byteStringConversions -These functions convert between @['Char']@ and 'BS.ByteString'.---}+These functions convert between @['Char']@ and 'BS.ByteString'. -} charListToByteString :: [Char] -> BS.ByteString charListToByteString = ASCII.Superset.fromCharList@@ -492,40 +459,36 @@ {- $refinement -See also: "ASCII.Refinement", "ASCII.CaseRefinement"---}+See also: "ASCII.Refinement", "ASCII.CaseRefinement" -} {- $lift -See also: "ASCII.Lift"---}+See also: "ASCII.Lift" -} -{- | Converts from ASCII to any larger type.+{-| Converts from ASCII to any larger type For example, @(lift \@ASCII.Char \@Word8)@ is the same function as 'charToWord8'. ->>> lift CapitalLetterA :: Word8-65+@+(lift CapitalLetterA :: Word8) == 65+@ And @(lift \@[ASCII.Char] \@Text)@ is equivalent to 'charListToText'. ->>> lift [CapitalLetterH,SmallLetterI,ExclamationMark] :: Text-"Hi!"--Due to the highly polymorphic nature of the 'lift' function, often it must used with an explicit type signature or type application to avoid any type ambiguity.+@+(lift [CapitalLetterH,SmallLetterI,ExclamationMark] :: Text) == "Hi!"+@ +Due to the highly polymorphic nature of the 'lift' function, often it must used+with an explicit type signature or type application to avoid any type ambiguity. -}- lift :: Lift ascii superset => ascii -> superset lift = ASCII.Lift.lift {- $supersetConversions -These functions all convert from one ASCII-superset type to another, failing if any of the characters in the input is outside the ASCII character set.---}+These functions all convert from one ASCII-superset type to another, failing if+any of the characters in the input is outside the ASCII character set. -} convertCharMaybe :: (CharSuperset char1, CharSuperset char2) => char1 -> Maybe char2 convertCharMaybe = ASCII.Superset.convertCharMaybe@@ -541,18 +504,19 @@ {- $monoSupersetConversions -These functions are all specializations of 'convertStringMaybe'. They convert a string from one ASCII-superset type to another.-->>> ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x50]-Just "HTTP"--If any of the characters in the input is outside the ASCII character set, the result is 'Nothing'.+These functions are all specializations of 'convertStringMaybe'.+They convert a string from one ASCII-superset type to another. ->>> ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x80]-Nothing+@+ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x50] == Just "HTTP"+@ --}+If any of the characters in the input is outside the ASCII character set, the+result is 'Nothing'. +@+ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x80] == Nothing+@ -} byteStringToUnicodeStringMaybe :: BS.ByteString -> Maybe Unicode.String byteStringToUnicodeStringMaybe = convertStringMaybe @@ -565,59 +529,48 @@ unicodeStringToByteListMaybe :: Unicode.String -> Maybe [Word8] unicodeStringToByteListMaybe = convertStringMaybe -{- | Returns True for ASCII letters:+{-| Returns True for ASCII letters: - 'ASCII.Char.SmallLetterA' to 'ASCII.Char.SmallLetterZ'-- 'ASCII.Char.CapitalLetterA' to 'ASCII.Char.CapitalLetterZ'---}-+- 'ASCII.Char.CapitalLetterA' to 'ASCII.Char.CapitalLetterZ' -} isLetter :: CharSuperset char => char -> Bool isLetter x = any ASCII.Predicates.isLetter (convertCharMaybe x) -{- | Returns True for the characters from 'ASCII.Char.Digit0' to 'ASCII.Char.Digit9'. -}-+{-| Returns True for the characters from 'ASCII.Char.Digit0' to+'ASCII.Char.Digit9'. -} isDigit :: CharSuperset char => char -> Bool isDigit x = any ASCII.Predicates.isDigit (convertCharMaybe x) --{- | Returns True for the characters from 'ASCII.Char.Digit0' to 'ASCII.Char.Digit7'. -}-+{-| Returns True for the characters from 'ASCII.Char.Digit0' to+'ASCII.Char.Digit7'. -} isOctDigit :: CharSuperset char => char -> Bool isOctDigit x = any ASCII.Predicates.isOctDigit (convertCharMaybe x) --{- | Returns True for characters in any of the following ranges:+{-| Returns True for characters in any of the following ranges: - 'ASCII.Char.Digit0' to 'ASCII.Char.Digit9' - 'ASCII.Char.CapitalLetterA' to 'ASCII.Char.CapitalLetterF'-- 'ASCII.Char.SmallLetterA' to 'ASCII.Char.SmallLetterF'---}-+- 'ASCII.Char.SmallLetterA' to 'ASCII.Char.SmallLetterF' -} isHexDigit :: CharSuperset char => char -> Bool isHexDigit x = any ASCII.Predicates.isHexDigit (convertCharMaybe x) -{- | Returns True for the following characters:+{-| Returns True for the following characters: - 'ASCII.Char.Space' - 'ASCII.Char.HorizontalTab' - 'ASCII.Char.LineFeed' - 'ASCII.Char.VerticalTab' - 'ASCII.Char.FormFeed'-- 'ASCII.Char.CarriageReturn'---}-+- 'ASCII.Char.CarriageReturn' -} isSpace :: CharSuperset char => char -> Bool isSpace x = any ASCII.Predicates.isSpace (convertCharMaybe x) -{- | Returns True if the character is either an ASCII letter ('isLetter') or an ASCII digit ('isDigit'). -}-+{-| Returns True if the character is either an ASCII letter ('isLetter') or an+ASCII digit ('isDigit'). -} isAlphaNum :: CharSuperset char => char -> Bool isAlphaNum x = any ASCII.Predicates.isAlphaNum (convertCharMaybe x) -{- | Returns True for the following characters:+{-| Returns True for the following characters: - 'ASCII.Char.ExclamationMark' - 'ASCII.Char.QuotationMark'@@ -641,14 +594,11 @@ - 'ASCII.Char.RightSquareBracket' - 'ASCII.Char.Underscore' - 'ASCII.Char.LeftCurlyBracket'-- 'ASCII.Char.RightCurlyBracket'---}-+- 'ASCII.Char.RightCurlyBracket' -} isPunctuation :: CharSuperset char => char -> Bool isPunctuation x = any ASCII.Predicates.isPunctuation (convertCharMaybe x) -{- | Returns True for the following characters:+{-| Returns True for the following characters: - 'ASCII.Char.DollarSign' - 'ASCII.Char.PlusSign'@@ -658,61 +608,46 @@ - 'ASCII.Char.Caret' - 'ASCII.Char.GraveAccent' - 'ASCII.Char.VerticalLine'-- 'ASCII.Char.Tilde'---}-+- 'ASCII.Char.Tilde' -} isSymbol :: CharSuperset char => char -> Bool isSymbol x = any ASCII.Predicates.isSymbol (convertCharMaybe x) -{- | Returns True for visible characters.--This includes all print characters except 'ASCII.Char.Space'.---}+{- |Returns True for visible characters +This includes all print characters except 'ASCII.Char.Space'. -} isVisible :: CharSuperset char => char -> Bool isVisible x = any ASCII.Predicates.isVisible (convertCharMaybe x) {- $numbers -See also: "ASCII.Decimal" and "ASCII.Hexadecimal"---}--{- |--Gives the ASCII string representation of an integer in decimal (base 10)-notation, using digits 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9',-leading with 'ASCII.Char.HyphenMinus' for negative numbers.--For example, @'showIntegralDecimal' (-512 :: 'Prelude.Integer')@ = @"-512"@.+See also: "ASCII.Decimal" and "ASCII.Hexadecimal" -} --}+{-| Gives the ASCII string representation of an integer in decimal (base 10)+ notation, using digits 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9',+ leading with 'ASCII.Char.HyphenMinus' for negative numbers +For example, @'showIntegralDecimal' (-512 :: 'Prelude.Integer')@ = @"-512"@. -} showIntegralDecimal :: (Integral n, StringSuperset string) => n -> string showIntegralDecimal = ASCII.Decimal.showIntegral -{- |+{-| Gives the ASCII string representation of an integer in hexadecimal (base 16)+ notation -Gives the ASCII string representation of an integer in hexadecimal (base 16)-notation, using digits 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9', for-digits 0 though 9. The representation of digits 10 to 15 is determined by the-value of 'Case' parameter: 'UpperCase' means 'ASCII.Char.CapitalLetterA' to+The characters 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9' represent digits+0 though 9. The representation of digits 10 to 15 is determined by the value of+'Case' parameter: 'UpperCase' means 'ASCII.Char.CapitalLetterA' to 'ASCII.Char.CapitalLetterF', and 'LowerCase' means 'ASCII.Char.SmallLetterA' to 'ASCII.Char.SmallLetterF'. For negative numbers, the resulting string begins with 'ASCII.Char.HyphenMinus'. -For example, @'showIntegralHexadecimal' 'UpperCase' ('Prelude.negate' (256 + 12) :: 'Prelude.Integer')@ = @"-10C"@.---}--showIntegralHexadecimal :: (Integral n, StringSuperset string) => Case -> n -> string+@+'showIntegralHexadecimal' 'UpperCase' ('Prelude.negate' (256 + 12) :: 'Prelude.Integer') == "-10C"+@ -}+showIntegralHexadecimal :: (Integral n, StringSuperset string) =>+ Case -> n -> string showIntegralHexadecimal = ASCII.Hexadecimal.showIntegral -{- |--Roughly the inverse of 'showIntegralDecimal'+{-| Roughly the inverse of 'showIntegralDecimal' * Leading zeroes are accepted, as in @"0074"@ and @"-0074"@ @@ -720,16 +655,13 @@ * If the input is empty * If the input contains any other extraneous characters-* If the resulting number would be outside the range supported by the 'Integral' (determined by its 'Bits' instance)---}--readIntegralDecimal :: (StringSuperset string, Integral number, Bits number) => string -> Maybe number+* If the resulting number would be outside the range supported by the 'Integral'+ (determined by its 'Bits' instance) -}+readIntegralDecimal :: (StringSuperset string, Integral number, Bits number) =>+ string -> Maybe number readIntegralDecimal = ASCII.Decimal.readIntegral -{- |--Roughly the inverse of 'showIntegralHexadecimal'+{-| Roughly the inverse of 'showIntegralHexadecimal' * Upper and lower case letters are treated equally * Leading zeroes are accepted, as in @"006a"@ and @"-006a"@@@ -738,60 +670,48 @@ * If the input is empty * If the input contains any other extraneous characters-* If the resulting number would be outside the range supported by the 'Integral' (determined by its 'Bits' instance)---}--readIntegralHexadecimal :: (StringSuperset string, Integral number, Bits number) => string -> Maybe number+* If the resulting number would be outside the range supported by the 'Integral'+ (determined by its 'Bits' instance) -}+readIntegralHexadecimal :: (StringSuperset string, Integral number, Bits number) =>+ string -> Maybe number readIntegralHexadecimal = ASCII.Hexadecimal.readIntegral -{- |--Gives the ASCII string representation of an natural number in decimal (base 10)-notation, using digits 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9'.--For example, @'showNaturalDecimal' 512@ = @"512"@.---}+{-| Gives the ASCII string representation of an natural number in decimal+ (base 10) notation, using digits 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9' +@+'showNaturalDecimal' 512 == @"512"+@ -} showNaturalDecimal :: DigitStringSuperset string => Natural -> string showNaturalDecimal = ASCII.Decimal.showNatural -{- |+{-| Gives the ASCII string representation of an integer in hexadecimal (base 16)+ notation -Gives the ASCII string representation of an integer in hexadecimal (base 16)-notation, using digits 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9', for-digits 0 though 9. The representation of digits 10 to 15 is determined by the-value of 'Case' parameter: 'UpperCase' means 'ASCII.Char.CapitalLetterA' to+Characters 'ASCII.Char.Digit0' through 'ASCII.Char.Digit9' represent digits 0+though 9. The representation of digits 10 to 15 is determined by the value of+'Case' parameter: 'UpperCase' means 'ASCII.Char.CapitalLetterA' to 'ASCII.Char.CapitalLetterF', and 'LowerCase' means 'ASCII.Char.SmallLetterA' to 'ASCII.Char.SmallLetterF'. -For example, @'showNaturalHexadecimal' 'UpperCase' (256 + 12)@ = @"10C"@.---}-+@+'showNaturalHexadecimal' 'UpperCase' (256 + 12) == "10C"+@ -} showNaturalHexadecimal :: HexStringSuperset string => Case -> Natural -> string showNaturalHexadecimal = ASCII.Hexadecimal.showNatural -{- |--Roughly the inverse of 'showNaturalDecimal'+{-| Roughly the inverse of 'showNaturalDecimal' * Leading zeroes are accepted, as in @"0074"@ Conditions where the result is 'Data.Maybe.Nothing': * If the input is empty-* If the input contains any other extraneous characters---}-+* If the input contains any other extraneous characters -} readNaturalDecimal :: DigitStringSuperset string => string -> Maybe Natural readNaturalDecimal = ASCII.Decimal.readNatural -{- |--Roughly the inverse of 'showNaturalHexadecimal'+{-| Roughly the inverse of 'showNaturalHexadecimal' * Upper and lower case letters are treated equally * Leading zeroes are accepted, as in @"006a"@@@ -799,82 +719,49 @@ Conditions where the result is 'Data.Maybe.Nothing': * If the input is empty-* If the input contains any other extraneous characters---}-+* If the input contains any other extraneous characters -} readNaturalHexadecimal :: HexStringSuperset string => string -> Maybe Natural readNaturalHexadecimal = ASCII.Hexadecimal.readNatural {- $digit -See also: "ASCII.Decimal"---}+See also: "ASCII.Decimal" -} {- $hexchar -See also: "ASCII.Hexadecimal"---}--{- |--Specialization of 'showNaturalDecimal'--See also: 'showIntegralDecimal'+See also: "ASCII.Hexadecimal" -} --}+{-| Specialization of 'showNaturalDecimal' +See also: 'showIntegralDecimal' -} showNaturalDigits :: Natural -> [Digit] showNaturalDigits = showNaturalDecimal -{- |--Specialization of 'readNaturalDecimal'--See also: 'readIntegralDecimal'---}+{-| Specialization of 'readNaturalDecimal' +See also: 'readIntegralDecimal' -} readNaturalDigits :: [Digit] -> Maybe Natural readNaturalDigits = readNaturalDecimal -{- |--Specialization of 'showNaturalHexadecimal'--See also: 'showIntegralHexadecimal'+{-| Specialization of 'showNaturalHexadecimal' --}+See also: 'showIntegralHexadecimal' -} showNaturalHexChars :: Case -> Natural -> [HexChar] showNaturalHexChars = showNaturalHexadecimal -{- |--Specialization of 'readNaturalHexadecimal'--See also: 'readIntegralHexadecimal'---}+{-| Specialization of 'readNaturalHexadecimal' +See also: 'readIntegralHexadecimal' -} readNaturalHexChars :: [HexChar] -> Maybe Natural readNaturalHexChars = readNaturalHexadecimal -{- |--A string containing a single digit character 0-9---}+{-| A string containing a single digit character 0-9 -} digitString :: DigitStringSuperset string => Digit -> string digitString x = ASCII.Decimal.fromDigitList [x] -{- |--A string containing a single hexadecimal digit character 0-9, A-F, or a-f.---}+{-| A string containing a single hexadecimal digit character+ 0-9, A-F, or a-f -} hexCharString :: HexStringSuperset string => HexChar -> string hexCharString x = ASCII.Hexadecimal.fromHexCharList [x]
test/Main.hs view
@@ -5,8 +5,7 @@ import ASCII.Char (Char (..)) import ASCII.Refinement (asciiUnsafe) -import Control.Monad (Monad (..), when)-import Data.Bool (Bool (..), not)+import Data.Bool (Bool (..)) import Data.Function (($)) import Data.Int (Int) import Data.List (map)@@ -14,108 +13,134 @@ import Data.Text (Text) import Data.Word (Word8) import Prelude (enumFromTo, maxBound, minBound)-import System.Exit (exitFailure) import System.IO (IO) -import Hedgehog (Property, assert, checkParallel, discover, property, withTests,- (===))+import Test.Hspec (describe, hspec, it, shouldBe) main :: IO ()-main = checkParallel $$(discover) >>= \ok -> when (not ok) exitFailure+main = hspec $ do -prop_letter_printable :: Property-prop_letter_printable = withTests 1 $ property $- charGroup CapitalLetterA === Printable+ describe "charGroup" $ do+ let c ~> g = charGroup c `shouldBe` g -prop_eot_control :: Property-prop_eot_control = withTests 1 $ property $- charGroup EndOfTransmission === Control+ it "A is printable" $ CapitalLetterA ~> Printable+ it "end-of-transmission is control" $ EndOfTransmission ~> Control -prop_eot_not_printable :: Property-prop_eot_not_printable = withTests 1 $ property $- assert $ not $ inGroup Printable EndOfTransmission+ describe "inGroup" $ do -prop_is_eot_control :: Property-prop_is_eot_control = withTests 1 $ property $- assert $ inGroup Control EndOfTransmission+ describe "tests Char" $ do+ it "end-of-transmission is not printable" $+ inGroup Printable EndOfTransmission `shouldBe` False+ it "end-of-transmission is control" $+ inGroup Control EndOfTransmission `shouldBe` True -prop_inGroup_printable :: Property-prop_inGroup_printable = withTests 1 $ property $- map (inGroup Printable) ([-1, 5, 65, 97, 127, 130] :: [Int]) === [False, False, True, True, False, False]+ describe "tests Int" $ do+ let i ~> b = inGroup Printable (i :: Int) `shouldBe` b -prop_cases :: Property-prop_cases = withTests 1 $ property $- map letterCase [SmallLetterA, CapitalLetterA, ExclamationMark] === [Just LowerCase, Just UpperCase, Nothing]+ it "-1 is not printable (isn't anything)" $ (-1) ~> False+ it "5 is not printable" $ 5 ~> False+ it "65 is printable" $ 65 ~> True+ it "97 is printable" $ 97 ~> True+ it "127 is not printable" $ 127 ~> False+ it "128 is not printable (isn't anything)" $ 128 ~> False -prop_cases_string_qq :: Property-prop_cases_string_qq = withTests 1 $ property $- map letterCase ([string|Hey!|] :: [ASCII Word8]) === [Just UpperCase, Just LowerCase, Just LowerCase, Nothing]+ describe "letterCase" $ do+ let ch ~> ca = letterCase ch `shouldBe` ca -prop_is_upper_char :: Property-prop_is_upper_char = withTests 1 $ property $- map (isCase UpperCase) [SmallLetterA, CapitalLetterA, ExclamationMark] === [False, True, False]+ describe "works with Char" $ do+ it "a is lower" $ SmallLetterA ~> Just LowerCase+ it "A is upper" $ CapitalLetterA ~> Just UpperCase+ it "! has no case" $ ExclamationMark ~> Nothing -prop_is_upper_string_qq :: Property-prop_is_upper_string_qq = withTests 1 $ property $- map (isCase UpperCase) ([string|Hey!|] :: [ASCII Word8]) === [True, False, False, False]+ it "works with ASCII Word8" $ do+ map letterCase ([string|Hey!|] :: [ASCII Word8]) `shouldBe`+ [Just UpperCase, Just LowerCase, Just LowerCase, Nothing] -prop_is_upper_int :: Property-prop_is_upper_int = withTests 1 $ property $- map (isCase UpperCase) ([-1, 65, 97, 150] :: [Int]) === [False, True, False, False]+ describe "isCase" $ do -prop_to_upper_letter :: Property-prop_to_upper_letter = withTests 1 $ property $- toCaseChar UpperCase SmallLetterA === CapitalLetterA+ describe "works with Char" $ do+ let c ~> b = isCase UpperCase c `shouldBe` b -prop_to_upper_char_qq :: Property-prop_to_upper_char_qq = withTests 1 $ property $- ([char|a|] :: ASCII Word8, toCaseChar UpperCase [char|a|] :: ASCII Word8) === (asciiUnsafe 97, asciiUnsafe 65)+ it "a is not upper" $ SmallLetterA ~> False+ it "A is upper" $ CapitalLetterA ~> True+ it "! is not upper" $ ExclamationMark ~> False -prop_to_upper_various :: Property-prop_to_upper_various = withTests 1 $ property $- toCaseString UpperCase [CapitalLetterH,SmallLetterE,SmallLetterY,ExclamationMark] === [CapitalLetterH, CapitalLetterE, CapitalLetterY, ExclamationMark]+ it "works with ASCII Word8" $ do+ map (isCase UpperCase) ([string|Hey!|] :: [ASCII Word8])+ `shouldBe` [True, False, False, False] -prop_to_upper_string_qq :: Property-prop_to_upper_string_qq = withTests 1 $ property $- (toCaseString UpperCase [string|Hey!|] :: ASCII Text) === asciiUnsafe "HEY!"+ describe "works with Int" $ do+ let i ~> b = isCase UpperCase (i :: Int) `shouldBe` b -prop_to_int :: Property-prop_to_int = withTests 1 $ property $- map charToInt [Null, CapitalLetterA, SmallLetterA, Delete] === [0, 65, 97, 127]+ it "-1 is not upper (isn't anything)" $ (-1) ~> False+ it "65 is upper" $ 65 ~> True+ it "97 is not upper" $ 97 ~> False+ it "128 is not upper (isn't anything)" $ 128 ~> False -prop_to_word8 :: Property-prop_to_word8 = withTests 1 $ property $- map charToWord8 [Null, CapitalLetterA, SmallLetterA, Delete] === [0, 65, 97, 127]+ describe "toCaseChar" $ do -prop_to_text :: Property-prop_to_text = withTests 1 $ property $- charListToText [CapitalLetterH, SmallLetterI, ExclamationMark] === "Hi!"+ describe "works with Char" $ do+ it "a to upper is A" $ toCaseChar UpperCase SmallLetterA+ `shouldBe` CapitalLetterA -prop_lift_to_word8 :: Property-prop_lift_to_word8 = withTests 1 $ property $- (lift CapitalLetterA :: Word8) === 65+ describe "works with ASCII Word8" $ do+ it "a to upper is 65" $ toCaseChar UpperCase ([char|a|] :: ASCII Word8)+ `shouldBe` (asciiUnsafe 65 :: ASCII Word8) -prop_lift_to_text :: Property-prop_lift_to_text = withTests 1 $ property $- (lift [CapitalLetterH,SmallLetterI,ExclamationMark] :: Text) === "Hi!"+ describe "toCaseString" $ do+ it "converts each Char to a case" $ do+ let check a b = toCaseString UpperCase a `shouldBe` b+ check [ CapitalLetterH, SmallLetterE, SmallLetterY, ExclamationMark ]+ [ CapitalLetterH, CapitalLetterE, CapitalLetterY, ExclamationMark ] -prop_bytes_to_string :: Property-prop_bytes_to_string = withTests 1 $ property $- ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x50] === Just "HTTP"+ it "works with ASCII Text" $+ (toCaseString UpperCase [string|Hey!|] :: ASCII Text)+ `shouldBe` asciiUnsafe "HEY!" -prop_bytes_to_string_fail :: Property-prop_bytes_to_string_fail = withTests 1 $ property $- ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x80] === Nothing+ describe "charToInt" $ do+ let c ~> i = charToInt c `shouldBe` i -prop_digitStrings :: Property-prop_digitStrings = withTests 1 $ property $- map digitString (enumFromTo minBound maxBound) ===- (["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] :: [Text])+ it "Null is 0" $ Null ~> 0+ it "A is 65" $ CapitalLetterA ~> 65+ it "a is 97" $ SmallLetterA ~> 97+ it "Delete is 127" $ Delete ~> 127 -prop_hexCharStrings :: Property-prop_hexCharStrings = withTests 1 $ property $- map hexCharString (enumFromTo minBound maxBound) ===- ( [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"- , "A", "B", "C", "D", "E", "F"- , "a", "b", "c", "d", "e", "f"- ] :: [Text] )+ describe "charToWord8" $ do+ let c ~> i = charToWord8 c `shouldBe` i++ it "Null is 0" $ Null ~> 0+ it "A is 65" $ CapitalLetterA ~> 65+ it "a is 97" $ SmallLetterA ~> 97+ it "Delete is 127" $ Delete ~> 127++ describe "charListToText" $ do+ it "packs a list of Char into Text" $+ charListToText [CapitalLetterH, SmallLetterI, ExclamationMark]+ `shouldBe` "Hi!"++ describe "lift" $ do+ it "converts Char to Word8" $ (lift CapitalLetterA :: Word8) `shouldBe` 65+ it "converts [Char] to Text" $+ (lift [CapitalLetterH, SmallLetterI, ExclamationMark] :: Text)+ `shouldBe` "Hi!"++ describe "byteListToUnicodeStringMaybe" $ do+ it "converts [Word8] to String" $+ ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x50]+ `shouldBe` Just "HTTP"+ it "can fail" $ ASCII.byteListToUnicodeStringMaybe [0x48, 0x54, 0x54, 0x80]+ `shouldBe` Nothing++ describe "digitString" $ do+ it "converts Digit to a single character of Text" $ do+ let f = digitString :: Digit -> Text+ map f (enumFromTo minBound maxBound) `shouldBe`+ ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]++ describe "hexCharString" $ do+ it "converts HexChar to a single character of Text" $ do+ let f = hexCharString :: HexChar -> Text+ map f (enumFromTo minBound maxBound) `shouldBe`+ [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"+ , "A", "B", "C", "D", "E", "F"+ , "a", "b", "c", "d", "e", "f" ]