packages feed

hformat 0.3.3.0 → 0.3.3.1

raw patch · 3 files changed

+345/−342 lines, 3 filesdep +semigroupsdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: semigroups

Dependency ranges changed: base

API changes (from Hackage documentation)

Files

hformat.cabal view
@@ -1,45 +1,48 @@-name:                hformat
-version:             0.3.3.0
-synopsis:            Simple Haskell formatting
-description: String formatting
-homepage:            http://github.com/mvoidex/hformat
-license:             BSD3
-license-file:        LICENSE
-author:              Alexandr Ruchkin
-maintainer:          voidex@live.com
-category:            Text
-build-type:          Simple
-cabal-version:       >=1.10
-
-source-repository head
-  type: git
-  location: git://github.com/mvoidex/hformat.git
-
-library
-  hs-source-dirs: src
-  default-language: Haskell2010
-  ghc-options: -Wall -fno-warn-tabs
-  default-extensions: UnicodeSyntax
-  exposed-modules:
-    Text.Format
-    Text.Format.Flags
-    Text.Format.Colored
-  build-depends:
-    base >= 4.8 && < 5,
-    base-unicode-symbols >= 0.2,
-    ansi-terminal >= 0.6,
-    text >= 1.2.1
-
-test-suite test
-  type: exitcode-stdio-1.0
-  main-is: Test.hs
-  hs-source-dirs: tests
-  ghc-options: -threaded -Wall -fno-warn-tabs
-  default-language: Haskell2010
-  default-extensions: UnicodeSyntax
-  build-depends:
-    base >= 4.8 && < 5,
-    base-unicode-symbols >= 0.2,
-    text >= 1.2.1,
-    hspec,
-    hformat
+name:                hformat+version:             0.3.3.1+synopsis:            Simple Haskell formatting+description: String formatting+homepage:            http://github.com/mvoidex/hformat+license:             BSD3+license-file:        LICENSE+author:              Alexandr Ruchkin+maintainer:          voidex@live.com+category:            Text+build-type:          Simple+cabal-version:       >=1.10++source-repository head+  type: git+  location: git://github.com/mvoidex/hformat.git++library+  hs-source-dirs: src+  default-language: Haskell2010+  ghc-options: -Wall -fno-warn-tabs+  default-extensions: UnicodeSyntax+  exposed-modules:+    Text.Format+    Text.Format.Flags+    Text.Format.Colored+  if !impl(ghc >= 8.0)+    build-depends:+      semigroups >= 0.18.2 && < 0.19+  build-depends:+    base >= 4.8 && < 5,+    base-unicode-symbols >= 0.2,+    ansi-terminal >= 0.6,+    text >= 1.2.1++test-suite test+  type: exitcode-stdio-1.0+  main-is: Test.hs+  hs-source-dirs: tests+  ghc-options: -threaded -Wall -fno-warn-tabs+  default-language: Haskell2010+  default-extensions: UnicodeSyntax+  build-depends:+    base >= 4.8 && < 5,+    base-unicode-symbols >= 0.2,+    text >= 1.2.1,+    hspec,+    hformat
src/Text/Format.hs view
@@ -1,246 +1,246 @@-{-# LANGUAGE FlexibleInstances, UndecidableInstances, DefaultSignatures #-}
-
--- | Format string with named args
---
--- >-- Named args
--- >"My name is {name}, I am {age} years old" ~~ ("name" ~% "Joe") ~~ ("age" ~% 24) ≡ "My name is Joe, I am 24 years old"
--- >-- Arg can have default value
--- >"{var:x} = {val:10}" ~~ ("var" ~% y) ≡ "y = 10"
--- >-- Numeric position can be used
--- >"{0} {1} {0}" ~~ "foo" ~~ "bar" ≡ "foo bar foo"
--- >-- Positions can be omitted
--- >"{} {}" ~~ "foo" ~~ 10 ≡ "foo 10"
--- >-- Double braces to escape them
--- >"{} and {{}}" ~~ 10 ≡ "10 and {}"
-module Text.Format (
-	FormattedPart(..), Formatted(..), withFlags,
-	FormatArg(..), Format(..), Formatter(..),
-	prebuild, build, getNamedArguments,
-	Formattable(..), Hole(..), fmt, FormatResult(..),
-	format, formats, (~~), (~%),
-
-	module Text.Format.Flags
-	) where
-
-import Prelude.Unicode
-
-import Control.Applicative
-import Data.Char (intToDigit)
-import Data.List (find, intercalate, nub)
-import Data.Maybe (fromMaybe, listToMaybe)
-import Data.Semigroup (Semigroup(..))
-import qualified Data.Text as T
-import Data.Text.Lazy (Text, unpack)
-import Data.String
-import Numeric
-import Text.Read (readMaybe)
-import Text.ParserCombinators.ReadP
-
-import Text.Format.Flags
-
-data FormattedPart = FormattedPart {
-	formattedFlags ∷ FormatFlags,
-	formattedValue ∷ String }
-		deriving (Eq, Ord, Show)
-
-instance IsString FormattedPart where
-	fromString = FormattedPart [] ∘ fromString
-
-newtype Formatted = Formatted { formattedParts ∷ [FormattedPart] } deriving (Eq, Ord, Show)
-
-instance IsString Formatted where
-	fromString = Formatted ∘ return ∘ fromString
-
-instance Semigroup Formatted where
-	Formatted l <> Formatted r = Formatted $ l ++ r
-
-instance Monoid Formatted where
-	mempty = Formatted []
-	Formatted l `mappend` Formatted r = Formatted $ l ++ r
-
-withFlags ∷ String → [String] → Formatted
-withFlags v fs = Formatted [FormattedPart fs v]
-
-data FormatArg = FormatNamed String ([String] → Formatted) | FormatPos ([String] → Formatted)
-
-data Format = Format {
-	formatString ∷ String,
-	formatArgs ∷ [FormatArg] }
-
-instance Show Format where
-	show = mconcat ∘ map formattedValue ∘ formattedParts ∘ prebuild
-
-instance IsString Format where
-	fromString str = Format str []
-
-data Formatter = Formatter {
-	formatter ∷ Either String Int,
-	formatterDefault ∷ Maybe String,
-	formatterFlags ∷ [String] }
-
-instance Show Formatter where
-	show (Formatter f def cfgs) = "{" ++ concat parts ++ "}" where
-		parts = [either id show f, fromMaybe "" (fmap ('=':) def), if null cfgs then "" else (':' : intercalate "," cfgs)]
-
-instance Read Formatter where
-	readsPrec _ = readP_to_S $ between (char '{') (char '}') $ do
-		n ← munch (∉ "=:}")
-		v ← option Nothing $ do
-			_ ← char '='
-			v' ← munch1 (∉ ":}")
-			return $ Just v'
-		cs ← option [] $ do
-			_ ← char ':'
-			flip sepBy (char ',') (munch1 (∉ ",}"))
-		return $ Formatter (maybe (Left n) Right $ readMaybe n) v cs
-
-prebuild ∷ Format → Formatted
-prebuild = buildFormat True
-
-build ∷ Format → Formatted
-build = buildFormat False
-
-buildFormat ∷ Bool → Format → Formatted
-buildFormat pre fstr = build' 0 fstr where
-	build' ∷ Int → Format → Formatted
-	build' _ (Format "" _) = mempty
-	build' i (Format ('{':'{':fstr') args) = fromString "{" `mappend` build' i (Format fstr' args)
-	build' i (Format ('}':'}':fstr') args) = fromString "}" `mappend` build' i (Format fstr' args)
-	build' i (Format ('{':'}':fstr') args) = formatArg' (Formatter (Right i) Nothing []) args `mappend` build' (succ i) (Format fstr' args)
-	build' i (Format ('{':fstr') args) = case reads ('{':fstr') of
-		[] → error $ "Can't parse formatter at " ++ fstr'
-		(f, fstr''):_ → formatArg' f args `mappend` build' i (Format fstr'' args)
-	build' i (Format fstr' args) = fromString s `mappend` build' i (Format fstr'' args) where
-		(s, fstr'') = break (∈ "{}") fstr'
-	formatArg' ∷ Formatter → [FormatArg] → Formatted
-	formatArg' f@(Formatter (Left name) defVal fmtCfgs) args
-		| pre = fromMaybe (formatted f fmtCfgs) lookArg
-		| otherwise = fromMaybe (error $ "Argument " ++ name ++ " not set") (lookArg <|> fmap (flip formatted fmtCfgs) defVal)
-		where
-			lookArg = do
-				FormatNamed _ fval ← find byName args
-				return $ fval fmtCfgs
-			byName (FormatNamed n _) = n ≡ name
-			byName _ = False
-	formatArg' f@(Formatter (Right i) defVal fmtCfgs) args
-		| pre = fromMaybe (formatted f fmtCfgs) lookIdx
-		| otherwise = fromMaybe (error $ "Argument at index " ++ show i ++ " not set") (lookIdx <|> fmap (flip formatted fmtCfgs) defVal)
-		where
-			lookIdx = do
-				FormatPos fval ← listToMaybe $ drop i $ filter isPos args
-				return $ fval fmtCfgs
-			isPos (FormatPos _) = True
-			isPos _ = False
-
-getNamedArguments ∷ Format → [String]
-getNamedArguments = nub ∘ getNamedArguments'
-	where
-		getNamedArguments' ∷ Format → [String]
-		getNamedArguments' (Format "" _) = mempty
-		getNamedArguments' (Format ('{':'{':fstr') args) = getNamedArguments' (Format fstr' args)
-		getNamedArguments' (Format ('}':'}':fstr') args) = getNamedArguments' (Format fstr' args)
-		getNamedArguments' (Format ('{':'}':fstr') args) = getNamedArguments' (Format fstr' args)
-		getNamedArguments' (Format fstr@('{':fstr') args) = case reads fstr of
-			[] → error $ "Can't parse formatter at " ++ fstr'
-			(f, fstr''):_ → getNamedArgument f `mappend` getNamedArguments' (Format fstr'' args)
-			where
-		getNamedArguments' (Format fstr' args) = getNamedArguments' (Format fstr'' args) where
-			(_, fstr'') = break (∈ "{}") fstr'
-		getNamedArgument ∷ Formatter → [String]
-		getNamedArgument (Formatter (Left name) _ _) = [name]
-		getNamedArgument _ = mempty
-
--- | Formattable class, by default using @show@
-class Formattable a where
-	formattable ∷ a → FormatFlags → Formatted
-	default formattable ∷ Show a ⇒ a → FormatFlags → Formatted
-	formattable x _ = fromString ∘ show $ x
-
-formatted ∷ Formattable a ⇒ a → FormatFlags → Formatted
-formatted v fmts = Formatted ∘ map addFmts ∘ formattedParts ∘ formattable v $ fmts where
-	addFmts (FormattedPart flags' v') = FormattedPart (nub $ fmts ++ flags') v'
-
-instance Formattable String where
-	formattable s _ = fromString s
-
-instance Formattable Char where
-	formattable ch _ = fromString [ch]
-
-instance Formattable Int where
-	formattable i fmts = fromString ∘ formatInt (baseFlag fmts) $ i
-instance Formattable Integer where
-	formattable i fmts = fromString ∘ formatInt (baseFlag fmts) $ i
-instance Formattable Double where
-	formattable d fmts = fromString ∘ formatDouble (preciseFlag fmts) $ d
-instance Formattable Float where
-	formattable f fmts = fromString ∘ formatDouble (preciseFlag fmts) $ f
-instance Formattable Bool
-
-instance Formattable Text where
-	formattable s _ = fromString ∘ unpack $ s
-
-instance Formattable T.Text where
-	formattable s _ = fromString ∘ T.unpack $ s
-
-instance Formattable Formatter where
-	formattable s _ = fromString ∘ show $ s
-
-class Hole a where
-	hole ∷ a → [FormatArg]
-
-instance Hole Formatted where
-	hole v = [FormatPos $ const v]
-
-instance {-# OVERLAPPING #-} Hole FormatArg where
-	hole = return
-
-instance {-# OVERLAPPING #-} Hole [FormatArg] where
-	hole = id
-
-instance {-# OVERLAPPING #-} Hole [[FormatArg]] where
-	hole = concat
-
-instance {-# OVERLAPPABLE #-} Formattable a ⇒ Hole a where
-	hole v = [FormatPos $ formatted v]
-
-fmt ∷ Formattable a ⇒ a → FormatArg
-fmt v = FormatPos $ formatted v
-
-class FormatResult r where
-	formatResult ∷ Format → r
-
-instance FormatResult Format where
-	formatResult = id
-
-instance {-# OVERLAPPING #-} FormatResult String where
-	formatResult = mconcat ∘ map formattedValue ∘ formattedParts ∘ build
-
-instance {-# OVERLAPPABLE #-} IsString s ⇒ FormatResult s where
-	formatResult = fromString ∘ formatResult
-
-instance {-# OVERLAPPABLE #-} FormatResult Formatted where
-	formatResult = build
-
-format ∷ FormatResult r ⇒ String → r
-format = formatResult ∘ fromString
-
-formats ∷ FormatResult r ⇒ String → [FormatArg] → r
-formats f = formatResult ∘ Format f
-
-infixl 7 ~~
-
-(~~) ∷ (Hole a, FormatResult r) ⇒ Format → a → r
-fstr ~~ arg = formatResult $ fstr { formatArgs = formatArgs fstr ++ hole arg }
-
-infixr 8 ~%
-
-(~%) ∷ Formattable a ⇒ String → a → FormatArg
-name ~% value = FormatNamed name (formatted value)
-
--- * Util
-
-formatInt ∷ (Show a, Integral a) ⇒ a → a → String
-formatInt base v = showIntAtBase base intToDigit v ""
-
-formatDouble ∷ RealFloat a ⇒ Maybe Int → a → String
-formatDouble p v = showGFloat p v ""
+{-# LANGUAGE FlexibleInstances, UndecidableInstances, DefaultSignatures #-}++-- | Format string with named args+--+-- >-- Named args+-- >"My name is {name}, I am {age} years old" ~~ ("name" ~% "Joe") ~~ ("age" ~% 24) ≡ "My name is Joe, I am 24 years old"+-- >-- Arg can have default value+-- >"{var:x} = {val:10}" ~~ ("var" ~% y) ≡ "y = 10"+-- >-- Numeric position can be used+-- >"{0} {1} {0}" ~~ "foo" ~~ "bar" ≡ "foo bar foo"+-- >-- Positions can be omitted+-- >"{} {}" ~~ "foo" ~~ 10 ≡ "foo 10"+-- >-- Double braces to escape them+-- >"{} and {{}}" ~~ 10 ≡ "10 and {}"+module Text.Format (+	FormattedPart(..), Formatted(..), withFlags,+	FormatArg(..), Format(..), Formatter(..),+	prebuild, build, getNamedArguments,+	Formattable(..), Hole(..), fmt, FormatResult(..),+	format, formats, (~~), (~%),++	module Text.Format.Flags+	) where++import Prelude.Unicode++import Control.Applicative+import Data.Char (intToDigit)+import Data.List (find, intercalate, nub)+import Data.Maybe (fromMaybe, listToMaybe)+import Data.Semigroup (Semigroup(..))+import qualified Data.Text as T+import Data.Text.Lazy (Text, unpack)+import Data.String+import Numeric+import Text.Read (readMaybe)+import Text.ParserCombinators.ReadP++import Text.Format.Flags++data FormattedPart = FormattedPart {+	formattedFlags ∷ FormatFlags,+	formattedValue ∷ String }+		deriving (Eq, Ord, Show)++instance IsString FormattedPart where+	fromString = FormattedPart [] ∘ fromString++newtype Formatted = Formatted { formattedParts ∷ [FormattedPart] } deriving (Eq, Ord, Show)++instance IsString Formatted where+	fromString = Formatted ∘ return ∘ fromString++instance Semigroup Formatted where+	Formatted l <> Formatted r = Formatted $ l ++ r++instance Monoid Formatted where+	mempty = Formatted []+	Formatted l `mappend` Formatted r = Formatted $ l ++ r++withFlags ∷ String → [String] → Formatted+withFlags v fs = Formatted [FormattedPart fs v]++data FormatArg = FormatNamed String ([String] → Formatted) | FormatPos ([String] → Formatted)++data Format = Format {+	formatString ∷ String,+	formatArgs ∷ [FormatArg] }++instance Show Format where+	show = mconcat ∘ map formattedValue ∘ formattedParts ∘ prebuild++instance IsString Format where+	fromString str = Format str []++data Formatter = Formatter {+	formatter ∷ Either String Int,+	formatterDefault ∷ Maybe String,+	formatterFlags ∷ [String] }++instance Show Formatter where+	show (Formatter f def cfgs) = "{" ++ concat parts ++ "}" where+		parts = [either id show f, fromMaybe "" (fmap ('=':) def), if null cfgs then "" else (':' : intercalate "," cfgs)]++instance Read Formatter where+	readsPrec _ = readP_to_S $ between (char '{') (char '}') $ do+		n ← munch (∉ "=:}")+		v ← option Nothing $ do+			_ ← char '='+			v' ← munch1 (∉ ":}")+			return $ Just v'+		cs ← option [] $ do+			_ ← char ':'+			flip sepBy (char ',') (munch1 (∉ ",}"))+		return $ Formatter (maybe (Left n) Right $ readMaybe n) v cs++prebuild ∷ Format → Formatted+prebuild = buildFormat True++build ∷ Format → Formatted+build = buildFormat False++buildFormat ∷ Bool → Format → Formatted+buildFormat pre fstr = build' 0 fstr where+	build' ∷ Int → Format → Formatted+	build' _ (Format "" _) = mempty+	build' i (Format ('{':'{':fstr') args) = fromString "{" `mappend` build' i (Format fstr' args)+	build' i (Format ('}':'}':fstr') args) = fromString "}" `mappend` build' i (Format fstr' args)+	build' i (Format ('{':'}':fstr') args) = formatArg' (Formatter (Right i) Nothing []) args `mappend` build' (succ i) (Format fstr' args)+	build' i (Format ('{':fstr') args) = case reads ('{':fstr') of+		[] → error $ "Can't parse formatter at " ++ fstr'+		(f, fstr''):_ → formatArg' f args `mappend` build' i (Format fstr'' args)+	build' i (Format fstr' args) = fromString s `mappend` build' i (Format fstr'' args) where+		(s, fstr'') = break (∈ "{}") fstr'+	formatArg' ∷ Formatter → [FormatArg] → Formatted+	formatArg' f@(Formatter (Left name) defVal fmtCfgs) args+		| pre = fromMaybe (formatted f fmtCfgs) lookArg+		| otherwise = fromMaybe (error $ "Argument " ++ name ++ " not set") (lookArg <|> fmap (flip formatted fmtCfgs) defVal)+		where+			lookArg = do+				FormatNamed _ fval ← find byName args+				return $ fval fmtCfgs+			byName (FormatNamed n _) = n ≡ name+			byName _ = False+	formatArg' f@(Formatter (Right i) defVal fmtCfgs) args+		| pre = fromMaybe (formatted f fmtCfgs) lookIdx+		| otherwise = fromMaybe (error $ "Argument at index " ++ show i ++ " not set") (lookIdx <|> fmap (flip formatted fmtCfgs) defVal)+		where+			lookIdx = do+				FormatPos fval ← listToMaybe $ drop i $ filter isPos args+				return $ fval fmtCfgs+			isPos (FormatPos _) = True+			isPos _ = False++getNamedArguments ∷ Format → [String]+getNamedArguments = nub ∘ getNamedArguments'+	where+		getNamedArguments' ∷ Format → [String]+		getNamedArguments' (Format "" _) = mempty+		getNamedArguments' (Format ('{':'{':fstr') args) = getNamedArguments' (Format fstr' args)+		getNamedArguments' (Format ('}':'}':fstr') args) = getNamedArguments' (Format fstr' args)+		getNamedArguments' (Format ('{':'}':fstr') args) = getNamedArguments' (Format fstr' args)+		getNamedArguments' (Format fstr@('{':fstr') args) = case reads fstr of+			[] → error $ "Can't parse formatter at " ++ fstr'+			(f, fstr''):_ → getNamedArgument f `mappend` getNamedArguments' (Format fstr'' args)+			where+		getNamedArguments' (Format fstr' args) = getNamedArguments' (Format fstr'' args) where+			(_, fstr'') = break (∈ "{}") fstr'+		getNamedArgument ∷ Formatter → [String]+		getNamedArgument (Formatter (Left name) _ _) = [name]+		getNamedArgument _ = mempty++-- | Formattable class, by default using @show@+class Formattable a where+	formattable ∷ a → FormatFlags → Formatted+	default formattable ∷ Show a ⇒ a → FormatFlags → Formatted+	formattable x _ = fromString ∘ show $ x++formatted ∷ Formattable a ⇒ a → FormatFlags → Formatted+formatted v fmts = Formatted ∘ map addFmts ∘ formattedParts ∘ formattable v $ fmts where+	addFmts (FormattedPart flags' v') = FormattedPart (nub $ fmts ++ flags') v'++instance Formattable String where+	formattable s _ = fromString s++instance Formattable Char where+	formattable ch _ = fromString [ch]++instance Formattable Int where+	formattable i fmts = fromString ∘ formatInt (baseFlag fmts) $ i+instance Formattable Integer where+	formattable i fmts = fromString ∘ formatInt (baseFlag fmts) $ i+instance Formattable Double where+	formattable d fmts = fromString ∘ formatDouble (preciseFlag fmts) $ d+instance Formattable Float where+	formattable f fmts = fromString ∘ formatDouble (preciseFlag fmts) $ f+instance Formattable Bool++instance Formattable Text where+	formattable s _ = fromString ∘ unpack $ s++instance Formattable T.Text where+	formattable s _ = fromString ∘ T.unpack $ s++instance Formattable Formatter where+	formattable s _ = fromString ∘ show $ s++class Hole a where+	hole ∷ a → [FormatArg]++instance Hole Formatted where+	hole v = [FormatPos $ const v]++instance {-# OVERLAPPING #-} Hole FormatArg where+	hole = return++instance {-# OVERLAPPING #-} Hole [FormatArg] where+	hole = id++instance {-# OVERLAPPING #-} Hole [[FormatArg]] where+	hole = concat++instance {-# OVERLAPPABLE #-} Formattable a ⇒ Hole a where+	hole v = [FormatPos $ formatted v]++fmt ∷ Formattable a ⇒ a → FormatArg+fmt v = FormatPos $ formatted v++class FormatResult r where+	formatResult ∷ Format → r++instance FormatResult Format where+	formatResult = id++instance {-# OVERLAPPING #-} FormatResult String where+	formatResult = mconcat ∘ map formattedValue ∘ formattedParts ∘ build++instance {-# OVERLAPPABLE #-} IsString s ⇒ FormatResult s where+	formatResult = fromString ∘ formatResult++instance {-# OVERLAPPABLE #-} FormatResult Formatted where+	formatResult = build++format ∷ FormatResult r ⇒ String → r+format = formatResult ∘ fromString++formats ∷ FormatResult r ⇒ String → [FormatArg] → r+formats f = formatResult ∘ Format f++infixl 7 ~~++(~~) ∷ (Hole a, FormatResult r) ⇒ Format → a → r+fstr ~~ arg = formatResult $ fstr { formatArgs = formatArgs fstr ++ hole arg }++infixr 8 ~%++(~%) ∷ Formattable a ⇒ String → a → FormatArg+name ~% value = FormatNamed name (formatted value)++-- * Util++formatInt ∷ (Show a, Integral a) ⇒ a → a → String+formatInt base v = showIntAtBase base intToDigit v ""++formatDouble ∷ RealFloat a ⇒ Maybe Int → a → String+formatDouble p v = showGFloat p v ""
tests/Test.hs view
@@ -1,51 +1,51 @@-{-# LANGUAGE OverloadedStrings #-}
-
-module Main (
-	main
-	) where
-
-import Prelude.Unicode
-
-import Text.Format
-
-import Test.Hspec
-
-main ∷ IO ()
-main = hspec $ do
-	describe "positional arguments" $ do
-		it "should format unnamed arguments"
-			(format "{} + {} = {}" ~~ (10 ∷ Int) ~~ (12 ∷ Int) ~~ (22 ∷ Int) ≡ str "10 + 12 = 22")
-		it "should format positional arguments"
-			(format "{0} + {0} = {1}" ~~ (10 ∷ Int) ~~ (20 ∷ Int) ≡ str "10 + 10 = 20")
-	describe "named arguments" $
-		it "should format named arguments"
-			(format "{x} + {y} = {z}" ~~ "x" ~% (1 ∷ Int) ~~ "y" ~% (2 ∷ Int) ~~ "z" ~% (3 ∷ Int) ≡ str "1 + 2 = 3")
-	describe "default values" $ do
-		it "should accept default values for positional arguments"
-			(format "{0=foo} is {1=bar}" ~~ str "blah" ≡ str "blah is bar")
-		it "should accept default values for named arguments"
-			(format "{x=12} + {y=13}" ~~ "y" ~% (10 ∷ Int) ≡ str "12 + 10")
-	describe "format options" $ do
-		it "should accept format options"
-			(format "x is {0=foo:octal}" ~~ (10 ∷ Int) ≡ str "x is 12")
-	describe "colorized output" $ do
-		it "should accept colors"
-			(format "x is {0:red}" ~~ (10 ∷ Int) ≡ Formatted [FormattedPart [] "x is ", FormattedPart ["red"] "10"])
-	describe "lists" $
-		it "should accept list of values"
-			(format "{0} + {x:10} = {1}" ~~ [fmt (3 ∷ Int), "x" ~% (5 ∷ Int), fmt (8 ∷ Int)] ≡ str "3 + 5 = 8")
-	describe "escape" $
-		it "should escape curly braces"
-			(format "{} is not {{}}" ~~ str "{}" ≡ str "{} is not {}")
-	describe "mix" $
-		it "should process mixed arguments"
-			(format "{1=foo} and {} are {what=args}" ~~ str "what" ~% str "quux" ~~ (10 ∷ Int) ~~ (20 ∷ Int) ≡ str "20 and 10 are quux")
-	describe "prebuild" $
-		it "should show partially formatted" $
-			show (format "{0} ≡ {1}" ~~ str "foo" ∷ Format) ≡ str "foo ≡ {1}"
-	describe "list of named arguments" $
-		it "should list the named arguments" $
-			getNamedArguments "Positional arguments are ignored: {0} {} {2}. I want just the following, without repetition: {foo}, {bar} and {foo}." ≡ ["foo", "bar"]
-
-str ∷ String → String
-str = id
+{-# LANGUAGE OverloadedStrings #-}++module Main (+	main+	) where++import Prelude.Unicode++import Text.Format++import Test.Hspec++main ∷ IO ()+main = hspec $ do+	describe "positional arguments" $ do+		it "should format unnamed arguments"+			(format "{} + {} = {}" ~~ (10 ∷ Int) ~~ (12 ∷ Int) ~~ (22 ∷ Int) ≡ str "10 + 12 = 22")+		it "should format positional arguments"+			(format "{0} + {0} = {1}" ~~ (10 ∷ Int) ~~ (20 ∷ Int) ≡ str "10 + 10 = 20")+	describe "named arguments" $+		it "should format named arguments"+			(format "{x} + {y} = {z}" ~~ "x" ~% (1 ∷ Int) ~~ "y" ~% (2 ∷ Int) ~~ "z" ~% (3 ∷ Int) ≡ str "1 + 2 = 3")+	describe "default values" $ do+		it "should accept default values for positional arguments"+			(format "{0=foo} is {1=bar}" ~~ str "blah" ≡ str "blah is bar")+		it "should accept default values for named arguments"+			(format "{x=12} + {y=13}" ~~ "y" ~% (10 ∷ Int) ≡ str "12 + 10")+	describe "format options" $ do+		it "should accept format options"+			(format "x is {0=foo:octal}" ~~ (10 ∷ Int) ≡ str "x is 12")+	describe "colorized output" $ do+		it "should accept colors"+			(format "x is {0:red}" ~~ (10 ∷ Int) ≡ Formatted [FormattedPart [] "x is ", FormattedPart ["red"] "10"])+	describe "lists" $+		it "should accept list of values"+			(format "{0} + {x:10} = {1}" ~~ [fmt (3 ∷ Int), "x" ~% (5 ∷ Int), fmt (8 ∷ Int)] ≡ str "3 + 5 = 8")+	describe "escape" $+		it "should escape curly braces"+			(format "{} is not {{}}" ~~ str "{}" ≡ str "{} is not {}")+	describe "mix" $+		it "should process mixed arguments"+			(format "{1=foo} and {} are {what=args}" ~~ str "what" ~% str "quux" ~~ (10 ∷ Int) ~~ (20 ∷ Int) ≡ str "20 and 10 are quux")+	describe "prebuild" $+		it "should show partially formatted" $+			show (format "{0} ≡ {1}" ~~ str "foo" ∷ Format) ≡ str "foo ≡ {1}"+	describe "list of named arguments" $+		it "should list the named arguments" $+			getNamedArguments "Positional arguments are ignored: {0} {} {2}. I want just the following, without repetition: {foo}, {bar} and {foo}." ≡ ["foo", "bar"]++str ∷ String → String+str = id