Skip to content
This repository has been archived by the owner on Dec 12, 2022. It is now read-only.

Commit

Permalink
Implementing error handling based on discussion in issue paldepind#35
Browse files Browse the repository at this point in the history
  • Loading branch information
jplikesbikes committed Mar 22, 2016
1 parent 3571576 commit f264be8
Show file tree
Hide file tree
Showing 5 changed files with 516 additions and 53 deletions.
133 changes: 126 additions & 7 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ a(2)(4) // => 6
Returns `Function` the curried function


## flyd.Either
Used to create `Right` and `Left` data types to put into streams. These data
types are wrappers around values. A `Right` value is meant to represent a
successful value while a `Left` represents a failure.

### Examples
```js
var s = flyd.stream(flyd.Either.Right(2));
s.right() // 2
```


## `flyd.endsOn`

Changes which `endsStream` should trigger the ending of `s`.
Expand Down Expand Up @@ -140,9 +152,9 @@ Returns `Boolean` `true` if is a Flyd streamn, `false` otherwise
Map a stream
Returns a new stream consisting of every value from `s` passed through
`fn`. I.e. `map` creates a new stream that listens to `s` and
applies `fn` to every new value.
Returns a new stream consisting of all Right values and plain values from `s`
passed through `fn`. I.e. `map` creates a new stream that listens to `s` and
applies `fn` to every Right and plain value.
__Signature__: `(a -> result) -> Stream a -> Stream result`
### Parameters
Expand All @@ -161,6 +173,29 @@ var squaredNumbers = flyd.map(function(n) { return n*n; }, numbers);
Returns `stream` a new stream with the mapped values
## `flyd.mapAll`
Like `flyd.map` except all values, including Lefts, are applied to the function.
__Signature__: `(a -> result) -> Stream a -> Stream result`
### Parameters
* `function` **`Function`** the function to apply


### Examples

```js
var numbers = flyd.stream(Either.Right(1));
var filtered = flyd.mapAll(function(v) {
if (s.isRight()) return v.right;
}, s);
```
Returns `stream` a new stream with the values mapped
## `flyd.merge`
Creates a new stream down which all values from both `stream1` and `stream2`
Expand Down Expand Up @@ -191,9 +226,9 @@ Returns `stream` a stream with the values from both sources
Listen to stream events
Similair to `map` except that the returned stream is empty. Use `on` for doing
Similar to `map` except that the returned stream is empty. Use `on` for doing
side effects in reaction to stream changes. Use the returned stream only if you
need to manually end it.
need to manually end it. This ignores Lefts.
__Signature__: `(a -> result) -> Stream a -> Stream undefined`
Expand Down Expand Up @@ -322,10 +357,66 @@ Returns `stream` a new stram with the functions applied to values
## `stream.isLeft`
Returns `true` if the last value in the stream is a Left value.
__Signature__: Called bound to `Stream a`: `Boolean`
### Examples
```js
var s = flyd.stream(1);
s.isLeft(); // false
s.left(2);
s.isLeft(); // true
```
## `stream.isRight`
Returns `true` if the last value in the stream is a Right value or a plain
value.
__Signature__: Called bound to `Stream a`: `Boolean`
### Examples
```js
var s = flyd.stream(1);
s.isRight(); // true
s(Either.Right(2));
s.isRight(); // true
s.left(-1);
s.isRight(); // false
```
## `stream.left`
If an argument is applied, wraps a value in a Left and pushes it down the stream.
__Signature__: Called bound to `Stream a`: `a -> Stream (Left a)`
If no argument is applied, returns the last value of the stream if it is a left
value. If it is not, an error is thrown.
__Signature__: Called bound to `Stream a`: `a`
### Examples
```js
var s = flyd.stream();
s.left(1);
s.left(); // 1
s(Either.Left(2);
s.left(); // 2
s(3);
s.left(); // TypeError
```
## `stream.map`
Returns a new stream identical to the original except every
value will be passed through `f`.
Returns a new stream identical to the original except all Right values and plain
values will be passed through `f`. This ignores any Left values in the stream.
_Note:_ This function is included in order to support the fantasy land
specification.
Expand All @@ -347,6 +438,28 @@ var squaredNumbers = numbers.map(function(n) { return n*n; });
Returns `stream` a new stream with the values mapped
## `stream.mapAll`
Similar to `stream.map` except all values, including Lefts, are passed through
`f`.
__Signature__: Called bound to `Stream a`: `(a -> b) -> Stream b`
### Parameters
* `function` **`Function`** the function to apply


