convertible-text 0.0.0 → 0.2.0
raw patch · 9 files changed
+328/−35 lines, 9 filesdep +HUnitdep +QuickCheckdep +template-haskelldep ~attemptnew-component:exe:runtests
Dependencies added: HUnit, QuickCheck, template-haskell, test-framework, test-framework-hunit, test-framework-quickcheck
Dependency ranges changed: attempt
Files
- Data/Convertible/Base.hs +37/−7
- Data/Convertible/Instances/C.hs +77/−0
- Data/Convertible/Instances/Map.hs +4/−0
- Data/Convertible/Instances/Num.hs +58/−3
- Data/Convertible/Instances/String.hs +80/−13
- Data/Convertible/Instances/Text.hs +25/−10
- Data/Convertible/Instances/Time.hs +10/−0
- convertible-text.cabal +29/−2
- runtests.hs +8/−0
Data/Convertible/Base.hs view
@@ -1,10 +1,9 @@ {-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TemplateHaskell #-} {- Copyright (C) 2009 John Goerzen <jgoerzen@complete.org> @@ -26,15 +25,20 @@ -} module Data.Convertible.Base( ConvertAttempt (..),+ failure, ConvertSuccess (..),+ cs,+ ca, ConversionException (..), convertUnsafe,- convertAttemptWrap+ convertAttemptWrap,+ deriveAttempts ) where import Data.Attempt import Control.Exception (Exception) import Data.Typeable (Typeable)+import Language.Haskell.TH ---------------------------------------------------------------------- -- Conversions@@ -47,20 +51,27 @@ -} convertAttempt :: a -> Attempt b +-- | A convenience synonym for 'convertAttempt'+ca :: ConvertAttempt x y => x -> Attempt y+ca = convertAttempt+ {- | A typeclass that represents something that guarantees a successful conversion. A @ConvertSuccess a b@ instance represents an @a@ that can be converted to a @b@. -}-class ConvertAttempt a b => ConvertSuccess a b where+class ConvertSuccess a b where {- | Convert @a@ to @b@. -} convertSuccess :: a -> b -instance ConvertSuccess a b => ConvertAttempt a b where- convertAttempt = return . convertSuccess+-- | A convenience synonym for 'convertSuccess'+cs :: ConvertSuccess x y => x -> y+cs = convertSuccess {- | Any type can be converted to itself. -} instance ConvertSuccess a a where convertSuccess = id+instance ConvertAttempt a a where+ convertAttempt = return -{-+{- FIXME consider exposing this {- | Lists of any convertible type can be converted. -} instance Convertible a b => Convertible [a] [b] where safeConvert = mapM safeConvert@@ -90,3 +101,22 @@ -> m b convertAttemptWrap = attempt (failure . ConversionException) return . convertAttempt++convertAttempt' :: ConvertSuccess x y => x -> Attempt y+convertAttempt' = return . convertSuccess++-- | Template Haskell to derive 'ConvertAttempt' instances from the+-- corresponding 'ConvertSuccess' instances.+deriveAttempts :: [(Name, Name)] -> Q [Dec]+deriveAttempts pairs = do+ ca' <- [|convertAttempt'|]+ return $ map (helper ca') pairs+ where+ helper ca' (x, y) =+ InstanceD+ []+ (ConT (mkName "ConvertAttempt") `AppT` ConT x `AppT` ConT y)+ [ FunD (mkName "convertAttempt")+ [ Clause [] (NormalB ca') []+ ]+ ]
Data/Convertible/Instances/C.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE TemplateHaskell #-} {- | Module : Data.Convertible.Instances.C Copyright : Copyright (C) 2009 John Goerzen@@ -28,6 +29,82 @@ import Data.Int import Data.Word import Foreign.C.Types++$(deriveAttempts+ [ (''CChar, ''Integer)+ , (''CDouble, ''CFloat)+ , (''CDouble, ''CLDouble)+ , (''CDouble, ''Double)+ , (''CDouble, ''Float)+ , (''CDouble, ''Integer)+ , (''CDouble, ''Rational)+ , (''CFloat, ''CDouble)+ , (''CFloat, ''CLDouble)+ , (''CFloat, ''Double)+ , (''CFloat, ''Float)+ , (''CFloat, ''Integer)+ , (''CFloat, ''Rational)+ , (''CInt, ''Integer)+ , (''CLDouble, ''CDouble)+ , (''CLDouble, ''CFloat)+ , (''CLDouble, ''Double)+ , (''CLDouble, ''Float)+ , (''CLDouble, ''Integer)+ , (''CLDouble, ''Rational)+ , (''CLLong, ''Integer)+ , (''CLong, ''Integer)+ , (''CSChar, ''Integer)+ , (''CShort, ''Integer)+ , (''CSize, ''Integer)+ , (''CUChar, ''Integer)+ , (''CUInt, ''Integer)+ , (''CULLong, ''Integer)+ , (''CULong, ''Integer)+ , (''CUShort, ''Integer)+ , (''CWchar, ''Integer)+ , (''Double, ''CDouble)+ , (''Double, ''CFloat)+ , (''Double, ''CLDouble)+ , (''Float, ''CDouble)+ , (''Float, ''CFloat)+ , (''Float, ''CLDouble)+ , (''Int16, ''CDouble)+ , (''Int16, ''CFloat)+ , (''Int16, ''CLDouble)+ , (''Int32, ''CDouble)+ , (''Int32, ''CFloat)+ , (''Int32, ''CLDouble)+ , (''Int64, ''CDouble)+ , (''Int64, ''CFloat)+ , (''Int64, ''CLDouble)+ , (''Int8, ''CDouble)+ , (''Int8, ''CFloat)+ , (''Int8, ''CLDouble)+ , (''Int, ''CDouble)+ , (''Int, ''CFloat)+ , (''Int, ''CLDouble)+ , (''Integer, ''CDouble)+ , (''Integer, ''CFloat)+ , (''Integer, ''CLDouble)+ , (''Rational, ''CDouble)+ , (''Rational, ''CFloat)+ , (''Rational, ''CLDouble)+ , (''Word16, ''CDouble)+ , (''Word16, ''CFloat)+ , (''Word16, ''CLDouble)+ , (''Word32, ''CDouble)+ , (''Word32, ''CFloat)+ , (''Word32, ''CLDouble)+ , (''Word64, ''CDouble)+ , (''Word64, ''CFloat)+ , (''Word64, ''CLDouble)+ , (''Word8, ''CDouble)+ , (''Word8, ''CFloat)+ , (''Word8, ''CLDouble)+ , (''Word, ''CDouble)+ , (''Word, ''CFloat)+ , (''Word, ''CLDouble)+ ]) -- remainder of this file generated by utils/genCinstances.hs
Data/Convertible/Instances/Map.hs view
@@ -28,6 +28,10 @@ instance Ord k => ConvertSuccess [(k, a)] (Map.Map k a) where convertSuccess = Map.fromList+instance Ord k => ConvertAttempt [(k, a)] (Map.Map k a) where+ convertAttempt = return . convertSuccess instance ConvertSuccess (Map.Map k a) [(k, a)] where convertSuccess = Map.toList+instance ConvertAttempt (Map.Map k a) [(k, a)] where+ convertAttempt = return . convertSuccess
Data/Convertible/Instances/Num.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE TemplateHaskell #-} {- | Module : Data.Convertible.Instances.Num Copyright : Copyright (C) 2009 John Goerzen@@ -44,11 +45,65 @@ ------------------------------------------------------------ -instance ConvertSuccess Integer Integer where- convertSuccess = id- instance ConvertSuccess Char Integer where convertSuccess = fromIntegral . fromEnum+instance ConvertAttempt Char Integer where+ convertAttempt = return . convertSuccess++$(deriveAttempts+ [ (''Double, ''Integer)+ , (''Float, ''Integer)+ , (''Rational, ''Integer)+ , (''Int, ''Integer)+ , (''Int8, ''Integer)+ , (''Int16, ''Integer)+ , (''Int32, ''Integer)+ , (''Int64, ''Integer)+ , (''Word, ''Integer)+ , (''Word8, ''Integer)+ , (''Word16, ''Integer)+ , (''Word32, ''Integer)+ , (''Word64, ''Integer)+ , (''Integer, ''Double)+ , (''Integer, ''Float)+ , (''Integer, ''Rational)+ , (''Int, ''Double)+ , (''Int8, ''Double)+ , (''Int16, ''Double)+ , (''Int32, ''Double)+ , (''Int64, ''Double)+ , (''Word, ''Double)+ , (''Word8, ''Double)+ , (''Word16, ''Double)+ , (''Word32, ''Double)+ , (''Word64, ''Double)+ , (''Int, ''Float)+ , (''Int8, ''Float)+ , (''Int16, ''Float)+ , (''Int32, ''Float)+ , (''Int64, ''Float)+ , (''Word, ''Float)+ , (''Word8, ''Float)+ , (''Word16, ''Float)+ , (''Word32, ''Float)+ , (''Word64, ''Float)+ , (''Int, ''Rational)+ , (''Int8, ''Rational)+ , (''Int16, ''Rational)+ , (''Int32, ''Rational)+ , (''Int64, ''Rational)+ , (''Word, ''Rational)+ , (''Word8, ''Rational)+ , (''Word16, ''Rational)+ , (''Word32, ''Rational)+ , (''Word64, ''Rational)+ , (''Double, ''Float)+ , (''Double, ''Rational)+ , (''Float, ''Double)+ , (''Float, ''Rational)+ , (''Rational, ''Double)+ , (''Rational, ''Float)+ ]) {- The following instances generated by util/genNumInstances.hs
Data/Convertible/Instances/String.hs view
@@ -2,6 +2,9 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_GHC -fno-warn-orphans #-} --------------------------------------------------------- --@@ -20,6 +23,9 @@ module Data.Convertible.Instances.String ( InvalidDayException (..) , InvalidBoolException (..)+#if TEST+ , testSuite+#endif ) where import Data.Convertible.Base@@ -36,8 +42,40 @@ import qualified Data.Text.Lazy as LT import Data.Time.Calendar-import Data.Ratio (Ratio) +#if TEST+import Test.Framework (testGroup, Test)+--import Test.Framework.Providers.HUnit+import Test.Framework.Providers.QuickCheck (testProperty)+--import Test.HUnit hiding (Test, path)+import Test.QuickCheck+import Data.Char (isDigit)+import Data.Ratio ((%))+#endif++$(deriveAttempts+ [ (''Bool, ''BL.ByteString)+ , (''Bool, ''BS.ByteString)+ , (''Bool, ''String)+ , (''Bool, ''LT.Text)+ , (''Bool, ''ST.Text)+ , (''Day, ''BL.ByteString)+ , (''Day, ''BS.ByteString)+ , (''Day, ''String)+ , (''Day, ''LT.Text)+ , (''Day, ''ST.Text)+ , (''Int, ''BL.ByteString)+ , (''Int, ''BS.ByteString)+ , (''Int, ''String)+ , (''Int, ''LT.Text)+ , (''Int, ''ST.Text)+ , (''Rational, ''BL.ByteString)+ , (''Rational, ''BS.ByteString)+ , (''Rational, ''String)+ , (''Rational, ''LT.Text)+ , (''Rational, ''ST.Text)+ ])+ {- Not needed yet fromString :: ConvertSuccess String a => String -> a fromString = convertSuccess@@ -108,11 +146,32 @@ convertAttempt = SF.read -- Rational-instance ConvertSuccess (Ratio Integer) [Char] where- convertSuccess = show-instance ConvertAttempt [Char] (Ratio Integer) where- convertAttempt = SF.read+instance ConvertSuccess Rational [Char] where+ convertSuccess = show . (fromRational :: Rational -> Double)+instance ConvertAttempt [Char] Rational where+ convertAttempt = fmap realToFrac . (SF.read :: String -> Attempt Double) +#if TEST+instance Arbitrary Rational where+ coarbitrary = undefined+ arbitrary = do+ n <- arbitrary+ d' <- arbitrary+ let d = if d' == 0 then 1 else d'+ return (n % d)++propRationalId :: Rational -> Bool+propRationalId r = convertAttempt (convertSuccess r :: String) `almostEquals` r++almostEquals :: Attempt Rational -> Rational -> Bool+almostEquals (Failure _) _ = False+almostEquals (Success x) y = abs (x - y) < 0.0001++propRationalAllDigits :: Rational -> Bool+propRationalAllDigits = all (\c -> isDigit c || c `elem` ".-e")+ . convertSuccess+#endif+ -- Instances for bytestrings and text (generated by utils/StringHelper.hs) instance ConvertAttempt BS.ByteString Day where@@ -139,13 +198,13 @@ convertAttempt = fromStringA <=< convertAttempt instance ConvertAttempt LT.Text Int where convertAttempt = fromStringA <=< convertAttempt-instance ConvertAttempt BS.ByteString (Ratio Integer) where+instance ConvertAttempt BS.ByteString Rational where convertAttempt = fromStringA <=< convertAttempt-instance ConvertAttempt BL.ByteString (Ratio Integer) where+instance ConvertAttempt BL.ByteString Rational where convertAttempt = fromStringA <=< convertAttempt-instance ConvertAttempt ST.Text (Ratio Integer) where+instance ConvertAttempt ST.Text Rational where convertAttempt = fromStringA <=< convertAttempt-instance ConvertAttempt LT.Text (Ratio Integer) where+instance ConvertAttempt LT.Text Rational where convertAttempt = fromStringA <=< convertAttempt instance ConvertSuccess Day BS.ByteString where convertSuccess = convertSuccess . toString@@ -171,11 +230,19 @@ convertSuccess = convertSuccess . toString instance ConvertSuccess Int LT.Text where convertSuccess = convertSuccess . toString-instance ConvertSuccess (Ratio Integer) BS.ByteString where+instance ConvertSuccess Rational BS.ByteString where convertSuccess = convertSuccess . toString-instance ConvertSuccess (Ratio Integer) BL.ByteString where+instance ConvertSuccess Rational BL.ByteString where convertSuccess = convertSuccess . toString-instance ConvertSuccess (Ratio Integer) ST.Text where+instance ConvertSuccess Rational ST.Text where convertSuccess = convertSuccess . toString-instance ConvertSuccess (Ratio Integer) LT.Text where+instance ConvertSuccess Rational LT.Text where convertSuccess = convertSuccess . toString++#if TEST+testSuite :: Test+testSuite = testGroup "Data.Convertible.Instances.String"+ [ testProperty "propRationalId" propRationalId+ , testProperty "propRationalAllDigits" propRationalAllDigits+ ]+#endif
Data/Convertible/Instances/Text.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_GHC -fno-warn-orphans #-} --------------------------------------------------------- --@@ -26,14 +28,35 @@ import qualified Data.Text.Encoding as STE import qualified Data.Text.Lazy.Encoding as LTE +$(deriveAttempts+ [ (''BL.ByteString, ''BS.ByteString)+ , (''BL.ByteString, ''String)+ , (''BL.ByteString, ''LT.Text)+ , (''BL.ByteString, ''ST.Text)+ , (''BS.ByteString, ''BL.ByteString)+ , (''BS.ByteString, ''String)+ , (''BS.ByteString, ''LT.Text)+ , (''BS.ByteString, ''ST.Text)+ , (''String, ''BL.ByteString)+ , (''String, ''BS.ByteString)+ , (''String, ''LT.Text)+ , (''String, ''ST.Text)+ , (''LT.Text, ''BL.ByteString)+ , (''LT.Text, ''BS.ByteString)+ , (''LT.Text, ''String)+ , (''LT.Text, ''ST.Text)+ , (''ST.Text, ''BL.ByteString)+ , (''ST.Text, ''BS.ByteString)+ , (''ST.Text, ''String)+ , (''ST.Text, ''LT.Text)+ ])+ toST :: ConvertSuccess a ST.Text => a -> ST.Text toST = convertSuccess toLT :: ConvertSuccess a LT.Text => a -> LT.Text toLT = convertSuccess -instance ConvertSuccess [Char] [Char] where- convertSuccess = id instance ConvertSuccess [Char] BS.ByteString where convertSuccess = convertSuccess . toST instance ConvertSuccess [Char] BL.ByteString where@@ -44,8 +67,6 @@ convertSuccess = LT.pack instance ConvertSuccess BS.ByteString [Char] where convertSuccess = convertSuccess . toST-instance ConvertSuccess BS.ByteString BS.ByteString where- convertSuccess = id instance ConvertSuccess BS.ByteString BL.ByteString where convertSuccess = BL.fromChunks . return instance ConvertSuccess BS.ByteString ST.Text where@@ -56,8 +77,6 @@ convertSuccess = convertSuccess . toLT instance ConvertSuccess BL.ByteString BS.ByteString where convertSuccess = BS.concat . BL.toChunks-instance ConvertSuccess BL.ByteString BL.ByteString where- convertSuccess = id instance ConvertSuccess BL.ByteString ST.Text where convertSuccess = convertSuccess . BS.concat . BL.toChunks instance ConvertSuccess BL.ByteString LT.Text where@@ -68,8 +87,6 @@ convertSuccess = STE.encodeUtf8 instance ConvertSuccess ST.Text BL.ByteString where convertSuccess = convertSuccess . STE.encodeUtf8-instance ConvertSuccess ST.Text ST.Text where- convertSuccess = id instance ConvertSuccess ST.Text LT.Text where convertSuccess = LT.fromChunks . return instance ConvertSuccess LT.Text [Char] where@@ -80,5 +97,3 @@ convertSuccess = LTE.encodeUtf8 instance ConvertSuccess LT.Text ST.Text where convertSuccess = ST.concat . LT.toChunks-instance ConvertSuccess LT.Text LT.Text where- convertSuccess = id
Data/Convertible/Instances/Time.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE TemplateHaskell #-} {- | Module : Data.ConvertAttempt.Instances.Time Copyright : Copyright (C) 2009 John Goerzen@@ -40,6 +41,15 @@ #endif import Data.Ratio import Foreign.C.Types++$(deriveAttempts+ [ (''NominalDiffTime, ''ST.TimeDiff)+ , (''POSIXTime, ''ST.ClockTime)+ , (''ST.CalendarTime, ''ZonedTime)+ , (''ST.ClockTime, ''POSIXTime)+ , (''ST.TimeDiff, ''NominalDiffTime)+ , (''ZonedTime, ''ST.CalendarTime)+ ]) ---------------------------------------------------------------------- -- Intra-System.Time stuff
convertible-text.cabal view
@@ -1,5 +1,5 @@ Name: convertible-text-Version: 0.0.0+Version: 0.2.0 License: LGPL Maintainer: Michael Snoyman <michael@snoyman.com> Author: John Goerzen, Michael Snoyman@@ -22,17 +22,30 @@ Cabal-Version: >=1.2 +flag buildtests+ description: Build the executable to run unit tests+ default: False++flag nolib+ description: Skip building the library.+ default: False+ flag time_gte_113 description: time > 1.1.3 has defined some more instances so omit them here library+ if flag(nolib)+ Buildable: False+ else+ Buildable: True Build-Depends: base >= 4 && < 5, old-time >= 1.0.0.2 && < 1.1, containers >= 0.2.0.1 && < 0.3, text >= 0.5 && < 0.6, bytestring >= 0.9.1.4 && < 0.10, safe-failure >= 0.4 && < 0.5,- attempt >= 0.2.0 && < 0.3+ attempt >= 0.2.1 && < 0.3,+ template-haskell if flag(time_gte_113) Build-Depends: time>=1.1.3 && <= 1.1.4 CPP-OPTIONS: -DTIME_GTE_113@@ -51,3 +64,17 @@ Data.Convertible.Instances.Time, Data.Convertible.Instances.Text, Data.Convertible.Instances.String++executable runtests+ if flag(buildtests)+ Buildable: True+ cpp-options: -DTEST+ build-depends: test-framework,+ test-framework-quickcheck,+ test-framework-hunit,+ HUnit,+ QuickCheck >= 1 && < 2+ else+ Buildable: False+ ghc-options: -Wall+ main-is: runtests.hs
+ runtests.hs view
@@ -0,0 +1,8 @@+import Test.Framework (defaultMain)++import qualified Data.Convertible.Instances.String++main :: IO ()+main = defaultMain+ [ Data.Convertible.Instances.String.testSuite+ ]