Comparing version 0.1.1 to 0.1.2
# Contributing | ||
Questions, comments, bug reports, and pull requests are all welcome. Submit them at [the project on GitHub](https://github.com/Obvious/sculpt/). If you haven't contributed to a [Medium](http://github.com/Obvious/) project before please head over to the [Open Source Project](https://github.com/Obvious/open-source#note-to-external-contributors) and fill out an contributor license agreement (it should be pretty painless). | ||
Questions, comments, bug reports, and pull requests are all welcome. Submit them at [the project on GitHub](https://github.com/Medium/sculpt/). If you haven't contributed to a [Medium](http://github.com/Medium/) project before please head over to the [Open Source Project](https://github.com/Medium/open-source#note-to-external-contributors) and fill out an contributor license agreement (it should be pretty painless). | ||
@@ -11,3 +11,3 @@ Bug reports that include steps-to-reproduce (including code) are the best. Even better, make them in the form of pull requests. | ||
[Fork](https://github.com/Obvious/sculpt/fork) the project on GitHub and make a pull request from your feature branch against the upstream master branch. Consider rebasing your branch onto the latest master before sending a pull request to make sure there are no merge conflicts, failing tests, or other regressions. | ||
[Fork](https://github.com/Medium/sculpt/fork) the project on GitHub and make a pull request from your feature branch against the upstream master branch. Consider rebasing your branch onto the latest master before sending a pull request to make sure there are no merge conflicts, failing tests, or other regressions. | ||
@@ -34,3 +34,3 @@ ### Code style | ||
If you introduce changes or new features that will affect users, consider updating or adding the relevant section of the [readme](https://github.com/Obvious/sculpt/blob/master/README.md). | ||
If you introduce changes or new features that will affect users, consider updating or adding the relevant section of the [readme](https://github.com/Medium/sculpt/blob/master/README.md). | ||
@@ -41,4 +41,4 @@ ## Tests | ||
Tests use [Mocha](http://visionmedia.github.io/mocha/) and can be run with `npm test`. Tests will automatically be run on [Travis CI](https://travis-ci.org/Obvious/sculpt) for new pull requests, and pull requests will only be merged if the tests pass. | ||
Tests use [Mocha](http://visionmedia.github.io/mocha/) and can be run with `npm test`. Tests will automatically be run on [Travis CI](https://travis-ci.org/Medium/sculpt) for new pull requests, and pull requests will only be merged if the tests pass. | ||
New features and bug fixes should have new unit tests. Don't be afraid to make the tests fun to read, we will all be fine without another example of asserting "foobar" or "example data". I like Vampire Weekend lyrics. Be creative. |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file Export all of the public modules. | ||
* @fileoverview Export all of the public modules. | ||
*/ | ||
@@ -11,6 +11,4 @@ var fs = require('fs') | ||
fs.readdirSync(libPath).forEach(function (lib) { | ||
if (lib.slice(0, 1) === '_') return | ||
var name = lib.replace('.js', '') | ||
exports[name] = require(path.join(libPath, name)) | ||
}) |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file An implementaion of the Mapper stream. | ||
* @fileoverview An implementaion of the Mapper stream. | ||
*/ | ||
@@ -6,0 +6,0 @@ var map = require('./map') |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A transform stream that removes chunks when the test function | ||
* @fileoverview A transform stream that removes chunks when the test function | ||
* returns a falsey value. | ||
*/ | ||
var util = require('util') | ||
var Base = require('./_base') | ||
var map = require('./map') | ||
@@ -13,34 +12,16 @@ /** | ||
* @param {Function} fn Determines whether a chunk is kept or removed based on return value. | ||
* @constructor | ||
* @return {Mapper} | ||
*/ | ||
function Filterer(fn) { | ||
this.fn = fn | ||
Base.call(this) | ||
} | ||
util.inherits(Filterer, Base) | ||
/** | ||
* @override | ||
*/ | ||
Filterer.prototype._safeTransform = function (chunk, enc, callback) { | ||
if (! this.isAsync()) { | ||
return this.fn(chunk) && this.push(chunk) | ||
} | ||
this.fn(chunk, function (err, valid) { | ||
if (valid) { | ||
this.push(chunk) | ||
module.exports = function (fn) { | ||
return map(function (data, callback) { | ||
if (! this.isAsync()) { | ||
var syncResult = fn(data) ? [data] : map.EMPTY_ARRAY | ||
return syncResult | ||
} | ||
callback(err) | ||
}.bind(this)) | ||
fn(data, function (err, valid) { | ||
var asyncResult = valid ? [data] : map.EMPTY_ARRAY | ||
callback(err, asyncResult) | ||
}) | ||
}).multi() | ||
} | ||
/** | ||
* Create a Filterer stream. | ||
* @param {Function} fn | ||
* @return {Filterer} | ||
*/ | ||
module.exports = function (fn) { | ||
return new Filterer(fn) | ||
} |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A transform stream that forks written values to a writable stream. | ||
* @fileoverview A transform stream that forks written values to a writable stream. | ||
*/ | ||
var util = require('util') | ||
var Base = require('./_base') | ||
var map = require('./map') | ||
@@ -12,26 +11,18 @@ /** | ||
* @param {stream.Writable} writable | ||
* @return {ObjectStream} | ||
* @return {Mapper} | ||
*/ | ||
module.exports = function (writable) { | ||
function Fork() { | ||
Base.call(this) | ||
} | ||
util.inherits(Fork, Base) | ||
var stream = map(function (data, cb) { | ||
writable.write(data, function (err) { | ||
cb(err, data) | ||
}) | ||
}).async() | ||
Fork.prototype._transform = function (chunk, enc, callback) { | ||
var wrappedCallback = function () { | ||
this.push(chunk) | ||
callback.apply(null, arguments) | ||
}.bind(this) | ||
writable.write(chunk, enc, wrappedCallback) | ||
} | ||
var fork = new Fork() | ||
// Bubble errors from the forked stream to the parent. | ||
writable.on('error', function () { | ||
var args = Array.prototype.slice.call(arguments) | ||
fork.emit.apply(fork, ['error'].concat(args)) | ||
stream.emit.apply(stream, ['error'].concat(args)) | ||
}) | ||
return fork | ||
return stream | ||
} |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A transform stream that joins incoming data with a separator | ||
* @fileoverview A transform stream that joins incoming data with a separator | ||
*/ | ||
var map = require('./map') | ||
var invoke = require('./invoke') | ||
@@ -14,7 +14,3 @@ /** | ||
module.exports = function (separator) { | ||
var mapper = function (arr) { | ||
return arr.join(separator) | ||
} | ||
return map(mapper) | ||
return invoke('join', separator) | ||
} |
103
lib/map.js
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A transform stream that maps each chunk before it's written. | ||
* @fileoverview A transform stream that maps each chunk before it's written. | ||
*/ | ||
var util = require('util') | ||
var Base = require('./_base') | ||
var Transform = require('stream').Transform | ||
@@ -13,10 +13,76 @@ /** | ||
* @param {Function} mapper | ||
* @param {Function=} flush | ||
*/ | ||
function Mapper(mapper) { | ||
function Mapper(mapper, flush) { | ||
Transform.call(this, { | ||
objectMode: true, | ||
// Patch from 0.11.7 | ||
// https://github.com/joyent/node/commit/ba72570eae938957d10494be28eac28ed75d256f | ||
highWaterMark: 16 | ||
}) | ||
this.mapper = mapper | ||
Base.call(this) | ||
if (flush) { | ||
this._flush = flush | ||
} | ||
} | ||
util.inherits(Mapper, Base) | ||
util.inherits(Mapper, Transform) | ||
/** | ||
* @override | ||
*/ | ||
Mapper.prototype._transform = function () { | ||
var method = this.isAsync() ? '_asyncTransform' : '_syncTransform' | ||
this[method].apply(this, arguments) | ||
} | ||
/** | ||
* Apply a syncronous transformation. | ||
* @param {*} chunk | ||
* @param {String} enc | ||
* @param {Function} callback | ||
*/ | ||
Mapper.prototype._syncTransform = function (chunk, enc, callback) { | ||
try { | ||
this.push(this.mapper(chunk)) | ||
callback() | ||
} catch (e) { | ||
callback(e) | ||
} | ||
} | ||
/** | ||
* Apply an asyncronous transformation. | ||
* @param {*} chunk | ||
* @param {String} enc | ||
* @param {Function} callback | ||
*/ | ||
Mapper.prototype._asyncTransform = function (chunk, enc, callback) { | ||
this.mapper(chunk, function (err, data) { | ||
this.push(data) | ||
callback(err) | ||
}.bind(this)) | ||
} | ||
/** | ||
* Set the stream to be async. This is only relevant for map and filter streams, and not | ||
* for the built in streams that implement them. | ||
* | ||
* @return {Mapper} | ||
*/ | ||
Mapper.prototype.async = function () { | ||
this._inAsyncMode = true | ||
return this | ||
} | ||
/** | ||
* Determine whether the stream is in async mode. | ||
* | ||
* @return {Boolean} | ||
*/ | ||
Mapper.prototype.isAsync = function () { | ||
return !! this._inAsyncMode | ||
} | ||
/** | ||
* Set the stream to allow pushing multiple values per call. This is only relevant for map streams, | ||
@@ -61,22 +127,17 @@ * and not for the built in streams that implement them. | ||
/** | ||
* @override | ||
* Create a Mapper stream. | ||
* @param {Function} mapper | ||
* @param {Function=} flush | ||
* @return {Mapper} | ||
*/ | ||
Mapper.prototype._safeTransform = function (chunk, enc, callback) { | ||
if (! this.isAsync()) { | ||
return this.push(this.mapper.apply(null, arguments)) | ||
} | ||
this.mapper(chunk, function (err, data) { | ||
this.push(data) | ||
callback(err) | ||
}.bind(this)) | ||
module.exports = function (mapper, flush) { | ||
return new Mapper(mapper, flush) | ||
} | ||
/** | ||
* Create a Mapper stream. | ||
* @param {Function} mapper | ||
* @return {Mapper} | ||
* Cache a single empty, immutable array. Used in streams that implement multi() to | ||
* avoid creating a new object each time we need an empty array. | ||
* @type {Array} | ||
* @constant | ||
*/ | ||
module.exports = function (mapper) { | ||
return new Mapper(mapper) | ||
} | ||
module.exports.EMPTY_ARRAY = Object.freeze([]) |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A transform stream that prepends a prefix to each chunk. | ||
* @fileoverview A transform stream that prepends a prefix to each chunk. | ||
*/ | ||
@@ -6,0 +6,0 @@ var map = require('./map') |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A transform stream that calls .replace() on each chunk. | ||
* @fileoverview A transform stream that calls .replace() on each chunk. | ||
*/ | ||
@@ -11,3 +11,3 @@ var map = require('./map') | ||
* @param {String|RegExp} find | ||
* @param {String|RegExp} replace | ||
* @param {String|Function} replace | ||
* @return {Mapper} | ||
@@ -14,0 +14,0 @@ */ |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A transform stream that splits chunks by separators. | ||
* @fileoverview A transform stream that splits chunks by separators. | ||
*/ | ||
@@ -16,3 +16,3 @@ var map = require('./map') | ||
var splitter = map(function (chunk) { | ||
var mapper = function (chunk) { | ||
cache += chunk.toString() | ||
@@ -22,5 +22,5 @@ var parts = cache.split(separator) | ||
return parts | ||
}).multi() | ||
} | ||
splitter._flush = function (cb) { | ||
var flush = function (cb) { | ||
this.push([cache]) | ||
@@ -30,3 +30,3 @@ cb() | ||
return splitter | ||
return map(mapper, flush).multi() | ||
} |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A transform stream that calls a function for each chunk but | ||
* @fileoverview A transform stream that calls a function for each chunk but | ||
* does not change the streaming data. | ||
@@ -6,0 +6,0 @@ */ |
{ | ||
"name": "sculpt", | ||
"version": "0.1.1", | ||
"version": "0.1.2", | ||
"description": "Generate Node 0.10-friendly transform streams to manipulate other streams.", | ||
@@ -11,6 +11,7 @@ "main": "index.js", | ||
"scripts": { | ||
"ensure-tests": "bin/ensure-tests", | ||
"jshint": "jshint lib/* test/* index.js", | ||
"jscs": "jscs lib/* test/* index.js", | ||
"mocha": "mocha --reporter spec --check-leaks", | ||
"test": "npm run jshint && npm run jscs && npm run mocha" | ||
"test": "npm run jshint && npm run jscs && npm run ensure-tests && npm run mocha" | ||
}, | ||
@@ -24,9 +25,9 @@ "devDependencies": { | ||
"license": "MIT", | ||
"homepage": "https://github.com/Obvious/sculpt", | ||
"homepage": "https://github.com/Medium/sculpt", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/Obvious/sculpt.git" | ||
"url": "git://github.com/Medium/sculpt.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/Obvious/sculpt/issues" | ||
"url": "https://github.com/Medium/sculpt/issues" | ||
}, | ||
@@ -33,0 +34,0 @@ "keywords": [ |
# Sculpt | ||
[![Build Status](https://secure.travis-ci.org/Obvious/sculpt.png?branch=master)](http://travis-ci.org/Obvious/sculpt) | ||
[![Build Status](https://secure.travis-ci.org/Medium/sculpt.svg?branch=master)](http://travis-ci.org/Medium/sculpt) | ||
@@ -27,2 +27,4 @@ A collection of Node.js [transform stream](http://nodejs.org/api/stream.html#stream_class_stream_transform) | ||
* [Replace](#replace) | ||
* [Split](#split) | ||
* [Byte Length](#byte-length) | ||
@@ -32,3 +34,3 @@ *Objects* | ||
* [Join](#join) | ||
* [Split](#split) | ||
* [Invoke](#invoke) | ||
@@ -205,2 +207,18 @@ *Control Flow* | ||
### Invoke | ||
**Arguments** | ||
* methodName: A method to call on each chunk. | ||
* args: Optional, arguments to pass to the named method | ||
```javascript | ||
var stream = sculpt.invoke('toString') | ||
stream.pipe(process.stdout) | ||
stream.end(123) | ||
// '123' | ||
``` | ||
### Split | ||
@@ -231,2 +249,21 @@ | ||
### Byte Length | ||
**Arguments** | ||
* length: Length in bytes for each output chunk | ||
Each output chunk will be a buffer of `length` bytes, except the last chunk, which will be however many bytes are left over. | ||
```javascript | ||
var stream = sculpt.byteLength(5) | ||
stream.on('data', function (chunk) { | ||
console.log(chunk.toString()) | ||
}) | ||
stream.end('abcdefghijk') | ||
// 'abcde' | ||
// 'fghij' | ||
// 'k' | ||
``` | ||
### Fork | ||
@@ -233,0 +270,0 @@ |
@@ -14,3 +14,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -17,0 +17,0 @@ 'Don\'t you know that it\'s insane?', |
@@ -19,3 +19,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.equal('Out of Cape Cod tonight', collector.getObjects().pop()) | ||
@@ -38,3 +38,3 @@ done() | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.equal('Out of Cape Cod tonight', collector.getObjects().pop()) | ||
@@ -53,3 +53,3 @@ done() | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([], collector.getObjects()) | ||
@@ -72,3 +72,3 @@ done() | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([], collector.getObjects()) | ||
@@ -75,0 +75,0 @@ done() |
@@ -15,3 +15,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual(['The Holy Roman Empire', 'roots for you'], forkedWritable.getObjects()) | ||
@@ -18,0 +18,0 @@ assert.deepEqual(['The Holy Roman Empire', 'roots for you'], collector.getObjects()) |
// Copyright 2014. A Medium Corporation | ||
/** | ||
* @file A simple transform stream that just collects incoming objects. | ||
* @fileoverview A simple transform stream that just collects incoming objects. | ||
*/ | ||
@@ -16,2 +16,5 @@ var sculpt = require('../../index') | ||
// Make sure it consumes the incoming data | ||
collector.on('data', function () {}) | ||
collector.getObjects = function () { | ||
@@ -18,0 +21,0 @@ return objects |
@@ -14,3 +14,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -17,0 +17,0 @@ 'Why would you lie about how much coal you have?', |
@@ -16,3 +16,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -40,3 +40,3 @@ 'WHY WOULD YOU LIE ABOUT HOW MUCH COAL YOU HAVE?', | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -64,3 +64,3 @@ 'WHY WOULD YOU LIE ABOUT HOW MUCH COAL YOU HAVE?', | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -92,3 +92,3 @@ 1, | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -95,0 +95,0 @@ 1, |
@@ -14,3 +14,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -17,0 +17,0 @@ 'Why would you lie about how much coal you have?', |
@@ -14,3 +14,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.equal('Baby baby baby baby it\'s a light on', collector.getObjects().pop()) | ||
@@ -29,3 +29,3 @@ done() | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.equal('Baby it\'s a light on', collector.getObjects().pop()) | ||
@@ -47,3 +47,3 @@ done() | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.equal('Baby baby baby baby RIDE on', collector.getObjects().pop()) | ||
@@ -50,0 +50,0 @@ done() |
@@ -14,3 +14,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -32,3 +32,3 @@ 'I took your counsel and came to ruin', | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.deepEqual([ | ||
@@ -35,0 +35,0 @@ 'Looked up full of fear', |
@@ -19,3 +19,3 @@ // Copyright 2014. A Medium Corporation | ||
stream.on('error', done) | ||
stream.on('end', function () { | ||
collector.on('end', function () { | ||
assert.equal(hannahs, 2) | ||
@@ -22,0 +22,0 @@ done() |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
42692
33
860
334