diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4a7ea30 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e1ac5c2 --- /dev/null +++ b/.travis.yml @@ -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 diff --git a/README.md b/README.md index a220e8e..2c1d46a 100644 --- a/README.md +++ b/README.md @@ -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`. @@ -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) @@ -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++; } @@ -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) @@ -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++; } @@ -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 @@ -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(), @@ -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`: diff --git a/package.json b/package.json index c09fe72..7c194e0 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,9 @@ "type": "git", "url": "https://github.com/jlongster/transducers.js.git" }, + "scripts": { + "test": "gulp && mocha ./build/*.spec.js" + }, "keywords": [ "browser", "client", @@ -14,19 +17,19 @@ "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" } } diff --git a/transducers.js b/transducers.js index 019fe3b..88d0b91 100644 --- a/transducers.js +++ b/transducers.js @@ -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) {