packages feed

text-format-heavy 0.1.5.2 → 0.1.5.3

raw patch · 5 files changed

+209/−126 lines, 5 filesdep +hspecdep +labelsdep +template-haskellPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: hspec, labels, template-haskell, text-format-heavy, th-lift, th-lift-instances

API changes (from Hackage documentation)

- Data.Text.Format.Heavy.Instances: instance Data.Text.Format.Heavy.Types.Formatable a => Data.Text.Format.Heavy.Types.ClosedVarContainer (GHC.Base.Maybe a)
- Data.Text.Format.Heavy.Instances: instance Data.Text.Format.Heavy.Types.Formatable a => Data.Text.Format.Heavy.Types.Formatable (GHC.Base.Maybe a)
- Data.Text.Format.Heavy.Instances: instance Data.Text.Format.Heavy.Types.Formatable a => Data.Text.Format.Heavy.Types.VarContainer (GHC.Base.Maybe a)
+ Data.Text.Format.Heavy.Instances: instance Data.Text.Format.Heavy.Types.Formatable a => Data.Text.Format.Heavy.Types.ClosedVarContainer (GHC.Maybe.Maybe a)
+ Data.Text.Format.Heavy.Instances: instance Data.Text.Format.Heavy.Types.Formatable a => Data.Text.Format.Heavy.Types.Formatable (GHC.Maybe.Maybe a)
+ Data.Text.Format.Heavy.Instances: instance Data.Text.Format.Heavy.Types.Formatable a => Data.Text.Format.Heavy.Types.VarContainer (GHC.Maybe.Maybe a)

Files

