packages feed

pptable 0.1.0.1 → 0.2.0.0

raw patch · 8 files changed

+486/−329 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Text.PrettyPrint.PrettyTable: class (Data a) => Tabilize a where listToBox a = case a of { [] -> [[nullBox]] x : xs -> gprintTable (from x) : listToBox xs } mapToBox m = elems (mapWithKey (\ k v -> text (show k) : gprintTable (from v)) m) vectorToBox v = toList $ fmap (\ x -> (gprintTable (from x))) v printMap m = do { let r = head . elems $ m; let header = constrFields . toConstr $ r; let header_box = "Key" : map (text) header; printBox $ alignBox $ header_box : mapToBox m } printList m = do { let r = head $ m; let header = constrFields . toConstr $ r; let header_box = map (text) header; printBox $ alignBox $ header_box : listToBox m } printVector m = do { let r = m ! 0; let header = constrFields . toConstr $ r; let header_box = map (text) header; printBox $ alignBox $ header_box : vectorToBox m }
- Text.PrettyPrint.PrettyTable: listToBox :: (Tabilize a, Generic a, GTabilize (Rep a)) => [a] -> [[Box]]
- Text.PrettyPrint.PrettyTable: mapToBox :: (Tabilize a, Generic a, GTabilize (Rep a), Show b) => Map b a -> [[Box]]
- Text.PrettyPrint.PrettyTable: printList :: Tabilize a => [a] -> IO ()
- Text.PrettyPrint.PrettyTable: printMap :: (Tabilize a, Show b) => Map b a -> IO ()
- Text.PrettyPrint.PrettyTable: printVector :: Tabilize a => Vector a -> IO ()
- Text.PrettyPrint.PrettyTable: vectorToBox :: (Tabilize a, Generic a, GTabilize (Rep a)) => Vector a -> [[Box]]
- Text.PrettyPrint.Tabilize: class (Data a) => Tabilize a where listToBox a = case a of { [] -> [[nullBox]] x : xs -> gprintTable (from x) : listToBox xs } mapToBox m = elems (mapWithKey (\ k v -> text (show k) : gprintTable (from v)) m) vectorToBox v = toList $ fmap (\ x -> (gprintTable (from x))) v printMap m = do { let r = head . elems $ m; let header = constrFields . toConstr $ r; let header_box = "Key" : map (text) header; printBox $ alignBox $ header_box : mapToBox m } printList m = do { let r = head $ m; let header = constrFields . toConstr $ r; let header_box = map (text) header; printBox $ alignBox $ header_box : listToBox m } printVector m = do { let r = m ! 0; let header = constrFields . toConstr $ r; let header_box = map (text) header; printBox $ alignBox $ header_box : vectorToBox m }
- Text.PrettyPrint.Tabilize: instance (Data.Data.Data a, GHC.Show.Show a) => Text.PrettyPrint.Tabilize.GTabilize (GHC.Generics.K1 i a)
- Text.PrettyPrint.Tabilize: instance (Text.PrettyPrint.Tabilize.GTabilize a, Text.PrettyPrint.Tabilize.GTabilize b) => Text.PrettyPrint.Tabilize.GTabilize (a GHC.Generics.:*: b)
- Text.PrettyPrint.Tabilize: instance (Text.PrettyPrint.Tabilize.GTabilize a, Text.PrettyPrint.Tabilize.GTabilize b) => Text.PrettyPrint.Tabilize.GTabilize (a GHC.Generics.:+: b)
- Text.PrettyPrint.Tabilize: instance Text.PrettyPrint.Tabilize.GTabilize GHC.Generics.U1
- Text.PrettyPrint.Tabilize: instance Text.PrettyPrint.Tabilize.GTabilize a => Text.PrettyPrint.Tabilize.GTabilize (GHC.Generics.M1 i c a)
- Text.PrettyPrint.Tabilize: listToBox :: Tabilize a => [a] -> [[Box]]
- Text.PrettyPrint.Tabilize: mapToBox :: (Tabilize a, Show b) => Map b a -> [[Box]]
- Text.PrettyPrint.Tabilize: printList :: Tabilize a => [a] -> IO ()
- Text.PrettyPrint.Tabilize: printMap :: (Tabilize a, Show b) => Map b a -> IO ()
- Text.PrettyPrint.Tabilize: printVector :: Tabilize a => Vector a -> IO ()
- Text.PrettyPrint.Tabilize: vectorToBox :: Tabilize a => Vector a -> [[Box]]
+ Text.PrettyPrint.Tabulate: class Boxable b
+ Text.PrettyPrint.Tabulate: class CellValueFormatter a where ppFormatter x = show x ppFormatterWithStyle _ x = "default_" ++ show x
+ Text.PrettyPrint.Tabulate: class (Data a) => Tabulate a where ppTable x = printTable x
+ Text.PrettyPrint.Tabulate: instance (Text.PrettyPrint.Tabulate.GTabulate a, Text.PrettyPrint.Tabulate.GTabulate b) => Text.PrettyPrint.Tabulate.GTabulate (a GHC.Generics.:*: b)
+ Text.PrettyPrint.Tabulate: instance (Text.PrettyPrint.Tabulate.GTabulate a, Text.PrettyPrint.Tabulate.GTabulate b) => Text.PrettyPrint.Tabulate.GTabulate (a GHC.Generics.:+: b)
+ Text.PrettyPrint.Tabulate: instance GHC.Show.Show k => Text.PrettyPrint.Tabulate.Boxable (Data.Map.Base.Map k)
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.Boxable Data.Vector.Vector
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.Boxable []
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.CellValueFormatter GHC.Base.String
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.CellValueFormatter GHC.Integer.Type.Integer
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.CellValueFormatter GHC.Types.Bool
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.CellValueFormatter GHC.Types.Double
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.CellValueFormatter GHC.Types.Float
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.CellValueFormatter GHC.Types.Int
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.CellValueFormatter a => Text.PrettyPrint.Tabulate.GTabulate (GHC.Generics.K1 i a)
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.GTabulate GHC.Generics.U1
+ Text.PrettyPrint.Tabulate: instance Text.PrettyPrint.Tabulate.GTabulate a => Text.PrettyPrint.Tabulate.GTabulate (GHC.Generics.M1 i c a)
+ Text.PrettyPrint.Tabulate: ppTable :: (Tabulate a, Boxable f, Generic a, GTabulate (Rep a)) => f a -> IO ()
+ Text.PrettyPrint.Tabulate: printTable :: (Boxable b, Data a, Generic a, GTabulate (Rep a)) => b a -> IO ()
+ Text.PrettyPrint.Tabulate: toBox :: (Boxable b, Data a, Generic a, GTabulate (Rep a)) => b a -> [[Box]]

