packages feed

enum-text (empty) → 0.1.0.0

raw patch · 6 files changed

+279/−0 lines, 6 filesdep +arraydep +basedep +bytestringsetup-changed

Dependencies added: array, base, bytestring, fmt, hashable, possibly, text, unordered-containers

Files

+ ChangeLog.md view
@@ -0,0 +1,3 @@+# 0.1.0.0++  * first release
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Chris Dornan (c) 2019++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 Chris Dornan 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,32 @@+# enum-text++A simple toolkit for rendering enumerated types into `Text` `Builder` (used by+the [`fmt`](http://hackage.haskell.org/package/fmt) package) and parsing them+back again into Text with the provided `TextParsable` type class.++To get the `Buildable` and `TextParsable` instances for an enumerated data type+use the following pattern:++```+import Fmt+import Text.Enum.Text++data Foo = FOO_bar | FOO_bar_baz+  deriving (Bounded,Enum,Eq,Ord,Show)++instance EnumText     Foo+instance Buildable    Foo where build     = buildEnumText+instance TextParsable Foo where parseText = parseEnumText+```++This will use the default configuration for generating the text of each+enumeration from the derived `show` text, namely:++  * removing the prefix upto and including the first underscore (`_`);+  * converting each subsequent underscore (`_`) into a dash (`-`).++See the Haddocks for details on how to override this default configuration for+any given enumeration type.++Functions for rendering text, generating and parsing UTF-8 encoded ByteStrings+(suitable for cassava) and `Hashable` functions are also provided `EnumText`.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ enum-text.cabal view
@@ -0,0 +1,47 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.1.+--+-- see: https://github.com/sol/hpack+--+-- hash: de41441f44fa188062adf3893567b62b7ee598e3ad3cac9d4a37c598b02684da++name:           enum-text+version:        0.1.0.0+synopsis:       A text rendering and parsing toolkit for enumerated types+description:    A text rendering and parsing toolkit for enumerated types. Please see the README on GitHub at <https://github.com/cdornan/enum-text#readme>+category:       Text+homepage:       https://github.com/cdornan/enum-text#readme+bug-reports:    https://github.com/cdornan/enum-text/issues+author:         Chris Dornan+maintainer:     chris@chrisdornan.com+copyright:      2019 Chris Dornan+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    ChangeLog.md++source-repository head+  type: git+  location: https://github.com/cdornan/enum-text++library+  exposed-modules:+      Text.Enum.Text+  other-modules:+      Paths_enum_text+  hs-source-dirs:+      src+  ghc-options: -Wall+  build-depends:+      array+    , base >=4.8.2 && <10+    , bytestring+    , fmt+    , hashable+    , possibly+    , text+    , unordered-containers+  default-language: Haskell2010
+ src/Text/Enum/Text.hs view
@@ -0,0 +1,165 @@+{-# LANGUAGE OverloadedStrings    #-}+{-# LANGUAGE RecordWildCards      #-}+{-# LANGUAGE ScopedTypeVariables  #-}++module Text.Enum.Text+  ( EnumText(..)+  , TextParsable(..)+  , EnumTextConfig(..)+  , defaultEnumTextConfig+  ) where++import           Data.Array+import qualified Data.ByteString.Char8          as B+import           Data.Coerce+import           Data.Hashable+import           Data.Possibly+import qualified Data.HashMap.Strict            as HM+import qualified Data.Text                      as T+import qualified Data.Text.Encoding             as TE+import           Fmt+++-- | a class for 'T.Text' parsers.+class TextParsable a where+  parseText :: T.Text -> Possibly a++{- | our toolkit for enumerated types which should be defined as follows:++@+import Fmt+import Text.Enum.Text++data Foo = FOO_bar | FOO_bar_baz+  deriving (Bounded,Enum,Eq,Ord,Show)++instance EnumText     Foo+instance Buildable    Foo where build     = buildEnumText+instance TextParsable Foo where parseText = parseEnumText+@++-}+class ( Buildable     e+      , Bounded       e+      , Enum          e+      , Eq            e+      , Ord           e+      , Show          e+      , TextParsable  e+      ) => EnumText e where++  -- | Configures the textual representation of @e@ generated by renderEnumText.+  configEnumText :: e -> EnumTextConfig+  configEnumText _ = defaultEnumTextConfig++  -- | Generate the standard textual representation according to+  -- 'configEnumText' by default.+  renderEnumText :: e -> T.Text+  renderEnumText e = enumTextArray ! I e++  -- | Sames as 'renderEnumText', but generating a 'Builder'.+  buildEnumText :: e -> Builder+  buildEnumText = build . renderEnumText++  -- | Parses an @e@ according to the 'renderEnumText' render.+  parseEnumText :: T.Text -> Possibly e+  parseEnumText txt = maybe (Left msg) Right $ HM.lookup txt hashmap_t+    where+      msg = "parseEnumText: enumeration not recognised: "++show txt++  -- | A cassava field encoder, using 'the renderEnumText' format.+  toFieldEnumText :: e -> B.ByteString+  toFieldEnumText e = enumByteStringArray ! I e++  -- | A cassava field parser using the 'renderEnumText' format.+  fromFieldEnumText_ :: Monad m => B.ByteString -> m e+  fromFieldEnumText_ bs = maybe (fail msg) return $ HM.lookup bs hashmap_b+    where+      msg = "fromFieldEnumText_: enumeration not recognised: "++show bs++  -- | For hashing @e@ with the 'renderEnumText' representation.+  hashWithSaltEnumText :: Int -> e -> Int+  hashWithSaltEnumText n = hashWithSalt n . toFieldEnumText+++-------------------------------------------------------------------------------+-- EnumTextConfig, defaultEnumTextConfig+-------------------------------------------------------------------------------++-- | configures the default implementation of 'renderEnumText'+data EnumTextConfig =+  EnumTextConfig+    { _etc_text_prep :: T.Text -> T.Text  -- ^ applied to the output of 'show'+                                          -- once converted to 'T.Text'; by+                                          -- default strips each data+                                          -- constructor up to and including+                                          -- the first '_'+    , _etc_char_prep :: Char -> Char      -- ^ applied to each character of+                                          -- the outpout of '_etc_text_prep'+    }++defaultEnumTextConfig :: EnumTextConfig+defaultEnumTextConfig =+  EnumTextConfig+    { _etc_text_prep = defaultTextPrep+    , _etc_char_prep = defaultCharPrep+    }++defaultTextPrep :: T.Text -> T.Text+defaultTextPrep txt = case T.uncons $ T.dropWhile (/='_') txt of+    Just (_,rst) | not $ T.null rst -> rst+    _ -> error $ "defaultTextPrep: bad data constructor: "++T.unpack txt++defaultCharPrep :: Char -> Char+defaultCharPrep c = case c of+    '_' -> '-'+    _   -> c+++-------------------------------------------------------------------------------+-- arrays+-------------------------------------------------------------------------------++newtype I a = I { _I :: a }+  deriving (Eq,Ord)++instance EnumText e => Ix (I e) where+  range   (l,h)   = coerce [_I l.._I h]+  index   (l,_) x = fromEnum (_I x) - fromEnum (_I l)+  inRange (l,h) x = _I l <= _I x && _I x <= _I h++-- | array of texts constructed with 'configEnumText'+enumTextArray :: forall e . EnumText e => Array (I e) T.Text+enumTextArray =+    listArray (I minBound,I maxBound)+      [ T.map _etc_char_prep $ _etc_text_prep $ T.pack $ show e+        | e <- [minBound..maxBound :: e]+        ]+  where+    EnumTextConfig{..} = configEnumText (minBound :: e)++-- | array of 'B.ByteString' generated from 'renderEnumText'+enumByteStringArray :: forall e . EnumText e => Array (I e) B.ByteString+enumByteStringArray = listArray (I minBound,I maxBound)+    [ TE.encodeUtf8 $ renderEnumText e+      | e <- [minBound..maxBound :: e]+      ]+++-------------------------------------------------------------------------------+-- hashmaps+-------------------------------------------------------------------------------++-- | 'T.Text' 'HM.HashMap' based on 'renderEnumText' representation+hashmap_t :: EnumText e => HM.HashMap T.Text e+hashmap_t = HM.fromList+    [ (renderEnumText c,c)+      | c <- [minBound..maxBound]+      ]++-- | 'B.ByteString' 'HM.HashMap' based on 'renderEnumText' representation+hashmap_b :: EnumText e => HM.HashMap B.ByteString e+hashmap_b = HM.fromList+    [ (TE.encodeUtf8 $ renderEnumText c,c)+      | c <- [minBound..maxBound]+      ]