Skip to content
Browse files

Merge branch 'AndreasMadsen-transform-stream'

  • Loading branch information...
2 parents cab0863 + 0ae4bd4 commit 8e81c8d4b1a8bf4c57a4f57b1531cca28609e429 @danmactough committed Jun 10, 2013
Showing with 58 additions and 36 deletions.
  1. +4 −3 README.md
  2. +16 −11 main.js
  3. +1 −0 package.json
  4. +8 −7 test/api-event.js
  5. +29 −15 test/api-stream.js
View
7 README.md
@@ -32,7 +32,8 @@ as I'm sure the stream API is stable and compatible with Node v0.10.x.
## Usage
-The easiest way to use feedparser is to just give it a [readable stream](http://nodejs.org/api/stream.html#stream_readable_stream).
+The easiest way to use feedparser is to just give it a [readable stream](http://nodejs.org/api/stream.html#stream_readable_stream).
+It will then return a readable object stream containing `article` objects.
```js
@@ -47,7 +48,7 @@ request('http://somefeedurl.xml')
.on('meta', function (meta) {
// do something
})
- .on('article', function (article) {
+ .on('data', function (article) {
// do something else
})
.on('end', function () {
@@ -108,7 +109,7 @@ See the `examples` directory.
* `error` - called with `error` whenever there is a an error of any kind (SAXError, Feedparser error, request error, etc.)
* `meta` - called with `meta` when it has been parsed
-* `article` - called with a single `article` when each article has been parsed
+* `data` and `article` - called with a single `article` when each article has been parsed
* `complete` - called with `meta` and `articles` when parsing is complete
* `end` - called with no parameters when parsing is complete or aborted (e.g., due to error)
* `response` - called with the HTTP `response` only when a url has been fetched via parseUrl or parseFile
View
27 main.js
@@ -18,11 +18,15 @@ var sax = require('sax')
, URL = require('url')
, util = require('util')
, EventEmitter = require('events').EventEmitter
- , Stream = require('stream').Stream
+ , TransformStream = require('stream').Transform
, STATUS_CODES = require('http').STATUS_CODES
, utils = require('./utils')
;
+if (TransformStream === undefined) {
+ TransformStream = require('readable-stream').Transform;
+}
+
/**
* FeedParser constructor. Most apps will only use one instance.
*
@@ -31,6 +35,10 @@ var sax = require('sax')
*/
function FeedParser (options) {
if (!(this instanceof FeedParser)) return new FeedParser(options);
+ TransformStream.call(this, {
+ objectMode: true
+ });
+
this.init();
this.parseOpts(options);
// See https://github.com/isaacs/sax-js for more info
@@ -42,11 +50,8 @@ function FeedParser (options) {
this.stream.on('text', this.handleText.bind(this));
this.stream.on('cdata', this.handleText.bind(this));
this.stream.on('end', this.handleEnd.bind(this));
- Stream.call(this);
- this.writable = true;
- this.readable = true;
}
-util.inherits(FeedParser, Stream);
+util.inherits(FeedParser, TransformStream);
/*
* Initializes the SAX stream
@@ -110,7 +115,7 @@ FeedParser.prototype.handleEnd = function (){
}
}
if (!this.errors.length) { this.emit('complete', this.meta, this.articles); }
- this.emit('end');
+ this.push(null);
if (this.stream) {
this.stream.removeAllListeners('end');
this.stream.removeAllListeners('error');
@@ -302,6 +307,7 @@ FeedParser.prototype.handleCloseTag = function (el){
item.meta = this.meta;
}
if (this.meta.author && !item.author) item.author = this.meta.author;
+ this.push(item);
this.emit('article', item);
this.articles.push(item);
} else if (!this.meta.title && // We haven't yet parsed all the metadata
@@ -988,15 +994,14 @@ FeedParser.prototype.handleItem = function handleItem (node, type, options){
};
// Naive Stream API
-FeedParser.prototype.write = function (data) {
+FeedParser.prototype._transform = function (data, encoding, done) {
this.stream.write(data);
- return true;
+ done();
};
-FeedParser.prototype.end = function (chunk) {
- if (chunk && chunk.length) this.stream.write(chunk);
+FeedParser.prototype._flush = function (done) {
this.stream.end();
- return true;
+ done();
};
function feedparser (options, callback) {
View
1 package.json
@@ -30,6 +30,7 @@
"request": "2.21.x",
"addressparser": "~0.1.3",
"array-indexofobject": "0.0.1",
+ "readable-stream": "1.0.x",
"resanitize": "~0.1.10"
},
"devDependencies": {
View
15 test/api-event.js
@@ -47,9 +47,8 @@ describe('Event API', function () {
assert.ok(articles.length);
events.push('complete');
})
- .on('end', function () {
- done();
- });
+ .on('end', done)
+ .resume();
});
});
@@ -73,7 +72,8 @@ describe('Event API', function () {
assert.ok(articles.length);
events.push('complete');
})
- .on('end', done);
+ .on('end', done)
+ .resume();
});
});
@@ -97,8 +97,8 @@ describe('Event API', function () {
assert.ok(articles.length);
events.push('complete');
})
- .on('end', done);
-
+ .on('end', done)
+ .resume();
});
});
@@ -110,7 +110,8 @@ describe('Event API', function () {
.on('error', function (err) {
assert.ok(err instanceof Error);
})
- .on('end', done);
+ .on('end', done)
+ .resume();
});
});
});
View
44 test/api-stream.js
@@ -1,23 +1,14 @@
+var fs = require('fs');
+
describe('Writeable Stream Input API', function () {
var feedPath = __dirname + '/feeds/rss2sample.xml';
- var events = [];
-
- beforeEach(function () {
- events = [];
- })
-
- afterEach(function () {
- assert.equal(events.indexOf('error'), -1);
- assert.ok(~events.indexOf('meta'));
- assert.ok(~events.indexOf('article'));
- assert.ok(~events.indexOf('complete'));
- });
-
describe('.pipe()', function () {
it('works', function (done) {
- require('fs').createReadStream(feedPath).pipe(FeedParser())
+ var events = [];
+
+ fs.createReadStream(feedPath).pipe(FeedParser())
.on('error', function (err) {
assert.ifError(err);
events.push('error');
@@ -35,7 +26,30 @@ describe('Writeable Stream Input API', function () {
assert.ok(articles.length);
events.push('complete');
})
- .on('end', done);
+ .on('end', function () {
+ assert.equal(events.indexOf('error'), -1);
+ assert.ok(~events.indexOf('meta'));
+ assert.ok(~events.indexOf('article'));
+ assert.ok(~events.indexOf('complete'));
+ done();
+ })
+ .resume();
+ });
+ });
+
+ describe('.pipe()', function () {
+ it('works', function (done) {
+ fs.createReadStream(feedPath)
+ .pipe(FeedParser())
+ .on('readable', function () {
+ var stream = this, items = [], item;
+ while (item = stream.read()) {
+ items.push(item);
+ }
+ assert.ok(items.length);
+ })
+ .on('end', done)
+ .on('error', done);
});
});

0 comments on commit 8e81c8d

Please sign in to comment.
Something went wrong with that request. Please try again.