Better repo architecture.

This commit is contained in:
Julien Fontanet 2015-04-07 18:01:33 +02:00
parent dd1d16f91c
commit 5ba7493613
9 changed files with 299 additions and 124 deletions

View File

@ -0,0 +1,65 @@
# http://EditorConfig.org
#
# Julien Fontanet's configuration
# https://gist.github.com/julien-f/8096213
# Top-most EditorConfig file.
root = true
# Common config.
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespaces = true
# CoffeeScript
#
# https://github.com/polarmobile/coffeescript-style-guide/blob/master/README.md
[*.{,lit}coffee]
indent_size = 2
indent_style = space
# Markdown
[*.{md,mdwn,mdown,markdown}]
indent_size = 4
indent_style = space
# Package.json
#
# This indentation style is the one used by npm.
[/package.json]
indent_size = 2
indent_style = space
# Jade
[*.jade]
indent_size = 2
indent_style = space
# JavaScript
#
# Two spaces seems to be the standard most common style, at least in
# Node.js (http://nodeguide.com/style.html#tabs-vs-spaces).
[*.js]
indent_size = 2
indent_style = space
# Less
[*.less]
indent_size = 2
indent_style = space
# Sass
#
# Style used for http://libsass.com
[*.s[ac]ss]
indent_size = 2
indent_style = space
# YAML
#
# Only spaces are allowed.
[*.yaml]
indent_size = 2
indent_style = space

View File

@ -1,28 +1,7 @@
# Logs
logs
*.log
/bower_components/
/dist/
# Runtime data
pids
*.pid
*.seed
npm-debug.log
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules
# Users Environment Variables
.lock-wscript
!node_modules/*
node_modules/*/

View File

@ -0,0 +1,2 @@
*.spec.js
*.spec.js.map

View File

@ -0,0 +1,5 @@
language: node_js
node_js:
- 'iojs'
- '0.12'
- '0.10'

View File

