comma-and 0.1.0.1 → 0.2.0.0
raw patch · 5 files changed
+213/−63 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Text.Comma: CommaValues :: s -> s -> CommaValues s
+ Text.Comma: [commaAndText] :: CommaValues s -> s
+ Text.Comma: [commaText] :: CommaValues s -> s
+ Text.Comma: commaEmptyWith :: (IsString s, Semigroup s, Foldable f) => s -> CommaValues s -> f s -> s
+ Text.Comma: commaWith :: (IsString s, Monoid s, Foldable f) => CommaValues s -> f s -> s
+ Text.Comma: data CommaValues s
+ Text.Comma: instance Data.String.IsString s => Data.Default.Class.Default (Text.Comma.CommaValues s)
+ Text.Comma: instance GHC.Classes.Eq s => GHC.Classes.Eq (Text.Comma.CommaValues s)
+ Text.Comma: instance GHC.Classes.Ord s => GHC.Classes.Ord (Text.Comma.CommaValues s)
+ Text.Comma: instance GHC.Read.Read s => GHC.Read.Read (Text.Comma.CommaValues s)
+ Text.Comma: instance GHC.Show.Show s => GHC.Show.Show (Text.Comma.CommaValues s)
+ Text.Comma: toCommaValues :: IsString s => CommaStyle -> CommaValues s
Files
- CHANGELOG.md +4/−0
- README.md +1/−1
- comma-and.cabal +2/−2
- src/Text/Comma.hs +183/−59
- test/Text/CommaSpec.hs +23/−1
CHANGELOG.md view
@@ -2,6 +2,10 @@ Convert a list of items to text by adding commas and an "and" at the end. +## Version 0.2.0.0++Introducing `CommaValues` to allow working with different languages.+ ## Version 0.1.0.0 The first working version of `comma-and`.
README.md view
@@ -18,7 +18,7 @@ ## *String-like* types? -The package can work with types that are an instance of `IsString` and `Monoid`. So this means it works with `String`, `Text`, `ByteString`, `MarkupM`, and probably a lot more types that concatenate with the `Monoid` instance, and are an instance of `IsString`.+The package can work with types that are an instance of `IsString` and `Monoid`. So this means it works with `String`, [`Text`](https://hackage.haskell.org/package/text/docs/Data-Text-Internal-Lazy.html#t:Text), [`ByteString`](https://hackage.haskell.org/package/bytestring/docs/Data-ByteString.html#t:ByteString), [`MarkupM`](https://hackage.haskell.org/package/blaze-markup/docs/Text-Blaze-Internal.html#t:MarkupM), [`LaTeX`](https://hackage.haskell.org/package/HaTeX-3.22.4.2/docs/Text-LaTeX-Base-Syntax.html#t:LaTeX), and probably a lot more types that concatenate with the `Monoid` instance, and are an instance of `IsString`. ## `comma-and` is *safe* Haskell
comma-and.cabal view
@@ -1,7 +1,7 @@ name: comma-and-version: 0.1.0.1+version: 0.2.0.0 synopsis: Join text together with commas, and "and".-description: Convert a 'Text' object into a visually pleasant URL component.+description: Join text together with commas, and "and". homepage: https://github.com/hapytex/comma-and#readme license: BSD3 license-file: LICENSE
src/Text/Comma.hs view
@@ -1,108 +1,232 @@ {-# LANGUAGE Safe #-} -{-|-Module : Text.Comma-Description : Join text together with a comma, and "and".-Maintainer : hapytexeu+gh@gmail.com-Stability : experimental-Portability : POSIX+-- |+-- Module : Text.Comma+-- Description : Join text together with a comma, and "and".+-- Maintainer : hapytexeu+gh@gmail.com+-- Stability : experimental+-- Portability : POSIX+--+-- This module provides functions to join elements of /string-like/ types by adding a comma between the elements, and an "and" (optionally with a comma) between the one-but-last and the last element.+module Text.Comma+ ( -- * Data structures for text joining+ CommaStyle (OxfordComma, NoComma),+ CommaValues (CommaValues, commaText, commaAndText),+ toCommaValues,+ lastJoin, -This module provides functions to join elements of /string-like/ types by adding a comma between the elements, and an "and" (optionally with a comma) between the one-but-last and the last element.--}+ -- * Join with commas and "and"+ commaAs,+ commaEmptyAs,+ commaWith,+ commaEmptyWith,+ comma,+ noComma,+ commaEmpty,+ noCommaEmpty, -module Text.Comma (- comma_, and_, commaAnd_- , CommaStyle(OxfordComma, NoComma)- , lastJoin- , commaAs, commaEmptyAs, comma, noComma, commaEmpty, noCommaEmpty- , combineWith, combineWithEmpty- ) where+ -- * Basic joining of elements+ combineWith,+ combineWithEmpty, -import Data.Default.Class(Default(def))-import Data.Foldable(toList)-import Data.String(IsString(fromString))+ -- * /String-like/ constants+ comma_,+ and_,+ commaAnd_,+ )+where +import Data.Default.Class (Default (def))+import Data.Foldable (toList)+import Data.String (IsString (fromString))+ -- | The /string-like/ value for a comma, so @", "@.-comma_- :: IsString s- => s -- ^ A /string-like/ type.+comma_ ::+ (IsString s) =>+ -- | A /string-like/ type.+ s comma_ = fromString ", " -- | The /string-like/ value for an "and", so @" and "@.-and_- :: IsString s- => s -- ^ A /string-like/ type.+and_ ::+ (IsString s) =>+ -- | A /string-like/ type.+ s and_ = fromString " and " -- | The /string-like/ value for a comma and an "and", so @", and "@.-commaAnd_- :: IsString s- => s -- ^ A /string-like/ type.+commaAnd_ ::+ (IsString s) =>+ -- | A /string-like/ type.+ s commaAnd_ = fromString ", and " +-- | A small data type that contains the /string-like/ values for the 'commaText, and the 'commaAndText': the join between the one but last, and last element. This can be used+-- to define a way to comma-and in a different language.+data CommaValues s+ = -- | The (only) data constructor that takes values for the comma and the "comma and" to join.+ CommaValues+ { -- | The text used to join two elements together, if the second element is /not/ the last element in the series.+ commaText :: s,+ -- | The text used to join the one but last and the last element together.+ commaAndText :: s+ }+ deriving (Eq, Ord, Read, Show)++instance (IsString s) => Default (CommaValues s) where+ def = CommaValues comma_ commaAnd_++-- | Convert the given 'CommaStyle' to the corresponding 'CommaValue' item.+toCommaValues ::+ (IsString s) =>+ -- | The given 'CommaStyle' to convert into the corrsponding 'CommaValues' object.+ CommaStyle ->+ -- | A 'CommaValues' object that contains the separators for the items.+ CommaValues s+toCommaValues OxfordComma = CommaValues comma_ commaAnd_+toCommaValues NoComma = CommaValues comma_ and_+ -- | The two different ways to join the last two items together: with or without a comma. data CommaStyle- = OxfordComma -- ^ The /Oxford comma/ which uses a comma before the latest element, also known as /Harvard comma/ or /series comma/.- | NoComma -- ^ The comma style where there is no comma before the "and" of the last item, informally known as the /Heathen comma/.+ = -- | The /Oxford comma/ which uses a comma before the latest element, also known as /Harvard comma/ or /series comma/.+ OxfordComma+ | -- | The comma style where there is no comma before the "and" of the last item, informally known as the /Heathen comma/.+ NoComma deriving (Bounded, Enum, Eq, Ord, Read, Show) instance Default CommaStyle where def = OxfordComma -- | Specify the string that determines how to join the last but one and the last item based on the 'CommaStyle'.-lastJoin- :: IsString s- => CommaStyle -- ^ The given comma style.- -> s -- ^ A string that specifies how to join the last but one item and the last item based on the comma style.+lastJoin ::+ (IsString s) =>+ -- | The given comma style.+ CommaStyle ->+ -- | A string that specifies how to join the last but one item and the last item based on the comma style.+ s lastJoin OxfordComma = commaAnd_ lastJoin _ = and_ -- | Join the 'Foldable' of elements with a given item for a comma and for the last join with a custom value if the 'Foldable' is empty.-combineWithEmpty- :: (Semigroup s, Foldable f)- => s -- ^ The item used if the foldable item is empty.- -> s -- ^ The /comma/ item placed between each item and the next, except for the last join.- -> s -- ^ The item used to join the one but last item and the last item.- -> f s -- ^ The 'Foldable' of items that should be joined.- -> s -- ^ The item generated by joining the elements with the comma and last join item.+combineWithEmpty ::+ (Semigroup s, Foldable f) =>+ -- | The item used if the foldable item is empty.+ s ->+ -- | The /comma/ item placed between each item and the next, except for the last join.+ s ->+ -- | The item used to join the one but last item and the last item.+ s ->+ -- | The 'Foldable' of items that should be joined.+ f s ->+ -- | The item generated by joining the elements with the comma and last join item.+ s combineWithEmpty e c0 c1 = _combine e c0 c1 . toList -- | Join the 'Foldable' of elements with a given item for a comma and for the last join.-combineWith- :: (Monoid s, Foldable f)- => s -- ^ The /comma/ item placed between each item and the next, except for the last join.- -> s -- ^ The item used to join the one but last item and the last item.- -> f s -- ^ The 'Foldable' of items that should be joined.- -> s -- ^ The item generated by joining the elements with the comma and last join item.+combineWith ::+ (Monoid s, Foldable f) =>+ -- | The /comma/ item placed between each item and the next, except for the last join.+ s ->+ -- | The item used to join the one but last item and the last item.+ s ->+ -- | The 'Foldable' of items that should be joined.+ f s ->+ -- | The item generated by joining the elements with the comma and last join item.+ s combineWith c0 c1 = _combine mempty c0 c1 . toList -_combine :: Semigroup s => s -> s -> s -> [s] -> s+_combine :: (Semigroup s) => s -> s -> s -> [s] -> s _combine e _ _ [] = e _combine _ _ _ [s] = s-_combine _ c0 c1 (x:x2:xs) = go xs x x2- where go [] s1 s2 = s1 <> c1 <> s2- go (s3:ss) s1 s2 = s1 <> c0 <> go ss s2 s3+_combine _ c0 c1 (x : x2 : xs) = go xs x x2+ where+ go [] s1 s2 = s1 <> c1 <> s2+ go (s3 : ss) s1 s2 = s1 <> c0 <> go ss s2 s3 --- | Joins the sequence of items with the /Oxford comma/ style, uses the empty string if there are no items.-comma :: (IsString s, Monoid s, Foldable f) => f s -> s+-- | Joins the sequence of items with the /Oxford comma/ style, uses 'mempty' as empty string if there are no items.+comma ::+ (IsString s, Monoid s, Foldable f) =>+ -- | The 'Foldable' of string-like elements to join.+ f s ->+ -- | The result that has joined the elements with commas and just "and" as last separator.+ s comma = combineWith comma_ commaAnd_ --- | Joins the sequence of items with the /no comma/ style, uses the empty string if there are no items.-noComma :: (IsString s, Monoid s, Foldable f) => f s -> s+-- | Joins the sequence of items with the /no comma/ style, uses 'mempty' as empty string if there are no items.+noComma ::+ (IsString s, Monoid s, Foldable f) =>+ -- | The 'Foldable' of string-like elements to join.+ f s ->+ -- | The result that has joined the elements with commas, and ", and" (with comma) as last separator.+ s noComma = combineWith comma_ and_ -- | Join the sequence of items with the /Oxford comma/ style, uses a given "string" if there are no items.-commaEmpty :: (IsString s, Semigroup s, Foldable f) => s -> f s -> s+commaEmpty ::+ (IsString s, Semigroup s, Foldable f) =>+ -- | The item to return if the 'Foldable' is empty.+ s ->+ -- | The 'Foldable' of string-like elements to join.+ f s ->+ -- | The result that has joined the elements with commas and just "and" as last separator.+ s commaEmpty e = combineWithEmpty e comma_ commaAnd_ -- | Join the sequence of items with the /no comma/ style, uses a given "string" if there are no items.-noCommaEmpty :: (IsString s, Semigroup s, Foldable f) => s -> f s -> s+noCommaEmpty ::+ (IsString s, Semigroup s, Foldable f) =>+ -- | The item to return if the 'Foldable' is empty.+ s ->+ -- | The 'Foldable' of string-like elements to join.+ f s ->+ -- | The result that has joined the elements with commas, and ", and" (with comma) as last separator.+ s noCommaEmpty e = combineWithEmpty e comma_ and_ --- | Join the sequence of items with the given comma style, uses the empty string if there are no items.-commaAs :: (IsString s, Monoid s, Foldable f) => CommaStyle -> f s -> s+-- | Join the sequence of items with the given comma style, uses 'mempty' as empty string if there are no items.+commaAs ::+ (IsString s, Monoid s, Foldable f) =>+ -- | The given 'CommaStyle' to use.+ CommaStyle ->+ -- | The 'Foldable' of string-like elements to join.+ f s ->+ -- | The result that has joined the elements with commas as specified by the given 'CommaStyle'.+ s commaAs = combineWith comma_ . lastJoin -- | Join the sequence of items with the given comma style, uses a given "string" if there are no items.-commaEmptyAs :: (IsString s, Semigroup s, Foldable f) => s -> CommaStyle -> f s -> s+commaEmptyAs ::+ (IsString s, Semigroup s, Foldable f) =>+ -- | The item to return if the 'Foldable' is empty.+ s ->+ -- | The given 'CommaStyle' to use.+ CommaStyle ->+ -- | The 'Foldable' of string-like elements to join.+ f s ->+ -- | The result that has joined the elements with commas as specified by the given 'CommaStyle'.+ s commaEmptyAs e = combineWithEmpty e comma_ . lastJoin++-- | Join the sequence of items with the given 'CommaValues', uses 'mempty' as empty string if there are no items.+commaWith ::+ (IsString s, Monoid s, Foldable f) =>+ -- | A 'CommaValues' object that determines the normal separator and the last separator.+ CommaValues s ->+ -- | The 'Foldable' of string-like elements to join.+ f s ->+ -- | The result that has joined the elements with commas as specified by the given 'CommaValues'.+ s+commaWith ~(CommaValues c ca) = combineWith c ca++-- | Join the sequence of items with the given 'CommaValues', uses a given "string" if there are no items.+commaEmptyWith ::+ (IsString s, Semigroup s, Foldable f) =>+ -- | The item to return if the 'Foldable' is empty.+ s ->+ -- | A 'CommaValues' object that determines the normal separator and the last separator.+ CommaValues s ->+ -- | The 'Foldable' of string-like elements to join.+ f s ->+ -- | The result that has joined the elements with commas as specified by the given 'CommaValues'.+ s+commaEmptyWith e ~(CommaValues c ca) = combineWithEmpty e c ca
test/Text/CommaSpec.hs view
@@ -3,7 +3,7 @@ import Data.Default.Class(Default(def)) import Test.Hspec(Spec, describe, it, shouldBe)-import Text.Comma(CommaStyle(OxfordComma, NoComma), comma, commaAs, commaEmpty, commaEmptyAs, lastJoin, noComma, noCommaEmpty)+import Text.Comma(CommaStyle(OxfordComma, NoComma), CommaValues(commaText, commaAndText), comma, commaAs, commaEmpty, commaEmptyAs, commaEmptyWith, commaWith, lastJoin, noComma, noCommaEmpty, toCommaValues) spec :: Spec spec = describe "and" $ do@@ -45,6 +45,24 @@ commaEmptyAs "and" NoComma ["red"] `shouldBe` "red" commaEmptyAs "and" NoComma ["red", "green"] `shouldBe` "red and green" commaEmptyAs "and" NoComma ["red", "green", "blue"] `shouldBe` "red, green and blue"+ it "commaWith" $ do+ commaWith (toCommaValues OxfordComma) [] `shouldBe` ""+ commaWith (toCommaValues OxfordComma) ["red"] `shouldBe` "red"+ commaWith (toCommaValues OxfordComma) ["red", "green"] `shouldBe` "red, and green"+ commaWith (toCommaValues OxfordComma) ["red", "green", "blue"] `shouldBe` "red, green, and blue"+ commaWith (toCommaValues NoComma) [] `shouldBe` ""+ commaWith (toCommaValues NoComma) ["red"] `shouldBe` "red"+ commaWith (toCommaValues NoComma) ["red", "green"] `shouldBe` "red and green"+ commaWith (toCommaValues NoComma) ["red", "green", "blue"] `shouldBe` "red, green and blue"+ it "commaEmptyWith" $ do+ commaEmptyWith "and" (toCommaValues OxfordComma) [] `shouldBe` "and"+ commaEmptyWith "and" (toCommaValues OxfordComma) ["red"] `shouldBe` "red"+ commaEmptyWith "and" (toCommaValues OxfordComma) ["red", "green"] `shouldBe` "red, and green"+ commaEmptyWith "and" (toCommaValues OxfordComma) ["red", "green", "blue"] `shouldBe` "red, green, and blue"+ commaEmptyWith "and" (toCommaValues NoComma) [] `shouldBe` "and"+ commaEmptyWith "and" (toCommaValues NoComma) ["red"] `shouldBe` "red"+ commaEmptyWith "and" (toCommaValues NoComma) ["red", "green"] `shouldBe` "red and green"+ commaEmptyWith "and" (toCommaValues NoComma) ["red", "green", "blue"] `shouldBe` "red, green and blue" it "lastJoin" $ do lastJoin OxfordComma `shouldBe` ", and " lastJoin NoComma `shouldBe` " and "@@ -54,3 +72,7 @@ maxBound `shouldBe` NoComma succ OxfordComma `shouldBe` NoComma compare OxfordComma NoComma `shouldBe` LT+ it "CommaValues" $ do+ toCommaValues def `shouldBe` def+ commaText (toCommaValues def) `shouldBe` commaText def+ commaAndText (toCommaValues def) `shouldBe` commaAndText def