packages feed

property-list 0.0.0.1.1 → 0.0.0.3

raw patch · 7 files changed

+512/−155 lines, 7 filesdep +mtldep +template-haskellPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: mtl, template-haskell

API changes (from Hackage documentation)

- Data.PropertyList: PLArray :: [PropertyList a] -> PropertyList a
- Data.PropertyList: PLBool :: Bool -> PropertyList a
- Data.PropertyList: PLData :: ByteString -> PropertyList a
- Data.PropertyList: PLDate :: UTCTime -> PropertyList a
- Data.PropertyList: PLDict :: (Map String (PropertyList a)) -> PropertyList a
- Data.PropertyList: PLInt :: Integer -> PropertyList a
- Data.PropertyList: PLReal :: Double -> PropertyList a
- Data.PropertyList: PLString :: String -> PropertyList a
- Data.PropertyList: PLVar :: a -> PropertyList a
- Data.PropertyList: data PropertyList a
- Data.PropertyList: dateFormat :: String
- Data.PropertyList: foldPropertyList :: ([a] -> a) -> (ByteString -> a) -> (UTCTime -> a) -> (Map String a -> a) -> (Double -> a) -> (Integer -> a) -> (String -> a) -> (Bool -> a) -> (t -> a) -> PropertyList t -> a
- Data.PropertyList: instance (Eq a) => Eq (PropertyList a)
- Data.PropertyList: instance (Ord a) => Ord (PropertyList a)
- Data.PropertyList: instance (Read a) => Read (PropertyList a)
- Data.PropertyList: instance (Show a) => Show (PropertyList a)
- Data.PropertyList: instance Eq UnparsedPlistItem
- Data.PropertyList: instance Functor PropertyList
- Data.PropertyList: instance Monad PropertyList
- Data.PropertyList: instance Ord UnparsedPlistItem
- Data.PropertyList: instance Read UnparsedPlistItem
- Data.PropertyList: instance Show UnparsedPlistItem
- Data.PropertyList: parsePlistItem :: PlistItem -> Either (PropertyList PlistItem) UnparsedPlistItem
- Data.PropertyList: parseT :: (Monad t) => (a -> Either (t a) b) -> a -> t b
- Data.PropertyList: plistItemToPropertyList :: PlistItem -> PropertyList UnparsedPlistItem
- Data.PropertyList: plistToPropertyList :: Plist -> PropertyList UnparsedPlistItem
- Data.PropertyList: propertyListToPlist :: (a -> PlistItem) -> PropertyList a -> Plist
- Data.PropertyList: propertyListToPlistItem :: (a -> PlistItem) -> PropertyList a -> PlistItem
- Data.PropertyList: unparsedPlistItemToPlistItem :: UnparsedPlistItem -> PlistItem
+ Data.PropertyList: alterDictionaryEntry :: (PropertyListItem i, PropertyListItem i') => String -> (Maybe i -> Maybe i') -> Maybe (Map String PropertyList) -> Maybe (Map String PropertyList)
+ Data.PropertyList: alterDictionaryEntryM :: (Monad m, PropertyListItem i, PropertyListItem i') => String -> (Maybe i -> m (Maybe i')) -> Maybe (Map String PropertyList) -> m (Maybe (Map String PropertyList))
+ Data.PropertyList: alterItemAtKeyPath :: (PropertyListItem i, PropertyListItem i') => [String] -> (Maybe i -> Maybe i') -> Maybe PropertyList -> Maybe PropertyList
+ Data.PropertyList: alterItemAtKeyPathM :: (Monad m, PropertyListItem i, PropertyListItem i') => [String] -> (Maybe i -> m (Maybe i')) -> Maybe PropertyList -> m (Maybe PropertyList)
+ Data.PropertyList: alterPropertyList :: (PropertyListItem i, PropertyListItem i') => (Maybe i -> Maybe i') -> Maybe PropertyList -> Maybe PropertyList
+ Data.PropertyList: alterPropertyListM :: (Monad m, PropertyListItem i, PropertyListItem i') => (Maybe i -> m (Maybe i')) -> Maybe PropertyList -> m (Maybe PropertyList)
+ Data.PropertyList: class PropertyListItem i
+ Data.PropertyList: fromPropertyList :: (PropertyListItem i) => PropertyList -> Maybe i
+ Data.PropertyList: getItemAtKeyPath :: (PropertyListItem i) => [String] -> Maybe PropertyList -> Maybe i
+ Data.PropertyList: listFromPropertyList :: (PropertyListItem i) => PropertyList -> Maybe [i]
+ Data.PropertyList: listToPropertyList :: (PropertyListItem i) => [i] -> PropertyList
+ Data.PropertyList: setItemAtKeyPath :: (PropertyListItem i) => [String] -> Maybe i -> Maybe PropertyList -> Maybe PropertyList
+ Data.PropertyList: toPropertyList :: (PropertyListItem i) => i -> PropertyList
+ Data.PropertyList: tryAlterDictionaryEntry :: (PropertyListItem i, PropertyListItem i') => String -> (Maybe i -> Maybe i') -> Maybe PropertyList -> (Maybe PropertyList, Bool)
+ Data.PropertyList: tryAlterDictionaryEntryM :: (Monad m, PropertyListItem i, PropertyListItem i') => String -> (Maybe i -> m (Maybe i')) -> Maybe PropertyList -> m (Maybe PropertyList)
+ Data.PropertyList: type PropertyList = PropertyList_ UnparsedPlistItem
+ Data.PropertyList: type PropertyList_ = M (PropertyListS [] (Map String))
- Data.PropertyList: readPropertyListFromFile :: FilePath -> IO (Either String (PropertyList UnparsedPlistItem))
+ Data.PropertyList: readPropertyListFromFile :: FilePath -> IO (Either String PropertyList)
- Data.PropertyList: writePropertyListToFile :: FilePath -> PropertyList UnparsedPlistItem -> IO ()
+ Data.PropertyList: writePropertyListToFile :: FilePath -> PropertyList -> IO ()

