Skip to content

Commit

Permalink
Make models streamable (#166)
Browse files Browse the repository at this point in the history
* make models streamable.

* typo.

* fix in docs.

* get full test coverage.
  • Loading branch information
fahad19 authored Apr 22, 2017
1 parent f262963 commit abf9aee
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 5 deletions.
66 changes: 65 additions & 1 deletion packages/frint-model/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
<!-- MarkdownTOC autolink=true bracket=round -->

- [Guide](#guide)
- [Installation](#installation)
- [Terminologies](#terminologies)
- [Usage](#usage)
- [API](#api)
- [Model](#model)
- [createModel](#createmodel)
- [model](#model-1)

<!-- /MarkdownTOC -->

Expand All @@ -29,6 +31,7 @@ Via [unpkg](https://unpkg.com) CDN:

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script>

<script src="https://unpkg.com/frint-model@latest/dist/frint-model.min.js"></script>

Expand All @@ -39,7 +42,8 @@ Via [unpkg](https://unpkg.com) CDN:

## Terminologies

* `Model`: An object class that holds data, e.g. configuration, customer information, etc.
* `Model`: An object that holds data, e.g. configuration, customer information, etc.
* `attributes`: The actual data in plain object, which is fed to the Model during construction.

## Usage

Expand Down Expand Up @@ -73,6 +77,19 @@ const shirt = new Shirt({
const color = shirt.getColor(); // blue
const size = shirt.getSize(); // medium
```

The model instance can also be observed for changes:

```js
shirt.get$().subscribe(function (shirtAttributes) {
// triggered when the model had any change
});

shirt.get$('color').subscribe(function (color) {
// triggered when the model's `color` key changes
});
```

---

# API
Expand Down Expand Up @@ -125,3 +142,50 @@ const Shirt = createModel({
},
});
```

## model

> const model = new Model();
The `Model` instance

### model.get

> model.get(key)
#### Arguments

1. `key` (`String`): Can be dot separated, like `deep.nested.path`. If empty, it returns all the attributes.

#### Returns

`Any`: The key's value.

### model.set

> model.set(key, value)
Sets the `value` for given `key` in the model.

#### Arguments

1. `key` (`String`)
1. `value` (`Any`)

#### Returns

`void`.

### get$

> get$(key)
Streams the model for given key.

#### Arguments

1. `key` (`String`)

#### Returns

`Observable`.
3 changes: 2 additions & 1 deletion packages/frint-model/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"frint"
],
"dependencies": {
"lodash": "^4.13.1"
"lodash": "^4.13.1",
"rxjs": "^5.3.0"
},
"bugs": {
"url": "https://github.com/Travix-International/frint/issues"
Expand Down
33 changes: 31 additions & 2 deletions packages/frint-model/src/Model.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,44 @@
import _ from 'lodash';
import { BehaviorSubject } from 'rxjs';

function Model(attributes) {
this.attributes = Object.assign({}, attributes);
this.$ = null;
}

Model.prototype.get = function get(key) {
function getFromAttributes(attributes, key) {
if (typeof key === 'undefined') {
return attributes;
}

if (typeof key !== 'string') {
return undefined;
}

return _.get(this.attributes, key);
return _.get(attributes, key);
}

Model.prototype.get = function get(key) {
return getFromAttributes(this.attributes, key);
};

Model.prototype.set = function set(key, value) {
_.set(this.attributes, key, value);

if (this.$) {
this.$.next(this.attributes);
}
};

Model.prototype.get$ = function get$(key) {
if (!this.$) {
this.$ = new BehaviorSubject(this.attributes);
}

return this.$
.map((attributes) => {
return getFromAttributes(attributes, key);
});
};

Model.prototype.toJS = function toJS() {
Expand Down
1 change: 0 additions & 1 deletion packages/frint-model/src/Model.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ describe('frint-model › Model', () => {
});

it('must return an undefined using .get() method if attribute doesn\'t exist', () => {
expect(myModelInstance.get()).to.be.deep.equal(undefined);
expect(myModelInstance.get('attributeNotExist')).to.be.deep.equal(undefined);
});
});
52 changes: 52 additions & 0 deletions packages/frint-model/src/createModel.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,56 @@ describe('frint-model › createModel', () => {
foo: 'bar'
});
});

it('returns undefined when non-string key is given', () => {
expect(myModelInstance.get(1)).to.be.equal(undefined);
expect(myModelInstance.get(true)).to.be.equal(undefined);
expect(myModelInstance.get(() => true)).to.be.equal(undefined);
});

describe('streams model attributes', function () {
const Person = createModel();

it('does not start observing until needed', function () {
const person = new Person({ name: 'Rowena Revenclaw' });
expect(person.$).to.equal(null);
});

it('streams all attributes', function (done) {
const person = new Person({ name: 'Helga Hufflepuff' });
person.get$().subscribe(function (personAttributes) {
expect(personAttributes).to.deep.equal({
name: 'Helga Hufflepuff',
});

done();
});
});

it('streams initial value for key', function (done) {
const person = new Person({ name: 'Salazar Slytherin' });
person.get$('name').subscribe(function (name) {
expect(name).to.equal('Salazar Slytherin');

done();
});
});

it('streams updated value for key', function () {
const person = new Person({ name: 'Salazar Slytherin' });
person.set('name', 'Rowena Revenclaw');

const names = [];
person.get$('name').subscribe(function (name) {
names.push(name);
});

person.set('name', 'Godric Gryffindor');

expect(names).to.deep.equal([
'Rowena Revenclaw',
'Godric Gryffindor',
]);
});
});
});

0 comments on commit abf9aee

Please sign in to comment.