Skip to content

Commit

Permalink
Add Decode/Encode instances for Record, simplify module structure (#53)
Browse files Browse the repository at this point in the history
* Add Decode/Encode instances for Record

* Docs

* Simplify the module structure

* Update README

* Better backwards-compatibility
  • Loading branch information
paf31 authored May 22, 2019
1 parent ad56cb7 commit 46f0999
Show file tree
Hide file tree
Showing 14 changed files with 655 additions and 342 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ First, define some data type and derive `Generic`:
To encode JSON, use `genericEncodeJSON`:

```purescript
> import Foreign.Class (class Encode, class Decode, encode, decode)
> import Foreign.Generic (defaultOptions, genericDecodeJSON, genericEncodeJSON)
> import Foreign.Generic (defaultOptions, genericEncodeJSON)
> opts = defaultOptions { unwrapSingleConstructors = true }
Expand All @@ -37,7 +36,8 @@ To encode JSON, use `genericEncodeJSON`:
And to decode JSON, use `genericDecodeJSON`:

```purescript
> import Control.Monad.Except
> import Control.Monad.Except (runExcept)
> import Foreign.Generic (genericDecodeJSON)
> runExcept (genericDecodeJSON opts "{\"a\":1}" :: _ MyRecord)
(Right (MyRecord { a: 1 }))
Expand All @@ -46,6 +46,9 @@ And to decode JSON, use `genericDecodeJSON`:
Badly formed JSON will result in a useful error, which can be inspected or pretty-printed:

```purescript
> import Data.Bifunctor (lmap)
> import Foreign (renderForeignError)
> lmap (map renderForeignError) $ runExcept (genericDecodeJSON opts "{\"a\":\"abc\"}" :: _ MyRecord)
(Left
(NonEmptyList
Expand Down
12 changes: 11 additions & 1 deletion generated-docs/Foreign/Class.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
## Module Foreign.Class

This module is provided for backwards-compatibility with the old API.

It is liable to be removed in a future release.


### Re-exported from Foreign.Generic.Class:

#### `Decode`

``` purescript
Expand Down Expand Up @@ -33,9 +40,11 @@ Decode Char
Decode Boolean
Decode Number
Decode Int
(Decode a) => Decode (Identity a)
(Decode a) => Decode (Array a)
(Decode a) => Decode (Maybe a)
(Decode v) => Decode (Object v)
(RowToList r rl, DecodeRecord r rl) => Decode { | r }
```

#### `Encode`
Expand Down Expand Up @@ -71,9 +80,10 @@ Encode Char
Encode Boolean
Encode Number
Encode Int
(Encode a) => Encode (Identity a)
(Encode a) => Encode (Array a)
(Encode a) => Encode (Maybe a)
(Encode v) => Encode (Object v)
(RowToList r rl, EncodeRecord r rl) => Encode { | r }
```


207 changes: 193 additions & 14 deletions generated-docs/Foreign/Generic.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
## Module Foreign.Generic

#### `defaultOptions`

``` purescript
defaultOptions :: Options
```

Default decoding/encoding options:

- Represent sum types as records with `tag` and `contents` fields
- Unwrap single arguments
- Don't unwrap single constructors
- Use the constructor names as-is
- Use the field names as-is

#### `genericDecode`

``` purescript
Expand Down Expand Up @@ -63,3 +49,196 @@ genericEncodeJSON :: forall a rep. Generic a rep => GenericEncode rep => Options
Write a value which has a `Generic` type as a JSON String


### Re-exported from Foreign:

#### `ForeignError`

``` purescript
data ForeignError
= ForeignError String
| TypeMismatch String String
| ErrorAtIndex Int ForeignError
| ErrorAtProperty String ForeignError
```

A type for foreign type errors

##### Instances
``` purescript
Eq ForeignError
Ord ForeignError
Show ForeignError
```

#### `Foreign`

``` purescript
data Foreign :: Type
```

A type for _foreign data_.

Foreign data is data from any external _unknown_ or _unreliable_
source, for which it cannot be guaranteed that the runtime representation
conforms to that of any particular type.

Suitable applications of `Foreign` are

- To represent responses from web services
- To integrate with external JavaScript libraries.

#### `F`

``` purescript
type F = Except MultipleErrors
```

An error monad, used in this library to encode possible failures when
dealing with foreign data.

The `Alt` instance for `Except` allows us to accumulate errors,
unlike `Either`, which preserves only the last error.

### Re-exported from Foreign.Generic.Class:

#### `SumEncoding`

``` purescript
data SumEncoding
= TaggedObject { tagFieldName :: String, contentsFieldName :: String, constructorTagTransform :: String -> String }
```

The encoding of sum types for your type.
`TaggedObject`s will be encoded in the form `{ [tagFieldName]: "ConstructorTag", [contentsFieldName]: "Contents"}`.
`constructorTagTransform` can be provided to transform the constructor tag to a form you use, e.g. `toLower`/`toUpper`.

#### `Options`

``` purescript
type Options = { sumEncoding :: SumEncoding, unwrapSingleConstructors :: Boolean, unwrapSingleArguments :: Boolean, fieldTransform :: String -> String }
```

Encoding/Decoding options which can be used to customize
`Decode` and `Encode` instances which are derived via
`Generic` (see `genericEncode` and `genericDecode`).

#### `Decode`

``` purescript
class Decode a where
decode :: Foreign -> F a
```

The `Decode` class is used to generate decoding functions
of the form `Foreign -> F a` using `generics-rep` deriving.

First, derive `Generic` for your data:

```purescript
import Data.Generic.Rep
data MyType = MyType ...
derive instance genericMyType :: Generic MyType _
```

You can then use the `genericDecode` and `genericDecodeJSON` functions
to decode your foreign/JSON-encoded data.

##### Instances
``` purescript
Decode Void
Decode Unit
Decode Foreign
Decode String
Decode Char
Decode Boolean
Decode Number
Decode Int
(Decode a) => Decode (Identity a)
(Decode a) => Decode (Array a)
(Decode a) => Decode (Maybe a)
(Decode v) => Decode (Object v)
(RowToList r rl, DecodeRecord r rl) => Decode { | r }
```

#### `Encode`

``` purescript
class Encode a where
encode :: a -> Foreign
```

The `Encode` class is used to generate encoding functions
of the form `a -> Foreign` using `generics-rep` deriving.

First, derive `Generic` for your data:

```purescript
import Data.Generic.Rep
data MyType = MyType ...
derive instance genericMyType :: Generic MyType _
```

You can then use the `genericEncode` and `genericEncodeJSON` functions
to encode your data as JSON.

##### Instances
``` purescript
Encode Void
Encode Unit
Encode Foreign
Encode String
Encode Char
Encode Boolean
Encode Number
Encode Int
(Encode a) => Encode (Identity a)
(Encode a) => Encode (Array a)
(Encode a) => Encode (Maybe a)
(Encode v) => Encode (Object v)
(RowToList r rl, EncodeRecord r rl) => Encode { | r }
```

#### `GenericDecode`

``` purescript
class GenericDecode a
```

##### Instances
``` purescript
GenericDecode NoConstructors
(IsSymbol name, GenericDecodeArgs rep, GenericCountArgs rep) => GenericDecode (Constructor name rep)
(GenericDecode a, GenericDecode b) => GenericDecode (Sum a b)
```

#### `GenericEncode`

``` purescript
class GenericEncode a
```

##### Instances
``` purescript
GenericEncode NoConstructors
(IsSymbol name, GenericEncodeArgs rep) => GenericEncode (Constructor name rep)
(GenericEncode a, GenericEncode b) => GenericEncode (Sum a b)
```

#### `defaultOptions`

``` purescript
defaultOptions :: Options
```

Default decoding/encoding options:

- Represent sum types as records with `tag` and `contents` fields
- Unwrap single arguments
- Don't unwrap single constructors
- Use the constructor names as-is
- Use the field names as-is

Loading

0 comments on commit 46f0999

Please sign in to comment.