Files

property-list.cabal view
@@ -1,5 +1,5 @@ name:                   property-list-version:                0.0.0.1.1+version:                0.0.0.3 stability:              experimental license:                PublicDomain @@ -19,12 +19,18 @@   exposed-modules:      Data.PropertyList   other-modules:        Data.PropertyList.Xml                         Data.PropertyList.Xml.Dtd+                        Data.PropertyList.Type+                        Data.PropertyList.Parse+                        Data.PropertyList.PropertyListItem   build-depends:        base >= 3 && <5,                         bytestring,                         containers,                          dataenc,                         HaXml >= 1.19,+                        mtl,                         old-locale,                         pretty,                         time,+                        +                        template-haskell,                         th-fold
src/Data/PropertyList.hs view
@@ -1,160 +1,24 @@-{-- -      ``Data/PropertyList''- -      rough cut type/reader/writer for Apple Property List format- -}-{-# LANGUAGE-        TemplateHaskell-  #-}--module Data.PropertyList where+module Data.PropertyList+    ( PropertyList+    , PropertyList_+    , UnparsedPlistItem(..)+    , readPropertyListFromFile+    , writePropertyListToFile+    +    , module Data.PropertyList.PropertyListItem+    ) where -import Prelude as P-import Data.PropertyList.Xml.Dtd as X+import Data.PropertyList.Type+import Data.PropertyList.Parse import Data.PropertyList.Xml -import qualified Data.Map as M-import Data.ByteString as B hiding (map)-import Data.Time-import System.Locale-import Codec.Binary.Base64 as B64--import Text.XML.HaXml.OneOfN-import Language.Haskell.TH.Fold--import Text.XML.HaXml.XmlContent+import Data.PropertyList.PropertyListItem -readPropertyListFromFile :: FilePath -> IO (Either String (PropertyList UnparsedPlistItem))+readPropertyListFromFile :: FilePath -> IO (Either String PropertyList) readPropertyListFromFile file = do         x <- readPlistFromFile file         return (fmap plistToPropertyList x) -writePropertyListToFile :: FilePath -> PropertyList UnparsedPlistItem -> IO ()+writePropertyListToFile :: FilePath -> PropertyList -> IO () writePropertyListToFile file plist = do         writePlistToFile file (propertyListToPlist unparsedPlistItemToPlistItem plist)--data PropertyList a-        = PLArray [PropertyList a]-        | PLData ByteString-        | PLDate UTCTime-        | PLDict  (M.Map String (PropertyList a))-        | PLReal Double-        | PLInt Integer-        | PLString String-        | PLBool Bool-        -        | PLVar a-        deriving (Eq, Ord, Show, Read)--instance Functor PropertyList where-        fmap f x = x >>= (return . f)--instance Monad PropertyList where-        return = PLVar-        x >>= f = foldPropertyList-                PLArray-                PLData-                PLDate-                PLDict-                PLReal-                PLInt-                PLString-                PLBool-                f x---- TODO: if possible, make 'fold' in th-utils detect the Functor instances for--- [] and Map k and automagically generate the call to fmap here-foldPropertyList :: ([a] -> a)-                 -> (ByteString -> a)-                 -> (UTCTime -> a)-                 -> (M.Map String a -> a)-                 -> (Double -> a)-                 -> (Integer -> a)-                 -> (String -> a)-                 -> (Bool -> a)-                 -> (t -> a)-                 -> PropertyList t -> a-foldPropertyList foldList a b foldMap c d e f g = foldIt-        where-                foldIt = $(fold ''PropertyList) foldArray a b foldDict c d e f g-                -                foldArray branches = foldList (fmap foldIt branches)-                foldDict dict = foldMap (fmap foldIt dict)--data UnparsedPlistItem-        = UnparsedData String-        | UnparsedDate String-        | UnparsedInt  String-        | UnparsedReal String-        deriving (Eq, Ord, Show, Read)--unparsedPlistItemToPlistItem :: UnparsedPlistItem -> PlistItem-unparsedPlistItemToPlistItem = $(fold ''UnparsedPlistItem)-        (TwoOf9   . Data    )-        (ThreeOf9 . Date    )-        (SixOf9   . AInteger)-        (FiveOf9  . AReal   )---- run an incremental parser - a function which takes--- a token type and returns either a subterm (possibly still--- containing unparsed tokens) or an unparsed token (possibly--- a new token, maybe even of a new type).  This interpretation--- of the action of this function is based on a term-algebra--- view of the monad in question.-parseT :: Monad t => (a -> Either (t a) b) -> a -> t b-parseT f = parse-        where parse token =-                either (>>= parse) return (f token)--plistToPropertyList :: Plist -> PropertyList UnparsedPlistItem-plistToPropertyList = parseT parsePlistItem . plistToPlistItem--plistItemToPropertyList :: PlistItem -> PropertyList UnparsedPlistItem-plistItemToPropertyList = plistToPropertyList . plistItemToPlist--parsePlistItem :: PlistItem -> Either (PropertyList PlistItem) UnparsedPlistItem-parsePlistItem item = case item of-        OneOf9   (Array x   )   -> accept PLArray (map return x)-        TwoOf9   (Data x    )   -> case decode x of -                Just d                  -> accept PLData (pack d)-                Nothing                 -> reject UnparsedData x-        ThreeOf9 (Date x    )   -> case parseTime defaultTimeLocale dateFormat x of-                Just t                  -> accept PLDate t-                Nothing                 -> reject UnparsedDate x-        FourOf9  (Dict x    )   -> accept PLDict (M.fromList [ (k, return v) | Dict_ (Key k) v <- x])-        FiveOf9  (AReal x   )   -> tryRead PLReal UnparsedReal x-        SixOf9   (AInteger x)   -> tryRead PLInt  UnparsedInt x-        SevenOf9 (AString  x)   -> accept PLString x-        EightOf9 (X.True    )   -> accept PLBool P.True-        NineOf9  (X.False   )   -> accept PLBool P.False-        -        where-                accept :: (a -> b) -> a -> Either b c-                accept con = Left  . con-                -                reject :: (a -> c) -> a -> Either b c-                reject con = Right . con-                -                tryRead :: Read a => (a -> b) -> (String -> c) -> String -> Either b c-                tryRead onGood onBad str =-                        case reads str of-                                ((result, ""):_) -> accept onGood result-                                _                -> reject onBad  str-                       -               -dateFormat :: String-dateFormat = "%FT%TZ"--propertyListToPlist :: (a -> PlistItem) -> PropertyList a -> Plist-propertyListToPlist fromOther = plistItemToPlist . propertyListToPlistItem fromOther--propertyListToPlistItem :: (a -> PlistItem) -> PropertyList a -> PlistItem-propertyListToPlistItem fromOther = foldPropertyList-          (\x -> OneOf9 (Array x)-        ) (\x -> TwoOf9 (Data (encode (unpack x)))-        ) (\x -> ThreeOf9 (Date (formatTime defaultTimeLocale dateFormat x))-        ) (\x -> FourOf9 (Dict [Dict_ (Key k) v | (k,v) <- M.toList x])-        ) (\x -> FiveOf9 (AReal (show x))-        ) (\x -> SixOf9 (AInteger (show x))-        ) (\x -> SevenOf9 (AString x)-        ) (\x -> if x then EightOf9 X.True else NineOf9 X.False-        ) fromOther
+ src/Data/PropertyList/Parse.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE +    TemplateHaskell+  #-}++module Data.PropertyList.Parse where++import Language.Haskell.TH.Fold++import Prelude as P+import Data.PropertyList.Xml.Dtd as X+import Data.PropertyList.Xml+import Data.PropertyList.Type++import qualified Data.Map as M+import Data.ByteString as B hiding (map)+import Data.Time+import System.Locale+import Codec.Binary.Base64 as B64++import Text.XML.HaXml.OneOfN+import Text.XML.HaXml.XmlContent++-- |run an incremental parser - a function which takes+-- a token type and returns either a subterm (possibly still+-- containing unparsed tokens) or an unparsed token (possibly+-- a new token, maybe even of a new type).  This interpretation+-- of the action of this function is based on a term-algebra+-- view of the monad in question.+parseT :: Monad t => (a -> Either (t a) b) -> a -> t b+parseT f = parse+        where parse token =+                either (>>= parse) return (f token)++unparsedPlistItemToPlistItem :: UnparsedPlistItem -> PlistItem+unparsedPlistItemToPlistItem = $(fold ''UnparsedPlistItem)+        (TwoOf9   . Data    )+        (ThreeOf9 . Date    )+        (SixOf9   . AInteger)+        (FiveOf9  . AReal   )++plistToPropertyList :: Plist -> PropertyList+plistToPropertyList = parseT parsePlistItem . plistToPlistItem++plistItemToPropertyList :: PlistItem -> PropertyList+plistItemToPropertyList = plistToPropertyList . plistItemToPlist++parsePlistItem :: PlistItem -> Either (PropertyList_ PlistItem) UnparsedPlistItem+parsePlistItem item = case item of+        OneOf9   (Array x   )   -> accept plArray (map return x)+        TwoOf9   (Data x    )   -> case decode x of +                Just d                  -> accept plData (pack d)+                Nothing                 -> reject UnparsedData x+        ThreeOf9 (Date x    )   -> case parseTime defaultTimeLocale dateFormat x of+                Just t                  -> accept plDate t+                Nothing                 -> reject UnparsedDate x+        FourOf9  (Dict x    )   -> accept plDict (M.fromList [ (k, return v) | Dict_ (Key k) v <- x])+        FiveOf9  (AReal x   )   -> tryRead plReal UnparsedReal x+        SixOf9   (AInteger x)   -> tryRead plInt  UnparsedInt x+        SevenOf9 (AString  x)   -> accept plString x+        EightOf9 (X.True    )   -> accept plBool P.True+        NineOf9  (X.False   )   -> accept plBool P.False+        +        where+                accept :: (a -> b) -> a -> Either b c+                accept con = Left  . con+                +                reject :: (a -> c) -> a -> Either b c+                reject con = Right . con+                +                tryRead :: Read a => (a -> b) -> (String -> c) -> String -> Either b c+                tryRead onGood onBad str =+                        case reads str of+                                ((result, ""):_) -> accept onGood result+                                _                -> reject onBad  str+                       +               +dateFormat :: String+dateFormat = "%FT%TZ"++propertyListToPlist :: (a -> PlistItem) -> PropertyList_ a -> Plist+propertyListToPlist fromOther = plistItemToPlist . propertyListToPlistItem fromOther++propertyListToPlistItem :: (a -> PlistItem) -> PropertyList_ a -> PlistItem+propertyListToPlistItem fromOther = foldPropertyList+          (\x -> OneOf9 (Array x)+        ) (\x -> TwoOf9 (Data (encode (unpack x)))+        ) (\x -> ThreeOf9 (Date (formatTime defaultTimeLocale dateFormat x))+        ) (\x -> FourOf9 (Dict [Dict_ (Key k) v | (k,v) <- M.toList x])+        ) (\x -> FiveOf9 (AReal (show x))+        ) (\x -> SixOf9 (AInteger (show x))+        ) (\x -> SevenOf9 (AString x)+        ) (\x -> if x then EightOf9 X.True else NineOf9 X.False+        ) fromOther
+ src/Data/PropertyList/PropertyListItem.hs view
@@ -0,0 +1,282 @@+{-# LANGUAGE+    TypeSynonymInstances,+    FlexibleInstances,+    GeneralizedNewtypeDeriving,+    TemplateHaskell+  #-}++module Data.PropertyList.PropertyListItem where++import Language.Haskell.TH+import Language.Haskell.TH.Syntax+import Language.Haskell.TH.Fold++import Data.PropertyList.Type++import qualified Data.Map as M+import Data.ByteString (ByteString)+import Data.Time+import Data.Char++import Text.XML.HaXml.OneOfN++import Control.Monad+import Control.Monad.State++-- |A class for items which can be converted to and from property lists+class PropertyListItem i where+    -- |Convert the item to a property list, usually by simply wrapping the+    -- value with the appropriate 'PropertyList_' constructor+    toPropertyList :: i -> PropertyList+    +    -- |Convert a property list to a property list item if its contents+    -- _exactly_ fit the target type.  Note that when using types+    -- such as 'M.Map' 'String' 'Int' (as opposed to 'M.Map' 'String'+    -- 'PropertyList') this will mean that a single element of the +    -- dictionary of a non-'Int' type will cause the entire conversion to+    -- fail.+    fromPropertyList :: PropertyList -> Maybe i+    +    -- |In order to support a general instance for lists without breaking+    -- String, we use the same trick as the Prelude uses for Show.+    -- Generally, the list methods should not be overridden, and maybe+    -- they shouldn't even be exported.+    listToPropertyList :: [i] -> PropertyList+    listToPropertyList      = plArray . map toPropertyList+    +    listFromPropertyList :: PropertyList -> Maybe [i]+    listFromPropertyList (S (PLArray x))    = mapM fromPropertyList x+    listFromPropertyList _ = Nothing++instance PropertyListItem a => PropertyListItem [a] where+    toPropertyList = listToPropertyList+    fromPropertyList = listFromPropertyList++{-# SPECIALIZE alterPropertyListM :: Monad m => (Maybe (M.Map String PropertyList) -> m (Maybe (M.Map String PropertyList)))+                    -> Maybe PropertyList -> m (Maybe PropertyList) #-}+alterPropertyListM ::+    (Monad m, PropertyListItem i, PropertyListItem i') +    => (Maybe i -> m (Maybe i'))+    -> Maybe PropertyList -> m (Maybe PropertyList)+alterPropertyListM f plist = do+    i' <- f (plist >>= fromPropertyList)+    return (fmap toPropertyList i')++{-# SPECIALIZE alterDictionaryEntryM :: Monad m => String -> (Maybe PropertyList -> m (Maybe PropertyList))+                    -> Maybe (M.Map String PropertyList) -> m (Maybe (M.Map String PropertyList)) #-}+alterDictionaryEntryM ::+    (Monad m, PropertyListItem i, PropertyListItem i') +    => String -> (Maybe i -> m (Maybe i'))+    -> Maybe (M.Map String PropertyList) -> m (Maybe (M.Map String PropertyList))+alterDictionaryEntryM k f Nothing = do+    i' <- f Nothing+    return (fmap (M.singleton k . toPropertyList) i')+alterDictionaryEntryM k f (Just dict) = do+    let (dict', i) = case M.splitLookup k dict of+            (pre, v, post) -> (M.union pre post, fromPropertyList =<< v)+    +    i' <- f i+    return $ case i' of+        Nothing+            | M.null dict'  -> Nothing+            | otherwise     -> Just dict'+        Just i' -> Just (M.insert k (toPropertyList i') dict)+        +tryAlterDictionaryEntryM ::+    (Monad m, PropertyListItem i, PropertyListItem i') +    => String -> (Maybe i -> m (Maybe i'))+    -> Maybe PropertyList -> m (Maybe PropertyList)+tryAlterDictionaryEntryM k f Nothing = do+    d' <- alterDictionaryEntryM k f Nothing+    return (fmap plDict d')+tryAlterDictionaryEntryM k f (Just (S (PLDict d))) = do+    d' <- alterDictionaryEntryM k f (Just d)+    return (fmap plDict d')+tryAlterDictionaryEntryM k f other = fail "Key path tries to pass through non-dictionary thing."++alterItemAtKeyPathM ::+    (Monad m, PropertyListItem i, PropertyListItem i')+    => [String] -> (Maybe i -> m (Maybe i'))+    -> Maybe PropertyList -> m (Maybe PropertyList)+alterItemAtKeyPathM [] f = alterPropertyListM f+alterItemAtKeyPathM (k:ks) f = tryAlterDictionaryEntryM k (alterItemAtKeyPathM ks f)++alterPropertyList ::+    (PropertyListItem i, PropertyListItem i') +    => (Maybe i -> Maybe i')+    -> Maybe PropertyList -> Maybe PropertyList+alterPropertyList f plist = fmap toPropertyList (f (fromPropertyList =<< plist))++alterDictionaryEntry ::+    (PropertyListItem i, PropertyListItem i') +    => String -> (Maybe i -> Maybe i')+    -> Maybe (M.Map String PropertyList) -> Maybe (M.Map String PropertyList)+alterDictionaryEntry k f Nothing = fmap (M.singleton k . toPropertyList) (f Nothing)+alterDictionaryEntry k f (Just dict) = case i' of+    Nothing+        | M.null dict'  -> Nothing+        | otherwise     -> Just dict'+    Just i' -> Just (M.insert k (toPropertyList i') dict)+    +    where+        (dict', i) = case M.splitLookup k dict of+            (pre, v, post) -> (M.union pre post, fromPropertyList =<< v)+        i' = f i++tryAlterDictionaryEntry ::+    (PropertyListItem i, PropertyListItem i') +    => String -> (Maybe i -> Maybe i')+    -> Maybe PropertyList -> (Maybe PropertyList, Bool)+tryAlterDictionaryEntry k f Nothing           = (fmap plDict (alterDictionaryEntry k f Nothing), True)+tryAlterDictionaryEntry k f (Just (S (PLDict d))) = (fmap plDict (alterDictionaryEntry k f (Just d)), True)+tryAlterDictionaryEntry k f other = (other, False)++-- |TODO: capture the success/failure of the operation?+-- (can fail if key path tries to enter something that isn't a dictionary)+alterItemAtKeyPath :: +    (PropertyListItem i, PropertyListItem i')+    => [String] -> (Maybe i -> Maybe i')+    -> Maybe PropertyList -> Maybe PropertyList+alterItemAtKeyPath  []    f plist= alterPropertyList f plist+alterItemAtKeyPath (k:ks) f plist = case tryAlterDictionaryEntry k (alterItemAtKeyPath ks f) plist of+    (_, False) -> error "Key path tries to pass through non-dictionary thing."+    (plist, True) -> plist++getItemAtKeyPath :: PropertyListItem i =>+    [String] -> Maybe PropertyList -> Maybe i+getItemAtKeyPath path plist = execState +    (alterItemAtKeyPathM path (\e -> put e >> return e) plist)+    Nothing++setItemAtKeyPath :: PropertyListItem i =>+    [String] -> Maybe i -> Maybe PropertyList -> Maybe PropertyList+setItemAtKeyPath path value plist = alterItemAtKeyPath path +    (\e -> value `asTypeOf` e) plist++instance PropertyListItem PropertyList where+    toPropertyList = id+    fromPropertyList = Just++instance PropertyListItem ByteString where+    toPropertyList = plData+    fromPropertyList (S (PLData x)) = Just x+    fromPropertyList _ = Nothing++instance PropertyListItem UTCTime where+    toPropertyList = plDate+    fromPropertyList (S (PLDate x)) = Just x+    fromPropertyList _ = Nothing++instance PropertyListItem a => PropertyListItem (M.Map String a) where+    {-# SPECIALIZE instance PropertyListItem (M.Map String PropertyList) #-}+    +    toPropertyList = plDict . fmap toPropertyList+    fromPropertyList (S (PLDict x)) = fmapM fromPropertyList x+        where fmapM f m = fmap M.fromList $ +                            sequence [ do { v <- f v; return (k, v)}+                                     | (k, v) <- M.toList m ]+    fromPropertyList _ = Nothing++instance PropertyListItem Double where+    toPropertyList = plReal+    fromPropertyList (S (PLInt i)) =  Just (fromInteger i)+    fromPropertyList (S (PLReal d)) = Just d+    fromPropertyList (S (PLString s)) = case reads s of+        [(d, "")] -> Just d+        _ -> Nothing+    fromPropertyList _ = Nothing++instance PropertyListItem Float where+    toPropertyList = toPropertyList . (realToFrac :: Float -> Double)+    fromPropertyList = fmap (realToFrac :: Double -> Float) . fromPropertyList++instance PropertyListItem Integer where+    toPropertyList = plInt+    fromPropertyList (S (PLInt i)) = Just i+    fromPropertyList (S (PLReal d)) = case properFraction d of+        (i, 0) -> Just i+        _ -> Nothing+    fromPropertyList (S (PLString s)) = case reads s of+        [(i, "")] -> Just i+        _ -> Nothing+    fromPropertyList _ = Nothing++instance PropertyListItem Int where+    toPropertyList = toPropertyList . toInteger+    fromPropertyList = fmap fromInteger . fromPropertyList++-- this instance doesnt make much sense by itself, but must be here to support strings+instance PropertyListItem Char where+    toPropertyList c = plString [c]+    fromPropertyList (S (PLString [c])) = Just c+    fromPropertyList _ = Nothing+    +    listToPropertyList = plString+    listFromPropertyList (S (PLString x)) = Just x+    listFromPropertyList (S (PLBool True)) = Just "YES"+    listFromPropertyList (S (PLBool False)) = Just "NO"+    listFromPropertyList (S (PLInt i)) = Just (show i)+    listFromPropertyList (S (PLReal d)) = Just (show d)+    listFromPropertyList other = Nothing++instance PropertyListItem Bool where+    toPropertyList = plBool+    fromPropertyList (S (PLBool d)) = Just d+    fromPropertyList (S (PLString b))+        | map toLower b `elem` ["yes", "true"]+        = Just True+        | map toLower b `elem` ["no", "false"]+        = Just False+    fromPropertyList _ = Nothing++instance PropertyListItem UnparsedPlistItem where+    toPropertyList = plVar+    fromPropertyList (V d) = Just d+    fromPropertyList _ = Nothing++-- The following TH generates, for Either and for all OneOfN types+--  (N in [2..20]), an instance of the form:+-- +-- instance (PropertyListItem a, PropertyListItem b, PropertyListItem c) => PropertyListItem (OneOf3 a b c) where+--     toPropertyList = $(fold ''OneOf3) toPropertyList toPropertyList toPropertyList+--     fromPropertyList pl = msum [ fmap OneOf3 (fromPropertyList pl)+--                                , fmap TwoOf3 (fromPropertyList pl)+--                                , fmap ThreeOf3 (fromPropertyList pl)+--                                ]++$(  let types = ''Either : [mkTcName ("OneOf" ++ show n) | n <- [2..20]]+        -- mkTcName ensures we have the type constructor and not the data constructor+        -- by assembling it with its 'flavour' explicitly set to match that of a known+        -- type constructor.+        mkTcName n = Name (mkOccName n) nameFlavour+            where Name _ nameFlavour = ''OneOf2+        +        mkInstance typeName = do+            TyConI (DataD _ _ _ cons _) <- reify typeName+            let conNames = [name | NormalC name _ <- cons]+            +            let tyVarNames = zipWith (\con n -> mkName ("a" ++ show n)) conNames [1..]+                +                tyVars = map varT tyVarNames+                typeWithVars = foldl appT (conT typeName) tyVars+                +                cxt = mapM (appT (conT ''PropertyListItem)) tyVars+                inst = appT (conT ''PropertyListItem) typeWithVars+                +                pl = mkName "pl"+                +                whre = +                    [ funD 'toPropertyList   [clause []        (normalB toPLbody  ) []]+                    , funD 'fromPropertyList [clause [varP pl] (normalB fromPLbody) []]+                    ]+                +                toPLbody = appsE (fold typeName : map (const (varE 'toPropertyList)) conNames)+                fromPLbody = appE (varE 'msum) $ listE+                    [ [| fmap $(conE con) (fromPropertyList $(varE pl)) |]+                    | con <- conNames+                    ]+        +            instanceD cxt inst whre+    in+    mapM mkInstance types+ )
+ src/Data/PropertyList/Type.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE +    TemplateHaskell,+    FlexibleContexts, UndecidableInstances,+    TypeSynonymInstances, RelaxedPolyRec+  #-}++module Data.PropertyList.Type where++import Language.Haskell.TH.Fold++import qualified Data.Map as M+import Data.ByteString as B hiding (map)+import Data.Time++-- |A property list possibly containing unparsed items (only when items fail +-- to parse or the user puts them there)+type PropertyList = PropertyList_ UnparsedPlistItem++data PropertyListS l m a+        = PLArray (l a)+        | PLData ByteString+        | PLDate UTCTime+        | PLDict  (m a)+        | PLReal Double+        | PLInt Integer+        | PLString String+        | PLBool Bool+        deriving (Eq, Ord, Show, Read)++foldPropertyListS :: (l a -> t)+                  -> (ByteString -> t)+                  -> (UTCTime -> t)+                  -> (m a -> t)+                  -> (Double -> t)+                  -> (Integer -> t)+                  -> (String -> t)+                  -> (Bool -> t) +                  -> PropertyListS l m a -> t+foldPropertyListS = $(fold ''PropertyListS)++instance (Functor l, Functor m) => Functor (PropertyListS l m) where+    fmap f = foldPropertyListS (PLArray . fmap f) PLData PLDate (PLDict . fmap f) PLReal PLInt PLString PLBool++data M f a+    = S (f (M f a))+    | V a++foldM :: (f (M f a) -> t) -> (a -> t) -> M f a -> t+foldM = $(fold ''M)++instance (Eq (f (M f a)),  Eq a) => Eq (M f a) where+    S x == S y  = (x == y)+    V a == V b  = (a == b)+    _ == _ = False+instance (Ord (f (M f a)),  Ord a) => Ord (M f a) where+    S x `compare` S y  = x `compare` y+    V a `compare` V b  = a `compare` b+    S _ `compare` V _  = LT+    V _ `compare` S _  = GT+    +instance (Show (f (M f a)), Show a) => Show (M f a) where+    showsPrec p (S x) = showParen (p > 10) (showString "S " . showsPrec 11 x)+    showsPrec p (V x) = showParen (p > 10) (showString "V " . showsPrec 11 x)++-- instance Read...++-- |The property-list term algebra type itself, parameterized over the type of+-- "structural holes" in the terms.+type PropertyList_ = M (PropertyListS [] (M.Map String))++plArray     x   = S (PLArray  x)+plData      x   = S (PLData   x)+plDate      x   = S (PLDate   x)+plDict      x   = S (PLDict   x)+plReal      x   = S (PLReal   x)+plInt       x   = S (PLInt    x)+plString    x   = S (PLString x)+plBool      x   = S (PLBool   x)+plVar       x   = V x++data UnparsedPlistItem+        = UnparsedData String+        | UnparsedDate String+        | UnparsedInt  String+        | UnparsedReal String+        deriving (Eq, Ord, Show, Read)++instance Functor f => Functor (M f) where+    fmap f (S x) = S (fmap (fmap f) x)+    fmap f (V x) = V (f x)++instance Functor f => Monad (M f) where+    return = V+    (S x) >>= f = S (fmap (>>= f) x)+    (V x) >>= f = f x++-- TODO: if possible, make 'fold' in th-utils detect the Functor instances for+-- [] and Map k and automagically generate the call to fmap here+foldPropertyList :: (Functor list, Functor map)+                 => (list a -> a)+                 -> (ByteString -> a)+                 -> (UTCTime -> a)+                 -> (map a -> a)+                 -> (Double -> a)+                 -> (Integer -> a)+                 -> (String -> a)+                 -> (Bool -> a)+                 -> (t -> a)+                 -> M (PropertyListS list map) t -> a+foldPropertyList foldList a b foldMap c d e f g = foldIt+        where+                foldIt = foldM foldS g+                foldS = foldPropertyListS foldArray a b foldDict c d e f+                +                foldArray branches = foldList (fmap foldIt branches)+                foldDict dict = foldMap (fmap foldIt dict)
src/Data/PropertyList/Xml.hs view
@@ -1,6 +1,3 @@-{-- -      ``Data/PropertyList/Xml''- -} {-# LANGUAGE         TemplateHaskell   #-}
src/Data/PropertyList/Xml/Dtd.hs view
@@ -1,5 +1,4 @@ {-- -      ``Data/PropertyList/Xml/Dtd''  -      generated by DtdToHaskell (from HaXml 1.19.4)  -      altered to fix ambiguities (added explicit Prelude imports)  -}