string-conv 0.1.2 → 0.2.0
raw patch · 6 files changed
+298/−147 lines, 6 filesdep +quickcheck-instancesdep +string-convdep +tastysetup-changed
Dependencies added: quickcheck-instances, string-conv, tasty, tasty-quickcheck
Files
- Data/String/Conv.hs +0/−118
- Setup.hs +1/−0
- changelog.md +4/−2
- src/Data/String/Conv.hs +138/−0
- string-conv.cabal +63/−27
- test/Main.hs +92/−0
− Data/String/Conv.hs
@@ -1,118 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}--module Data.String.Conv- ( StringConv (..)- , toS- , toSL- , convS- , convSL- , Leniency (..)- ) where---------------------------------------------------------------------------------import Data.ByteString.Char8 as B-import Data.ByteString.Lazy.Char8 as LB-import Data.Text as T-import Data.Text.Encoding as T-import Data.Text.Encoding.Error as T-import Data.Text.Lazy as LT-import Data.Text.Lazy.Encoding as LT------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Data type representing the two leniency modes defining how decoding--- failure is handled.-data Leniency = Lenient | Strict- deriving (Eq,Show,Read,Ord,Enum,Bounded)------------------------------------------------------------------------------------ | A type class to standardize string conversions. With this type class you--- only need to remember one function for converting between any two string--- variants. This package includes support for String, ByteString, and Text--- as well as the Lazy and Strict variants where necessary.------ This type class lets you control how conversion should behave when failure--- is possible. Strict mode will cause an exception to be thrown when--- decoding fails. Lenient mode will attempt to recover, inserting a--- replacement character for invalid bytes.------ StringConv's `toS` function is most useful when you have a fully defined--- string conversion with a fixed (non-polymorphic) input and output type. Of--- course you can still use it when you don't have a fixed type. In that case--- you might need to specify a type class constraint such as @StringConv--- s String@.-class StringConv a b where- strConv :: Leniency -> a -> b------------------------------------------------------------------------------------ | Universal string conversion function for strict decoding.-toS :: StringConv a b => a -> b-toS = strConv Strict------------------------------------------------------------------------------------ | Universal string conversion function for lenient decoding.-toSL :: StringConv a b => a -> b-toSL = strConv Lenient---instance StringConv String String where strConv _ = id-instance StringConv String B.ByteString where strConv l = T.encodeUtf8 . strConv l-instance StringConv String LB.ByteString where strConv l = LT.encodeUtf8 . strConv l-instance StringConv String T.Text where strConv _ = T.pack-instance StringConv String LT.Text where strConv _ = LT.pack--instance StringConv B.ByteString String where strConv l = T.unpack . strConv l-instance StringConv B.ByteString B.ByteString where strConv _ = id-instance StringConv B.ByteString LB.ByteString where strConv _ = LB.fromChunks . return-instance StringConv B.ByteString T.Text where strConv = decodeUtf8T-instance StringConv B.ByteString LT.Text where strConv l = strConv l . LB.fromChunks . return--instance StringConv LB.ByteString String where strConv l = LT.unpack . strConv l-instance StringConv LB.ByteString B.ByteString where strConv _ = B.concat . LB.toChunks-instance StringConv LB.ByteString LB.ByteString where strConv _ = id-instance StringConv LB.ByteString T.Text where strConv l = decodeUtf8T l . strConv l-instance StringConv LB.ByteString LT.Text where strConv = decodeUtf8LT--instance StringConv T.Text String where strConv _ = T.unpack-instance StringConv T.Text B.ByteString where strConv _ = T.encodeUtf8-instance StringConv T.Text LB.ByteString where strConv l = strConv l . T.encodeUtf8-instance StringConv T.Text LT.Text where strConv _ = LT.fromStrict-instance StringConv T.Text T.Text where strConv _ = id--instance StringConv LT.Text String where strConv _ = LT.unpack-instance StringConv LT.Text T.Text where strConv _ = LT.toStrict-instance StringConv LT.Text LT.Text where strConv _ = id-instance StringConv LT.Text LB.ByteString where strConv _ = LT.encodeUtf8-instance StringConv LT.Text B.ByteString where strConv l = strConv l . LT.encodeUtf8------------------------------------------------------------------------------------ | Convenience helper for dispatching based on leniency.-decodeUtf8T :: Leniency -> B.ByteString -> T.Text-decodeUtf8T Lenient = T.decodeUtf8With T.lenientDecode-decodeUtf8T Strict = T.decodeUtf8With T.strictDecode------------------------------------------------------------------------------------ | Convenience helper for dispatching based on leniency.-decodeUtf8LT :: Leniency -> LB.ByteString -> LT.Text-decodeUtf8LT Lenient = LT.decodeUtf8With T.lenientDecode-decodeUtf8LT Strict = LT.decodeUtf8With T.strictDecode------------------------------------------------------------------------------------ | A lens for 'toS' to make it slightly more convenient in some scenarios.-convS :: (StringConv a b, StringConv b a, Functor f) => (b -> f b) -> a -> f a-convS f a = fmap toS (f (toS a))------------------------------------------------------------------------------------ | A lens for 'toSL' to make it slightly more convenient in some scenarios.-convSL :: (StringConv a b, StringConv b a, Functor f) => (b -> f b) -> a -> f a-convSL f a = fmap toSL (f (toSL a))-
Setup.hs view
@@ -1,2 +1,3 @@ import Distribution.Simple+ main = defaultMain
changelog.md view
@@ -1,6 +1,8 @@-0.1.2+0.2.0 =====-* Fixed bug where String <-> ByteString conversion would trim characters to 8 bits. Now it goes through conversion to Text first.+* Don't set optimization flag for library+* Add property tests and fix to make String <-> ByteString conversion safer [PR 6](https://github.com/Soostone/string-conv/pull/6).+* Add lib-Werror flag for development 0.1.1 =====
+ src/Data/String/Conv.hs view
@@ -0,0 +1,138 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Data.String.Conv+ ( StringConv (..),+ toS,+ toSL,+ convS,+ convSL,+ Leniency (..),+ )+where++------------------------------------------------------------------------------+import Data.ByteString as B+import Data.ByteString.Lazy as LB+import Data.Text as T+import Data.Text.Encoding as T+import Data.Text.Encoding.Error as T+import Data.Text.Lazy as LT+import Data.Text.Lazy.Encoding as LT++------------------------------------------------------------------------------++------------------------------------------------------------------------------++-- | Data type representing the two leniency modes defining how decoding+-- failure is handled.+data Leniency = Lenient | Strict+ deriving (Eq, Show, Read, Ord, Enum, Bounded)++------------------------------------------------------------------------------++-- | A type class to standardize string conversions. With this type class you+-- only need to remember one function for converting between any two string+-- variants. This package includes support for String, ByteString, and Text+-- as well as the Lazy and Strict variants where necessary.+--+-- This type class lets you control how conversion should behave when failure+-- is possible. Strict mode will cause an exception to be thrown when+-- decoding fails. Lenient mode will attempt to recover, inserting a+-- replacement character for invalid bytes.+--+-- StringConv's `toS` function is most useful when you have a fully defined+-- string conversion with a fixed (non-polymorphic) input and output type. Of+-- course you can still use it when you don't have a fixed type. In that case+-- you might need to specify a type class constraint such as @StringConv+-- s String@.+class StringConv a b where+ strConv :: Leniency -> a -> b++------------------------------------------------------------------------------++-- | Universal string conversion function for strict decoding.+toS :: StringConv a b => a -> b+toS = strConv Strict++------------------------------------------------------------------------------++-- | Universal string conversion function for lenient decoding.+toSL :: StringConv a b => a -> b+toSL = strConv Lenient++instance StringConv String String where strConv _ = id++instance StringConv String B.ByteString where strConv _ = T.encodeUtf8 . T.pack++instance StringConv String LB.ByteString where strConv _ = LT.encodeUtf8 . LT.pack++instance StringConv String T.Text where strConv _ = T.pack++instance StringConv String LT.Text where strConv _ = LT.pack++instance StringConv B.ByteString String where strConv l = T.unpack . decodeUtf8T l++instance StringConv B.ByteString B.ByteString where strConv _ = id++instance StringConv B.ByteString LB.ByteString where strConv _ = LB.fromChunks . return++instance StringConv B.ByteString T.Text where strConv = decodeUtf8T++instance StringConv B.ByteString LT.Text where strConv l = strConv l . LB.fromChunks . return++instance StringConv LB.ByteString String where strConv l = LT.unpack . decodeUtf8LT l++instance StringConv LB.ByteString B.ByteString where strConv _ = B.concat . LB.toChunks++instance StringConv LB.ByteString LB.ByteString where strConv _ = id++instance StringConv LB.ByteString T.Text where strConv l = decodeUtf8T l . strConv l++instance StringConv LB.ByteString LT.Text where strConv = decodeUtf8LT++instance StringConv T.Text String where strConv _ = T.unpack++instance StringConv T.Text B.ByteString where strConv _ = T.encodeUtf8++instance StringConv T.Text LB.ByteString where strConv l = strConv l . T.encodeUtf8++instance StringConv T.Text LT.Text where strConv _ = LT.fromStrict++instance StringConv T.Text T.Text where strConv _ = id++instance StringConv LT.Text String where strConv _ = LT.unpack++instance StringConv LT.Text T.Text where strConv _ = LT.toStrict++instance StringConv LT.Text LT.Text where strConv _ = id++instance StringConv LT.Text LB.ByteString where strConv _ = LT.encodeUtf8++instance StringConv LT.Text B.ByteString where strConv l = strConv l . LT.encodeUtf8++------------------------------------------------------------------------------++-- | Convenience helper for dispatching based on leniency.+decodeUtf8T :: Leniency -> B.ByteString -> T.Text+decodeUtf8T Lenient = T.decodeUtf8With T.lenientDecode+decodeUtf8T Strict = T.decodeUtf8With T.strictDecode++------------------------------------------------------------------------------++-- | Convenience helper for dispatching based on leniency.+decodeUtf8LT :: Leniency -> LB.ByteString -> LT.Text+decodeUtf8LT Lenient = LT.decodeUtf8With T.lenientDecode+decodeUtf8LT Strict = LT.decodeUtf8With T.strictDecode++------------------------------------------------------------------------------++-- | A lens for 'toS' to make it slightly more convenient in some scenarios.+convS :: (StringConv a b, StringConv b a, Functor f) => (b -> f b) -> a -> f a+convS f a = fmap toS (f (toS a))++------------------------------------------------------------------------------++-- | A lens for 'toSL' to make it slightly more convenient in some scenarios.+convSL :: (StringConv a b, StringConv b a, Functor f) => (b -> f b) -> a -> f a+convSL f a = fmap toSL (f (toSL a))
string-conv.cabal view
@@ -1,35 +1,71 @@-name: string-conv-version: 0.1.2-synopsis: Standardized conversion between string types-description: Avoids the need to remember many different functions- for converting string types. Just use one universal- function toS for all monomorphic string conversions.-license: BSD3-license-file: LICENSE-author: Ozgun Ataman-maintainer: ozgun.ataman@soostone.com-copyright: Soostone Inc, 2012-2015-category: Data, String, Text-homepage: https://github.com/Soostone/string-conv-bug-reports: https://github.com/Soostone/string-conv/issues-build-type: Simple-cabal-version: >=1.8+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.34.6.+--+-- see: https://github.com/sol/hpack++name: string-conv+version: 0.2.0+synopsis: Standardized conversion between string types+description: Avoids the need to remember many different functions for converting string types. Just use one universal function toS for all monomorphic string conversions.+category: Data, String, Text+homepage: https://github.com/Soostone/string-conv+bug-reports: https://github.com/Soostone/string-conv/issues+author: Ozgun Ataman+maintainer: ozgun.ataman@soostone.com+copyright: Soostone Inc, 2012-2015+license: BSD3+license-file: LICENSE+build-type: Simple extra-source-files:- README.md- changelog.md+ README.md+ changelog.md +source-repository head+ type: git+ location: https://github.com/Soostone/string-conv+ flag lib-Werror- default: False- manual: True+ description: Turn on -Wall and -Werror. Should always be enabled in development. -source-repository head- type: git- location: https://github.com/Soostone/string-conv.git+ manual: True+ default: False library- exposed-modules: Data.String.Conv- build-depends: base >= 4.4 && < 5, bytestring, text+ exposed-modules:+ Data.String.Conv+ other-modules:+ Paths_string_conv+ hs-source-dirs:+ src+ build-depends:+ base >=4.4 && <5+ , bytestring+ , text if flag(lib-Werror)- ghc-options: -Werror+ ghc-options: -Wall -Werror -fwarn-redundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns -Widentities+ else+ ghc-options: -Wall -fwarn-redundant-constraints -Wincomplete-record-updates -Widentities+ default-language: Haskell2010 - ghc-options: -Wall+test-suite tests+ type: exitcode-stdio-1.0+ main-is: Main.hs+ other-modules:+ Paths_string_conv+ hs-source-dirs:+ test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ base >=4.4 && <5+ , bytestring+ , quickcheck-instances >=0.3.17+ , string-conv+ , tasty+ , tasty-quickcheck+ , text+ if flag(lib-Werror)+ ghc-options: -Wall -Werror -fwarn-redundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns -Widentities+ else+ ghc-options: -Wall -fwarn-redundant-constraints -Wincomplete-record-updates -Widentities+ default-language: Haskell2010
+ test/Main.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE OverloadedStrings #-}++import Data.ByteString as B+import Data.ByteString.Lazy as LB+import Data.String.Conv+import Data.Text as T+import Data.Text.Lazy as LT+import Test.QuickCheck.Instances.ByteString ()+import Test.QuickCheck.Instances.Text ()+import Test.Tasty+import Test.Tasty.QuickCheck++main :: IO ()+main =+ defaultMain $+ testGroup+ " tests"+ [ strictDecoding,+ lenientDecoding+ ]++strictDecoding :: TestTree+strictDecoding =+ testGroup+ "strict decoding (toS method)"+ [ testProperty "converting String to String" $ do+ \s -> s == (toS (toS (s :: String) :: String)),+ testProperty "converting String to strict ByteString" $ do+ \s -> s == (toS (toS (s :: String) :: B.ByteString)),+ testProperty "converting String to lazy ByteString" $ do+ \s -> s == (toS (toS (s :: String) :: LB.ByteString)),+ testProperty "converting String to strict Text" $ do+ \s -> s == (toS (toS (s :: String) :: T.Text)),+ testProperty "converting String to lazy Text" $ do+ \s -> s == (toS (toS (s :: String) :: LT.Text)),+ testProperty "converting strict ByteString to strict ByteString" $ do+ \s -> s == (toS (toS (s :: B.ByteString) :: B.ByteString)),+ testProperty "converting strict ByteString to lazy ByteString" $ do+ \s -> s == (toS (toS (s :: B.ByteString) :: LB.ByteString)),+ testProperty "converting lazy ByteString to lazy ByteString" $ do+ \s -> s == (toS (toS (s :: LB.ByteString) :: LB.ByteString)),+ testProperty "converting strict Text to lazy ByteString" $ do+ \s -> s == (toS (toS (s :: T.Text) :: LB.ByteString)),+ testProperty "converting strict Text to strict ByteString" $ do+ \s -> s == (toS (toS (s :: LB.ByteString) :: B.ByteString)),+ testProperty "converting strict Text to strict Text" $ do+ \s -> s == (toS (toS (s :: T.Text) :: T.Text)),+ testProperty "converting strict Text to lazy Text" $ do+ \s -> s == (toS (toS (s :: T.Text) :: LT.Text)),+ testProperty "converting lazy Text to strict ByteString" $ do+ \s -> s == (toS (toS (s :: LT.Text) :: B.ByteString)),+ testProperty "converting lazy Text to lazy ByteString" $ do+ \s -> s == (toS (toS (s :: LT.Text) :: LB.ByteString)),+ testProperty "converting lazy Text to lazy Text" $ do+ \s -> s == (toS (toS (s :: LT.Text) :: LT.Text))+ ]++lenientDecoding :: TestTree+lenientDecoding =+ testGroup+ "lenient decoding (toSL method)"+ [ testProperty "converting String to String" $ do+ \s -> s == (toSL (toSL (s :: String) :: String)),+ testProperty "converting String to strict ByteString" $ do+ \s -> s == (toSL (toSL (s :: String) :: B.ByteString)),+ testProperty "converting String to lazy ByteString" $ do+ \s -> s == (toSL (toSL (s :: String) :: LB.ByteString)),+ testProperty "converting String to strict Text" $ do+ \s -> s == (toSL (toSL (s :: String) :: T.Text)),+ testProperty "converting String to lazy Text" $ do+ \s -> s == (toSL (toSL (s :: String) :: LT.Text)),+ testProperty "converting strict ByteString to strict ByteString" $ do+ \s -> s == (toSL (toSL (s :: B.ByteString) :: B.ByteString)),+ testProperty "converting strict ByteString to lazy ByteString" $ do+ \s -> s == (toSL (toSL (s :: B.ByteString) :: LB.ByteString)),+ testProperty "converting lazy ByteString to lazy ByteString" $ do+ \s -> s == (toSL (toSL (s :: LB.ByteString) :: LB.ByteString)),+ testProperty "converting strict Text to lazy ByteString" $ do+ \s -> s == (toSL (toSL (s :: T.Text) :: LB.ByteString)),+ testProperty "converting strict Text to strict ByteString" $ do+ \s -> s == (toSL (toSL (s :: LB.ByteString) :: B.ByteString)),+ testProperty "converting strict Text to strict Text" $ do+ \s -> s == (toSL (toSL (s :: T.Text) :: T.Text)),+ testProperty "converting strict Text to lazy Text" $ do+ \s -> s == (toSL (toSL (s :: T.Text) :: LT.Text)),+ testProperty "converting lazy Text to strict ByteString" $ do+ \s -> s == (toSL (toSL (s :: LT.Text) :: B.ByteString)),+ testProperty "converting lazy Text to lazy ByteString" $ do+ \s -> s == (toSL (toSL (s :: LT.Text) :: LB.ByteString)),+ testProperty "converting lazy Text to lazy Text" $ do+ \s -> s == (toSL (toSL (s :: LT.Text) :: LT.Text))+ ]