Skip to content

Commit

Permalink
update changelog and package.json
Browse files Browse the repository at this point in the history
  • Loading branch information
ds300 committed Dec 15, 2015
1 parent cf3c7de commit 458bda6
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 1 deletion.
226 changes: 226 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,229 @@
## 0.12.0

### Highlights
- `Derivable#derive` does more stuff (destructuring, property/index lookup, regex matching)
- `Derivable#react` now provides options for declarative lifecycle control.
- Composite Lenses
- Fine-grained Equality checks
- Removed a bunch of API cruft.

### New Stuff

#### Declarative Reactor Lifecycle Control

Prior to this release, the lifecycles of Reactors were controlled imperatively using the`Reactor#start` and `Reactor#stop` methods. This was somewhat verbose and, more importantly, went against the grain of this whole declarative/reactive thing we have going here.

Now there is a better way: providing a lifetime configuration object as a second argument to the `.react` method. Here are the options:

```javascript
interface Lifecycle {
from?: (() => boolean) | Derivable<boolean>;
when?: (() => boolean) | Derivable<boolean>;
until?: (() => boolean) | Derivable<boolean>;
skipFirst?: boolean;
once?: boolean;
onStart?: () => void;
onStop?: () => void;
}
```
`from` determines this initialization time of the reactor. i.e. when the given derivable becomes truthy, the reactor is initialized.

`when` causes `.start` and `.stop` to be called when the given derivable becomes truthy and falsey respectively (but not before the reactor has been initialized, and not after it has been killed).

`until` causes the reactor to be killed when the given derivable becomes truthy.

`skipFirst` causes the first invocation of the reactor (after it has been initialized, and when `when` is truthy) to be ignored. This is typically used if the state of the world at the time of declaration is such that invoking the reactor would be redundant or harmful.

`once` causes the reactor to be killed immediately following its first invocation.

`onStart` and `onStop` are the same lifecycle hooks that were previously provided.

Example usage:

```typescript
const n = atom(0);

n.react(n => console.log(`n is ${n}`), {
from: () => n.get() > 0, // start when n > 0
when: () => n.get() %2 === 0, // only react when n is even
until: () => n.get() => 5 // stop when n >= 5
});
// ... no output

n.set(1);
// ... no output (n is odd)

n.set(2);
// $> n is 2

n.set(3);
// ... no output (n is odd)

n.set(4);
// $> n is 4

n.set(5);
// ... no output (reactor was killed)

n.set(4);
// ... no output (reactors don't come back from the dead)
```

#### `Derivable#derive` new capabilities

- RegExp matching

```javascript
const string = atom('hello world');
const firstLetters = string.derive(/\b\w/g);

firstLetters.get();
// => ['h', 'w']
```

- Property/Index lookup
```javascript
const obj = atom({foo: 'FOO!'});
const foo = obj.derive('foo');

foo.get();
// => 'FOO!'

const arr = atom(['one', 'two']);
const first = arr.derive(0);

first.get();
// => 'one'
```

- Destructuring
```javascript
const string = atom('hello world')
const [len, upper, firstChar, words] = string.derive([
'length', s => s.toUpperCase(), 0, /\w+/g
]);
```

Also note that these work with derivable versions of the arguments:

```javascript
const arr = atom(['one', 'two', 'three']);
const idx = atom(0);
const item = arr.derive(idx);

item.get();
// => 'one'

idx.set(1);
item.get();
// => 'two'
```



#### Composite Lenses
Previously 'lensed atoms' could only have one underlying atom. It is now possible to lens over an arbitrary number of atoms using the new `CompositeLens` interface:

```typescript
type CompositeLens<T> = {
// no-arg getter uses lexical closure to deref and combine atoms
get: () => T,

// one-arg setter to tease apart the value being set and push it
// up to the atoms manually
// runs in an implicit transaction.
set: (value: T) => void
}
```
Instances of which may be passed to a new 1-arity version of the top-level `lens` function to create lensed atoms:
```typescript
const $FirstName = atom('John');
const $LastName = atom('Steinbeck');

const $Name = lens({
get: () => $FirstName.get() + ' ' + $LastName.get(),
set: (val) => {
const [first, last] = val.split(' ');
$FirstName.set(first);
$LastName.set(last);
}
});

$Name.get(); // => 'John Steinbeck'

$Name.set('James Joyce').

$LastName.get(); // => 'Joyce'
```

#### Fine-grained Equality Control

Because JS has no standard way to override equality comparisons, DerivableJS makes it possible to inject equality-checking logic at the module level using the top-level function [`withEquality`](http://ds300.github.io/derivablejs/#derivable-withEquality) which returns a new instance of DerivableJS using the given equality-checking function.

It is now also possible to do this on a per-derivable basis.

The new `Derivable#withEquality` method creates a clone of a derivable, which new derivable uses the given equality-checking function. It looks like this:

```javascript
import { equals } from 'ramda'

const $Person = atom({name: "Steve"}).withEquality(equals);
$Person.react(({name}) => console.log(`name is ${name}`));
// $> name is Steve

$Person.set({name: "Steve"});
// ... no output (this would print the name again
// if using DerivableJS's standard equality function
// which only does strict-equality (===) checks if no .equals
// method is present on the arguments being compared)
```

#### `atomic`/`atomically`

These new top-level functions are identical to `transaction`/`transact` respectively except that they do not create new (nested) transactions if already in a transaction. This is almost always the desired behaviour, unless you want to gracefully abort transactions.

### Breaking changes:

##### The `Derivable#react` method:
- no longer returns a Reactor.
- only accepts functions as the first argument.
- does not bind the given function to the context of the resultant reactor.

You can get the old behaviour by converting

```javascript
d.react(f);
```
to
```javascript
d.reactor(f).start().force();
```

Although it is recommended to switch to using the new declarative lifecycle stuffs if possible.

##### The `Derivable#reactWhen` method was removed
Use `$d.react(r, {when: $when})`.

##### Dependent reactors are no longer stopped automatically when their governors are.
That was a silly idea...

##### The following top-level functions were removed due to cruftiness:
- `derive` (except the tagged template string version, that's still there). Use the `Derivable#derive` method instead.
- `mDerive`. Use the `Derivable#mDerive` method instead.
- 2+ arity version of `lens`. Use the `Derivable#lens` method instead.
- `lookup`. Use the `Derivable#derive(string|number)` method instead.
- `destruct`. Use the `Derivable#derive([string|number])` method instead.
- `ifThenElse`. Use the `Derivable#then` method instead.
- `mIfThenElse`. Use the `Derivable#mThen` method instead.
- `not`. Use the `Derivable#not` method instead.
- `switchCase`. Use the `Derivable#switch` method instead.
- `get`. Use the `Derivable#get` method instead.
- `set`. Use the `Atom#set` method instead.
- `swap`. Use the `Atom#swap` method instead.


## 0.11.0

#### `Derivable#reactWhen` method
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "derivable",
"version": "0.11.0",
"version": "0.12.0",
"description": "Functional Reactive State for JavaScript & TypeScript",
"author": "David Sheldrick",
"files": [
Expand Down

0 comments on commit 458bda6

Please sign in to comment.