api-opentheory-unicode (empty) → 1.0
raw patch · 5 files changed
+252/−0 lines, 5 filesdep +basedep +bytestringdep +directorysetup-changed
Dependencies added: base, bytestring, directory, opentheory-unicode
Files
- LICENSE +17/−0
- Setup.hs +6/−0
- api-opentheory-unicode.cabal +39/−0
- src/Unicode.hs +81/−0
- testsrc/Main.hs +109/−0
+ LICENSE view
@@ -0,0 +1,17 @@+Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,6 @@+module Main(main)++import Distribution.Simple++main :: IO ()+main = defaultMain
+ api-opentheory-unicode.cabal view
@@ -0,0 +1,39 @@+name: api-opentheory-unicode+version: 1.0+category: Text+synopsis: OpenTheory unicode character API+license: MIT+license-file: LICENSE+cabal-version: >= 1.8.0.2+build-type: Simple+author: Joe Leslie-Hurd <joe@gilith.com>+maintainer: Joe Leslie-Hurd <joe@gilith.com>+description:+ This package provides an API to the unicode character package+ opentheory-unicode which is automatically generated by OpenTheory.++Library+ build-depends:+ base >= 4.0 && < 5.0,+ bytestring >= 0.9 && < 1.0,+ opentheory-unicode >= 1.0 && < 2.0++ hs-source-dirs: src++ ghc-options: -Wall++ exposed-modules:+ Unicode++executable api-opentheory-unicode-test+ build-depends:+ base >= 4.0 && < 5.0,+ bytestring >= 0.9 && < 1.0,+ directory >= 1.0 && < 2.0,+ opentheory-unicode >= 1.0 && < 2.0++ hs-source-dirs: src, testsrc++ ghc-options: -Wall++ main-is: Main.hs
+ src/Unicode.hs view
@@ -0,0 +1,81 @@+{- |+module: Unicode+description: Unicode character API+license: MIT++maintainer: Joe Leslie-Hurd <joe@gilith.com>+stability: provisional+portability: portable+-}+module Unicode+ ( toString,+ newline,+ decode,+ encode,+ reencode,+ hDecode,+ hEncode,+ hReencode,+ decodeFile,+ encodeFile,+ reencodeFile )+where++import qualified Data.ByteString.Lazy as ByteString+import qualified Data.Char as Char+import qualified Data.Word as Word+import qualified System.IO as IO++import qualified OpenTheory.Unicode.UTF8 as UTF8+import OpenTheory.Unicode++toString :: Unicode -> String+toString = show . Char.chr . fromIntegral . unUnicode++newline :: [Unicode]+newline = [Unicode 10]++decode :: IO [Either Word.Word8 Unicode]+decode =+ do b <- ByteString.getContents+ return (UTF8.decode (ByteString.unpack b))++encode :: [Unicode] -> IO ()+encode c =+ let b = ByteString.pack (UTF8.encode c) in+ ByteString.putStr b++reencode :: [Either Word.Word8 Unicode] -> IO ()+reencode c =+ let b = ByteString.pack (UTF8.reencode c) in+ ByteString.putStr b++hDecode :: IO.Handle -> IO [Either Word.Word8 Unicode]+hDecode h =+ do b <- ByteString.hGetContents h+ return (UTF8.decode (ByteString.unpack b))++hEncode :: IO.Handle -> [Unicode] -> IO ()+hEncode h c =+ let b = ByteString.pack (UTF8.encode c) in+ ByteString.hPut h b++hReencode :: IO.Handle -> [Either Word.Word8 Unicode] -> IO ()+hReencode h c =+ let b = ByteString.pack (UTF8.reencode c) in+ ByteString.hPut h b++decodeFile :: FilePath -> IO [Either Word.Word8 Unicode]+decodeFile f =+ do b <- ByteString.readFile f+ return (UTF8.decode (ByteString.unpack b))++encodeFile :: FilePath -> [Unicode] -> IO ()+encodeFile f c =+ let b = ByteString.pack (UTF8.encode c) in+ ByteString.writeFile f b++reencodeFile :: FilePath -> [Either Word.Word8 Unicode] -> IO ()+reencodeFile f c =+ let b = ByteString.pack (UTF8.reencode c) in+ ByteString.writeFile f b
+ testsrc/Main.hs view
@@ -0,0 +1,109 @@+{- |+module: Main+description: Testing the Unicode character library and API+license: MIT++maintainer: Joe Leslie-Hurd <joe@gilith.com>+stability: provisional+portability: portable+-}+module Main+ ( main )+where++import qualified Data.List as List+import qualified Data.Either as Either+import qualified Data.Word as Word+import qualified System.Directory as Directory++import Unicode+import qualified OpenTheory.Unicode as Unicode++demoLength :: Int+demoLength = 7621++testLength :: Int+testLength = 79++noInvalid :: [Either Word.Word8 Unicode.Unicode] -> Bool+noInvalid = all (Either.either (const False) (const True))++getTestFiles :: FilePath -> IO [FilePath]+getTestFiles d =+ do fs <- Directory.getDirectoryContents d+ let fs' = filter (List.isPrefixOf "test") fs+ return (map (\f -> d ++ "/" ++ f) fs')++readTestCharFile :: Maybe Int -> FilePath -> IO ()+readTestCharFile x f =+ do l <- decodeFile f+ let a = noInvalid l+ case x of+ Nothing ->+ if a+ then error $ "invalid file " ++ f ++ " was successfully decoded"+ else return ()+ Just n ->+ if not a+ then error $ "valid file " ++ f ++ " could not be decoded"+ else+ if length l == n+ then return ()+ else+ error $ "valid file " ++ f ++ " has bad line length: " +++ show (length l)++readValidCharFile :: Int -> FilePath -> IO ()+readValidCharFile n = readTestCharFile (Just n)++readInvalidCharFile :: FilePath -> IO ()+readInvalidCharFile = readTestCharFile Nothing++partitionTestCharFile :: IO ()+partitionTestCharFile =+ do skip <- Directory.doesFileExist "test/valid/test061.txt"+ if skip+ then return ()+ else+ do putStrLn "\nsplitting UTF-8 test file into valid and invalid lines"+ cs <- decodeFile "test/test.txt"+ mapM_ outputLine (filter testLine (readLines 1 cs))+ where+ isNewline :: Either Word.Word8 Unicode.Unicode -> Bool+ isNewline (Left _) = False+ isNewline (Right c) = let n = Unicode.unUnicode c in n == 10 || n == 13++ chopNewline :: [Either Word.Word8 Unicode.Unicode] ->+ [Either Word.Word8 Unicode.Unicode]+ chopNewline [] = []+ chopNewline (_ : cs) = cs++ readLines :: Int -> [Either Word.Word8 Unicode.Unicode] ->+ [(Int,[Either Word.Word8 Unicode.Unicode])]+ readLines _ [] = []+ readLines lineno inp =+ let (line,inp') = List.span (not . isNewline) inp in+ let inp'' = chopNewline inp' in+ (lineno,line) : readLines (lineno + 1) inp''++ testLine :: (Int,[Either Word.Word8 Unicode.Unicode]) -> Bool+ testLine (lineno,line) = not (lineno < 61 || null line)++ outputLine :: (Int,[Either Word.Word8 Unicode.Unicode]) -> IO ()+ outputLine (lineno,line) =+ let valid = noInvalid line in+ let n = show lineno in+ let f = "test/" ++ (if valid then "valid" else "invalid") +++ "/test" ++ replicate (3 - length n) '0' ++ n ++ ".txt" in+ reencodeFile f line++main :: IO ()+main =+ do partitionTestCharFile+ readValidCharFile demoLength "test/demo.txt"+ validTestFiles <- getTestFiles "test/valid"+ invalidTestFiles <- getTestFiles "test/invalid"+ mapM_ (readValidCharFile testLength) validTestFiles+ mapM_ readInvalidCharFile invalidTestFiles+ putStrLn " all tests pass"+ return ()