Comparing version 0.5.0 to 0.6.0
@@ -318,37 +318,31 @@ // **N3Lexer** tokenizes N3 documents. | ||
this._input = input; | ||
immediately(function () { self._tokenizeToEnd(callback, true); }); | ||
// If a callback was passed, asynchronously call it | ||
if (typeof callback === 'function') | ||
immediately(function () { self._tokenizeToEnd(callback, true); }); | ||
// If no callback was passed, tokenize synchronously and return | ||
else { | ||
var tokens = [], error; | ||
this._tokenizeToEnd(function (e, t) { e ? (error = e) : tokens.push(t); }, true); | ||
if (error) throw error; | ||
return tokens; | ||
} | ||
} | ||
// Otherwise, the input will be streamed. | ||
// Otherwise, the input must be a stream. | ||
else { | ||
this._input = ''; | ||
// If no input was given, it will be streamed through `addChunk` and ended with `end` | ||
if (!input || typeof input === 'function') { | ||
this.addChunk = addChunk; | ||
this.end = end; | ||
if (!callback) | ||
callback = input; | ||
} | ||
// Otherwise, the input itself must be a stream | ||
else { | ||
if (typeof input.setEncoding === 'function') | ||
input.setEncoding('utf8'); | ||
input.on('data', addChunk); | ||
input.on('end', end); | ||
} | ||
if (typeof input.setEncoding === 'function') | ||
input.setEncoding('utf8'); | ||
// Adds the data chunk to the buffer and parses as far as possible | ||
input.on('data', function (data) { | ||
if (self._input !== null) { | ||
self._input += data; | ||
self._tokenizeToEnd(callback, false); | ||
} | ||
}); | ||
// Parses until the end | ||
input.on('end', function () { | ||
if (self._input !== null) | ||
self._tokenizeToEnd(callback, true); | ||
}); | ||
} | ||
// Adds the data chunk to the buffer and parses as far as possible | ||
function addChunk(data) { | ||
if (self._input !== null) { | ||
self._input += data; | ||
self._tokenizeToEnd(callback, false); | ||
} | ||
} | ||
// Parses until the end | ||
function end() { | ||
if (self._input !== null) | ||
self._tokenizeToEnd(callback, true); | ||
} | ||
}, | ||
@@ -355,0 +349,0 @@ }; |
@@ -663,2 +663,3 @@ // **N3Parser** parses N3 documents. | ||
parse: function (input, tripleCallback, prefixCallback) { | ||
var self = this; | ||
// The read callback is the next function to be executed when a token arrives. | ||
@@ -670,24 +671,22 @@ // We start reading in the top context. | ||
// If the input argument is not given, shift parameters | ||
if (typeof input === 'function') | ||
prefixCallback = tripleCallback, tripleCallback = input, input = null; | ||
// Parse synchronously if no callbacks are given. | ||
if (!tripleCallback && !prefixCallback) { | ||
var triples = [], error; | ||
this._callback = function (e, t) { e ? (error = e) : t && triples.push(t); }; | ||
this._lexer.tokenize(input).every(function (token) { | ||
return self._readCallback = self._readCallback(token); | ||
}); | ||
if (error) throw error; | ||
return triples; | ||
} | ||
// Set the triple and prefix callbacks. | ||
// Parse asynchronously otherwise, executing the read callback when a token arrives. | ||
this._callback = tripleCallback || noop; | ||
this._prefixCallback = prefixCallback || noop; | ||
// Execute the read callback when a token arrives. | ||
var self = this; | ||
this._lexer.tokenize(input, function (error, token) { | ||
if (error !== null) | ||
self._callback(error), self._callback = noop; | ||
else if (self._readCallback !== undefined) | ||
else if (self._readCallback) | ||
self._readCallback = self._readCallback(token); | ||
}); | ||
// If no input was given, it can be added with `addChunk` and ended with `end` | ||
if (!input) { | ||
this.addChunk = this._lexer.addChunk; | ||
this.end = this._lexer.end; | ||
} | ||
}, | ||
@@ -694,0 +693,0 @@ }; |
@@ -369,2 +369,3 @@ // **N3Store** objects store N3 triples by graph in memory. | ||
this._ids[name] = ++this._id; | ||
this._entities[this._id] = name; | ||
return name; | ||
@@ -371,0 +372,0 @@ }, |
@@ -16,15 +16,14 @@ // **N3StreamParser** parses an N3 stream into a triple stream | ||
// Set up parser | ||
var self = this, parser = new N3Parser(options); | ||
var self = this, parser = new N3Parser(options), onData, onEnd; | ||
parser.parse( | ||
// Pass dummy stream to obtain `data` and `end` callbacks | ||
{ on: function (event, cb) { event === 'data' ? (onData = cb) : (onEnd = cb); } }, | ||
// Handle triples by pushing them down the pipeline | ||
function (error, triple) { | ||
triple && self.push(triple) || | ||
error && self.emit('error', error); | ||
}, | ||
function (error, t) { error && self.emit('error', error) || t && self.push(t); }, | ||
// Emit prefixes through the `prefix` event | ||
this.emit.bind(this, 'prefix')); | ||
function (prefix, uri) { self.emit('prefix', prefix, uri); }); | ||
// Implement Transform methods on top of parser | ||
this._transform = function (chunk, encoding, done) { parser.addChunk(chunk); done(); }; | ||
this._flush = function (done) { parser.end(); done(); }; | ||
// Implement Transform methods through parser callbacks | ||
this._transform = function (chunk, encoding, done) { onData(chunk); done(); }; | ||
this._flush = function (done) { onEnd(); done(); }; | ||
} | ||
@@ -31,0 +30,0 @@ util.inherits(N3StreamParser, Transform); |
{ | ||
"name": "n3", | ||
"version": "0.5.0", | ||
"version": "0.6.0", | ||
"description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.", | ||
@@ -5,0 +5,0 @@ "author": "Ruben Verborgh <ruben.verborgh@gmail.com>", |
@@ -128,2 +128,4 @@ # Lightning fast, asynchronous, streaming RDF for JavaScript | ||
Pass a second callback to `parse` to retrieve prefixes as they are read. | ||
<br> | ||
If no callbacks are provided, parsing happens synchronously. | ||
@@ -139,22 +141,2 @@ By default, `N3.Parser` parses a permissive superset of Turtle, TriG, N-Triples and N-Quads. | ||
### From RDF chunks to triples | ||
`N3.Parser` can also parse triples from RDF documents arriving in chunks, | ||
for instance, when being downloaded or read from disk. | ||
Use `addChunk` to add a piece of data, and `end` to signal the end. | ||
``` js | ||
var parser = N3.Parser(), triples = []; | ||
parser.parse(function (error, triple, prefixes) { triple && triples.push(triple); }); | ||
parser.addChunk('@prefix c: <http://example.org/cartoons#>.\n'); | ||
parser.addChunk('c:Tom a '); | ||
parser.addChunk('c:Cat. c:Jerry a'); | ||
console.log(triples); // First triple | ||
parser.addChunk(' c:Mouse.'); | ||
parser.end(); | ||
console.log(triples); // Both triples | ||
``` | ||
### From an RDF stream to triples | ||
@@ -161,0 +143,0 @@ |
var N3Lexer = require('../N3').Lexer; | ||
var chai = require('chai'), | ||
events = require('events'); | ||
EventEmitter = require('events'); | ||
var expect = chai.expect; | ||
@@ -75,4 +75,4 @@ chai.should(); | ||
// Try parsing | ||
var lexer = new N3Lexer(); | ||
lexer.tokenize(function (error, token) { | ||
var stream = new EventEmitter(), lexer = new N3Lexer(); | ||
lexer.tokenize(stream, function (error, token) { | ||
error.should.be.an.instanceof(Error); | ||
@@ -82,3 +82,3 @@ error.message.should.equal('Syntax error: unexpected "<\\u1234>" on line 1.'); | ||
}); | ||
lexer.addChunk('<\\u1234>'); | ||
stream.emit('data', '<\\u1234>'); | ||
// Restore global isNaN | ||
@@ -93,4 +93,4 @@ global.isNaN = isNaN; | ||
// Try parsing | ||
var lexer = new N3Lexer(); | ||
lexer.tokenize(function (error, token) { | ||
var stream = new EventEmitter(), lexer = new N3Lexer(); | ||
lexer.tokenize(stream, function (error, token) { | ||
error.should.be.an.instanceof(Error); | ||
@@ -100,3 +100,3 @@ error.message.should.equal('Syntax error: unexpected "<\\U12345678>" on line 1.'); | ||
}); | ||
lexer.addChunk('<\\U12345678>'); | ||
stream.emit('data', '<\\U12345678>'); | ||
// Restore global isNaN | ||
@@ -652,22 +652,9 @@ global.isNaN = isNaN; | ||
describe('using the addChunk/end interface', function () { | ||
var tokens = [], lexer = new N3Lexer(); | ||
lexer.tokenize(function (error, token) { !error && tokens.push(token); }); | ||
lexer.addChunk('<a> '); | ||
lexer.addChunk('<b> '); | ||
lexer.addChunk('<c>.'); | ||
lexer.end(); | ||
it('parses all chunks', function () { | ||
tokens.should.have.length(5); | ||
}); | ||
}); | ||
describe('passing data after the stream has been finished', function () { | ||
var tokens = [], lexer = new N3Lexer(); | ||
lexer.tokenize(function (error, token) { !error && tokens.push(token); }); | ||
lexer.addChunk('<a> '); | ||
lexer.end(); | ||
lexer.addChunk('<b> '); | ||
lexer.end(); | ||
var tokens = [], stream = new EventEmitter(), lexer = new N3Lexer(); | ||
lexer.tokenize(stream, function (error, token) { !error && tokens.push(token); }); | ||
stream.emit('data', '<a> '); | ||
stream.emit('end'); | ||
stream.emit('data', '<b> '); | ||
stream.emit('end'); | ||
@@ -680,8 +667,9 @@ it('parses only the first chunk (plus EOF)', function () { | ||
describe('passing data after an error has occured', function () { | ||
var tokens = [], lexer = new N3Lexer(); | ||
lexer.tokenize(function (error, token) { !error && tokens.push(token); }); | ||
lexer.addChunk('<a> '); | ||
lexer.addChunk('error '); | ||
lexer.end(); | ||
lexer.addChunk('<b> '); | ||
var tokens = [], stream = new EventEmitter(), lexer = new N3Lexer(); | ||
lexer.tokenize(stream, function (error, token) { !error && tokens.push(token); }); | ||
stream.emit('data', '<a> '); | ||
stream.emit('data', ' error '); | ||
stream.emit('end'); | ||
stream.emit('data', '<b> '); | ||
stream.emit('end'); | ||
@@ -692,2 +680,26 @@ it('parses only the first chunk', function () { | ||
}); | ||
describe('called with a string and without callback', function () { | ||
var lexer = new N3Lexer(), | ||
tokens = lexer.tokenize('<a> <b> <c>.'); | ||
it('returns all tokens synchronously', function () { | ||
tokens.should.deep.equal([ | ||
{ line: 1, type: 'IRI', value: 'a', prefix: '' }, | ||
{ line: 1, type: 'IRI', value: 'b', prefix: '' }, | ||
{ line: 1, type: 'IRI', value: 'c', prefix: '' }, | ||
{ line: 1, type: '.', value: '', prefix: '' }, | ||
{ line: 1, type: 'eof', value: '', prefix: '' }, | ||
]); | ||
}); | ||
}); | ||
describe('called with an erroneous string and without callback', function () { | ||
var lexer = new N3Lexer(); | ||
it('throws an error', function () { | ||
(function () { lexer.tokenize('<a> bar'); }) | ||
.should.throw('Syntax error: unexpected "bar" on line 1.'); | ||
}); | ||
}); | ||
}); | ||
@@ -741,3 +753,3 @@ }); | ||
var elements = Array.prototype.slice.call(arguments), | ||
stream = new events.EventEmitter(); | ||
stream = new EventEmitter(); | ||
@@ -744,0 +756,0 @@ stream.setEncoding = function (encoding) { |
@@ -589,2 +589,20 @@ var N3Store = require('../N3').Store; | ||
describe('An N3Store containing a blank node', function () { | ||
var store = new N3Store({ defaultGraph: 'http://example.org/#defaultGraph' }); | ||
var b1 = store.createBlankNode(); | ||
store.addTriple('s1', 'p1', b1).should.be.true; | ||
describe('when searched with more than one variable', function () { | ||
it('should return a triple with the blank node as an object', | ||
shouldIncludeAll(store.find(), | ||
['s1', 'p1', b1, store.defaultGraph])); | ||
}); | ||
describe('when searched with one variable', function () { | ||
it('should return a triple with the blank node as an object', | ||
shouldIncludeAll(store.find('s1', 'p1'), | ||
['s1', 'p1', b1, store.defaultGraph])); | ||
}); | ||
}); | ||
describe('An N3Store', function () { | ||
@@ -591,0 +609,0 @@ var store = new N3Store(); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
312544
5638
392