Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
18 changes: 18 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
sudo: false

language: node_js

node_js:
- 6
- 4

cache:
directories:
- node_modules

install:
- npm i -g npm@latest
- npm install

notifications:
email: false
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
transducers.js
==============

# transducers.js
[![Build Status](https://travis-ci.org/jlongster/transducers.js.svg?branch=master)](https://travis-ci.org/jlongster/transducers.js)
[![NPM version](https://badge.fury.io/js/transducers.js.svg)](http://badge.fury.io/js/transducers.js)
[![Dependency Status](https://img.shields.io/david/jlongster/transducers.js.svg)](https://david-dm.org/jlongster/transducers.js)
[![npm](https://img.shields.io/npm/dm/transducers.js.svg?maxAge=2592000)]()

A small library for generalized transformation of data. This provides a bunch of transformation functions that can be applied to any data structure. It is a direct port of Clojure's [transducers](http://blog.cognitect.com/blog/2014/8/6/transducers-are-coming) in JavaScript. Read more in [this post](http://jlongster.com/Transducers.js--A-JavaScript-Library-for-Transformation-of-Data).

The algorithm behind this, explained in the above post, not only allows for it to work with any data structure (arrays, objects, iterators, immutable data structures, you name it) but it also provides better performance than other alternatives such as underscore or lodash. This is because there are no intermediate collections. See [this post](http://jlongster.com/Transducers.js-Round-2-with-Benchmarks) for benchmarks.

```
npm install transducers.js
```bash
npm install transducers.js --save
```

For browsers, grab the file `dist/transducers.js`.
Expand All @@ -16,7 +21,7 @@ When writing programs, we frequently write methods that take in collections, do
A transducer is a function that takes a reducing function and returns a new one. It can perform the necessary work and call the original reducing function to move on to the next "step". In this library, a transducer a little more than that (it's actually an object that also supports init and finalizer methods) but generally you don't have to worry about these internal details. Read [my post](http://jlongster.com/Transducers.js--A-JavaScript-Library-for-Transformation-of-Data) if you want to learn more about the algorithm.

```js
var transform = compose(
const transform = compose(
map(x => x * 3),
filter(x => x % 2 === 0),
take(2)
Expand All @@ -26,7 +31,7 @@ seq([1, 2, 3, 4, 5], transform);
// -> [ 6, 12 ]

function* nums() {
var i = 1;
const i = 1;
while(true) {
yield i++;
}
Expand Down Expand Up @@ -67,7 +72,7 @@ The above functions optionally take a collection to immediately perform the tran
The signature of running an immediate map is the same familiar one as seen in lodash and underscore, but now you can drop the collection to make a transducer and run multiple transformations with good performance:

```js
var transform = compose(
const transform = compose(
map(x => x + 1),
filter(x => x % 2 === 0),
take(2)
Expand Down Expand Up @@ -111,7 +116,7 @@ toArray({ foo: 1, bar: 2 });

// Make an array from an iterable
function* nums() {
var i = 1;
const i = 1;
while(true) {
yield i++;
}
Expand All @@ -120,7 +125,7 @@ into([], take(3), nums());
// -> [ 1, 2, 3 ]

// Lazily transform an iterable
var iter = seq(nums(), compose(map(x => x * 2),
const iter = seq(nums(), compose(map(x => x * 2),
filter(x => x > 4));
iter.next().value; // -> 6
iter.next().value; // -> 8
Expand Down Expand Up @@ -176,7 +181,7 @@ The builtin transformations perform well because they minimize allocations, but
This not only works with all the JavaScript data structures you can think of, but it even works for things like streams. Soon channels from [js-csp](https://github.com/ubolonton/js-csp) will be able to take a transformation and you get all of this for channels for free:

```js
var ch = chan(1, compose(
const ch = chan(1, compose(
cat,
map(x => x + 1),
dedupe(),
Expand All @@ -190,7 +195,7 @@ While it's great that you can apply transducers to custom data structures, it's

This conforms to the [official transducer spec](https://github.com/cognitect-labs/transducers-js/issues/20) so if you implement this, you can use it with all transducer libraries that conform to it.

To implement the transducer protocol, you add methods to the prototype of your data structure. A transformer is an object with three methods: `init`, `result`, and `step`. `init` returns a new empty object, `result`, can perform any finalization steps on the resulting collection, and `step` performs a reduce.
To implement the transducer protocol, you add methods to the prototype of your data structure. A transformer is an object with three methods: `init`, `result`, and `step`. `init` returns a new empty object, `result`, can perform any finalization steps on the resulting collection, and `step` performs a reduce.

These methods are namespaced and in the future could be symbols. Here's what it looks like for `Immutable.List`:

Expand Down
25 changes: 14 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,29 @@
"type": "git",
"url": "https://github.com/jlongster/transducers.js.git"
},
"scripts": {
"test": "gulp && mocha ./build/*.spec.js"
},
"keywords": [
"browser",
"client",
"functional",
"util"
],
"devDependencies": {
"benchmark": "^1.0.0",
"benchmark": "^2.1.1",
"es6-macros": "0.0.7",
"expect.js": "^0.3.1",
"gulp": "^3.8.8",
"gulp-header": "^1.1.1",
"gulp-sourcemaps": "^1.1.5",
"gulp-sweetjs": "^0.5.4",
"gulp": "^3.9.1",
"gulp-header": "^1.8.8",
"gulp-sourcemaps": "^1.6.0",
"gulp-sweetjs": "^0.6.1",
"lodash": "lodash/lodash",
"mocha": "^1.21.4",
"source-map-support": "^0.2.7",
"sweet.js": "^0.7.1",
"underscore": "^1.7.0",
"webpack": "^1.4.0-beta9",
"immutable": "^3.7.1"
"mocha": "^3.0.2",
"source-map-support": "^0.4.2",
"sweet.js": "^2.2.1",
"underscore": "^1.8.3",
"webpack": "^1.13.2",
"immutable": "^3.8.1"
}
}
5 changes: 3 additions & 2 deletions transducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ var protocols = {
};

function throwProtocolError(name, coll) {
throw new Error("don't know how to " + name + " collection: " +
coll);
throw new Error(
"don't know how to " + name + " collection: " + coll
);
}

function fulfillsProtocol(obj, name) {
Expand Down