Data/Text/Format/Heavy/Build.hs view
@@ -1,33 +1,43 @@ {-# LANGUAGE OverloadedStrings #-}  module Data.Text.Format.Heavy.Build-  (format, formatEither,-   makeBuilder,+  ( format+  , formatEither+  , makeBuilder+  ,    -- * Formatters building utilities-   align, applySign, applySharp, convertText,-   formatInt, formatStr, formatFloat, formatBool-  ) where+    align+  , applySign+  , applySharp+  , convertText+  , formatInt+  , formatStr+  , formatFloat+  , formatBool+  )+where -import Control.Monad-import Data.Monoid-import Data.Maybe-import qualified Data.Text as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Builder as B-import Data.Text.Lazy.Builder.Int (decimal, hexadecimal)-import Data.Text.Lazy.Builder.RealFloat+import           Control.Monad+import           Data.Monoid+import           Data.Maybe+import qualified Data.Text                     as T+import qualified Data.Text.Lazy                as TL+import qualified Data.Text.Lazy.Builder        as B+import           Data.Text.Lazy.Builder.Int     ( decimal+                                                , hexadecimal+                                                )+import           Data.Text.Lazy.Builder.RealFloat -import Data.Text.Format.Heavy.Types-import Data.Text.Format.Heavy.Formats+import           Data.Text.Format.Heavy.Types+import           Data.Text.Format.Heavy.Formats  makeBuilder :: VarContainer c => Format -> c -> Either String B.Builder makeBuilder (Format items) vars = mconcat `fmap` mapM go items-  where-    go (FString s) = Right $ B.fromLazyText s-    go (FVariable name fmt) =-      case lookupVar name vars of-        Nothing -> Left $ "Parameter not found: " ++ TL.unpack name-        Just var -> formatVar fmt var+ where+  go (FString s         ) = Right $ B.fromLazyText s+  go (FVariable name fmt) = case lookupVar name vars of+    Nothing  -> Left $ "Parameter not found: " ++ TL.unpack name+    Just var -> formatVar fmt var {-# INLINE makeBuilder #-}  -- | The main formatting function.@@ -36,10 +46,10 @@ format fmt vars = either error id $ formatEither fmt vars  -- | The main formatting function.--- This version returns @Left@ value with error description in case of error in +-- This version returns @Left@ value with error description in case of error in -- format string or error during formatting. formatEither :: VarContainer vars => Format -> vars -> Either String TL.Text-formatEither fmt vars = either Left (Right . B.toLazyText) $ makeBuilder fmt vars+formatEither fmt vars = B.toLazyText `fmap` makeBuilder fmt vars  align' :: Int -> Align -> Char -> B.Builder -> B.Builder align' width AlignLeft fill text =@@ -51,65 +61,65 @@  -- | Align text within available width according to format align :: GenericFormat -> B.Builder -> B.Builder-align fmt text =-  case (gfAlign fmt, gfWidth fmt) of-    (Just a, Just w) -> align' w a (gfFillChar fmt) text-    _ -> text+align fmt text = case (gfAlign fmt, gfWidth fmt) of+  (Just a, Just w) -> align' w a (gfFillChar fmt) text+  _                -> text  -- | Add @+/-@ sign to the number representation, if required applySign :: (Num a, Ord a) => Sign -> a -> B.Builder -> B.Builder applySign Always x text =-  if x >= 0-    then B.singleton '+' <> text-    else B.singleton '-' <> text+  if x >= 0 then B.singleton '+' <> text else B.singleton '-' <> text applySign OnlyNegative x text =-  if x >= 0-    then text-    else B.singleton '-' <> text+  if x >= 0 then text else B.singleton '-' <> text applySign SpaceForPositive x text =-  if x >= 0-    then B.singleton ' ' <> text-    else B.singleton '-' <> text+  if x >= 0 then B.singleton ' ' <> text else B.singleton '-' <> text  -- | Add @0x@ to the number representation, if required applySharp :: Bool -> Radix -> B.Builder -> B.Builder-applySharp False _ text = text-applySharp True Decimal text = text-applySharp True Hexadecimal text = B.fromLazyText "0x" <> text+applySharp False _           text = text+applySharp True  Decimal     text = text+applySharp True  Hexadecimal text = B.fromLazyText "0x" <> text  -- | Apply text conversion. convertText :: Maybe Conversion -> B.Builder -> B.Builder-convertText Nothing builder = builder-convertText (Just conv) builder = B.fromLazyText $ converter $ B.toLazyText builder-  where-    converter = case conv of-                  UpperCase -> TL.toUpper-                  LowerCase -> TL.toLower-                  TitleCase -> TL.toTitle+convertText Nothing     builder = builder+convertText (Just conv) builder = B.fromLazyText $ converter $ B.toLazyText+  builder+ where+  converter = case conv of+    UpperCase -> TL.toUpper+    LowerCase -> TL.toLower+    TitleCase -> TL.toTitle  -- | Format integer number according to GenericFormat formatInt :: Integral a => GenericFormat -> a -> B.Builder-formatInt fmt x = align fmt $ applySign (gfSign fmt) x $ applySharp (gfLeading0x fmt) radix $ inRadix-  where-   radix = fromMaybe Decimal (gfRadix fmt)-   inRadix = case radix of-               Decimal -> decimal (abs x)-               Hexadecimal -> hexadecimal (abs x)+formatInt fmt x = align fmt $ applySign (gfSign fmt) x $ applySharp+  (gfLeading0x fmt)+  radix+  inRadix+ where+  radix = fromMaybe Decimal (gfRadix fmt)+  conversion = fromMaybe LowerCase (gfConvert fmt)+  inRadix = case radix of+    Decimal     -> decimal (abs x)+    Hexadecimal -> case conversion of+      LowerCase -> hexadecimal (abs x)+      _         -> B.fromLazyText . TL.toUpper . B.toLazyText . hexadecimal . abs $ x  -- | Format floating-point number according to GenericFormat formatFloat :: RealFloat a => GenericFormat -> a -> B.Builder formatFloat fmt x =-    align fmt+  align fmt     $ applySign (gfSign fmt) x     $ formatRealFloat Fixed (gfPrecision fmt)     $ abs x  -- | Format Text according to GenericFormat. formatStr :: GenericFormat -> TL.Text -> B.Builder-formatStr fmt text = convertText (gfConvert fmt) $ align fmt $ B.fromLazyText text+formatStr fmt text =+  convertText (gfConvert fmt) $ align fmt $ B.fromLazyText text  -- | Format boolean value. formatBool :: BoolFormat -> Bool -> B.Builder-formatBool fmt True = B.fromLazyText $ bfTrue fmt+formatBool fmt True  = B.fromLazyText $ bfTrue fmt formatBool fmt False = B.fromLazyText $ bfFalse fmt-
Data/Text/Format/Heavy/Parse/VarFormat.hs view
@@ -4,10 +4,11 @@   where  import Data.Maybe+import Control.Applicative ((<|>)) import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.Builder as B-import Text.Parsec+import Text.Parsec hiding ((<|>))  import Data.Text.Format.Heavy.Types import Data.Text.Format.Heavy.Formats@@ -24,7 +25,7 @@     let leading0x = fromMaybe False mbLeading0x     mbWidth <- optionMaybe (pWidth <?> "width specification")     mbPrecision <- optionMaybe (pPrecision <?> "precision specification")-    mbRadix <- optionMaybe (pRadix <?> "radix specification")+    mbRadixConvert <- optionMaybe (pRadix <?> "radix specification")     mbConvert <- optionMaybe (pConvert <?> "conversion specification")     return $ GenericFormat {                gfFillChar = fill@@ -33,8 +34,8 @@              , gfLeading0x = leading0x              , gfWidth = mbWidth              , gfPrecision = mbPrecision-             , gfRadix = mbRadix-             , gfConvert = mbConvert+             , gfRadix = fst <$> mbRadixConvert+             , gfConvert = mbConvert <|> fmap snd mbRadixConvert              }   where     pAlign :: Parsec TL.Text st Align@@ -91,14 +92,16 @@     pPrecision = do       char '.'       natural-    -    pRadix :: Parsec TL.Text st Radix++    pRadix :: Parsec TL.Text st (Radix, Conversion)     pRadix = do-      rc <- oneOf "xhd"+      rc <- oneOf "xXhHd"       case rc of-        'x' -> return Hexadecimal-        'h' -> return Hexadecimal-        'd' -> return Decimal+        'x' -> return (Hexadecimal, LowerCase)+        'X' -> return (Hexadecimal, UpperCase)+        'h' -> return (Hexadecimal, LowerCase)+        'H' -> return (Hexadecimal, UpperCase)+        'd' -> return (Decimal, LowerCase)      pConvert :: Parsec TL.Text st Conversion     pConvert = do@@ -175,4 +178,3 @@   in  if TL.null xFmtStr         then Nothing         else Just (TL.init xFmtStr, nothingStr)-
README.md view
@@ -1,6 +1,8 @@ text-format-heavy README ======================== +[![Build Status](https://travis-ci.org/portnov/text-format-heavy.svg?branch=master)](https://travis-ci.org/portnov/text-format-heavy)+ This is Haskell string formatting library, which prefers functionality and extendability over light weight and (probably, in some cases) performance. This library is more or less analog of Python's string.format function, and
+ tests/Spec.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE OverloadedStrings #-}++import Test.Hspec+import Data.Time++import Data.Text.Format.Heavy+import Data.Text.Format.Heavy.Time++main :: IO ()+main = hspec $ do+  describe "trivial" $ do+    it "formats string literal without formatting characters" $ do+      format "hello world" () `shouldBe` "hello world"++  describe "simple" $ do+    it "formats int properly" $ do+      format "integer: {}" (Single (7 :: Int)) `shouldBe` "integer: 7"++    it "formats strings properly" $ do+      format "string: {}" (Single ("hello" :: String)) `shouldBe` "string: hello"++    it "handles parameter numbers" $ do+      format "one: {0}, two: {1}" ((1:: Int), (2::Int)) `shouldBe` "one: 1, two: 2"+      format "two: {1}, one: {0}" ((1:: Int), (2::Int)) `shouldBe` "two: 2, one: 1"++  describe "documentation" $ do+    it "formats examples from wiki" $ do+      format "hex: {:#x}" (Single (427 :: Int)) `shouldBe` "hex: 0x1ab"+      format "hex: {:#h}" (Single (427 :: Int)) `shouldBe` "hex: 0x1ab"+      format "hex: {:#X}" (Single (427 :: Int)) `shouldBe` "hex: 0x1AB"+      format "hex: {:#H}" (Single (427 :: Int)) `shouldBe` "hex: 0x1AB"+      format "dec: {:#d}" (Single (17 :: Int)) `shouldBe` "dec: 17"+      format "center: <{0:^10}>" (Single ("hello" :: String)) `shouldBe` "center: <   hello  >"+      format "float: {:+6.4}" (Single (2.718281828 :: Double)) `shouldBe` "float: +2.7183"++    it "formats booleans" $ do+      format "default: {}" (Single True) `shouldBe` "default: true"+      format "enable: {:yes:no}" (Single False) `shouldBe` "enable: no"++    it "formats maybes" $ do+      format "Value: {:.3|<undefined>}." (Single (2.718281828 :: Float)) `shouldBe` "Value: 2.718."+      format "Value: {:.3|<undefined>}." (Single (Nothing :: Maybe Float)) `shouldBe` "Value: <undefined>."+      format "Value: {:.3}." (Single (Nothing :: Maybe Float)) `shouldBe` "Value: ."++    it "formats time" $ do+      let Just time = parseTimeM True defaultTimeLocale rfc822DateFormat "Sat,  3 Jun 2017 19:06:01 YEKT" :: Maybe ZonedTime+      format "time: {:%H:%M:%S}" (Single time) `shouldBe` "time: 19:06:01"+      format "time: {:%H:%M:%S %Z}" (Single time) `shouldBe` "time: 19:06:01 YEKT"+      format "default: {}" (Single time) `shouldBe` "default: Sat,  3 Jun 2017 19:06:01 YEKT"+
text-format-heavy.cabal view
@@ -1,64 +1,83 @@-name:                text-format-heavy-version:             0.1.5.2-synopsis:            Full-weight string formatting library, analog of Python's string.format-description:         This package contains full-featured string formatting function, similar to-                     Python's string.format. Features include:-                     .-                     * Automatically numbered variable placeholders;-                     .-                     * Positional variable placeholders;-                     .-                     * Named variable placeholders;-                     .-                     * Placeholders can be used in any order; one variable can be used several-                       times or not used at all.-                     .-                     * Specific format can be used for each variable substitution.-                     .-                     This package prefers functionality over "light weight" and (probably) performance. -                     It also exposes all required interfaces to extend and customize it.-                     .-                     For more details, please refer to <https://github.com/portnov/text-format-heavy/wiki Wiki>.-                     See also the @examples/@ directory.-                     -license:             BSD3-license-file:        LICENSE-author:              Ilya Portnov-maintainer:          portnov84@rambler.ru--- copyright:           -category:            Text-build-type:          Simple-extra-source-files:  ChangeLog.md,-                     README.md,-                     examples/test.hs,-                     examples/Benchmarks.hs-cabal-version:       >=1.10+cabal-version: 1.12 -library-  exposed-modules:     Data.Text.Format.Heavy,-                       Data.Text.Format.Heavy.Parse,-                       Data.Text.Format.Heavy.Parse.Types,-                       Data.Text.Format.Heavy.Parse.VarFormat,-                       Data.Text.Format.Heavy.Parse.Braces,-                       Data.Text.Format.Heavy.Parse.Shell,-                       Data.Text.Format.Heavy.Build,-                       Data.Text.Format.Heavy.Types,-                       Data.Text.Format.Heavy.Formats,-                       Data.Text.Format.Heavy.Instances,-                       Data.Text.Format.Heavy.Time-  -- other-modules:       -  other-extensions:    ExistentialQuantification-  build-depends:       base >=4.8 && <5,-                       text >=1.2 && <1.3,-                       bytestring >= 0.10,-                       parsec >=3.1 && <3.2,-                       containers >= 0.5,-                       data-default >= 0.7,-                       time >= 1.5-  -- hs-source-dirs:      -  default-language:    Haskell2010+-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 8997cbee7e77bc2355f247d0ff85ba397d2b6e2414b974868c48f7b720aaf3e6 +name:           text-format-heavy+version:        0.1.5.3+synopsis:       Full-weight string formatting library, analog of Python's string.format+description:    This package contains full-featured string formatting function, similar to Python's string.format. Features include:+                * Automatically numbered variable placeholders;+                * Positional variable placeholders;+                * Named variable placeholders;+                * Placeholders can be used in any order; one variable can be used several+                  times or not used at all.+                .+                * Specific format can be used for each variable substitution.+                This package prefers functionality over "light weight" and (probably) performance.  It also exposes all required interfaces to extend and customize it.+                For more details, please refer to <https://github.com/portnov/text-format-heavy/wiki Wiki>. See also the @examples/@ directory.+category:       Text+homepage:       https://github.com/portnov/text-format-heavy#readme+bug-reports:    https://github.com/portnov/text-format-heavy/issues+author:         Ilya Portnov+maintainer:     portnov84@rambler.ru+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    ChangeLog.md+    README.md+    examples/test.hs+    examples/Benchmarks.hs+ source-repository head   type: git-  location: https://github.com/portnov/text-format-heavy.git+  location: https://github.com/portnov/text-format-heavy +library+  exposed-modules:+      Data.Text.Format.Heavy+      Data.Text.Format.Heavy.Build+      Data.Text.Format.Heavy.Formats+      Data.Text.Format.Heavy.Instances+      Data.Text.Format.Heavy.Parse+      Data.Text.Format.Heavy.Parse.Braces+      Data.Text.Format.Heavy.Parse.Shell+      Data.Text.Format.Heavy.Parse.Types+      Data.Text.Format.Heavy.Parse.VarFormat+      Data.Text.Format.Heavy.Time+      Data.Text.Format.Heavy.Types+  other-modules:+      Paths_text_format_heavy+  hs-source-dirs:+      ./.+  build-depends:+      base >=4.8 && <5+    , bytestring >=0.10+    , containers >=0.5+    , data-default >=0.7+    , labels+    , parsec >=3.1 && <3.2+    , template-haskell >=2.8+    , text >=1.2 && <1.3+    , th-lift+    , th-lift-instances+    , time >=1.5+  default-language: Haskell2010++test-suite spec+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Paths_text_format_heavy+  hs-source-dirs:+      tests+  build-depends:+      base >=4.8 && <5+    , hspec+    , text-format-heavy+    , time >=1.5+  default-language: Haskell2010