Hello community, here is the log from the commit of package ghc-envelope for openSUSE:Factory checked in at 2017-03-03 17:50:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-envelope (Old) and /work/SRC/openSUSE:Factory/.ghc-envelope.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-envelope" Fri Mar 3 17:50:05 2017 rev:2 rq:461627 version:0.2.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-envelope/ghc-envelope.changes 2016-11-01 09:50:52.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.ghc-envelope.new/ghc-envelope.changes 2017-03-03 17:50:06.417899365 +0100 @@ -1,0 +2,5 @@ +Sun Feb 12 14:15:17 UTC 2017 - [email protected] + +- Update to version 0.2.1.0 with cabal2obs. + +------------------------------------------------------------------- Old: ---- envelope-0.1.0.0.tar.gz New: ---- envelope-0.2.1.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-envelope.spec ++++++ --- /var/tmp/diff_new_pack.vFxemS/_old 2017-03-03 17:50:07.489747984 +0100 +++ /var/tmp/diff_new_pack.vFxemS/_new 2017-03-03 17:50:07.493747420 +0100 @@ -1,7 +1,7 @@ # # spec file for package ghc-envelope # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,16 +19,16 @@ %global pkg_name envelope %bcond_with tests Name: ghc-%{pkg_name} -Version: 0.1.0.0 +Version: 0.2.1.0 Release: 0 Summary: Defines generic 'Envelope' type to wrap reponses from a JSON API License: BSD-3-Clause -Group: System/Libraries +Group: Development/Languages/Other Url: https://hackage.haskell.org/package/%{pkg_name} Source0: https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz BuildRequires: ghc-Cabal-devel -# Begin cabal-rpm deps: BuildRequires: ghc-aeson-devel +BuildRequires: ghc-http-api-data-devel BuildRequires: ghc-mtl-devel BuildRequires: ghc-rpm-macros BuildRequires: ghc-text-devel @@ -37,7 +37,6 @@ BuildRequires: ghc-Glob-devel BuildRequires: ghc-doctest-devel %endif -# End cabal-rpm deps %description Please see README.md. @@ -56,20 +55,14 @@ %prep %setup -q -n %{pkg_name}-%{version} - %build %ghc_lib_build - %install %ghc_lib_install - %check -%if %{with tests} -%{cabal} test -%endif - +%cabal_test %post devel %ghc_pkg_recache @@ -83,5 +76,6 @@ %files devel -f %{name}-devel.files %defattr(-,root,root,-) +%doc README.md %changelog ++++++ envelope-0.1.0.0.tar.gz -> envelope-0.2.1.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/envelope-0.1.0.0/README.md new/envelope-0.2.1.0/README.md --- old/envelope-0.1.0.0/README.md 1970-01-01 01:00:00.000000000 +0100 +++ new/envelope-0.2.1.0/README.md 2016-10-27 09:06:53.000000000 +0200 @@ -0,0 +1,48 @@ + +Web.Envelope +============ + +[](https://hackage.haskell.org/package/envelope) [](http://travis-ci.org/cdepillabout/envelope) + + +This module exports an `Envelope` type that can be used to wrap reponses from a JSON REST API. It provides a successful `Success` response, and a failure `Err` response. + +Here is a small demonstration of returning a success response: + +```haskell +>>> import qualified Data.ByteString.Lazy.Char8 as C8 +>>> import Data.Aeson (decode, encode) +>>> let successEnvelope = toSuccessEnvelope 3 :: Envelope Text Int +>>> C8.putStrLn $ encode successEnvelope +{"data":3} +>>> decode "{\"data\":3}" :: Maybe (Envelope Text Int) +Just (EnvelopeSuccess (Success 3)) +``` + +Your data gets wrapped in an object with a single `"data"` field: + +```json +{ + "data": 3 +} +``` + +Now lets look at how an error response is encoded and decoded. It is encoded +as an object with two members: @\"extra\"@ and @\"error\"@. + +```haskell +>>> let errorEnvelope = toErrEnvelope "DB_ERROR" "there was an error in the database" :: Envelope String Int +>>> C8.putStrLn $ encode errorEnvelope +{"extra":"there was an error in the database","error":"DB_ERROR"} +>>> decode "{\"extra\":\"there was an error in the database\",\"error\":\"DB_ERROR\"}" :: Maybe (Envelope String Int) +Just (EnvelopeErr (Err {errErr = "DB_ERROR", errExtra = Just "there was an error in the database"})) +``` + +Your error type and extra message get wrapped in an object: + +```json +{ + "extra": "there was an error in the database", + "error": "DB_ERROR" +} +``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/envelope-0.1.0.0/envelope.cabal new/envelope-0.2.1.0/envelope.cabal --- old/envelope-0.1.0.0/envelope.cabal 2016-04-06 08:09:35.000000000 +0200 +++ new/envelope-0.2.1.0/envelope.cabal 2016-10-27 09:35:54.000000000 +0200 @@ -1,5 +1,5 @@ name: envelope -version: 0.1.0.0 +version: 0.2.1.0 synopsis: Defines generic 'Envelope' type to wrap reponses from a JSON API. description: Please see README.md homepage: https://github.com/cdepillabout/envelope#readme @@ -10,7 +10,7 @@ copyright: 2016 Dennis Gosnell category: Web build-type: Simple --- extra-source-files: +extra-source-files: README.md cabal-version: >=1.10 library @@ -18,6 +18,7 @@ exposed-modules: Web.Envelope build-depends: base >= 4.8 && < 5 , aeson >= 0.11 + , http-api-data >= 0.3 , mtl >= 2.2 , text >= 1.2 default-language: Haskell2010 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/envelope-0.1.0.0/src/Web/Envelope.hs new/envelope-0.2.1.0/src/Web/Envelope.hs --- old/envelope-0.1.0.0/src/Web/Envelope.hs 2016-04-07 06:07:26.000000000 +0200 +++ new/envelope-0.2.1.0/src/Web/Envelope.hs 2016-10-27 09:34:27.000000000 +0200 @@ -1,6 +1,7 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE OverloadedStrings #-} @@ -48,6 +49,8 @@ , Envelope'(..) , Success(..) , Err(..) + , toErr + , toErr' , throwEnvelopeErr , throwEnvelopeErr' , toSuccessEnvelope @@ -59,15 +62,23 @@ import Control.Monad.Except (MonadError, throwError) import Control.Applicative ((<|>)) import Data.Aeson - ( (.=), (.:), FromJSON(..), ToJSON(..), Value(..), object ) + ((.=), (.:), FromJSON(..), ToJSON(..), Value(..), object) import Data.Aeson.TH (deriveJSON) import Data.Aeson.Types (Parser, typeMismatch) import Data.Data (Data) +import Data.Maybe (maybeToList) import Data.Text (Text) import Data.Typeable (Typeable) import GHC.Generics (Generic) +import Web.FormUrlEncoded + (FromForm(fromForm), ToForm(toForm), fromEntriesByKey, lookupMaybe, + lookupUnique, parseUnique) +import Web.HttpApiData + (FromHttpApiData, ToHttpApiData(toQueryParam)) +import Web.Internal.FormUrlEncoded (Form) --- | Main type to be used. Wrapper around responses from an API, mainly used with a JSON API. +-- | Main type to be used. Wrapper around responses from an API, mainly used +-- with a JSON API. -- -- Type synonym around 'Envelope''. type Envelope e a = Envelope' (Err e) (Success a) @@ -95,15 +106,35 @@ <|> EnvelopeErr <$> parseJSON v <|> typeMismatch "Envelope'" v --- | Newtype wrapper to be able to provide 'ToJSON' and 'FromJSON' instances. --- Used with 'Envelope'. +-- | Uses the underlying 'ToForm' instance for both the 'EnvelopeErr' case and +-- the 'EnvelopeSuccess' case. +instance (ToForm a, ToForm e) => + ToForm (Envelope' e a) where + toForm :: Envelope' e a -> Form + toForm (EnvelopeErr err) = toForm err + toForm (EnvelopeSuccess succ) = toForm succ + +-- | Looks for the key @\"error\"@ in the 'Form'. If it is found, assume this +-- form is an @'Err e'@. If it is not found, assume this 'Form' is an @a@. +-- +-- __WARNING__: If the @a@ is encoded with a key @\"error\"@, this 'Form' will +-- be decoded as a 'EnvelopeErr' instead of a 'EnvelopeSuccess'. This is +-- probably not what you want. +instance (FromForm a, FromHttpApiData e) => + FromForm (Envelope' (Err e) a) where + fromForm :: Form -> Either Text (Envelope' (Err e) a) + fromForm form = + case lookupUnique "error" form of + -- Key "error" doesn't exist, so assume this is an @a@. + Left _ -> EnvelopeSuccess <$> fromForm form + -- Key "error exists, so assume this is an @'Err' e@. + Right _ -> EnvelopeErr <$> fromForm form + +-- | Newtype wrapper to be able to provide specific instances. Used with +-- 'Envelope'. newtype Success a = Success a deriving (Data, Eq, Generic, Show, Typeable) -instance (ToJSON a) => ToJSON (Success a) where - toJSON :: Success a -> Value - toJSON (Success a) = object ["data" .= a] - -- | For @'Success' a@, wrap the @a@ in an object with a @\"data\"@ field. -- -- The resulting JSON object will look like this: @@ -111,21 +142,35 @@ -- @ -- { \"data\": ... } -- @ +instance (ToJSON a) => ToJSON (Success a) where + toJSON :: Success a -> Value + toJSON (Success a) = object ["data" .= a] + +-- | Parse the JSON object produced by the 'ToJSON' instance. instance (FromJSON e) => FromJSON (Success e) where parseJSON :: Value -> Parser (Success e) parseJSON (Object v) = Success <$> v .: "data" parseJSON invalid = typeMismatch "Success" invalid --- | Newtype wrapper to be able to provide 'ToJSON' and 'FromJSON' instances. +-- | Use the 'ToForm' instance of the underlying datatype. +instance (ToForm a) => + ToForm (Success a) where + toForm :: Success a -> Form + toForm (Success a) = toForm a + +-- | Use the 'FromForm' instance of the underlying datatype. +instance (FromForm a) => + FromForm (Success a) where + fromForm :: Form -> Either Text (Success a) + fromForm form = Success <$> fromForm form + +-- | Wrapper to add an extra field with info about the error. Used with +-- 'Envelope'. data Err e = Err { errErr :: e -- ^ Actual error information we want to send. , errExtra :: Maybe Text -- ^ Additional error information in plain text. } deriving (Data, Eq, Generic, Show, Typeable) -instance (ToJSON e) => ToJSON (Err e) where - toJSON :: Err e -> Value - toJSON (Err e extra) = object ["error" .= e, "extra" .= extra] - -- | For @'Err' e@, wrap the @e@ in an object with @\"extra\"@ and @\"error\"@ fields. -- -- The resulting JSON object will look like this: @@ -133,12 +178,52 @@ -- @ -- { \"extra\": ..., \"error\": .... } -- @ +instance (ToJSON e) => ToJSON (Err e) where + toJSON :: Err e -> Value + toJSON (Err e extra) = object ["error" .= e, "extra" .= extra] + +-- | Parse the JSON object produced by the 'ToJSON' instance. instance (FromJSON e) => FromJSON (Err e) where parseJSON :: Value -> Parser (Err e) parseJSON (Object v) = Err <$> v .: "error" <*> v .: "extra" parseJSON invalid = typeMismatch "Err" invalid +-- | Just use the 'ToForm' instance of the underlying datatype. +-- +-- The resulting Form object will look like this: +-- +-- @ +-- [(\"extra\", ...), (\"error\", ....)] +-- @ +instance (ToHttpApiData e) => + ToForm (Err e) where + toForm :: Err e -> Form + toForm (Err err maybeExtra) = + fromEntriesByKey + [("error" :: Text, [toQueryParam err]), ("extra", maybeToList maybeExtra)] + +-- | Parse a form produced by the 'ToForm' instance. Use 'FromHttpApiData's +-- 'Web.HttpApiData.parseQueryParam' to parse the @error@ parameter. +instance (FromHttpApiData e) => + FromForm (Err e) where + fromForm :: Form -> Either Text (Err e) + fromForm form = Err <$> parseUnique "error" form <*> lookupMaybe "extra" form + +-- | Smart constructor for 'Err'. +-- +-- >>> toErr "DB_ERROR" "an error occurred" +-- Err {errErr = "DB_ERROR", errExtra = Just "an error occurred"} +toErr :: e -> Text -> Err e +toErr e extra = Err e (Just extra) + +-- | Smart constructor for 'Err' that doesn't use an 'errExtra'. +-- +-- >>> toErr' "DB_ERROR" +-- Err {errErr = "DB_ERROR", errExtra = Nothing} +toErr' :: e -> Err e +toErr' e = Err e Nothing + -- | Wrap an @a@ in a success 'Envelope'. -- -- >>> toSuccessEnvelope 3 :: Envelope String Int