### Examples

```js
var numbers = flyd.stream(Either.Right(1));
var filtered = numbers.mapAll(function(v) { if (s.isRight()) return v.right; });
```

Returns `stream` a new stream with the values mapped


## `stream.of`


Expand All @@ -366,6 +479,12 @@ var m = n.of(1);
Returns `stream` the new stream


## `stream.right`

An alias for `stream`. Used to set the value of the stream or get the last Right
value out of the stream.


## `stream.toString`

Get a human readable view of a stream
Expand Down
59 changes: 33 additions & 26 deletions ERRORS.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,54 @@
# Errors in flyd
`Kefir` handles streams by seeing it as values wrapped in an event description. These descriptions partition events into `value` and `error`, and `Kefir`'s API is written with that in mind.

The goal of this is to determine how to bring functionality similar to that into `flyd`.

## Ethos
* It should not be the concern of `flyd` to handle exceptions for the user -- any `throw` should result in a hard failure.
* Silent failures are bad (current way `flyd` handles Promise.reject)
* API must follow [fantasty-land](https://github.com/fantasyland/fantasy-land)
* Unopinionated implementation as possible

+ It should not be the concern of `flyd` to handle exceptions for the user -- any `throw` should result in a hard failure.
+ Silent failures are bad (current way `flyd` handles Promise.reject)
+ Be as unopinionated in implementation as possible
+ Be functional in design
+ Be as backward compatible as possible with the current api

## Concepts
+ The stream is of `events`
+ Each stream has a `left` and a `right` side
+ Each stream has a `left` and a `right` side (like an Either)
+ The right side is the domain objects
+ The left side is meta in our case errors
+ Keep the api by default operating on `right`
+ The left side is meta (in most cases errors)
+ By default the api operates on the `right` side

## The Api
`s` is a stream

### Setting data s(...) is overloaded
+ `s(value)` alias to `s.right(value)` is the default case takes a value makes it a right and pushes it down the stream
+ `s(value)` is the default case takes a value makes it a right and pushes it down the stream
+ `s(promise)` if the promise resolves pushes a right, otherwise pushes a left
+ `s(either)` pushes a right or left based on either.left either.right (maybe an internal `isEither` function)
+ *new `s.left(value)` sets the stream to a left of `value`
+ `s(either)` pushes down right or left based on either.left either.right
+ `s.left(value)` sets the stream to a left of `value`

### Getting data
+ `s()` alias to `s.right()` get the last right value or throws an exception if there is a left value
+ *new `s.left()` get the last left value or throws an exception if there is a right value
+ *new `s.isRight()` and `s.isLeft()` return boolean so you know what the stream contains
+ `s()` get the last right value or throws an exception if there is a left value
+ `s.left()` get the last left value or throws an exception if there is a right value

### Checking stream state
+ `s.isLeft()` return boolean so you know what the stream contains

### Core functions
+ `.map()` works only on rights and ignores lefts
+ *new `.mapAll()` gets all events as an `Either` or some other lightweight type defining `lefts` and `rights`
+ `.mapAll()` gets all events as an `Either`
+ `.combine()` and `.merge()` stay the same they work on streams
+ `.scan()` needs more thought
+ `ap()` works on `rights` only
+ `.scan()` works on `rights` only
+ `.on()` works on `rights` only

### Move `.transduce()` to a module

### Add some helper modules
+ `.onAll()`
+ `.mapLeft()`
+ `.swap()` swaps `rights` and `lefts` - might want this in core for performance reasons
+ others ...
### The Either implementation
There are no additional dependencies and we have provided a minimal implementation for basic use. If you plan on using `.mapAll` we recommend overriding the methods in flyd.Either. You can use [folktale/data.either](https://github.com/folktale/data.either) for example as shown below.
```
var DE = require('data.either');
flyd.Either.Right = DE.Right;
flyd.Either.Left = DE.Left;
flyd.Either.isEither = function(obj) { return obj instanceof DE; };
flyd.Either.isRight = function(e) { return e.isRight; };
flyd.Either.getRight = function(e) { return e.value; };
flyd.Either.getLeft = function(e) { return e.value; };
```

### Other functionality
Keeping with the ethos of flyd any further functions like `.swap` or `.onAll` should be implemented as modules.
Loading

0 comments on commit f264be8

Please sign in to comment.