packages feed

aeson-options 0.0.0 → 0.1.0

raw patch · 3 files changed

+83/−12 lines, 3 filesdep ~aesondep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: aeson, base

API changes (from Hackage documentation)

+ Data.Aeson.Options: genericParseJSONStripType :: forall a. (Typeable a, Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
+ Data.Aeson.Options: genericToJSONStripType :: forall a. (Typeable a, Generic a, GToJSON Zero (Rep a)) => a -> Value
+ Data.Aeson.Options: stripTypeOptions :: forall a. Typeable a => Options

Files

CHANGELOG.md view
@@ -4,6 +4,13 @@ `aeson-options` uses [PVP Versioning][1]. The change log is available [on GitHub][2]. +0.1.0+=====++* Add options that strip type name from field prefixes.+* Support build with GHC-8.6.1.+  Disable build with GHC-8.0.2 on CI.+ 0.0.0 ===== 
aeson-options.cabal view
@@ -1,5 +1,6 @@+cabal-version:       2.0 name:                aeson-options-version:             0.0.0+version:             0.1.0 synopsis:            Options to derive FromJSON/ToJSON instances description:         Options to derive FromJSON/ToJSON instances. homepage:            https://github.com/serokell/aeson-options@@ -11,11 +12,11 @@ maintainer:          Serokell <hi@serokell.io> copyright:           2018 Serokell build-type:          Simple- extra-source-files:  CHANGELOG.md                    , README.md-cabal-version:       >=2.0-+tested-with:         GHC == 8.2.2+                   , GHC == 8.4.3+                   , GHC == 8.6.1  source-repository head   type:                git@@ -25,7 +26,7 @@   hs-source-dirs:      src   exposed-modules:     Data.Aeson.Options -  build-depends:       base >= 4.9 && < 5+  build-depends:       base >= 4.10 && < 5                      , aeson >= 1.0 && < 1.4    ghc-options:         -Wall -fno-warn-orphans
src/Data/Aeson/Options.hs view
@@ -1,18 +1,32 @@--- | Options used to derive FromJSON/ToJSON instance. These options--- generally comply to our style regarding names. Of course sometimes--- they don't fit one's needs, so treat them as just sensible--- defaults.+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications    #-} +{- | Options used to derive FromJSON/ToJSON instance. These options generally+comply to our style regarding names. Of course sometimes they don't fit one's+needs, so treat them as just sensible defaults.+-}+ module Data.Aeson.Options-       ( defaultOptions+       ( -- * Custom options+         defaultOptions        , leaveTagOptions        , defaultOptionsPS+       , stripTypeOptions++         -- * Generic functions+       , genericParseJSONStripType+       , genericToJSONStripType        ) where +import Data.Aeson.Types (Parser) import Data.Char (isLower, isPunctuation, isUpper, toLower)-import Data.List (findIndex)+import Data.List (findIndex, isPrefixOf)+import GHC.Generics (Generic, Rep)+import Type.Reflection (Typeable, typeRep) -import qualified Data.Aeson.TH as A+import qualified Data.Aeson as A  headToLower :: String -> String headToLower []     = error "Can not use headToLower on empty String"@@ -58,3 +72,52 @@     A.defaultOptions     { A.constructorTagModifier = headToLower . stripConstructorPrefix     }++{- | Allows to create 'A.FromJSON' instance that strips the data type name prefix+from every field. Doesn't change name of the fields that doesn't start with the+type name.++>>> data Foo = Foo { fooBar :: String, fooQuux :: Int } deriving (Generic, Show)+>>> instance FromJSON Foo where parseJSON = genericParseJSONStripType+>>> decode @Foo "{ \"bar\": \"test\", \"quux\": 42 }"+Just (Foo {fooBar = "test", fooQuux = 42})+-}+genericParseJSONStripType+    :: forall a .+       (Typeable a, Generic a, A.GFromJSON A.Zero (Rep a))+    => A.Value+    -> Parser a+genericParseJSONStripType = A.genericParseJSON (stripTypeOptions @a)++{- | Allows to create 'A.ToJSON' instance that strips the data type name prefix+from every field. Doesn't change name of the fields that doesn't start with the+type name.++>>> data Foo = Foo { fooBar :: String, fooQuux :: Int } deriving (Generic, Show)+>>> instance ToJSON Foo where toJSON = genericToJSONStripType+>>> encode $ Foo { fooBar = "test", fooQuux = 42 }+"{\"quux\":42,\"bar\":\"test\"}"+-}+genericToJSONStripType+    :: forall a .+       (Typeable a, Generic a, A.GToJSON A.Zero (Rep a))+    => a+    -> A.Value+genericToJSONStripType = A.genericToJSON (stripTypeOptions @a)++{- | Options to strip type name from the field names. See+'genericParseJSONStripType' and 'genericToJSONStripType' for examples.+-}+stripTypeOptions :: forall a . Typeable a => A.Options+stripTypeOptions = A.defaultOptions+    { A.fieldLabelModifier = stripTypeNamePrefix+    }+  where+    typeName :: String+    typeName = headToLower $ show $ typeRep @a++    stripTypeNamePrefix :: String -> String+    stripTypeNamePrefix fieldName =+        if typeName `isPrefixOf` fieldName+            then headToLower $ drop (length typeName) fieldName+            else fieldName