packages feed

text-conversions 0.1.0 → 0.2.0

raw patch · 6 files changed

+63/−65 lines, 6 files

Files

CHANGELOG.md view
@@ -1,5 +1,11 @@ # Changelog +## 0.2.0 (May 25, 2016)++### Breaking Changes++- The `ConvertText` typeclass has been split into two simpler functions, `convertText` and `decodeConvertText`. This means the vision of a unified function for converting between *any* two textual datatypes is no longer implemented, but the original attempt had too many problems to really be worth the cost. Specifically, instances like `FromText (Maybe Foo)` would cause problems due to the overlapping instances, which have now been removed.+ ## 0.1.0 (May 24, 2016)  - Initial release
README.md view
@@ -21,3 +21,7 @@ > convertText (UTF8 ("\xc3\x28" :: ByteString)) :: Maybe Text Nothing ```++[For more details, see the documentation on Hackage.][hackage]++[hackage]: https://hackage.haskell.org/package/text-conversions
package.yaml view
@@ -1,5 +1,5 @@ name: text-conversions-version: '0.1.0'+version: '0.2.0' category: Data synopsis: Safe conversions between textual types description: Safe conversions between textual types@@ -18,11 +18,9 @@  ghc-options: -Wall default-extensions:-- FlexibleContexts - FlexibleInstances - MultiParamTypeClasses - OverloadedStrings-- ScopedTypeVariables  library:   source-dirs: src
src/Data/Text/Conversions.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE Safe #-} {-# LANGUAGE DeriveFunctor #-}  {-|@@ -23,24 +24,25 @@    Most of the time, you will not need to create your own instances or use the   underlying functions that make the conversion machinery tick. Instead, just-  use the 'convertText' method to automatically convert between two textual-  datatypes automatically, whatever they may be.+  use the 'convertText' method to convert between two textual datatypes or the+  'decodeConvertText' method to perform a conversion that can fail.    Examples:    >>> convertText ("hello" :: String) :: Text   "hello"-  >>> convertText (UTF8 ("hello" :: ByteString)) :: Maybe Text+  >>> decodeConvertText (UTF8 ("hello" :: ByteString)) :: Maybe Text   Just "hello"-  >>> convertText (UTF8 ("\xc3\x28" :: ByteString)) :: Maybe Text+  >>> decodeConvertText (UTF8 ("\xc3\x28" :: ByteString)) :: Maybe Text   Nothing -} module Data.Text.Conversions-  ( ConvertText(..)-  , DecodeText(..)+  ( DecodeText(..)   , FromText(..)   , ToText(..)   , UTF8(..)+  , convertText+  , decodeConvertText   ) where  import Control.Error.Util (hush)@@ -63,9 +65,8 @@ {-|   A simple typeclass that handles converting arbitrary datatypes to   'Data.Text.Text' when the operation cannot fail. If you have a type that-  satisfies that requirement, implement this typeclass, /not/ 'ConvertText'.-  However, you probably do not want to call 'toText' directly; call-  'convertText', instead.+  satisfies that requirement, implement this typeclass, but if the operation can+  fail, use 'DecodeText' instead. -} class ToText a where   toText :: a -> T.Text@@ -81,50 +82,36 @@  {-|   A simple typeclass that handles converting arbitrary datatypes to-  'Data.Text.Text' when the operation can fail (the functor in question is-  expected to be 'Data.Maybe.Maybe' or 'Data.Either.Either'). If you have a type-  that satisfies that requirement, implement this typeclass, /not/-  'ConvertText'. However, you probably do not want to call 'decodeText'-  directly; call 'convertText', instead.+  'Data.Text.Text' when the operation can fail. If you have a type that+  satisfies that requirement, implement this typeclass, but if the operation+  cannot fail, use 'ToText' instead. -} class Functor f => DecodeText f a where   decodeText :: a -> f T.Text  {-|-  A typeclass that provides a way to /safely/ convert between arbitrary textual-  datatypes, including conversions that can potentially fail.-  __Do not implement this typeclass directly__, implement 'ToText', 'FromText',-  or 'DecodeText', instead, which this typeclass defers to. Use the-  'convertText' function to actually perform conversions.--  At a basic level, 'convertText' can convert between textual types, like-  between 'String' and 'Data.Text.Text':+  A function that provides a way to /safely/ convert between arbitrary textual+  datatypes where the conversion to text cannot fail.    >>> convertText ("hello" :: String) :: Text   "hello"+-}+convertText :: (ToText a, FromText b) => a -> b+convertText = fromText . toText -  More interestingly, 'convertText' can also convert between binary data and-  textual data in the form of 'Data.ByteString.ByteString'. Since binary data-  can represent text in many different potential encodings, it is necessary to-  use a newtype that picks the particular encoding, like 'UTF8': +{-|+  A function that provides a way to /safely/ convert between arbitrary textual+  datatypes where the conversion to text can fail, such as decoding binary data+  to text. Since binary data can represent text in many different potential+  encodings, it is necessary to use a newtype that picks the particular+  encoding, like 'UTF8':+   >>> convertText (UTF8 ("hello" :: ByteString)) :: Maybe Text   Just "hello"--  Note that the result of converting a 'Data.ByteString.ByteString' is a 'Maybe'-  'Data.Text.Text' since the decoding can fail. -}-class ConvertText a b where-  convertText :: a -> b--instance (ToText a, FromText b) => ConvertText a b where-  convertText = fromText . toText--instance {-# OVERLAPPING #-} (DecodeText Maybe a, FromText b) => ConvertText a (Maybe b) where-  convertText = fmap fromText . decodeText--instance {-# OVERLAPPING #-} (DecodeText (Either e) a, FromText b) => ConvertText a (Either e b) where-  convertText = fmap fromText . decodeText+decodeConvertText :: (DecodeText f a, FromText b) => a -> f b+decodeConvertText = fmap fromText . decodeText  instance ToText   T.Text  where toText   = id instance FromText T.Text  where fromText = id
test/Data/Text/ConversionsSpec.hs view
@@ -1,22 +1,14 @@-module Data.Text.ConversionsSpec where+module Data.Text.ConversionsSpec (spec) where  import Test.Hspec import Data.Text.Conversions -import Data.String (IsString(..))- import qualified Data.Text as T import qualified Data.Text.Lazy as TL  import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL -data BoringString = BoringString-  deriving (Eq, Show)--instance IsString BoringString where-  fromString _ = BoringString- newtype Upper = Upper T.Text deriving (Eq, Show) newtype Lower = Lower T.Text deriving (Eq, Show) @@ -29,9 +21,15 @@ instance DecodeText Maybe FailableString where   decodeText _ = Just "failable" +data FailableRepresentation = FailableRepresentation+  deriving (Eq, Show)++instance FromText (Maybe FailableRepresentation) where+  fromText _ = Just FailableRepresentation+ spec :: Spec spec = do-  describe "ConvertText" $ do+  describe "convertText" $ do     it "can convert strings to and from text" $ do       convertText ("hello" :: String) `shouldBe` ("hello" :: T.Text)       convertText ("hello" :: T.Text) `shouldBe` ("hello" :: String)@@ -43,18 +41,23 @@     it "can convert between things with ToText/FromText conversions" $       convertText (Upper "HELLO") `shouldBe` Lower "hello" +    it "can convert between things with FromText instances that produce functors" $+      convertText ("hello" :: T.Text) `shouldBe` Just FailableRepresentation++    describe "UTF8" $+      it "properly encodes text as bytestrings" $ do+        convertText ("hello" :: T.Text) `shouldBe` UTF8 ("hello" :: B.ByteString)+        convertText ("hello" :: T.Text) `shouldBe` UTF8 ("hello" :: BL.ByteString)++  describe "decodeConvertText" $ do     it "can convert between things in functors with a DecodeText instance" $-      convertText FailableString `shouldBe` Just ("failable" :: TL.Text)+      decodeConvertText FailableString `shouldBe` Just ("failable" :: TL.Text)      describe "UTF8" $ do       it "successfully decodes properly encoded bytestrings" $ do-        convertText (UTF8 ("hello" :: B.ByteString)) `shouldBe` Just ("hello" :: T.Text)-        convertText (UTF8 ("hello" :: BL.ByteString)) `shouldBe` Just ("hello" :: T.Text)+        decodeConvertText (UTF8 ("hello" :: B.ByteString)) `shouldBe` Just ("hello" :: T.Text)+        decodeConvertText (UTF8 ("hello" :: BL.ByteString)) `shouldBe` Just ("hello" :: T.Text)        it "fails to decode improperly encoded bytestrings" $ do-        convertText (UTF8 ("invalid \xc3\x28" :: B.ByteString)) `shouldBe` (Nothing :: Maybe T.Text)-        convertText (UTF8 ("invalid \xc3\x28" :: BL.ByteString)) `shouldBe` (Nothing :: Maybe T.Text)--      it "properly encodes text as bytestrings" $ do-        convertText ("hello" :: T.Text) `shouldBe` UTF8 ("hello" :: B.ByteString)-        convertText ("hello" :: T.Text) `shouldBe` UTF8 ("hello" :: BL.ByteString)+        decodeConvertText (UTF8 ("invalid \xc3\x28" :: B.ByteString)) `shouldBe` (Nothing :: Maybe T.Text)+        decodeConvertText (UTF8 ("invalid \xc3\x28" :: BL.ByteString)) `shouldBe` (Nothing :: Maybe T.Text)
text-conversions.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack  name:           text-conversions-version:        0.1.0+version:        0.2.0 synopsis:       Safe conversions between textual types description:    Safe conversions between textual types category:       Data@@ -30,7 +30,7 @@ library   hs-source-dirs:       src-  default-extensions: FlexibleContexts FlexibleInstances MultiParamTypeClasses OverloadedStrings ScopedTypeVariables+  default-extensions: FlexibleInstances MultiParamTypeClasses OverloadedStrings   ghc-options: -Wall   build-depends:       base >= 4.7 && < 5@@ -46,7 +46,7 @@   main-is: Main.hs   hs-source-dirs:       test-  default-extensions: FlexibleContexts FlexibleInstances MultiParamTypeClasses OverloadedStrings ScopedTypeVariables+  default-extensions: FlexibleInstances MultiParamTypeClasses OverloadedStrings   ghc-options: -Wall -rtsopts -threaded -with-rtsopts=-N   build-depends:       base