Files

+ CHANGELOG.md view
@@ -0,0 +1,17 @@+0.2.0.0+-------++* This release contains *breaking* changes+* Name of Tabilize class changed to Tabulate+* printList, printMap and printVector all replaced with polymorphic method ppTable+* New class Boxable with default instances for List, Vector and Map+* Use prinf library to print basic types+* New class CellValueFormatter with default instances for basic type+* Boxable instance to extend to other Traversable instances+* CellValueFormatter class to extend formatting++0.1.0.1+-------++* Intial version+* Can print List, Map or Vector in tabular format
README.md view
@@ -1,41 +1,67 @@ # README # -PrettyTable : Print any list, vector or map as a well-formatted readable table.+Text.PrettyPrint.Tabulate : Print any list, vector or map as a well-formatted readable table. -### Text.PrettyPrint.PrettyTable ###+### Text.PrettyPrint.Tabulate ###  * This module provides simple functions used to print values in tabular format-* Version 0.1.0+* Version 0.2.0.0 * Contributions and Bug Reports welcome. Please use the Github issue tracker. -### Examples ###+### Example ###  ``` haskell- -- Printing a list of records- :set -XDeriveGeneric- :set -XDeriveDataTypeable - import qualified GHC.Generics as G- import Data.Data+  -- ./Example.hs+  :set -XDeriveGeneric+  :set -XDeriveDataTypeable - -- A record structure that will in a list- data Stock = Stock {ticker::String, price::Double, marketCap::Double} deriving (Data, G.Generic)+  import qualified GHC.Generics as G+  import Data.Data - -- Create an instance of Tabilize- instance Tabilize Stock+  import qualified Text.PrettyPrint.Tabulate as T+  import qualified Data.Map as Map+  import qualified Data.List as List+  import qualified Data.Vector as Vector - let yahoo =  Stock {ticker="YHOO", price=42.29101010, marketCap=40e9}- let google = Stock {ticker="GOOG", price=774.210101, marketCap=532.09e9}- let amazon = Stock {ticker="AMZN", price=799.161717, marketCap=378.86e9} - -- List of records- let tickers = [yahoo, google, amazon]+  data Stock = Stock {ticker::String, price::Double, marketCap::Double} deriving (Data, G.Generic)+  instance T.Tabulate Stock - printList tickers+  let yahoo =  Stock {ticker="YHOO", price=42.29101010, marketCap=40e9}+  let google = Stock {ticker="GOOG", price=774.210101, marketCap=532.09e9}+  let amazon = Stock {ticker="AMZN", price=799.161717, marketCap=378.86e9} - ticker     price          marketCap- "YHOO"     42.2910101         4.0e10- "GOOG"     774.210101      5.3209e11- "AMZN"     799.161717      3.7886e11++  -- List of records+  let tickers = [yahoo, google, amazon]++  -- The record type 'Stock' can also be in a Map+  let tickers_map = Map.fromList [(10, yahoo), (100, google), (1000, amazon)]++  -- Or in a Vector+  let tickers_vector = Vector.fromList tickers++  -- Print table from List+  T.ppTable tickers+   ticker     price              marketCap+   YHOO         42.291010100     4.000000000e10+   GOOG        774.210101000     5.320900000e11+   AMZN        799.161717000     3.788600000e11++   -- Print table from Map+   T.ppTable tickers_map+   Key      ticker     price              marketCap+   10       YHOO         42.291010100     4.000000000e10+   100      GOOG        774.210101000     5.320900000e11+   1000     AMZN        799.161717000     3.788600000e11+++   -- Print table from Vector+   T.ppTable tickers_vector+   ticker     price              marketCap+   YHOO         42.291010100     4.000000000e10+   GOOG        774.210101000     5.320900000e11+   AMZN        799.161717000     3.788600000e11  ```
pptable.cabal view
@@ -1,5 +1,5 @@ name:                pptable-version:             0.1.0.1+version:             0.2.0.0 synopsis:            Pretty Print containers in a tabular format description:         Please see README.md homepage:            https://github.com/gdevanla/pptable#readme@@ -10,12 +10,12 @@ copyright:           2016 Guru Devanla category:            Text build-type:          Simple-extra-source-files:  README.md+extra-source-files:  README.md, CHANGELOG.md cabal-version:       >=1.10  library   hs-source-dirs:      src-  exposed-modules:     Text.PrettyPrint.Tabilize, Text.PrettyPrint.PrettyTable+  exposed-modules:     Text.PrettyPrint.Tabulate, Text.PrettyPrint.Tabulate.Example   build-depends:       base >= 4.7 && < 5                      , syb                      , containers@@ -44,4 +44,4 @@  source-repository head   type:     git-  location: https://github.com/githubuser/pptable+  location: https://github.com/gdevanla/pptable
− src/Text/PrettyPrint/PrettyTable.hs
@@ -1,85 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE TypeOperators #-}---- | This module features methods that can be used to print values contained--- inside a list \/ a map \/ or a vector--- in a tabular format.--module Text.PrettyPrint.PrettyTable-    (-      -- ** Example of output-      -- $outputexample--      -- ** Basic Steps-      -- $steps-      -      -- ** Usage Example-      -- $examplelist-      -      -- ** Tabilize methods-      Tabilize(..)--      -- ** Custom Rendering-      -- $return_box-      -    ) where--import Text.PrettyPrint.Tabilize----- $outputexample--- > ticker     price          marketCap--- > "YHOO"     42.2910101         4.0e10--- > "GOOG"     774.210101      5.3209e11--- > "AMZN"     799.161717      3.7886e11---- $steps------ * Declare the new data type that will be the element of a list, map or a vector.--- * The type could be a basic data constructor or a record type--- * Derive 'Generic' and 'Data' for the type--- * Make the type an instance of 'Text.PrettyPrint.Tabilize.Tabilize'--- * Create values of the type and add them to a list, map or vector--- * Use one of the 'printList', 'printMap' and 'printVector' methods to print the values in a tabular format---- $notes--- Note that any nested algebraic instances will be displayed by calling their respective 'Show' methods---- $examplelist------ > -- Printing a list of records--- > :set -XDeriveGeneric--- > :set -XDeriveDataTypeable--- >--- > import qualified GHC.Generics as G--- > import Data.Data--- >--- > -- A record structure that will in a list--- > data Stock = Stock {ticker::String, price::Double, marketCap::Double} deriving (Data, G.Generic)--- >--- > -- Create an instance of Tabilize--- > instance Tabilize Stock--- > --- > let yahoo =  Stock {ticker="YHOO", price=42.29101010, marketCap=40e9}--- > let google = Stock {ticker="GOOG", price=774.210101, marketCap=532.09e9}--- > let amazon = Stock {ticker="AMZN", price=799.161717, marketCap=378.86e9}--- >--- > -- List of records--- > let tickers = [yahoo, google, amazon]--- > --- > printList tickers--- > --- > ticker     price          marketCap--- > "YHOO"     42.2910101         4.0e10--- > "GOOG"     774.210101      5.3209e11--- > "AMZN"     799.161717      3.7886e11----- $return_box--- In cases, where the 'printList', 'printMap' or 'printVector' statements are not adequate, the 'listToBox', 'vectorToBox' and 'mapToBox' methods--- return the B.Box value. The user can then use some of the methods provided by--- "Text.PrettyPrint.Box" module.
− src/Text/PrettyPrint/Tabilize.hs
@@ -1,187 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ConstrainedClassMethods #-}---- | Module implements the default methods for Tabilize--module Text.PrettyPrint.Tabilize-    (-      -      Tabilize-    , printList-    , printMap-    , printVector-    -    , listToBox-    , mapToBox-    , vectorToBox--    )where--import Data.Data-import Data.Typeable-import Data.Generics.Aliases-import GHC.Generics as G-import GHC.Show-import qualified Data.Map as Map-import qualified Text.PrettyPrint.Boxes as B-import qualified Data.List as List-import Text.Printf-import qualified Data.Vector as V------ | The Generalized class that provides the print--- | functionality for any type that derives Generics and Data-class GTabilize f where-  gprintTable :: f a -> [B.Box]----- | The instance class for Unit type-instance GTabilize U1 where-  gprintTable _ = []---- | Any records or product types--- | Nested algebraic types are printed using their respective Show methods-instance (GTabilize a, GTabilize b) => GTabilize (a :*: b) where-    gprintTable (a :*: b) = gprintTable a ++ gprintTable b---- | Sum types-instance (GTabilize a, GTabilize b) => GTabilize (a :+: b) where-    gprintTable (L1 x) = gprintTable x-    gprintTable (R1 x) = gprintTable x---- | -instance (GTabilize a) => GTabilize (M1 i c a) where-  gprintTable (M1 x) = gprintTable x----- | The leaf method that actually creates the Boxes that will--- | be used to render the boxes as a table.-instance (Data a, Show a) => GTabilize (K1 i a) where-  gprintTable (K1 x) = createBox x---- | Create the B.Box around the provided value--- | If the value is an algebraic type the algebraic types--- | Show method is used. All values have to be an instance of--- | Data. This dependency is there to support identify Numeric--- | values for right-aligning those values-createBox :: (Data x, Show x) => x -> [B.Box]-createBox x-  | isBool = [B.text $ show x]-  | isNumeric = [B.text $ printf "%10s" . show $ x]-  | otherwise = [B.text $ show x]-  where-    isBool = get_type == "Bool"-    isNumeric = get_type == "Integer" || get_type == "Double" || get_type == "Float"-    get_type = tyConName . typeRepTyCon . typeOf $ x---- | Perform the final alignment of all--- | generated [[B.Box]]-alignBox :: [[B.Box]] -> B.Box-alignBox b = B.hsep 5 B.left cols-  where-    cols = List.map (B.vcat B.left) $ List.transpose b---- | Helper method that detects an algebraic data type-isAlgRepConstr t = case dataTypeRep . dataTypeOf $ t of-  AlgRep [_] -> True-  _ -> False---- | Specialized class that provides default methods--- methods to print List, Map or Vector values as a--- pretty table-class (Data a) => Tabilize a where-  -- | Return a list of values wrapped in a Box. Each entry in input is assumed to be a-  -- list of records keyed by any data type. The first entry in the-  -- list of values will be used to infer the names of fields-  listToBox :: [a] -> [[B.Box]]--  -- | Return a list of values wrapped in Box. Each entry in input is assumed to be a-  -- list of records keyed by any data type. The first entry in the-  -- list of values will be used to infer the names of fields-  mapToBox ::(Show b) => Map.Map b a -> [[B.Box]]--  -  -- | Return a list of values wrapped in Box. Each entry in input is assumed to be a-  -- list of records keyed by any data type. The first entry in the-  -- list of values will be used to infer the names of fields-  vectorToBox :: V.Vector a -> [[B.Box]]--  default listToBox :: (G.Generic a, GTabilize (Rep a)) => [a] -> [[B.Box]]-  listToBox a = case a of-    [] -> [[B.nullBox]]-    x:xs -> gprintTable (from x):listToBox xs--  -  default mapToBox :: (G.Generic a, GTabilize (Rep a), Show b) => Map.Map b a -> [[B.Box]]-  mapToBox m =  Map.elems-                (Map.mapWithKey-                 (\k v -> B.text (show k):gprintTable (from v))-                 m)--  default vectorToBox :: (G.Generic a, GTabilize (Rep a)) => V.Vector a -> [[B.Box]]-  vectorToBox v = V.toList $ fmap (\x -> (gprintTable (from x))) v--  -- |-  -- > import qualified Data.Map as M-  -- > -- declare a Map-  -- > data Portfolio = M.Map String Stock-  -- > Add the Stock values we create-  -- > let p = M.fromList [("YHOO", yahoo), ("GOOG", google), ("AMZN" amazon)]-  -- >-  -- > printMap p-  -- >-  -- > Key        ticker     price          marketCap-  -- > "amzn"     "AMZN"     799.161717      3.7886e11-  -- > "goog"     "GOOG"     774.210101      5.3209e11-  -- > "yhoo"     "YHOO"     42.2910101         4.0e10-  printMap :: (Show b) => Map.Map b a -> IO ()-  printMap m = do-    let r = head . Map.elems $ m-    let header = constrFields . toConstr $ r-    let header_box = "Key":List.map (B.text) header-    B.printBox $ alignBox $ header_box:mapToBox m--  -- |-  -- > -- List of records-  -- > let tickers = [yahoo, google, amazon]-  -- > -  -- > printList tickers-  -- > -  -- > ticker     price          marketCap-  -- > "YHOO"     42.2910101         4.0e10-  -- > "GOOG"     774.210101      5.3209e11-  -- > "AMZN"     799.161717      3.7886e11-  printList :: [a] -> IO ()-  printList m = do-    let r = head $ m-    let header = constrFields . toConstr $ r-    let header_box = List.map (B.text) header-    B.printBox $ alignBox $ header_box:listToBox m--  -- |-  -- > import qualified Data.Vector as V-  -- > -- Vector of records-  -- > let tickers = V.fromList [yahoo, google, amazon]-  -- > -  -- > printVector tickers-  -- > -  -- > ticker     price          marketCap-  -- > "YHOO"     42.2910101         4.0e10-  -- > "GOOG"     774.210101      5.3209e11-  -- > "AMZN"     799.161717      3.7886e11-  printVector :: V.Vector a -> IO ()-  printVector m = do-    let r = m V.! 0-    let header = constrFields . toConstr $ r-    let header_box = List.map (B.text) header-    B.printBox $ alignBox $ header_box:vectorToBox m--  -- print :: (Functor f) => f a -> f [B.Box]-  -- default ppTabFL :: (G.Generic a, Tabilize (Rep a), Functor f) => (f a) -> f [B.Box]-  -- ppTabFL f = fmap (\x -> (gprintTable (from x))) f-
+ src/Text/PrettyPrint/Tabulate.hs view
@@ -0,0 +1,222 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ConstrainedClassMethods #-}+{-# LANGUAGE MultiParamTypeClasses #-}++-- | Module implements the default methods for Tabulate++module Text.PrettyPrint.Tabulate+    (+      Tabulate(..)+    , Boxable(..)+    , CellValueFormatter+    +    )where++import Data.Data+import Data.Typeable+import Data.Generics.Aliases+import GHC.Generics as G+import GHC.Show+import qualified Data.Map as Map+import qualified Text.PrettyPrint.Boxes as B+import qualified Data.List as List+import Text.Printf+import qualified Data.Vector as V++-- | Future change to support providing custom formatting functions+data TablizeValueFormat = T {floatValueFormat::Maybe (Float -> String),+                             stringValueFormat::Maybe (String -> String),+                             integerValueFormat::Maybe (Integer -> String),+                             intValueFormat::Maybe (Int -> String),+                             doubleValueFormat::Maybe (Double -> String)}++-- | Default TabulateValueFormat+getDefaultTabulateValueFormat = T {floatValueFormat=Nothing,+                                   stringValueFormat=Nothing,+                                   integerValueFormat=Nothing,+                                   intValueFormat=Nothing,+                                   doubleValueFormat=Nothing}+++-- | The Generalized class that implements the print feature+--   for any type that derives Generics and Data+class GTabulate f where+  -- | Print with default style+  gprintTable :: f a -> [B.Box]++  -- | For future, will be able to print with provided style+  gprintTableWithStyle :: TablizeValueFormat -> f a -> [B.Box]++--- | The instance class for Unit type+instance GTabulate U1 where+  gprintTable _ = []+  gprintTableWithStyle _ _ = []++-- | Any records or product types+-- | Nested algebraic types are printed using their respective Show methods+instance (GTabulate a, GTabulate b) => GTabulate (a :*: b) where+    gprintTable (a :*: b) = gprintTable a ++ gprintTable b+    gprintTableWithStyle style (a :*: b) = gprintTableWithStyle style a ++ gprintTableWithStyle style b++-- | Sum types+instance (GTabulate a, GTabulate b) => GTabulate (a :+: b) where+    gprintTable (L1 x) = gprintTable x+    gprintTable (R1 x) = gprintTable x++    gprintTableWithStyle style (L1 x) = gprintTableWithStyle style x+    gprintTableWithStyle style (R1 x) = gprintTableWithStyle style x++-- | +instance (GTabulate a) => GTabulate (M1 i c a) where+  gprintTable (M1 x) = gprintTable x+  gprintTableWithStyle style (M1 x) = gprintTableWithStyle style x+++-- | The leaf method that actually creates the Boxes that will+-- be used to render the boxes as a table.+instance (CellValueFormatter a) => GTabulate (K1 i a) where+  gprintTable (K1 x) = [B.text $ ppFormatter x]+  gprintTableWithStyle style (K1 x) = [B.text $ ppFormatterWithStyle style x]+++-- |  Class that implements formatting using printf.+--    Default instances for String, Char, Int, Integer, Double and Float+--    are provided. For types that are not an instance of this class+--    `show` is used.+class CellValueFormatter a where++  -- Function that can be implemented by each instance+  ppFormatter :: a -> String++  -- Future support for this signature will be added+  ppFormatterWithStyle :: TablizeValueFormat -> a -> String++  -- Default instance of function for types that do+  -- do not have their own instance+  default ppFormatter :: (Show a) => a -> String+  ppFormatter x =  show x++  -- Future support.+  default ppFormatterWithStyle :: (Show a) => TablizeValueFormat ->  a -> String+  ppFormatterWithStyle _ x =  "default_" ++ show x+++instance CellValueFormatter Integer where+  ppFormatter x = printf "%d" x+  +  ppFormatterWithStyle style x = case integerValueFormat style of+    Just f -> f x+    Nothing -> ppFormatter x++instance CellValueFormatter Int where+  ppFormatter x = printf "%d" x++  ppFormatterWithStyle style x = case intValueFormat style of+    Just f -> f x+    Nothing -> ppFormatter x+++instance CellValueFormatter Float where+  ppFormatter x = printf "%14.9g" x++  ppFormatterWithStyle style x = case floatValueFormat style of+    Just f -> f x+    Nothing -> ppFormatter x++instance CellValueFormatter String where+  ppFormatter x = printf "%s" x++  ppFormatterWithStyle style x = case stringValueFormat style of+    Just f -> f x+    Nothing -> ppFormatter x+++instance CellValueFormatter Double where+  ppFormatter x = printf "%14.9g" x++  ppFormatterWithStyle style x = case doubleValueFormat style of+    Just f -> f x+    Nothing -> ppFormatter x++instance CellValueFormatter Bool++-- | Perform the final alignment of all+-- | generated [[B.Box]]+alignBox :: [[B.Box]] -> B.Box+alignBox b = B.hsep 5 B.left cols+  where+    cols = List.map (B.vcat B.left) $ List.transpose b++-- | Helper method that detects an algebraic data type+isAlgRepConstr t = case dataTypeRep . dataTypeOf $ t of+  AlgRep [_] -> True+  _ -> False++-- | Class that can be derived by a 'Traversable' to create+--   a list of 'Box' values and print as a Table.+--   Default instances for List, Map and Vector are already provided.+class Boxable b where+  toBox :: (Data a, G.Generic a, GTabulate(Rep a)) => b a ->  [[B.Box]]+  --toBoxWithStyle :: (Data a, G.Generic a, GTabulate(Rep a)) => TablizeValueFormat -> b a ->  [[B.Box]]+  +  printTable :: (Data a, G.Generic a, GTabulate(Rep a)) => b a -> IO ()+  --printTableWithStyle :: (Data a, G.Generic a, GTabulate(Rep a)) => TablizeValueFormat -> b a -> IO ()++instance Boxable [] where+  toBox a = case a of+    [] -> [[B.nullBox]]+    x:xs -> gprintTable (from x):toBox xs++  -- | Prints a "List" as a table. Called by "ppTable"+  -- | Need not be called directly+  printTable m = do+    let r = head $ m+    let header = constrFields . toConstr $ r+    let header_box = List.map (B.text) header+    B.printBox $ alignBox $ header_box:toBox m++  +instance Boxable V.Vector where+  toBox v = V.toList $ fmap (\x -> (gprintTable (from x))) v++  -- | Prints a "Vector" as a table. Called by "ppTable"+  -- | Need not be called directly+  printTable m = do+    let r = m V.! 0+    let header = constrFields . toConstr $ r+    let header_box = List.map (B.text) header+    B.printBox $ alignBox $ header_box:toBox m++instance (Show k) => Boxable (Map.Map k) where+  -- | Returns a Map of Boxed values+  toBox m =  Map.elems+              (Map.mapWithKey+               (\k v -> B.text (show k):gprintTable (from v))+               m)+  -- | Prints a "Map" as a table. Called by "ppTable"+  -- | Need not be called directly+  printTable m = do+    let r = head . Map.elems $ m+    let header = constrFields . toConstr $ r+    let header_box = "Key":List.map (B.text) header+    B.printBox $ alignBox $ header_box:toBox m++    +-- | The elements in a Traverserable should be an instance of Tabulate to be displayed in a tabular format+class  (Data a) => Tabulate a where++  -- | Generic function that will be provided by the GTabulate class.+  ppTable :: (Boxable f) => f a -> IO()+  --ppTableWithStyle :: TablizeValueFormat -> f a -> IO()++  default ppTable :: (Boxable f, G.Generic a, GTabulate (Rep a)) => f a -> IO ()+  ppTable x = printTable x++  --default ppTableWithStyle :: (Boxable f, G.Generic a, GTabulate (Rep a)) => TablizeValueFormat -> f a -> IO ()+  --ppTableWithStyle x = printTableWithStyle x+
+ src/Text/PrettyPrint/Tabulate/Example.hs view
@@ -0,0 +1,180 @@+-- | Example usage of ppTable library+++module Text.PrettyPrint.Tabulate.Example+  (++    -- * Setup extensions+    -- $setup_extensions+    +    -- * Required imports+    -- $import_generics_and_data++    -- * Import 'Tabulate'+    -- $import_tabulate++    -- * Use any 'Traversable' +    -- $import_containers++    -- * Declare an instance of Tabulate+    -- $declare_record++    -- * Sample Data+    -- $create_sample_data++    -- * Printing the table+    -- $print_table++    -- * Complete Example+    -- $complete_example++    -- * Output+    -- $output+    +    -- * Extending+    -- ** Extending for any 'Traversable'+    -- $boxable_instance+    +    -- ** Customizing formatting+    -- $cell_value_formatter+    +++  ) where++import Text.PrettyPrint.Tabulate++-- $setup_extensions+-- > :set -XDeriveGeneric+-- > :set -XDeriveDataTypeable++-- $import_generics_and_data+-- Generics and Data need to be imported since+-- and type that will needs to be printed in tabular format+-- needs to derive from Generic and Data+--+-- > import qualified GHC.Generics as G+-- > import Data.Data+--++-- $import_tabulate+-- Tabulate class and ppTable function are the only declarations+-- to quickly using the library for printing in tabular format+--+-- > import qualified Text.PrettyPrint.Tabulate as T++-- $import_containers+-- The data type that we will print in tabular format will have+-- to be an element of a 'Traversable' instance. The ppTable library+-- provides default instances for 'Data.Map', 'Data.Vector' and 'Data.List'.+--+-- We import these modules here to provide examples of their use+-- +-- > import qualified Data.Map as Map+-- > import qualified Data.List as List+-- > import qualified Data.Vector as Vector+--++-- $declare_record+--+-- A record structure  that will be an element in a 'Traversable' instance.+-- The data type has to derive from 'Generic' and 'Data'. +-- Also an default instance of 'Tabulate' is declared+--+-- > data Stock = Stock {ticker::String, price::Double, marketCap::Double} deriving (Data, G.Generic)+-- > instance T.Tabulate Stock+--++-- $create_sample_data+-- +-- > yahoo =  Stock {ticker="YHOO", price=42.29101010, marketCap=40e9}+-- > google = Stock {ticker="GOOG", price=774.210101, marketCap=532.09e9}+-- > amazon = Stock {ticker="AMZN", price=799.161717, marketCap=378.86e9}+-- > -- List of records+-- > tickers = [yahoo, google, amazon]+-- >+-- > -- The record type 'Stock' can also be in a Map+-- > tickers_map = Map.fromList [(10, yahoo), (100, google), (1000, amazon)]+-- >+-- > -- Or in a Vector+-- > tickers_vector = Vector.fromList tickers++-- $print_table+-- +-- >  putStrLn "\nElements in a List, with records fields as column names\n"+-- >  T.ppTable tickers+-- >+-- >  putStrLn "\nElement in a map, with Key as first column\n"+-- >  T.ppTable tickers_map+-- >+-- >  putStrLn "\nElement in a Vector\n"+-- >  T.ppTable tickers_vector+-- +  ++-- $complete_example+--+-- > -- ./Example.hs+-- > :set -XDeriveGeneric+-- > :set -XDeriveDataTypeable+-- >+-- > import qualified GHC.Generics as G+-- > import Data.Data+-- >+-- > import qualified Text.PrettyPrint.Tabulate as T+-- > import qualified Data.Map as Map+-- > import qualified Data.List as List+-- > import qualified Data.Vector as Vector+-- >+-- >+-- > data Stock = Stock {ticker::String, price::Double, marketCap::Double} deriving (Data, G.Generic)+-- > instance T.Tabulate Stock+-- >+-- > let yahoo =  Stock {ticker="YHOO", price=42.29101010, marketCap=40e9}+-- > let google = Stock {ticker="GOOG", price=774.210101, marketCap=532.09e9}+-- > let amazon = Stock {ticker="AMZN", price=799.161717, marketCap=378.86e9}+-- >+-- >+-- > -- List of records+-- > let tickers = [yahoo, google, amazon]+--+-- > -- The record type 'Stock' can also be in a Map+-- > let tickers_map = Map.fromList [(10, yahoo), (100, google), (1000, amazon)]+-- >+-- > -- Or in a Vector+-- > let tickers_vector = Vector.fromList tickers++-- $output+-- > -- Print table from List+-- > T.ppTable tickers+-- > ticker     price              marketCap+-- > YHOO         42.291010100     4.000000000e10+-- > GOOG        774.210101000     5.320900000e11+-- > AMZN        799.161717000     3.788600000e11+-- >+-- > -- Print table from Map+-- >T.ppTable tickers_map+-- > Key      ticker     price              marketCap+-- > 10       YHOO         42.291010100     4.000000000e10+-- > 100      GOOG        774.210101000     5.320900000e11+-- > 1000     AMZN        799.161717000     3.788600000e11+-- >+-- >+-- > -- Print table from Vector+-- > T.ppTable tickers_vector+-- > ticker     price              marketCap+-- > YHOO         42.291010100     4.000000000e10+-- > GOOG        774.210101000     5.320900000e11+-- > AMZN        799.161717000     3.788600000e11+-- >++++-- $boxable_instance+-- Any 'Traversable' containers can be extended to work with ppTable by implementing+-- an instance of 'Tabulate'++-- $cell_value_formatter+-- Default instances of 'CellValueFormatter' for 'Int', 'Integer', 'String', 'Float' and 'Double' are provided.+-- To customize formatting of any types, an specific implementation of 'CellValueFormatter' can be provided.+
test/Spec.hs view
@@ -3,11 +3,11 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ConstrainedClassMethods #-} -import Test.Tasty+ import Data.Map as M import Data.List as L import Data.Vector as V-import Text.PrettyPrint.PrettyTable+import qualified Text.PrettyPrint.Tabulate as T import GHC.Generics as G import Data.Data import Text.PrettyPrint.Boxes as B@@ -23,45 +23,29 @@                test_float::Float,                test_double::Double}   deriving (Data, Show, G.Generic)-data R01 =  R01 {r1_id::Int, nested_r::R0}-  deriving (Show, G.Generic, Data)-data R3 =  R3 {r3_id::Int, nested_rlist::[R0]}-  deriving (Show, G.Generic, Data)-data R4 = R4 {r4_id::Int, nested_rtuple::(R0,R0)}-  deriving (Show, G.Generic, Data)--instance Tabilize R0-instance Tabilize R01-instance Tabilize R3-instance Tabilize R4+-- data R01 =  R01 {r1_id::Int, nested_r::R0}+--   deriving (Show, G.Generic, Data)+-- data R3 =  R3 {r3_id::Int, nested_rlist::[R0]}+--   deriving (Show, G.Generic, Data)+-- data R4 = R4 {r4_id::Int, nested_rtuple::(R0,R0)}+--   deriving (Show, G.Generic, Data) +instance T.Tabulate R0+-- instance T.Tabulate R01+-- instance T.Tabulate R3+-- instance T.Tabulate R4  getR0 = R0 {test_string="Jack-somone"            , test_integer=10            , test_double=10.101            , test_float=0.101021} --- nested record-getR1 = R01 {r1_id=1001, nested_r=getR0}---- nested record in list-getR3 = R3 {r3_id=1001, nested_rlist=[getR0, getR0]}--- tested nested record in tuple -getR4 = R4 {r4_id=1001, nested_rtuple=(getR0, getR0)}----testVector = testCase "testVector" (-    -- do-      -- create Vector-      -- getBox-      -- inspect Box (rows and columns)---    )- testList = testCase "testList"   (     do-      let b = (L.head . L.head) $ listToBox [getR0]+      let b = (L.head . L.head) $ T.toBox [getR0]       assertEqual "check rows" (B.rows b) 1-      assertEqual "check cols" (B.cols b) 13+      assertEqual "check cols" (B.cols b) 11   )  testLists = testGroup "test printing lists" [