Skip to content

Commit

Permalink
finish stream-converter
Browse files Browse the repository at this point in the history
  • Loading branch information
Simion Florentin committed Aug 20, 2015
1 parent 8d40b9c commit 1550a60
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 0 deletions.
49 changes: 49 additions & 0 deletions .eslintrc
@@ -0,0 +1,49 @@
{
"env": {
"node": true,
"mocha": true
},

"rules": {
// Best Practices
"curly": [2, "all"],
"dot-notation": 2,
"eqeqeq": [2, "allow-null"],
"guard-for-in": 2,
"no-caller": 2,
"no-multi-str": 2,
"no-multi-spaces": 2,
"no-unused-vars": 2,
"no-with": 2,

// Variables
"no-undef": 2,

// Stylistic Issues
"array-bracket-spacing": [2, "never"],
"brace-style": [2, "1tbs", {"allowSingleLine": true}],
"camelcase": [2, {"properties": "never"}],
"eol-last": 2,
"indent": [2, 2, {"VariableDeclarator": 2, "SwitchCase": 1}],
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
"new-cap": 2,
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
"no-multiple-empty-lines": 2,
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
"no-trailing-spaces": 2,
"object-curly-spacing": [2, "never"],
"operator-linebreak": [2, "after"],
"quotes": [2, "single", "avoid-escape"],
"semi-spacing": [2, {"before": false, "after": true}],
"space-after-keywords": [2, "always"],
"space-before-function-paren": [2, {"anonymous": "never", "named": "never"}],
"space-before-blocks": [2,"always"],
"space-in-parens": [2, "never"],
"space-infix-ops": 2,
"space-unary-ops": [2, {"nonwords": false}],
"space-return-throw-case": 2,

// Legacy
"max-len": [2, 80, 4, {ignoreUrls: true}]
}
}
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
node_modules
coverage
6 changes: 6 additions & 0 deletions .npmignore
@@ -0,0 +1,6 @@
.travis.yml
.eslintrc
.gitignore
test
examples
coverage
9 changes: 9 additions & 0 deletions .travis.yml
@@ -0,0 +1,9 @@
language: node_js
node_js:
- '0.12'
- '0.11'
script:
- npm test
- npm run linter
- npm run coverage
after_success: cat ${TRAVIS_BUILD_DIR}/coverage/lcov.info | coveralls
70 changes: 70 additions & 0 deletions README.md
@@ -0,0 +1,70 @@
# stream-converter
[![Build Status](https://travis-ci.org/flore77/stream-converter.svg?branch=master)](https://travis-ci.org/flore77/stream-converter)
[![Coverage Status](https://coveralls.io/repos/flore77/stream-converter/badge.svg?branch=master&service=github)](https://coveralls.io/github/flore77/stream-converter?branch=master)

Converts anything to a Node.js ReadStream, i.e [Readable Stream](http://devdocs.io/node/stream#stream_class_stream_readable).

## Install
`npm install stream-converter`

## Usage

```js
var streamify = require('stream-converter');

/**
* Converts source to a ReadStream
*
* @param {String|Buffer|Array|Object|Stream}
* @param {Object} [options]
*/
var stream = streamify(source, options);
```
You can also check the `examples` folder in the repo.

## Converting Streams
Indeed, it doesn't convert anything, it is just `returning` the `stream` passed as `param`, it will recognize
[readable-streams](https://www.npmjs.com/package/readable-stream) as also Node.js Core
[streams](http://devdocs.io/node/stream).

## Converting Buffers or Strings

```js
//options is not required
var stream = streamify(bufferOrString, options);
```
We can pipe it (for example):
```js
stream.pipe(process.stdout);
```
or you can listen to the `data` event:
```js
stream.on('data', function() {
//do something
});
```
or every possible operation on `streams`. Possible options are:

```js
var options = {
highWaterMark: Number,
encoding: String,
objectMode: Boolean,
path: Boolean
};
```

For the first three options you can read more in the documentation provided above. For the last one, i.e `path`,
it's an option for `Strings`, if it is set to `true` it will treat the string like a `path`, i.e. it will return
a `stream` using [fs.createReadStream](http://devdocs.io/node/fs#fs_fs_createreadstream_path_options).

## Converting Arrays and Objects

```js
var stream = streamify(objectOrArray);
```
There are `no` options available, they are converted by `default` to a stream using `objectMode: true`. Because
of this, they `cannot be piped` to a writeable stream, that accepts only `Buffers` or `Strings`. But you can `listen`
to `events` and other stream stuff.

You can pipe arrays, but **only** if they contain `Strings` and `Buffers`.
24 changes: 24 additions & 0 deletions examples/convert-array.js
@@ -0,0 +1,24 @@
var streamify = require('../index.js');

var array = ['1', 'anything', new Buffer('Hello, World!\n')];

// this will work because it is an array only of strings and Buffers
streamify(array).pipe(process.stdout);

var array1 = [1, 3, 'anything'];

//this will throw an error, try it
//streamify(array1).pipe(process.stdout);

//but we can listen to the data event and collect the data
var stream = streamify(array1);
var result = [];

stream.on('data', function(data) {
result.push(data);
});

stream.on('end', function() {
//the output will be equal to array1
console.log(result);
});
21 changes: 21 additions & 0 deletions examples/convert-buffer.js
@@ -0,0 +1,21 @@
var streamify = require('../index.js');

var buffer = new Buffer('I will be converted into a stream!\n');

// piping
streamify(buffer).pipe(process.stdout);

var stream = streamify(buffer);
var chunks = [];

// listen to events
stream.on('data', function(data) {
chunks.push(data);
});

stream.on('end', function() {
var result = Buffer.concat(chunks);
console.log(result.toString());
});


16 changes: 16 additions & 0 deletions examples/convert-object.js
@@ -0,0 +1,16 @@
var streamify = require('../index.js');

var object = {
prop1: 'I am an object',
prop2: 7
};

// this will throw error, try it
//streamify(object).pipe(process.stdout);

var stream = streamify(object);

stream.on('data', function(data) {
console.log(data);
});

5 changes: 5 additions & 0 deletions examples/convert-string-path.js
@@ -0,0 +1,5 @@
var streamify = require('../index.js');

var path = './examples/text';

streamify(path, {path: true}).pipe(process.stdout);
20 changes: 20 additions & 0 deletions examples/convert-string.js
@@ -0,0 +1,20 @@
var streamify = require('../index.js');

var string = 'I will be coverted into a stream!\n';

// piping
streamify(string).pipe(process.stdout);

var stream = streamify(string);
var str = '';

stream.setEncoding('utf8');

// listen to events
stream.on('data', function(data) {
str += data;
});

stream.on('end', function() {
console.log(str);
});
1 change: 1 addition & 0 deletions examples/text
@@ -0,0 +1 @@
Hi, I am a stream!
90 changes: 90 additions & 0 deletions index.js
@@ -0,0 +1,90 @@
var Stream = require('readable-stream').Stream;
var NodeStream = require('stream').Stream;
var Readable = require('readable-stream').Readable;
var util = require('util');
var fs = require('fs');

util.inherits(ArrayStream, Readable);
util.inherits(StringOrBufferStream, Readable);
util.inherits(ObjectStream, Readable);

/**
* Transforms an Array into a ReadStream
*
* @param {Array} array - The input Array to transform
*/
function ArrayStream(array) {
Readable.call(this, {objectMode: true});

this._iter = 0;
this._array = array;
}

ArrayStream.prototype._read = function() {
if (this._iter < this._array.length) {
this.push(this._array[this._iter++]);
return;
}

this.push(null);
}

/**
* Transforms a String or a Buffer into a ReadStream
*
* @param {String|Buffer} - The input String or Buffer to transform
*/
function StringOrBufferStream(stringOrBuffer, options) {
Readable.call(this, options);

this._stringOrBuffer = stringOrBuffer;
}

StringOrBufferStream.prototype._read = function() {
this.push(this._stringOrBuffer);
this._stringOrBuffer = null;
}

/**
* Transforms an object into a ReadStream
*
* @param {Object} - The input Object to transform
*/
function ObjectStream(object) {
Readable.call(this, {objectMode: true});

this._object = object;
}

ObjectStream.prototype._read = function() {
this.push(this._object);
this._object = null;
}

/**
* Transforms everything into a ReadStream
*
* @param {String||Buffer|Object|Array|Stream} source
* @param {Object} [options]
*/
module.exports = function(source, options) {
if (source instanceof Stream || source instanceof NodeStream) {
return source;
} else if (source instanceof Array) {
return new ArrayStream(source);
} else if (source instanceof Buffer) {
return new StringOrBufferStream(source, options);
} else if (typeof source === 'string') {
// if options.path is set to true, then the String must be treat like a path
if (options !== undefined && options.path === true) {
return fs.createReadStream(source, options);
}

return new StringOrBufferStream(source, options);
} else if (typeof source === 'object') {
return new ObjectStream(source);
} else {
throw new Error('Your argument doesn\'t match any of this ' +
'{String|Buffer|Object|Array|Stream}');
}
};
48 changes: 48 additions & 0 deletions package.json
@@ -0,0 +1,48 @@
{
"name": "stream-converter",
"version": "0.0.1",
"description": "Converts anything to a Node.js ReadStream",
"main": "index.js",
"scripts": {
"test": "mocha",
"coverage": "istanbul cover _mocha",
"linter": "eslint ."
},
"pre-commit": [
"./node_modules/.bin/eslint ."
],
"repository": {
"type": "git",
"url": "git+https://github.com/flore77/stream-converter.git"
},
"keywords": [
"stream",
"convert",
"converter",
"array",
"buffer",
"string",
"object",
"path",
"streamify"
],
"author": "Simion Florentin",
"license": "MIT",
"bugs": {
"url": "https://github.com/flore77/stream-converter/issues"
},
"homepage": "https://github.com/flore77/stream-converter#readme",
"dependencies": {
"readable-stream": "^2.0.2"
},
"devDependencies": {
"chai": "^3.2.0",
"concat-stream": "^1.5.0",
"coveralls": "^2.11.4",
"eslint": "^1.1.0",
"istanbul": "^0.3.18",
"mocha": "^2.2.5",
"pre-git": "^0.6.2",
"tmp": "0.0.27"
}
}

0 comments on commit 1550a60

Please sign in to comment.