mori
Version:
Persistent Data Structures for JavaScript
221 lines (157 loc) • 5.18 kB
Markdown
# mori
<img src="http://cloud.github.com/downloads/swannodette/mori/mori.png" alt="Mori" title="Mori"/>
A simple bridge to ClojureScript's persistent data structures and [supporting APIs](http://swannodette.github.io/mori/) for vanilla JavaScript. Pull requests welcome.
## Breaking changes in 0.3.0
This release includes several breaking changes:
* More idiomatic JavaScript API naming scheme
* No EDN reader
* No zippers
* No data diffing
These missing options will likely find their way back into Mori when
Mori builds can leverage Google Closure Modules.
## Getting it
You can install the latest release via npm:
```shell
npm install mori
```
The installed package contains a single optimized JavaScript file `mori.js`.
Load `mori` in your Node.js programs as you would any other module:
```javascript
var mori = require("mori");
```
In a browser, you can load mori with a script tag, as you would any other JavaScript library:
```html
<script src="mori.js" type="text/javascript"></script>
```
You can also load it as an AMD module, e.g. with [RequireJS](http://requirejs.org/).
## Build
### Prerequisites
You will first need to install the [Java](http://www.oracle.com/technetwork/java/javase/downloads/index.html) SDK, if it's not already installed on your system.
On Windows, you will need to manually install [Leiningen](http://github.com/technomancy/leiningen). On UNIX-like systems, Leiningen will be installed within the project automatically if the `lein` executable is not found on your path or if your `lein` version predates `2.0.0`.
### Clone the repo
```shell
git clone https://github.com/swannodette/mori.git
cd mori
```
### On a UNIX-like system build with
```shell
./scripts/build.sh
```
### Alternatively using npm
```shell
npm run-script build
```
### On Windows
```shell
./scripts/build.ps1
```
The build process will generate an optimized JavaScript file `mori.js`, which is suitable for use with Node.js, or in a Web browser or other JavaScript environments. You can also load it as an AMD module.
## Usage
You can use it from your projects like so:
```javascript
var inc = function(n) {
return n+1;
};
mori.intoArray(mori.map(inc, mori.vector(1,2,3,4,5)));
// => [2,3,4,5,6]
```
Efficient non-destructive updates!
```javascript
var v1 = mori.vector(1,2,3);
var v2 = mori.conj(v1, 4);
v1.toString(); // => '[1 2 3]'
v2.toString(); // => '[1 2 3 4]'
```
```javascript
var sum = function(a, b) {
return a + b;
};
mori.reduce(sum, mori.vector(1, 2, 3, 4)); // => 10
```
Lazy sequences!
```javascript
var _ = mori;
_.intoArray(_.interpose("foo", _.vector(1, 2, 3, 4)));
// => [1, "foo", 2, "foo", 3, "foo", 4]
```
Or if it's more your speed, use it from CoffeeScript!
```coffeescript
inc = (x) -> x+1
r = mori.map inc, mori.vector(1,2,3,4,5)
mori.intoArray r
```
### Documentation
You can find extensive [documentation and examples](http://swannodette.github.io/mori/) here.
## More Examples
### Efficient Freeze/Thaw
For vectors and maps we provide an efficient thaw and freeze
operations:
```javascript
var m = mori;
// ~220ms with V8 version 3.29.80 MBP 2.26ghz
for(var j = 0; j < 10; j++) {
var s = new Date();
var arr = [];
for(var i = 0; i < 10000000; i++) {
arr.push(i);
}
print("Array push " + arr.length + " items " + ((new Date())-s));
gc();
}
// ~70ms
for(var j = 0; j < 10; j++) {
s = new Date();
var mv = m.mutable.thaw(m.vector());
for(var i = 0; i < 10000000; i++) {
mv = m.mutable.conj.f2(mv, i);
}
var v = m.mutable.freeze(mv);
print("Mutable vector conj " + m.count(v) + " items " + ((new Date())-s));
gc();
}
```
### ES6 Map/Set inspired interfaces
All Mori maps and sets support all the non-mutating methods of the
proposed ES6
[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
and
[Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
interfaces. The main difference with the spec is that key lookup is
based on value not reference. `keys`, `values`, and `entries` methods
return the proposed mutable iterators:
```javascript
var m = mori;
var h = m.hashMap("foo", 1, "bar", 2);
h.has("foo"); // => true
h.get("foo"); // => 1
var iter = h.keys();
iter.next(); // => {done: false, value: "foo"}
```
This feature is subject to changes in the ES6 proposal.
### Transducers
Mori includes Transducers. Zero allocation collection operations FTW:
```javascript
var m = mori;
var a = [];
for(var i = 0; i < 1000000; i++) {
a.push(i);
}
// make it immutable
var v = m.into(m.vector(), a);
function time(f) {
var s = new Date();
f();
console.log(((new Date())-s)+"ms");
}
// ~190ms V8 version 3.29.80 MBP 2.26ghz
time(function() {
var xf = m.comp(m.map(m.inc), m.map(m.inc), m.map(m.inc));
return m.transduce(xf, m.completing(m.sum), 0, v);
}, 10);
// ~440ms
time(function() {
return a.map(m.inc).map(m.inc).map(m.inc).reduce(function(a,b){return a+b;}, 0);
}, 10);
```
Copyright (C) 2012-2015 David Nolen and contributors
Distributed under the [Eclipse Public License](https://raw.github.com/swannodette/mori/master/epl-v10.html), the same as Clojure.