Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling default attributes for node/edge/graph statements #55

Merged
merged 3 commits into from
Feb 18, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions src/dot.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,57 @@ dagre.dot.toGraph = function(str) {
g.addEdge(id, source, target, edge);
}

function handleStmt(stmt) {
var defaultAttrs = {
_default: {},

get: function get(type, attrs) {
if (typeof this._default[type] !== "undefined") {
var mergedAttrs = {};
// clone default attributes so they won't get overwritten in the next step
mergeAttributes(this._default[type], mergedAttrs);
// merge statement attributes with default attributes, precedence give to stmt attributes
mergeAttributes(attrs, mergedAttrs);
return mergedAttrs;
} else {
return attrs;
}
},

set: function set(type, attrs) {
this._default[type] = this.get(type, attrs);
}
};

function handleStmt(stmt, skipDefaultAttributes) {
var attrs;
if (typeof skipDefaultAttributes === "undefined" || skipDefaultAttributes !== true) {
attrs = defaultAttrs.get(stmt.type, stmt.attrs);
} else {
attrs = stmt.attrs;
}

switch (stmt.type) {
case "node":
createNode(stmt.id, stmt.attrs);
createNode(stmt.id, attrs);
break;
case "edge":
var prev;
stmt.elems.forEach(function(elem) {
handleStmt(elem);
// Default attribute inclusion has to be skipped for nested calls
// to not overwrite attributes that have been defined through preceding
// default attribute statements.
//
// Test "overrides redefined default attributes" in test/dot-test.js checks that.
handleStmt(elem, true);

switch(elem.type) {
case "node":
var curr = elem.id;

if (prev) {
createEdge(prev, curr, stmt.attrs);
createEdge(prev, curr, attrs);
if (undir) {
createEdge(curr, prev, stmt.attrs);
createEdge(curr, prev, attrs);
}
}
prev = curr;
Expand All @@ -59,7 +92,7 @@ dagre.dot.toGraph = function(str) {
});
break;
case "attr":
// Ignore for now
defaultAttrs.set(stmt.attrType, stmt.attrs);
break;
default:
throw new Error("Unsupported statement type: " + stmt.type);
Expand Down
45 changes: 45 additions & 0 deletions test/dot-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,49 @@ describe("dagre.dot.toGraph", function() {
var g = dagre.dot.toGraph("digraph { a [label=\"\"]; }");
assert.equal(g.node("a").label, "");
});
it("adds default attributes to nodes", function() {
var dot = "digraph { node [color=black shape=box]; n1 [label=\"n1\"]; n2 [label=\"n2\"]; n1 -> n2; }";
var g = dagre.dot.toGraph(dot);
assert.equal(g.node("n1").color, "black");
assert.equal(g.node("n1").shape, "box");
assert.equal(g.node("n1").label, "n1");

assert.equal(g.node("n2").color, "black");
assert.equal(g.node("n2").shape, "box");
assert.equal(g.node("n2").label, "n2");
});
it("combines multiple default attribute statements", function() {
var dot = "digraph { node [color=black]; node [shape=box]; n1 [label=\"n1\"]; }";
var g = dagre.dot.toGraph(dot);
assert.equal(g.node("n1").color, "black");
assert.equal(g.node("n1").shape, "box");
});
it("takes statement order into account when applying default attributes", function() {
var dot = "digraph { node [color=black]; n1 [label=\"n1\"]; node [shape=box]; n2 [label=\"n2\"]; }";
var g = dagre.dot.toGraph(dot);
assert.equal(g.node("n1").color, "black");
assert.equal(g.node("n1").shape, undefined);

assert.equal(g.node("n2").color, "black");
assert.equal(g.node("n2").shape, "box");
});
it("overrides redefined default attributes", function() {
var dot = "digraph { node [color=black]; n1 [label=\"n1\"]; node [color=green]; n2 [label=\"n2\"]; n1 -> n2; }";
var g = dagre.dot.toGraph(dot);
assert.equal(g.node("n1").color, "black");
assert.equal(g.node("n2").color, "green");

// Implementation detail:
// toGraph::handleStmt wants to assure that nodes used in an edge definition
// are defined by calling createNode for those nodes. If these nested createNode
// calls don't skip merging the default attributes, the attributes of already
// defined nodes could be overwritten, causing both nodes in this test case to
// have "color" set to green.
});
it("does not carry attributes from one node over to the next", function() {
var dot = "digraph { node [color=black]; n1 [label=\"n1\" fontsize=12]; n2 [label=\"n2\"]; n1 -> n2; }";
var g = dagre.dot.toGraph(dot);
assert.equal(g.node("n1").fontsize, 12);
assert.equal(g.node("n2").fontsize, undefined, "n2.fontsize should not be defined");
});
});