comma-and (empty) → 0.1.0.0
raw patch · 8 files changed
+242/−0 lines, 8 filesdep +QuickCheckdep +basedep +comma-andsetup-changed
Dependencies added: QuickCheck, base, comma-and, data-default-class, hspec
Files
- CHANGELOG.md +7/−0
- LICENSE +30/−0
- README.md +27/−0
- Setup.hs +2/−0
- comma-and.cabal +53/−0
- src/Text/Comma.hs +108/−0
- test/Main.hs +3/−0
- test/Text/CommaSpec.hs +12/−0
+ CHANGELOG.md view
@@ -0,0 +1,7 @@+# `comma-and` changelog++Convert a list of items to text by adding commas and an "and" at the end.++## Version 0.1.0.0++The first working version of `comma-and`.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Willem Van Onsem (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Willem Van Onsem nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,27 @@+# comma-and+[](https://github.com/hapytex/comma-and/actions/workflows/build-ci.yml)+[](https://matrix.hackage.haskell.org/#/package/comma-and)+[](https://hackage.haskell.org/package/comma-and)++Joins text items together by separating these with commas, and "and" at the end.++## Usage++We can combine elements with:++```+ghci> comma ["red", "green", "blue"]+"red, green, and blue"+```++The package has tooling for the two different comma styles, and can work with any *string-like* type.++## `comma-and` is *safe* Haskell++The module is compiled with `Safe` and does not depend on unsafe modules.++## Contribute++You can contribute by making a pull request on the [*GitHub repository*](https://github.com/hapytex/comma-and).++You can contact the package maintainer by sending a mail to [`hapytexeu+gh@gmail.com`](mailto:hapytexeu+gh@gmail.com).
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ comma-and.cabal view
@@ -0,0 +1,53 @@+name: comma-and+version: 0.1.0.0+synopsis: Join text together with commas, and "and".+description: Convert a 'Text' object into a visually pleasant URL component.+homepage: https://github.com/hapytex/comma-and#readme+license: BSD3+license-file: LICENSE+author: Willem Van Onsem+maintainer: hapytexeu+gh@gmail.com+copyright: 2020 Willem Van Onsem+category: utils+build-type: Simple+extra-source-files:+ README.md+ , CHANGELOG.md+cabal-version: >=1.10++library+ hs-source-dirs: src+ exposed-modules:+ Text.Comma+ build-depends:+ base >= 4.7 && < 5+ , data-default-class >=0.1 && <0.2+ default-language: Haskell2010++test-suite gulsify+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs: test+ other-modules:+ Text.CommaSpec+ build-depends:+ base+ , comma-and+ , data-default-class >=0.1 && <0.2+ , hspec ==2.*+ , QuickCheck >=2.8+ build-tool-depends: hspec-discover:hspec-discover == 2.*+ default-language: Haskell2010+ default-extensions:+ BlockArguments+ , OverloadedStrings+ ghc-options:+ -Wall -Wcompat -Wcompat+ -Wincomplete-record-updates+ -Wincomplete-uni-patterns+ -Wredundant-constraints+++source-repository head+ type: git+ location: https://github.com/hapytex/comma-and
+ src/Text/Comma.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE Safe #-}++{-|+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 (+ comma_, and_, commaAnd_+ , CommaStyle(OxfordComma, NoComma)+ , lastJoin+ , commaAs, commaEmptyAs, comma, noComma, commaEmpty, noCommaEmpty+ , combineWith, combineWithEmpty+ ) 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_ = fromString ", "++-- | The /string-like/ value for an "and", so @" and "@.+and_+ :: IsString s+ => s -- ^ A /string-like/ type.+and_ = fromString " and "++-- | The /string-like/ value for a comma and an "and", so @", and "@.+commaAnd_+ :: IsString s+ => s -- ^ A /string-like/ type.+commaAnd_ = fromString ", 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/.+ 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 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 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 c0 c1 = _combine mempty c0 c1 . toList++_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++-- | 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+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+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 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 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+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 e = combineWithEmpty e comma_ . lastJoin
+ test/Main.hs view
@@ -0,0 +1,3 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}+-- cabal v2-test --test-show-details=direct+-- cabal v2-test --test-show-details=direct --test-options="--color --format=progress"
+ test/Text/CommaSpec.hs view
@@ -0,0 +1,12 @@+module Text.CommaSpec where++import Test.Hspec(Spec, describe, it, shouldBe)+import Text.Comma(comma)++spec :: Spec+spec = describe "comma" $ do+ it "comma" $ do+ comma [] `shouldBe` ""+ comma ["red"] `shouldBe` "red"+ comma ["red", "green"] `shouldBe` "red, and green"+ comma ["red", "green", "blue"] `shouldBe` "red, green, and blue"