aeson 0.11.0.0 → 0.11.1.0
raw patch · 7 files changed
+140/−12 lines, 7 filesdep +base-orphansdep +natsdep +taggeddep ~QuickCheckdep ~semigroupsPVP ok
version bump matches the API change (PVP)
Dependencies added: base-orphans, nats, tagged
Dependency ranges changed: QuickCheck, semigroups
API changes (from Hackage documentation)
Files
- Data/Aeson/Types/Instances.hs +53/−4
- aeson.cabal +17/−4
- benchmarks/aeson-benchmarks.cabal +3/−2
- changelog.md +18/−0
- tests/Instances.hs +26/−0
- tests/Properties.hs +11/−1
- tests/UnitTests.hs +12/−1
Data/Aeson/Types/Instances.hs view
@@ -61,6 +61,7 @@ , typeMismatch ) where +import Control.Applicative (Const(..)) import Data.Aeson.Encode.Functions (brackets, builder, encode, foldable, list) import Data.Aeson.Functions (hashMapKey, mapHashKeyVal, mapKey, mapKeyVal) import Data.Aeson.Types.Class@@ -71,11 +72,14 @@ import Data.Functor.Identity (Identity(..)) import Data.Hashable (Hashable(..)) import Data.Int (Int8, Int16, Int32, Int64)+import Data.List.NonEmpty (NonEmpty(..)) import Data.Maybe (fromMaybe) import Data.Monoid ((<>)) import Data.Monoid (Dual(..), First(..), Last(..))+import Data.Proxy (Proxy(..)) import Data.Ratio (Ratio, (%), numerator, denominator) import Data.Scientific (Scientific)+import Data.Tagged (Tagged(..)) import Data.Text (Text, pack, unpack) import Data.Time (Day, LocalTime, NominalDiffTime, TimeOfDay, UTCTime, ZonedTime)@@ -86,6 +90,7 @@ import Data.Version (Version, showVersion, parseVersion) import Text.ParserCombinators.ReadP (readP_to_S) import Foreign.Storable (Storable)+import Numeric.Natural (Natural) import Prelude hiding (foldr) import qualified Data.Aeson.Encode.Builder as E import qualified Data.Aeson.Parser.Time as Time@@ -111,11 +116,9 @@ import qualified Data.Vector.Unboxed as VU #if MIN_VERSION_base(4,8,0)-import Numeric.Natural #else import Control.Applicative ((<$>), (<*>), pure) import Data.Monoid (mempty)-import Data.Traversable as Tr (traverse) import Data.Word (Word) #endif @@ -353,7 +356,6 @@ parseJSON = withScientific "Integral" $ pure . truncate {-# INLINE parseJSON #-} -#if MIN_VERSION_base(4,8,0) instance ToJSON Natural where toJSON = toJSON . toInteger {-# INLINE toJSON #-}@@ -366,7 +368,6 @@ if Scientific.coefficient s < 0 then fail $ "Expected a Natural number but got the negative number: " <> show s else pure $ truncate s-#endif instance ToJSON Int8 where toJSON = Number . fromIntegral@@ -491,6 +492,20 @@ parseJSON = withText "Lazy Text" $ pure . LT.fromStrict {-# INLINE parseJSON #-} +instance (ToJSON a) => ToJSON (NonEmpty a) where+ toJSON = toJSON . toList+ {-# INLINE toJSON #-}++ toEncoding = toEncoding . toList+ {-# INLINE toEncoding #-}++instance (FromJSON a) => FromJSON (NonEmpty a) where+ parseJSON = withArray "NonEmpty a" $+ (>>= ne) . Tr.sequence . zipWith parseIndexedJSON [0..] . V.toList+ where+ ne [] = fail "Expected a NonEmpty but got an empty list"+ ne (x:xs) = pure (x :| xs)+ instance OVERLAPPABLE_ (ToJSON a) => ToJSON [a] where toJSON = Array . V.fromList . map toJSON {-# INLINE toJSON #-}@@ -1529,6 +1544,40 @@ go [(v,[])] = return v go (_ : xs) = go xs go _ = fail $ "could not parse Version"++instance ToJSON (Proxy a) where+ toJSON _ = Null+ {-# INLINE toJSON #-}++ toEncoding _ = Encoding E.null_+ {-# INLINE toEncoding #-}++instance FromJSON (Proxy a) where+ {-# INLINE parseJSON #-}+ parseJSON Null = pure Proxy+ parseJSON v = typeMismatch "Proxy" v++instance ToJSON b => ToJSON (Tagged a b) where+ toJSON (Tagged x) = toJSON x+ {-# INLINE toJSON #-}++ toEncoding (Tagged x) = toEncoding x+ {-# INLINE toEncoding #-}++instance FromJSON b => FromJSON (Tagged a b) where+ {-# INLINE parseJSON #-}+ parseJSON = fmap Tagged . parseJSON++instance ToJSON a => ToJSON (Const a b) where+ toJSON (Const x) = toJSON x+ {-# INLINE toJSON #-}++ toEncoding (Const x) = toEncoding x+ {-# INLINE toEncoding #-}++instance FromJSON a => FromJSON (Const a b) where+ {-# INLINE parseJSON #-}+ parseJSON = fmap Const . parseJSON -- | @withObject expected f value@ applies @f@ to the 'Object' when @value@ is an @Object@ -- and fails using @'typeMismatch' expected@ otherwise.
aeson.cabal view
@@ -1,5 +1,5 @@ name: aeson-version: 0.11.0.0+version: 0.11.1.0 license: BSD3 license-file: LICENSE category: Text, Web, JSON@@ -100,6 +100,7 @@ mtl, scientific >= 0.3.1 && < 0.4, syb,+ tagged >=0.8.3 && <0.9, template-haskell >= 2.7, text >= 1.1.1.0, transformers,@@ -107,9 +108,13 @@ vector >= 0.7.1 if !impl(ghc >= 8.0)- -- `Data.Semigroup` is available in base only since GHC 8.0- build-depends: semigroups >= 0.16.1+ -- `Data.Semigroup` is available in base only since GHC 8.0 / base 4.9+ build-depends: semigroups >= 0.16.1 && < 0.19 + if !impl(ghc >= 7.10)+ -- `Numeric.Natural` is available in base only since GHC 7.10 / base 4.8+ build-depends: nats >=1 && <1.1+ if flag(old-locale) build-depends: time < 1.5, old-locale else@@ -145,13 +150,15 @@ build-depends: HUnit,- QuickCheck >= 2.7,+ QuickCheck >= 2.7 && <2.8.3, aeson, attoparsec, base,+ base-orphans >=0.5.3 && <0.6, bytestring, containers, ghc-prim >= 0.2,+ tagged, template-haskell, test-framework, test-framework-hunit,@@ -162,10 +169,16 @@ vector, quickcheck-instances >=0.3.12 + if !impl(ghc >= 8.0)+ build-depends: semigroups >= 0.16.1 && < 0.19+ if flag(old-locale) build-depends: time < 1.5, old-locale else build-depends: time >= 1.5++ if !impl(ghc >= 7.10)+ build-depends: nats >=1 && <1.1 source-repository head type: git
benchmarks/aeson-benchmarks.cabal view
@@ -44,6 +44,7 @@ mtl, scientific >= 0.3.1 && < 0.4, syb,+ tagged >=0.8.3 && <0.9, template-haskell >= 2.4, text >= 1.1.1.0, time,@@ -52,8 +53,8 @@ vector >= 0.7.1 if !impl(ghc >= 8.0)- -- `Data.Semigroup` is available in base only since GHC 8.0- build-depends: semigroups >= 0.16.1+ -- `Data.Semigroup` is available in base only since GHC 8.0 / base 4.9+ build-depends: semigroups >= 0.16.1 && < 0.19 if flag(old-locale) build-depends: time < 1.5, old-locale
changelog.md view
@@ -1,5 +1,23 @@ For the latest version of this document, please see [https://github.com/bos/aeson/blob/master/changelog.md](https://github.com/bos/aeson/blob/master/changelog.md). +## 0.11.1.0++The only changes are added instances.++These are new:+* `ToJSON a => ToJSON (NonEmpty a)`+* `FromJSON a => FromJSON (NonEmpty a)`+* `ToJSON (Proxy a)`+* `FromJSON (Proxy a)`+* `ToJSON b => ToJSON (Tagged a b)`+* `FromJSON b => FromJSON (Tagged a b)`+* `ToJSON a => ToJSON (Const a b)`+* `FromJSON a => FromJSON (Const a b)`++These are now available for older GHCs:+* `ToJSON Natural`+* `FromJSON Natural`+ # 0.11.0.0 This release should be close to backwards compatible with aeson 0.9.
tests/Instances.hs view
@@ -14,13 +14,22 @@ listOf1, oneof, resize) import Data.Time.Clock (UTCTime(..)) import Data.Time (ZonedTime(..), TimeZone(..))+import Data.List.NonEmpty (NonEmpty(..)) import Data.Version import Data.Aeson.Types+import Control.Applicative (Const(..))+import Data.Tagged (Tagged(..))+import Data.Proxy (Proxy(..)) import Control.Applicative import Functions +import Data.Orphans () import Test.QuickCheck.Instances () +#if !MIN_VERSION_base(4,8,0) && !MIN_VERSION_QuickCheck(2,8,3)+import Numeric.Natural+#endif+ -- "System" types. instance Arbitrary DotNetTime where@@ -136,6 +145,9 @@ instance Arbitrary Version where arbitrary = makeVersion . fmap getNonNegative <$> resize 4 (listOf1 arbitrary) +instance Arbitrary a => Arbitrary (NonEmpty a) where+ arbitrary = (:|) <$> arbitrary <*> arbitrary+ -- Version tags are deprecated, so we avoid using them in the Arbitrary -- instance. However, the recommended constructor 'makeVersion' is not -- exported by "Data.Version" until base-4.8.0.0. For previous versions,@@ -145,3 +157,17 @@ makeVersion :: [Int] -> Version makeVersion b = Version b [] #endif++#if !MIN_VERSION_base(4,8,0) && !MIN_VERSION_QuickCheck(2,8,3)+instance Arbitrary Natural where+ arbitrary = fromInteger . abs <$> arbitrary+#endif++instance Arbitrary (Proxy a) where+ arbitrary = pure Proxy++instance Arbitrary b => Arbitrary (Tagged a b) where+ arbitrary = Tagged <$> arbitrary++instance Arbitrary a => Arbitrary (Const a b) where+ arbitrary = Const <$> arbitrary
tests/Properties.hs view
@@ -2,18 +2,23 @@ module Properties where +import Control.Applicative (Const) import Data.Aeson (eitherDecode)-import Data.Aeson.Encode (encode, encodeToBuilder)+import Data.Aeson.Encode (encode) import Data.Aeson.Internal (IResult(..), formatError, ifromJSON, iparse) import Data.Aeson.Parser (value) import Data.Aeson.Types import Data.ByteString.Builder (toLazyByteString) import Data.Int (Int8)+import Data.List.NonEmpty (NonEmpty) import Data.Time (Day, LocalTime, NominalDiffTime, TimeOfDay, UTCTime, ZonedTime)+import Data.Proxy (Proxy)+import Data.Tagged (Tagged) import Data.Version (Version) import Encoders import Instances ()+import Numeric.Natural (Natural) import Test.Framework (Test, testGroup) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.QuickCheck (Arbitrary(..), Property, (===), (.&&.), counterexample)@@ -127,6 +132,7 @@ testProperty "Bool" $ roundTripEq True , testProperty "Double" $ roundTripEq (1 :: Approx Double) , testProperty "Int" $ roundTripEq (1 :: Int)+ , testProperty "NonEmpty Char" $ roundTripEq (undefined :: NonEmpty Char) , testProperty "Integer" $ roundTripEq (1 :: Integer) , testProperty "String" $ roundTripEq ("" :: String) , testProperty "Text" $ roundTripEq T.empty@@ -139,6 +145,10 @@ , testProperty "ZonedTime" $ roundTripEq (undefined :: ZonedTime) , testProperty "NominalDiffTime" $ roundTripEq (undefined :: NominalDiffTime) , testProperty "Version" $ roundTripEq (undefined :: Version)+ , testProperty "Natural" $ roundTripEq (undefined :: Natural)+ , testProperty "Proxy" $ roundTripEq (undefined :: Proxy Int)+ , testProperty "Tagged" $ roundTripEq (undefined :: Tagged Int Char)+ , testProperty "Const" $ roundTripEq (undefined :: Const Int Char) , testGroup "ghcGenerics" [ testProperty "OneConstructor" $ roundTripEq OneConstructor , testProperty "Product2" $ roundTripEq (undefined :: Product2 Int Bool)
tests/UnitTests.hs view
@@ -4,6 +4,7 @@ module UnitTests (ioTests, tests) where +import Control.Applicative (Const(..)) import Control.Monad (forM) import Data.Aeson (decode, eitherDecode, encode, genericToJSON, genericToEncoding, FromJSON(..), withObject, (.:), (.:?), (.:!)) import Data.Aeson.Encode (encodeToTextBuilder)@@ -11,10 +12,13 @@ import Data.Aeson.TH (deriveJSON) import Data.Aeson.Types (ToJSON(..), Value, camelTo, camelTo2, defaultOptions, omitNothingFields) import Data.Char (toUpper)+import Data.List.NonEmpty (NonEmpty(..)) import Data.Maybe (fromMaybe)+import Data.Proxy (Proxy(..))+import Data.Sequence (Seq)+import Data.Tagged (Tagged(..)) import Data.Time (UTCTime) import Data.Time.Format (parseTime)-import Data.Sequence (Seq) import GHC.Generics (Generic) import Test.Framework (Test, testGroup) import Test.Framework.Providers.HUnit (testCase)@@ -223,7 +227,12 @@ , assertEqual "Nothing" "null" $ encode (Nothing :: Maybe Int) , assertEqual "Just" "1" $ encode (Just 1 :: Maybe Int) , assertEqual "Just Nothing" "null" $ encode (Just Nothing :: Maybe (Maybe Int))+ , assertEqual "Proxy Int" "null" $ encode (Proxy :: Proxy Int)+ , assertEqual "Tagged Char Int" "1" $ encode (Tagged 1 :: Tagged Char Int)+ , assertEqual "Const Char Int" "\"c\"" $ encode (Const 'c' :: Const Char Int) , assertEqual "Tuple" "[1,2]" $ encode ((1, 2) :: (Int, Int))+ , assertEqual "NonEmpty" "[1,2,3]" $ encode (1 :| [2, 3] :: NonEmpty Int)+ , assertEqual "()" "[]" $ encode () ] jsonDecoding :: [Assertion]@@ -231,6 +240,8 @@ assertEqual "Nothing" (Nothing :: Maybe Int) (decode "null") , assertEqual "Just" (Just 1 :: Maybe Int) (decode "1") , assertEqual "Just Nothing" (Just Nothing :: Maybe (Maybe Int)) (decode "null")+ , assertEqual "NonEmpty" (Just (1 :| [2, 3]) :: Maybe (NonEmpty Int)) (decode "[1,2,3]")+ , assertEqual "()" (Just ()) (decode "[]") ] ------------------------------------------------------------------------------