Initial commit.
This commit is contained in:
commit
1107483c86
|
@ -0,0 +1,2 @@
|
||||||
|
scratch/
|
||||||
|
node_modules/
|
|
@ -0,0 +1,23 @@
|
||||||
|
all:
|
||||||
|
npm install .
|
||||||
|
|
||||||
|
keys: private-key.pem server-cert.pem
|
||||||
|
|
||||||
|
private-key.pem:
|
||||||
|
openssl genrsa -des3 -passout pass:a -out $@ 1024
|
||||||
|
openssl rsa -passin pass:a -in $@ -out $@
|
||||||
|
|
||||||
|
server-cert.pem: private-key.pem
|
||||||
|
openssl req -new -x509 -nodes -sha1 -days 365 \
|
||||||
|
-subj /CN=server.minimart.leastfixedpoint.com \
|
||||||
|
-passin pass:a \
|
||||||
|
-key private-key.pem > $@
|
||||||
|
|
||||||
|
clean-keys:
|
||||||
|
rm -f private-key.pem server-cert.pem
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f dist/*.js
|
||||||
|
|
||||||
|
veryclean: clean
|
||||||
|
rm -rf node_modules/
|
|
@ -0,0 +1,11 @@
|
||||||
|
# Syndicate-JS: Syndicate for Javascript environments
|
||||||
|
|
||||||
|
## A walk through the code
|
||||||
|
|
||||||
|
Source files in `src/`, from most general to most specific:
|
||||||
|
|
||||||
|
- `reflect.js`: Reflection on function formal parameter lists.
|
||||||
|
- `util.js`: Functions `extend` and `kwApply`.
|
||||||
|
- `route.js`: Implementation of dataspace trie structure.
|
||||||
|
- `syndicate.js`: Implementation of core leaf actors and networks.
|
||||||
|
- `main.js`: Main package entry point.
|
|
@ -0,0 +1 @@
|
||||||
|
Directory for build products, checked in to the repo for ease-of-use.
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"name": "syndicate-js",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Syndicate in the browser",
|
||||||
|
"homepage": "https://github.com/tonyg/syndicate",
|
||||||
|
"main": "src/main.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/tonyg/syndicate"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rm -f dist/*",
|
||||||
|
"build-debug": "browserify src/main.js -d -s Syndicate -o dist/syndicate.js",
|
||||||
|
"build-min": "browserify src/main.js -s Syndicate -o dist/_syndicate.js && uglifyjs dist/_syndicate.js -o dist/syndicate.min.js && rm dist/_syndicate.js",
|
||||||
|
"build": "npm run build-debug && npm run build-min",
|
||||||
|
"watch": "watchify src/main.js -d -s Syndicate -o dist/syndicate.js",
|
||||||
|
"test": "mocha",
|
||||||
|
"prepublish": "npm run build"
|
||||||
|
},
|
||||||
|
"author": "Tony Garnock-Jones <tonyg@ccs.neu.edu>",
|
||||||
|
"devDependencies": {
|
||||||
|
"watchify": "^3.7.0",
|
||||||
|
"uglify-js": "^2.6.1",
|
||||||
|
"browserify": "^13.0.0",
|
||||||
|
"mocha": "^2.4.5",
|
||||||
|
"expect.js": "^0.3.1",
|
||||||
|
"immutable": "^3.7.6"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
module.exports = require("./syndicate.js");
|
||||||
|
|
||||||
|
// module.exports.DOM = require("./dom-driver.js");
|
||||||
|
// module.exports.JQuery = require("./jquery-driver.js");
|
||||||
|
// module.exports.RoutingTableWidget = require("./routing-table-widget.js");
|
||||||
|
// module.exports.WebSocket = require("./websocket-driver.js");
|
||||||
|
module.exports.Reflect = require("./reflect.js");
|
||||||
|
|
||||||
|
// module.exports.Ground = require("./ground.js").Ground;
|
||||||
|
// module.exports.Actor = require("./actor.js").Actor;
|
||||||
|
// module.exports.Spy = require("./spy.js").Spy;
|
||||||
|
// module.exports.WakeDetector = require("./wake-detector.js").WakeDetector;
|
||||||
|
|
||||||
|
// var Worker = require("./worker.js");
|
||||||
|
// module.exports.Worker = Worker.Worker;
|
||||||
|
// module.exports.WorkerGround = Worker.WorkerGround;
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Reflection on function formal parameter lists.
|
||||||
|
// This module is based on Angular's "injector" code,
|
||||||
|
// https://github.com/angular/angular.js/blob/master/src/auto/injector.js,
|
||||||
|
// MIT licensed, and hence:
|
||||||
|
// Copyright (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||||
|
// Copyright (c) 2014 Tony Garnock-Jones
|
||||||
|
|
||||||
|
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
|
||||||
|
var FN_ARG_SPLIT = /,/;
|
||||||
|
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
||||||
|
|
||||||
|
function formalParameters(fn) {
|
||||||
|
var result = [];
|
||||||
|
|
||||||
|
var fnText = fn.toString().replace(STRIP_COMMENTS, '');
|
||||||
|
var argDecl = fnText.match(FN_ARGS);
|
||||||
|
var args = argDecl[1].split(FN_ARG_SPLIT);
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
var trimmed = args[i].trim();
|
||||||
|
if (trimmed) { result.push(trimmed); }
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.formalParameters = formalParameters;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,27 @@
|
||||||
|
var Route = require("./route.js");
|
||||||
|
var Util = require("./util.js");
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*/
|
||||||
|
/* Events and Actions */
|
||||||
|
|
||||||
|
var __ = Route.__;
|
||||||
|
var _$ = Route._$;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
module.exports.__ = __;
|
||||||
|
module.exports._$ = _$;
|
||||||
|
|
||||||
|
// module.exports.sub = sub;
|
||||||
|
// module.exports.pub = pub;
|
||||||
|
// module.exports.spawn = spawn;
|
||||||
|
// module.exports.updateRoutes = updateRoutes;
|
||||||
|
// module.exports.sendMessage = sendMessage;
|
||||||
|
// module.exports.shutdownWorld = shutdownWorld;
|
||||||
|
|
||||||
|
// module.exports.World = World;
|
||||||
|
// module.exports.DemandMatcher = DemandMatcher;
|
||||||
|
// module.exports.Deduplicator = Deduplicator;
|
||||||
|
module.exports.Route = Route;
|
|
@ -0,0 +1,23 @@
|
||||||
|
var Reflect = require("./reflect.js");
|
||||||
|
|
||||||
|
module.exports.extend = function (what, _with) {
|
||||||
|
for (var prop in _with) {
|
||||||
|
if (_with.hasOwnProperty(prop)) {
|
||||||
|
what[prop] = _with[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return what;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.kwApply = function (f, thisArg, args) {
|
||||||
|
var formals = Reflect.formalParameters(f);
|
||||||
|
var actuals = []
|
||||||
|
for (var i = 0; i < formals.length; i++) {
|
||||||
|
var formal = formals[i];
|
||||||
|
if (!(formal in args)) {
|
||||||
|
throw new Error("Function parameter '"+formal+"' not present in args");
|
||||||
|
}
|
||||||
|
actuals.push(args[formal]);
|
||||||
|
}
|
||||||
|
return f.apply(thisArg, actuals);
|
||||||
|
};
|
|
@ -0,0 +1,380 @@
|
||||||
|
var Immutable = require('immutable');
|
||||||
|
var expect = require('expect.js');
|
||||||
|
var util = require('util');
|
||||||
|
var r = require("../src/route.js");
|
||||||
|
|
||||||
|
function checkPrettyTrie(m, expected) {
|
||||||
|
expect(r.prettyTrie(m)).to.equal(expected.join('\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkTrieKeys(actual, expected) {
|
||||||
|
expect((Immutable.Set(actual).map(Immutable.List))
|
||||||
|
.equals(Immutable.Set(expected).map(Immutable.List))).to.be(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("basic pattern compilation", function () {
|
||||||
|
var sAny = Immutable.Set(['mAny']);
|
||||||
|
var sAAny = Immutable.Set(['mAAny']);
|
||||||
|
var mAny = r.compilePattern(sAny, r.__);
|
||||||
|
var mAAny = r.compilePattern(sAAny, ['A', r.__]);
|
||||||
|
|
||||||
|
it("should print as expected", function () {
|
||||||
|
checkPrettyTrie(mAny, [' ★ >{["mAny"]}']);
|
||||||
|
checkPrettyTrie(mAAny, [' < "A" ★ > >{["mAAny"]}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("of wildcard", function () {
|
||||||
|
it("should match anything", function () {
|
||||||
|
expect(r.matchValue(mAny, 'hi')).to.eql(sAny);
|
||||||
|
expect(r.matchValue(mAny, ['A', 'hi'])).to.eql(sAny);
|
||||||
|
expect(r.matchValue(mAny, ['B', 'hi'])).to.eql(sAny);
|
||||||
|
expect(r.matchValue(mAny, ['A', [['hi']]])).to.eql(sAny);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("of A followed by wildcard", function () {
|
||||||
|
it("should match A followed by anything", function () {
|
||||||
|
expect(r.matchValue(mAAny, 'hi')).to.be(null);
|
||||||
|
expect(r.matchValue(mAAny, ['A', 'hi'])).to.eql(sAAny);
|
||||||
|
expect(r.matchValue(mAAny, ['B', 'hi'])).to.be(null);
|
||||||
|
expect(r.matchValue(mAAny, ['A', [['hi']]])).to.eql(sAAny);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should observe basic (in)equivalences", function () {
|
||||||
|
expect(Immutable.is(mAny, mAAny)).to.be(false);
|
||||||
|
expect(Immutable.is(mAny, mAny)).to.be(true);
|
||||||
|
expect(Immutable.is(mAAny, mAAny)).to.be(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("unions", function () {
|
||||||
|
it("should collapse common prefix wildcard", function () {
|
||||||
|
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [r.__, 'B'])),
|
||||||
|
[' < ★ "A" > >{["A"]}',
|
||||||
|
' "B" > >{["B"]}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should unroll wildcard unioned with nonwildcard", function () {
|
||||||
|
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
|
||||||
|
r.compilePattern(Immutable.Set(['W']), r.__)),
|
||||||
|
[' ★ >{["W"]}',
|
||||||
|
' < ★ "A" ★...> >{["W"]}',
|
||||||
|
' > >{["A","W"]}',
|
||||||
|
' ★...> >{["W"]}',
|
||||||
|
' > >{["W"]}',
|
||||||
|
' > >{["W"]}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should properly multiply out", function () {
|
||||||
|
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
|
||||||
|
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [3, 4])),
|
||||||
|
[' < ★ 2 > >{["A"]}',
|
||||||
|
' 1 2 > >{["A"]}',
|
||||||
|
' 3 > >{["C"]}',
|
||||||
|
' 3 2 > >{["A"]}',
|
||||||
|
' 4 > >{["B"]}']);
|
||||||
|
|
||||||
|
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [3, 4])),
|
||||||
|
[' < 1 3 > >{["C"]}',
|
||||||
|
' 3 4 > >{["B"]}']);
|
||||||
|
|
||||||
|
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
|
||||||
|
r.compilePattern(Immutable.Set(['C']), [1, 3])),
|
||||||
|
[' < ★ 2 > >{["A"]}',
|
||||||
|
' 1 2 > >{["A"]}',
|
||||||
|
' 3 > >{["C"]}']);
|
||||||
|
|
||||||
|
checkPrettyTrie(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [3, 4])),
|
||||||
|
[' < ★ 2 > >{["A"]}',
|
||||||
|
' 3 2 > >{["A"]}',
|
||||||
|
' 4 > >{["B"]}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correctly construct intermediate values", function () {
|
||||||
|
var MU = r.emptyTrie;
|
||||||
|
MU = r.union(MU, r.compilePattern(Immutable.Set(['A']), [r.__, 2]));
|
||||||
|
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}']);
|
||||||
|
MU = r.union(MU, r.compilePattern(Immutable.Set(['C']), [1, 3]));
|
||||||
|
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}',
|
||||||
|
' 1 2 > >{["A"]}',
|
||||||
|
' 3 > >{["C"]}']);
|
||||||
|
MU = r.union(MU, r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||||
|
checkPrettyTrie(MU, [' < ★ 2 > >{["A"]}',
|
||||||
|
' 1 2 > >{["A"]}',
|
||||||
|
' 3 > >{["C"]}',
|
||||||
|
' 3 2 > >{["A"]}',
|
||||||
|
' 4 > >{["B"]}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle identical patterns with different pids", function () {
|
||||||
|
var m = r.union(r.compilePattern(Immutable.Set('B'), [2]),
|
||||||
|
r.compilePattern(Immutable.Set('C'), [3]));
|
||||||
|
checkPrettyTrie(m, [' < 2 > >{["B"]}',
|
||||||
|
' 3 > >{["C"]}']);
|
||||||
|
m = r.union(r.compilePattern(Immutable.Set('A'), [2]), m);
|
||||||
|
checkPrettyTrie(m, [' < 2 > >{["A","B"]}',
|
||||||
|
' 3 > >{["C"]}']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("projections", function () {
|
||||||
|
describe("with picky structure", function () {
|
||||||
|
var proj = r.compileProjection(r._$("v", [[r.__]]));
|
||||||
|
|
||||||
|
it("should include things that match as well as wildcards", function () {
|
||||||
|
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), r.__),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [['b']])),
|
||||||
|
proj),
|
||||||
|
[' < < ★ > > >{["A"]}',
|
||||||
|
' "b" > > >{["B","A"]}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should exclude things that lack the required structure", function () {
|
||||||
|
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), r.__),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), ['b'])),
|
||||||
|
proj),
|
||||||
|
[' < < ★ > > >{["A"]}']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("simple positional", function () {
|
||||||
|
var proj = r.compileProjection([r._$, r._$]);
|
||||||
|
|
||||||
|
it("should collapse common prefixes", function () {
|
||||||
|
checkPrettyTrie(r.project(r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
|
||||||
|
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [3, 4])),
|
||||||
|
proj),
|
||||||
|
[' 1 2 >{["A"]}',
|
||||||
|
' 3 >{["C"]}',
|
||||||
|
' 3 4 >{["B"]}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should yield a correct set of results", function () {
|
||||||
|
var u = r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
|
||||||
|
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||||
|
checkTrieKeys(r.trieKeys(r.project(u, proj)), [[1, 2], [1, 3], [3, 4]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("subtract after union", function () {
|
||||||
|
var R1 = r.compilePattern(Immutable.Set(['A']), [r.__, "B"]);
|
||||||
|
var R2 = r.compilePattern(Immutable.Set(['B']), ["A", r.__]);
|
||||||
|
var R12 = r.union(R1, R2);
|
||||||
|
|
||||||
|
it("should have sane preconditions", function () { // Am I doing this right?
|
||||||
|
checkPrettyTrie(R1, [' < ★ "B" > >{["A"]}']);
|
||||||
|
checkPrettyTrie(R2, [' < "A" ★ > >{["B"]}']);
|
||||||
|
checkPrettyTrie(R12, [' < "A" "B" > >{["B","A"]}',
|
||||||
|
' ★ > >{["B"]}',
|
||||||
|
' ★ "B" > >{["A"]}']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should yield the remaining ingredients of the union", function () {
|
||||||
|
expect(Immutable.is(r.subtract(R12, R1), R2)).to.be(true);
|
||||||
|
expect(Immutable.is(r.subtract(R12, R2), R1)).to.be(true);
|
||||||
|
expect(Immutable.is(r.subtract(R12, R1), R1)).to.be(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("trie equality", function () {
|
||||||
|
it("should not rely on object identity", function () {
|
||||||
|
expect(Immutable.is(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [r.__, 'B'])),
|
||||||
|
r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [r.__, 'B']))))
|
||||||
|
.to.be(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should respect commutativity of union", function () {
|
||||||
|
expect(Immutable.is(r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 'A']),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [r.__, 'B'])),
|
||||||
|
r.union(r.compilePattern(Immutable.Set(['B']), [r.__, 'B']),
|
||||||
|
r.compilePattern(Immutable.Set(['A']), [r.__, 'A']))))
|
||||||
|
.to.be(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("trieKeys on wild tries", function () {
|
||||||
|
var M = r.union(r.compilePattern(Immutable.Set(['A']), [r.__, 2]),
|
||||||
|
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||||
|
|
||||||
|
it("should yield null to signal an infinite result", function () {
|
||||||
|
expect(r.trieKeys(r.project(M, r.compileProjection([r._$, r._$])))).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should extract just the second array element successfully", function () {
|
||||||
|
checkTrieKeys(r.trieKeys(r.project(M, r.compileProjection([r.__, r._$]))),
|
||||||
|
[[2],[3],[4]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
var M2 = r.project(M, r.compileProjection([r._$, r._$]));
|
||||||
|
|
||||||
|
it("should survive double-projection", function () {
|
||||||
|
checkTrieKeys(r.trieKeys(r.project(M2, r.compileProjection(r.__, r._$))),
|
||||||
|
[[2],[3],[4]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should survive embedding and reprojection", function () {
|
||||||
|
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(true, [r.embeddedTrie(M2)]),
|
||||||
|
r.compileProjection([r.__, r._$]))),
|
||||||
|
[[2],[3],[4]]);
|
||||||
|
checkTrieKeys(r.trieKeys(r.project(r.compilePattern(true, [[r.embeddedTrie(M2)]]),
|
||||||
|
r.compileProjection([[r.__, r._$]]))),
|
||||||
|
[[2],[3],[4]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("trieKeys using multiple-values in projections", function () {
|
||||||
|
var M = r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
|
||||||
|
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||||
|
var proj = r.compileProjection([r._$, r._$]);
|
||||||
|
var M2 = r.project(M, proj);
|
||||||
|
|
||||||
|
it("should be able to extract ordinary values", function () {
|
||||||
|
checkTrieKeys(r.trieKeys(M2), [[1,2],[1,3],[3,4]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be able to be reprojected as a sequence of more than one value", function () {
|
||||||
|
checkTrieKeys(r.trieKeys(r.project(M2, r.compileProjection(r._$, r._$))),
|
||||||
|
[[1,2],[1,3],[3,4]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be convertible into objects with $-indexed fields", function () {
|
||||||
|
expect(r.trieKeysToObjects(r.trieKeys(M2), proj))
|
||||||
|
.to.eql([{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
|
||||||
|
expect(r.projectObjects(M, proj))
|
||||||
|
.to.eql([{'$0': 3, '$1': 4}, {'$0': 1, '$1': 2}, {'$0': 1, '$1': 3}]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("trieKeys using multiple-values in projections, with names", function () {
|
||||||
|
var M = r.union(r.compilePattern(Immutable.Set(['A']), [1, 2]),
|
||||||
|
r.compilePattern(Immutable.Set(['C']), [1, 3]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [3, 4]));
|
||||||
|
|
||||||
|
it("should yield named fields", function () {
|
||||||
|
expect(r.projectObjects(M, r.compileProjection([r._$("fst"), r._$("snd")])))
|
||||||
|
.to.eql([{'fst': 3, 'snd': 4}, {'fst': 1, 'snd': 2}, {'fst': 1, 'snd': 3}]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should yield numbered fields where names are missing", function () {
|
||||||
|
expect(r.projectObjects(M, r.compileProjection([r._$, r._$("snd")])))
|
||||||
|
.to.eql([{'$0': 3, 'snd': 4}, {'$0': 1, 'snd': 2}, {'$0': 1, 'snd': 3}]);
|
||||||
|
expect(r.projectObjects(M, r.compileProjection([r._$("fst"), r._$])))
|
||||||
|
.to.eql([{'fst': 3, '$1': 4}, {'fst': 1, '$1': 2}, {'fst': 1, '$1': 3}]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("complex erasure", function () {
|
||||||
|
var A = r.compilePattern(Immutable.Set(['A']), r.__);
|
||||||
|
var B = r.union(r.compilePattern(Immutable.Set(['B']), [[[["foo"]]]]),
|
||||||
|
r.compilePattern(Immutable.Set(['B']), [[[["bar"]]]]));
|
||||||
|
describe("after a union", function () {
|
||||||
|
var R0 = r.union(A, B);
|
||||||
|
var R1a = r.subtract(R0, B);
|
||||||
|
var R1b = r.subtract(R0, A);
|
||||||
|
|
||||||
|
it("should yield the other parts of the union", function () {
|
||||||
|
expect(Immutable.is(R1a, A)).to.be(true);
|
||||||
|
expect(Immutable.is(R1b, B)).to.be(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("embedding tries in patterns", function () {
|
||||||
|
var M1a =
|
||||||
|
r.compilePattern(Immutable.Set(['A']),
|
||||||
|
[1, r.embeddedTrie(r.compilePattern(Immutable.Set(['B']), [2, 3])), 4]);
|
||||||
|
var M1b =
|
||||||
|
r.compilePattern(Immutable.Set(['A']), [1, [2, 3], 4]);
|
||||||
|
var M2a =
|
||||||
|
r.compilePattern(Immutable.Set(['A']),
|
||||||
|
[r.embeddedTrie(r.compilePattern(Immutable.Set(['B']), [1, 2])),
|
||||||
|
r.embeddedTrie(r.compilePattern(Immutable.Set(['C']), [3, 4]))]);
|
||||||
|
var M2b =
|
||||||
|
r.compilePattern(Immutable.Set(['A']), [[1, 2], [3, 4]]);
|
||||||
|
|
||||||
|
it("should yield tries equivalent to the original patterns", function () {
|
||||||
|
expect(Immutable.is(M1a, M1b)).to.be(true);
|
||||||
|
expect(Immutable.is(M2a, M2b)).to.be(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("calls to matchPattern", function () {
|
||||||
|
it("should yield appropriately-named/-numbered fields", function () {
|
||||||
|
expect(r.matchPattern([1, 2, 3], [r.__, 2, r._$])).to.eql({'$0': 3, 'length': 1});
|
||||||
|
expect(r.matchPattern([1, 2, 3], [r.__, 2, r._$("three")])).to.eql({'three': 3, 'length': 1});
|
||||||
|
expect(r.matchPattern([1, 2, 3], [r._$, 2, r._$("three")]))
|
||||||
|
.to.eql({'$0': 1, 'three': 3, 'length': 2});
|
||||||
|
expect(r.matchPattern([1, 2, 3], [r._$("one"), 2, r._$]))
|
||||||
|
.to.eql({'one': 1, '$1': 3, 'length': 2});
|
||||||
|
expect(r.matchPattern([1, 2, 3], [r._$("one"), 2, r._$("three")]))
|
||||||
|
.to.eql({'one': 1, 'three': 3, 'length': 2});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fail on value mismatch", function () {
|
||||||
|
expect(r.matchPattern([1, 2, 3], [r.__, 999, r._$("three")])).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should fail on array length mismatch", function () {
|
||||||
|
expect(r.matchPattern([1, 2, 3], [r.__, 2, r._$("three"), 4])).to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches substructure", function () {
|
||||||
|
expect(r.matchPattern([1, [2, 999], 3], [r._$("one"), r._$(null, [2, r.__]), r._$("three")]))
|
||||||
|
.to.eql({ one: 1, '$1': [ 2, 999 ], three: 3, length: 3 });
|
||||||
|
expect(r.matchPattern([1, [2, 999], 3], [r._$("one"), r._$("two", [2, r.__]), r._$("three")]))
|
||||||
|
.to.eql({ one: 1, two: [ 2, 999 ], three: 3, length: 3 });
|
||||||
|
expect(r.matchPattern([1, [999, 2], 3], [r._$("one"), r._$(null, [2, r.__]), r._$("three")]))
|
||||||
|
.to.be(null);
|
||||||
|
expect(r.matchPattern([1, [999, 2], 3], [r._$("one"), r._$("two", [2, r.__]), r._$("three")]))
|
||||||
|
.to.be(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches nested captures", function () {
|
||||||
|
expect(r.matchPattern([1, [2, 999], 3], [r._$("one"), r._$(null, [2, r._$]), r._$("three")]))
|
||||||
|
.to.eql({ one: 1, '$2': 999, '$1': [ 2, 999 ], three: 3, length: 4 });
|
||||||
|
expect(r.matchPattern([1, [2, 999], 3], [r._$("one"), r._$("two", [2, r._$]), r._$("three")]))
|
||||||
|
.to.eql({ one: 1, '$2': 999, two: [ 2, 999 ], three: 3, length: 4 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Projection with no captures", function () {
|
||||||
|
it("should yield the empty sequence when there's a match", function () {
|
||||||
|
var emptySequence = [' >{["A"]}'];
|
||||||
|
|
||||||
|
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||||
|
r.compileProjection(r.__)),
|
||||||
|
emptySequence);
|
||||||
|
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||||
|
r.compileProjection([r.__, r.__])),
|
||||||
|
emptySequence);
|
||||||
|
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||||
|
r.compileProjection(["X", r.__])),
|
||||||
|
emptySequence);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should yield the empty trie when there's no match", function () {
|
||||||
|
expect(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||||
|
r.compileProjection(["Y", r.__]))).to.be(r.emptyTrie);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should yield nonempty sequences when there are captures after all", function () {
|
||||||
|
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||||
|
r.compileProjection([r.__, r._$])),
|
||||||
|
[' ★ >{["A"]}']);
|
||||||
|
checkPrettyTrie(r.project(r.compilePattern(Immutable.Set(['A']), ["X", r.__]),
|
||||||
|
r.compileProjection([r._$, r._$])),
|
||||||
|
[' "X" ★ >{["A"]}']);
|
||||||
|
});
|
||||||
|
});
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue