table-layout 0.8.0.0 → 0.8.0.1
raw patch · 9 files changed
+229/−51 lines, 9 filesdep ~HUnitdep ~QuickCheckdep ~base
Dependency ranges changed: HUnit, QuickCheck, base, data-default-class
Files
- src/Text/Layout/Table.hs +7/−6
- src/Text/Layout/Table/Internal.hs +4/−3
- src/Text/Layout/Table/Position/Internal.hs +19/−1
- src/Text/Layout/Table/Primitives/AlignSpec/Internal.hs +3/−1
- src/Text/Layout/Table/Primitives/Basic.hs +6/−10
- src/Text/Layout/Table/Primitives/Column.hs +7/−6
- src/Text/Layout/Table/Primitives/LenSpec/Internal.hs +5/−1
- table-layout.cabal +54/−23
- test-suite/TestSpec.hs +124/−0
src/Text/Layout/Table.hs view
@@ -40,7 +40,6 @@ , noCutMark , singleCutMark , doubleCutMark- , ellipsisCutMark -- * Basic grid layout , Row@@ -316,9 +315,10 @@ -- in a traversal over the input columns by using 'deriveColModInfos'. Finally, -- 'columnModifier' will interpret them and apply the appropriate modification -- function to the cells of the column.-data ColModInfo = FillAligned OccSpec AlignInfo- | FillTo Int- | FitTo Int (Maybe (OccSpec, AlignInfo))+data ColModInfo+ = FillAligned OccSpec AlignInfo+ | FillTo Int+ | FitTo Int (Maybe (OccSpec, AlignInfo)) -- | Private show function. showCMI :: ColModInfo -> String@@ -475,8 +475,9 @@ colsAllG p = rowsG . colsAsRowsAll p -- | Specifies a header.-data Header = Header [HeaderColSpec] [String]- | NoHeader+data Header+ = Header [HeaderColSpec] [String]+ | NoHeader -- | No header is used by default. instance Default Header where
src/Text/Layout/Table/Internal.hs view
@@ -7,9 +7,10 @@ import Text.Layout.Table.Primitives.Basic -- | Groups rows together, which should not be visually seperated from each other.-newtype RowGroup = RowGroup- { rows :: [[String]]- }+newtype RowGroup+ = RowGroup+ { rows :: [[String]]+ } -- | Group the given rows together. rowsG :: [Row String] -> RowGroup
src/Text/Layout/Table/Position/Internal.hs view
@@ -1,9 +1,27 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE EmptyDataDecls #-} module Text.Layout.Table.Position.Internal where import Data.Default.Class -- | Specifies a position relative from a beginning.-data Position orientation = Start | Center | End deriving (Show, Eq)+data Position orientation+ = Start+ | Center+ | End+ deriving Eq++instance Show (Position H) where+ show p = case p of+ Start -> "left"+ Center -> "center"+ End -> "right"++instance Show (Position V) where+ show p = case p of+ Start -> "top"+ Center -> "center"+ End -> "bottom" instance Default (Position orientation) where def = Start
src/Text/Layout/Table/Primitives/AlignSpec/Internal.hs view
@@ -11,7 +11,9 @@ import Text.Layout.Table.Primitives.Occurence -- | Determines whether a column will align at a specific letter.-data AlignSpec = AlignOcc OccSpec | NoAlign+data AlignSpec+ = AlignOcc OccSpec+ | NoAlign -- | No alignment is the default. instance Default AlignSpec where
src/Text/Layout/Table/Primitives/Basic.hs view
@@ -6,7 +6,6 @@ , doubleCutMark , singleCutMark , noCutMark- , ellipsisCutMark -- * String-related tools , spaces@@ -43,14 +42,15 @@ -- | Specifies how the place looks where a 'String' has been cut. Note that the -- cut mark may be cut itself, to fit into a column.-data CutMark = CutMark- { leftMark :: String- , rightMark :: String- }+data CutMark+ = CutMark+ { leftMark :: String+ , rightMark :: String+ } -- | A single ellipsis unicode character is used to show cut marks. instance Default CutMark where- def = ellipsisCutMark+ def = singleCutMark "…" -- | Specify two different cut marks, one for cuts on the left and one for cuts -- on the right.@@ -64,10 +64,6 @@ -- | Don't show any cut mark when text is cut. noCutMark :: CutMark noCutMark = singleCutMark ""--{-# DEPRECATED ellipsisCutMark "Use def instead." #-}-ellipsisCutMark :: CutMark-ellipsisCutMark = singleCutMark "…" spaces :: Int -> String spaces = flip replicate ' '
src/Text/Layout/Table/Primitives/Column.hs view
@@ -16,12 +16,13 @@ -- | Specifies the layout of a column.-data ColSpec = ColSpec- { lenSpec :: LenSpec- , position :: Position H- , alignSpec :: AlignSpec- , cutMark :: CutMark- }+data ColSpec+ = ColSpec+ { lenSpec :: LenSpec+ , position :: Position H+ , alignSpec :: AlignSpec+ , cutMark :: CutMark+ } instance Default ColSpec where def = column def def def def
src/Text/Layout/Table/Primitives/LenSpec/Internal.hs view
@@ -9,7 +9,11 @@ import Data.Default.Class -- | Determines how long a column will be.-data LenSpec = Expand | Fixed Int | ExpandUntil Int | FixedUntil Int+data LenSpec+ = Expand+ | Fixed Int+ | ExpandUntil Int+ | FixedUntil Int instance Default LenSpec where def = expand
table-layout.cabal view
@@ -6,7 +6,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 0.8.0.0+version: 0.8.0.1 synopsis: Layout text as grid or table. @@ -30,23 +30,23 @@ A small tutorial is provided in the `README.md` file. -- URL for the project homepage or repository.-homepage: https://github.com/muesli4/table-layout-license: BSD3-license-file: LICENSE-author: Moritz Bruder-maintainer: muesli4@gmail.com-category: Text-build-type: Simple+homepage: https://github.com/muesli4/table-layout+license: BSD3+license-file: LICENSE+author: Moritz Bruder+maintainer: muesli4@gmail.com+category: Text+build-type: Simple -- Extra files to be distributed with the package, such as examples or a -- README.-extra-source-files: README.md+extra-source-files: README.md -- Constraint on the version of Cabal needed to build this package.-cabal-version: >=1.10+cabal-version: >=1.10 source-repository head- type: git- location: git://github.com/muesli4/table-layout.git+ type: git+ location: git://github.com/muesli4/table-layout.git library@@ -69,11 +69,15 @@ -- LANGUAGE extensions used by modules in this package.- other-extensions: RecordWildCards+ other-extensions: RecordWildCards,+ EmptyDataDecls,+ FlexibleInstances,+ PatternSynonyms,+ MultiWayIf -- Other library packages from which modules are imported.- build-depends: base >=4.8 && <4.10,- data-default-class ==0.0.*,+ build-depends: base >=4.8 && <4.11,+ data-default-class >=0.1.1 && < 0.2, data-default-instances-base ==0.1.* hs-source-dirs: src@@ -83,24 +87,51 @@ executable table-layout-test-styles main-is: Test.hs- build-depends: base >=4.8 && <4.10,- data-default-class ==0.0.*,+ build-depends: base >=4.8 && <4.11,+ data-default-class >=0.1.1 && < 0.2, data-default-instances-base ==0.1.* hs-source-dirs: src- other-modules: Text.Layout.Table+ other-modules: Text.Layout.Table,+ Text.Layout.Table.Internal,+ Text.Layout.Table.Justify,+ Text.Layout.Table.Position,+ Text.Layout.Table.Position.Internal,+ Text.Layout.Table.Primitives.AlignSpec,+ Text.Layout.Table.Primitives.AlignSpec.Internal,+ Text.Layout.Table.Primitives.Basic,+ Text.Layout.Table.Primitives.Column,+ Text.Layout.Table.Primitives.LenSpec,+ Text.Layout.Table.Primitives.LenSpec.Internal,+ Text.Layout.Table.Primitives.Occurence,+ Text.Layout.Table.Style Text.Layout.Table.Vertical+ default-language: Haskell2010 test-suite table-layout-tests type: exitcode-stdio-1.0 hs-source-dirs: test-suite, src main-is: Spec.hs- build-depends: base >=4.8 && <4.10,- QuickCheck >=2.8 && < 2.10,- HUnit ==1.3.*,- data-default-class ==0.0.*,+ build-depends: base >=4.8 && <4.11,+ QuickCheck >=2.8 && < 2.11,+ HUnit >=1.3,+ data-default-class >=0.1.1 && < 0.2, data-default-instances-base ==0.1.*, hspec - other-modules: Text.Layout.Table, Text.Layout.Table.Primitives.Basic+ other-modules: TestSpec,+ Text.Layout.Table,+ Text.Layout.Table.Internal,+ Text.Layout.Table.Justify,+ Text.Layout.Table.Position,+ Text.Layout.Table.Position.Internal,+ Text.Layout.Table.Primitives.AlignSpec,+ Text.Layout.Table.Primitives.AlignSpec.Internal,+ Text.Layout.Table.Primitives.Basic,+ Text.Layout.Table.Primitives.Column,+ Text.Layout.Table.Primitives.LenSpec,+ Text.Layout.Table.Primitives.LenSpec.Internal,+ Text.Layout.Table.Primitives.Occurence,+ Text.Layout.Table.Style,+ Text.Layout.Table.Vertical default-language: Haskell2010
+ test-suite/TestSpec.hs view
@@ -0,0 +1,124 @@+module TestSpec+ ( spec+ ) where++import Test.Hspec+import Test.Hspec.QuickCheck+import Test.QuickCheck+import Test.HUnit++import Text.Layout.Table+import Text.Layout.Table.Primitives.Occurence+import Text.Layout.Table.Primitives.Basic++spec :: Spec+spec = do+ describe "fill" $ do+ describe "fillLeft" $ do+ it "ex1" $ fillLeft 4 "ab" `shouldBe` " ab"+ describe "fillRight" $ do+ it "ex1" $ fillRight 4 "ab" `shouldBe` "ab "+ describe "fillCenter" $ do+ it "ex1" $ fillCenter 4 "ab" `shouldBe` " ab "++ describe "mark" $ do+ prop "left mark does not change length" $ \s -> length (applyMarkLeftWith customCM s) `shouldBe` length s+ prop "right mark does not change length" $ \s -> length (applyMarkRightWith customCM s) `shouldBe` length s++ describe "fit" $ do+ describe "fitRightWith" $ do+ let fitRight = fitRightWith customCM+ it "ex1" $ fitRight 4 "12345678" `shouldBe` "1..>"+ describe "fitLeftWith" $ do+ let fitLeft = fitLeftWith customCM+ it "ex1" $ fitLeft 4 "12345678" `shouldBe` "<..8"+ describe "fitCenterWith" $ do+ let fitCenter = fitCenterWith customCM+ it "ex1" $ fitCenter 7 "12345678" `shouldBe` "<..5678"+ it "ex1" $ fitCenter 6 "12345678" `shouldBe` "<....>"++ -- TODO implement test cases+ -- describe "ColModInfo" $ do+ -- it "ensureWidthCMI" $ ++ describe "pad" $ do+ prop "left" $ propPadLeft+ prop "right" $ propPadRight+ prop "center" $ propPadCenter++ describe "trimOrPad" $ do+ prop "pad" $ forAll hposG $ \p s (Positive (Small n)) -> length s > n || trimOrPad p noCutMark n s == pad p n s+ it "left" $ trimOrPad left customCM 5 "1234567890" `shouldBe` "12..>"+ it "right" $ trimOrPad right customCM 5 "1234567890" `shouldBe` "<..90"+ it "center" $ trimOrPad center customCM 8 "1234567890" `shouldBe` "<..56..>"++ describe "align" $ do+ let ai = deriveAlignInfo occS "abc:42"+ it "ex1" $ align occS ai "c:4" `shouldBe` " c:4 "+ it "ex2" $ align occS ai "x" `shouldBe` " x "+ it "ex3" $ align occS ai ":x" `shouldBe` " :x "++ describe "alignFixed" $ do+ -- 5 spaces on each side.+ let ai = deriveAlignInfo occS " : "+ alignFixed' p l = alignFixed p customCM l occS ai+ ai2 = deriveAlignInfo occS " : "+ alignFixed2' p l = alignFixed p customCM l occS ai2+ it "left 1" $ alignFixed' left 6 "ab:42" `shouldBe` " ..>"+ it "left 2" $ alignFixed' left 6 "abcd:42" `shouldBe` " ab..>"++ it "left 3" $ alignFixed' left 5 "32" `shouldBe` " 32"++ it "right 1" $ alignFixed' right 6 "ab:1234" `shouldBe` "<..34 "+ it "right 2" $ alignFixed' right 6 "ab:12" `shouldBe` "<.. "+ -- ensure left-biased centering:+ -- aligned to full length: " abcd:12 "+ -- right-biased centering: "bcd:12"+ -- left-biased centering: "cd:12 "+ it "center 1" $ alignFixed' center 6 "abcd:12" `shouldBe` "<..12 "+ -- use same string position: "ab:12 "+ it "center 2" $ alignFixed' center 6 "ab:12" `shouldBe` "ab:12 "+ -- ensure left-biased centering:+ -- aligned to full length: " abcd:12 "+ -- right-biased centering: " abcd:"+ -- left-biased centering: "abcd:1"+ it "center 3" $ alignFixed2' center 6 "abcd:12" `shouldBe` "abc..>"+ -- use same string position: " ab:1"+ it "center 4" $ alignFixed2' center 6 "ab:12" `shouldBe` " a..>"++ -- TODO add test cases for all combinations of lengths+ -- (i.e.: i mod 2 = 1, i mod 2 = 0, l + r mod 2 = 0, l + r mod 2 = 1)++ prop "alignFixed length" $ forAll hposG $ \p s (Positive (Small n)) -> length (alignFixed' p n s) `shouldBe` n+ where+ customCM = doubleCutMark "<.." "..>"+ occS = predOccSpec (== ':')++ hposG = elements [left, center, right]+ noWS = (/= ' ')++ propPadLeft :: String -> Positive (Small Int) -> Bool+ propPadLeft s (Positive (Small n)) =+ let len = length s+ padded = pad left n s+ in if len < n+ then take len padded == s && all (== ' ') (drop len padded)+ else True++ propPadRight :: String -> Positive (Small Int) -> Bool+ propPadRight s (Positive (Small n)) =+ let len = length s+ padded = pad right n s+ in if len < n+ then drop (n - len) padded == s && all (== ' ') (take (n - len) padded)+ else True++ propPadCenter :: String -> Positive (Small Int) -> Bool+ propPadCenter s (Positive (Small n)) =+ let len = length s+ padded = pad center n s+ (q, r) = (n - len) `divMod` 2+ trimLeft = drop q padded+ in if len < n+ then all (== ' ') (take q padded) && take len trimLeft == s && (drop len trimLeft) == replicate (q + r) ' '+ else True