@ -1,2 +1,182 @@
# collection
A collection class with a batch feature with commit/rollback/replay
# collection [![Build Status](https://travis-ci.org/marsaud/collection.png?branch=master)](https://travis-ci.org/marsaud/collection)
> Generic in-memory collection with events
## Install
Installation of the [npm package](https://npmjs.org/package/collection):
```
> npm install --save collection
```
## Usage
```javascript
var Collection = require('collection')
```
### Creation
```javascript
// Creates a new collection.
var col = new Collection()
```
### Manipulation
**Inserting a new entry**
```javascript
col.add('foo', true)
```
**Updating an existing entry**
```javascript
col.update('foo', false)
```
**Inserting or updating an entry**
```javascript
col.set('bar', true)
```
**Notifying an external update**
> If an entry is an object, it can be updated directly without using
> the `set`/`update` methods.
>
> To make sure the collection stay in sync and the correct events are
> sent, the `touch` method can be used to notify the change.
```javascript
var baz = {}
col.add('baz', baz)
baz.prop = true
col.touch('baz')
```
> Because this is a much used pattern, `touch` returns the entry to
> allow its direct modification.
```javascript
col.touch('baz').prop = false
```
**Removing an existing entry**
```javascript
col.unset('bar')
```
**Removing all entries**
```javascript
col.clear()
```
### Query
**Checking the existence of an entry**
```javascript
var hasBar = col.has('bar')
```
**Getting an existing entry**
```javascript
var foo = col.get('foo')
// The second parameter can be used to specify a fallback in case the
// entry does not exist.
var bar = col.get('bar', 6.28)
```
**Getting the number of entries**
```javascript
var size = col.size
```
### Events
> The events are emitted asynchronously (at the next turn/tick of the
> event loop) and are deduplicated which means, for instance, that an
> addition followed by an update will result only in a single
> addition.
**New entries**
```javascript
col.on('add', (added) => {
forEach(added, (value, key) => {
console.log('+ %s: %j', key, value)
})
})
```
**Updated entries**
```javascript
col.on('update', (updated) => {
forEach(updated, (value, key) => {
console.log('- %s: %j', key, value)
})
})
```
**Removed entries**
```javascript
col.on('remove', (removed) => {
// For consistency, `removed` is also a map but contrary to `ædded`
// and `updated`, the values associated to the keys are not
// significant since the entries have already be removed.
forEach(removed, (value, key) => {
console.log('± %s', key)
})
})
```
## Development
### Installing dependencies
```
> npm install
```
### Compilation
The sources files are watched and automatically recompiled on changes.
```
> npm run dev
```
### Tests
```
> npm run test-dev
```
## Contributions
Contributions are *very* welcomed, either on the documentation or on
the code.
You may:
- report any [issue](https://github.com/marsaud/collection/issues)
you've encountered;
- fork and create a pull request.
## License
ISC © [Vates SAS](http://vates.fr)

View File

@ -1,24 +1,50 @@
{
"name": "xo-collection",
"private": true,
"name": "collection",
"version": "0.0.0",
"description": "A generice batch collection attempt",
"main": "collection.js",
"license": "ISC",
"description": "Generic in-memory collection with events",
"keywords": [],
"homepage": "https://github.com/marsaud/collection",
"bugs": "https://github.com/marsaud/collection/issues",
"repository": {
"type": "git",
"url": "https://github.com/marsaud/collection.git"
},
"author": {
"name": "Fabrice Marsaud",
"email": "fabrice.marsaud@vates.fr"
},
"preferGlobal": false,
"main": "dist/",
"files": [
"dist/"
],
"dependencies": {
"babel-runtime": "^5",
"lodash.foreach": "^3.0.2",
"make-error": "^0.3.0"
},
"devDependencies": {
"babel": "^4.7.16",
"chai": "^2.2.0",
"babel": "^5",
"chai": "*",
"dirty-chai": "^1.2.0",
"event-to-promise": "^0.3.2",
"leche": "^2.1.1",
"mocha": "^2.2.1",
"sinon": "^1.14.1"
"mocha": "*",
"sinon": "^1.14.1",
"standard": "*"
},
"scripts": {
"test": "mocha --require babel/register *.spec.js"
"build": "mkdir --parents dist && babel --optional=runtime --compact=true --source-maps --out-dir=dist/ src/",
"dev": "mkdir --parents dist && babel --watch --optional=runtime --compact=true --source-maps --out-dir=dist/ src/",
"prepublish": "npm run build",
"test": "standard && npm run build && mocha 'dist/**/*.spec.js'",
"test-dev": "standard && mocha --watch --reporter=min 'dist/**/*.spec.js'"
},
"author": "Fabrice Marsaud <fabrice.marsaud@vates.fr>",
"license": "aGPLv3"
"standard": {
"ignore": [
"dist/**"
]
}
}

View File

@ -1,11 +1,11 @@
import events from 'events'
import makeError from 'make-error'
export const DuplicateEntry = makeError('DuplicateEntry')
export const BufferAlreadyFlushed = makeError('BufferAlreadyFlushed')
export const DuplicateEntry = makeError('DuplicateEntry')
export const IllegalAdd = makeError('IllegalAdd')
export const NoSuchEntry = makeError('NoSuchEntry')
export const IllegalTouch = makeError('IllegalTouch')
export const NoSuchEntry = makeError('NoSuchEntry')
export default class Collection extends events.EventEmitter {
constructor () {

View File

@ -1,12 +1,11 @@
/* eslint-env mocha */
import Collection, {DuplicateEntry, NoSuchEntry} from './collection'
import Collection, {DuplicateEntry, NoSuchEntry} from './index'
import eventToPromise from 'event-to-promise'
import sinon from 'sinon'
import chai from 'chai'
const expect = chai.expect
import chai, {expect} from 'chai'
import dirtyChai from 'dirty-chai'
chai.use(dirtyChai)

View File

@ -1,81 +0,0 @@
import Collection from './collection';
let col = new Collection.Collection();
col.add('foo', 1);
// An object with id property
// ====================
// Jouer sur le passage par référence, et la convention d'objets avec une prop ID
let obj = {id: 'bar', content: 2};
col.add(obj);
console.log(obj.get('bar'));
// > {id: 'bar', content: 2}
col.bufferChanges(true);
col.update('bar').content = 4;
// update accesses obj at bar key and marks bar as updated. No event emitted.
col.get('bar').content = 5;
obj.content = 6;
// bar is already marked as updated, so ...
col.flush();
// ...Emits an update as bar has been "updated to 6"
col.bufferChanges(true);
col.update(obj).content = 7; // Short writing without knowing ID
// WARNING, do not change ID after adding ...
col.bufferChanges(false);
col.flush();
// No event emitted ... exception thrown ?...
col.bufferChanges(true);
col.update(obj);
col.flush();
// Emits an update event as bar has been "updated to 7"
// ------------------------------------------------------------
// Special cases :
let foo = {id: 'foo'};
let bar = {id: 'bar'};
col.add(foo);
try {
col.update(foo, bar);
} catch(e) {
// Throws an instant exception on ID violation
console.error(e);
}
try {
col.udpate('foo', bar);
} catch(e) {
// Same
console.error(e);
}
try {
col.update(foo).id = 'bar';
} catch (e) {
// Throws an exception at Event emission (key !== content.id)
console.error(e);
}
col.bufferChanges(true);
col.remove(foo);
col.add(foo);
col.bufferChanges(false);
// Silent...(No events)
col.bufferChanges(true);
col.update(foo).id = 'bar';
// Nothing happens
try {
col.flush();
} catch (e) {
// Throws
console.log(e);
}