hsprocess-0.2: src/System/Console/HSProcess/Representable.hs
{-
Copyright 2013 Mario Pastorelli (pastorelli.mario@gmail.com)
This file is part of HSProcess.
HSProcess is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
HSProcess is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with HSProcess. If not, see <http://www.gnu.org/licenses/>.
-}
{-# LANGUAGE ExistentialQuantification
, ExtendedDefaultRules
, OverloadedStrings
, ScopedTypeVariables #-}
module System.Console.HSProcess.Representable (
Row (repr')
, Rows (repr)
, printRows
, printRow
) where
import Control.Exception (SomeException,handle)
import Data.ByteString.Lazy.Char8
import qualified Data.ByteString.Lazy.Char8 as C8 hiding (hPutStrLn)
import qualified Data.List as L
import Data.Set (Set)
import qualified Data.Set as S
import Data.Map (Map)
import qualified Data.Map as M
import GHC.IO.Exception (IOErrorType(ResourceVanished),IOException(ioe_type))
import qualified System.IO as IO
handleErrors :: IO () -> IO ()
handleErrors = handle (\(e :: SomeException) -> IO.hPrint IO.stderr e)
-- ------------------------
-- Rows class and instances
-- | A type that instantiate Rows is a type that can be represented as
-- a list of rows, where typically a row is a line.
--
-- For example:
--
-- >>> mapM_ Data.ByteString.Lazy.Char8.putStrLn $ repr [1,2,3,4]
-- 1
-- 2
-- 3
-- 4
class (Show a) => Rows a where
repr :: a -> [C8.ByteString]
repr = (:[]) . C8.pack . show
printRows :: forall a . (Rows a) => Bool -> a -> IO ()
printRows b = printRows_ . repr
where printRows_ [] = return ()
printRows_ (x:xs) = do
f x
handle ioExceptionsHandler (continue xs)
f = if b then handleErrors . C8.putStrLn else C8.putStrLn
continue xs = IO.hFlush IO.stdout >> printRows_ xs
ioExceptionsHandler e = case ioe_type e of
ResourceVanished -> return ()
_ -> IO.hPrint IO.stderr e
instance Rows Bool
instance Rows Double
instance Rows Float
instance Rows Int
instance Rows Integer
instance Rows () where
repr = const [C8.empty]
instance Rows Char where
repr = (:[]) . C8.singleton
instance Rows ByteString where
repr = (:[])
instance (Rows a) => Rows (Maybe a) where
repr = maybe [C8.empty] repr
instance (Row a, Row b) => Rows (a,b) where
repr (x,y) = [repr' x,repr' y]
instance (Row a, Row b) => Rows (Map a b) where
repr = listAsRows . M.toList
instance (ListAsRows a) => Rows (Set a) where
repr = listAsRows . S.toList
-- Lists
class (Row a) => ListAsRows a where
listAsRows :: [a] -> [ByteString]
listAsRows = L.map repr'
instance ListAsRows ByteString
instance ListAsRows Bool
instance ListAsRows Double
instance ListAsRows Float
instance ListAsRows Int
instance ListAsRows Integer
instance (Row a) => ListAsRows (Maybe a)
instance ListAsRows ()
instance (ListAsRow a,ListAsRows a) => ListAsRows [a]
instance (Row a,Row b) => ListAsRows (a,b)
instance (Row a,Row b,Row c) => ListAsRows (a,b,c)
instance ListAsRows Char where
listAsRows = (:[]) . C8.pack
instance (ListAsRows a) => Rows [a] where
repr = listAsRows
instance (ListAsRow a,ListAsRows a) => ListAsRows (Set a) where
listAsRows = listAsRows . L.map S.toList
instance (Row a,Row b) => ListAsRows (Map a b) where
listAsRows = listAsRows . L.map M.toList
-- ---------------------------
-- Row class and instances
-- | A Row is something that can be expressed as a line.
-- The output of repr' should be formatted such that
-- it can be read and processed from the command line.
--
-- For example:
--
-- >>> IO.putStrLn $ show [1,2,3,4]
-- [1,2,3,4]
--
-- >>> Data.ByteString.Lazy.Char8.putStrLn $ repr' [1,2,3,4]
-- 1 2 3 4
class (Show a) => Row a where
repr' :: a -> ByteString
repr' = C8.pack . show
instance Row Bool
instance Row Float
instance Row Double
instance Row Int
instance Row Integer
instance Row ()
instance Row Char where
repr' = C8.singleton
printRow :: forall a . (Row a) => Bool -> a -> IO ()
printRow b = if b then handleErrors . f else f
where f = C8.putStrLn . repr'
class (Show a) => ListAsRow a where
listRepr :: [a] -> ByteString
listRepr = C8.intercalate " " . L.map (C8.pack . show)
instance ListAsRow Bool
instance ListAsRow Float
instance ListAsRow Int
instance ListAsRow Integer
instance ListAsRow ()
instance (ListAsRow a) => ListAsRow [a] where
listRepr = C8.intercalate "\t" . L.map listRepr
instance ListAsRow Char where
listRepr = C8.pack
instance ListAsRow ByteString where
listRepr = C8.intercalate " "
instance (Row a,Row b) => ListAsRow (a,b) where
listRepr = C8.intercalate "\t" . L.map (\(x,y) -> C8.unwords [repr' x,repr' y])
instance (ListAsRow a) => Row [a] where
repr' = listRepr
instance (ListAsRow a) => Row (Set a) where
repr' = listRepr . S.toList
instance (Row a,Row b) => Row (Map a b) where
repr' = listRepr . M.toList
instance Row ByteString where
repr' = id
instance (Row a) => Row (Maybe a) where
repr' Nothing = C8.empty
repr' (Just x) = repr' x
instance (Row a,Row b) => Row (a,b) where
repr' (a,b) = C8.intercalate " " [repr' a,repr' b]
instance (Row a,Row b,Row c) => Row (a,b,c) where
repr' (a,b,c) = C8.intercalate " " [repr' a,repr' b,repr' c]