Skip to content

Commit

Permalink
Merge branch 'master' into FLUID-5552
Browse files Browse the repository at this point in the history
  • Loading branch information
cindyli committed Jan 21, 2015
2 parents 74cb790 + c860fe5 commit 9323991
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 125 deletions.
19 changes: 12 additions & 7 deletions src/framework/core/js/DataBinding.js
Expand Up @@ -1013,6 +1013,7 @@ var fluid_2_0 = fluid_2_0 || {};
if (sourceCode === "primitive") {
if (!fluid.model.isSameValue(targetSlot, source)) {
changedValue = source;
++options.unchanged;
}
} else if (targetCode !== sourceCode || sourceCode === "array" && source.length !== targetSlot.length) {
// RH is not primitive - array or object and mismatching or any array rewrite
Expand Down Expand Up @@ -1051,7 +1052,7 @@ var fluid_2_0 = fluid_2_0 || {};
// After the 1.5 release, this will replace the old "applyChangeRequest"
// Changes: "MERGE" action abolished
// ADD/DELETE at root can be destructive
// changes tracked in optional final argument holding "changeMap: {}, changes: 0"
// changes tracked in optional final argument holding "changeMap: {}, changes: 0, unchanged: 0"
fluid.model.applyHolderChangeRequest = function (holder, request, options) {
options = fluid.model.defaultAccessorConfig(options);
options.deltaMap = options.changeMap ? {} : null;
Expand Down Expand Up @@ -1088,18 +1089,19 @@ var fluid_2_0 = fluid_2_0 || {};
* not contain circular links.
* @param modela The first model to be compared
* @param modelb The second model to be compared
* @param options If supplied, will receive a map and summary of the change content between the objects. It should hold
* {changeMap (Object/String), changes (int)} summarising the number and location of the differences
* between the structures. The <code>changeMap</code> is an isomorphic map of the object structures to values "ADD" or "DELETE" indicating
* that values have been added/removed at that location. <code>changes</code> counts the number of such changes. The two objects are
* identical iff <code>changes === 0</code>. Note that in the case the object structure differs at the root, <code>changeMap</code> will hold
* @param options {Object} If supplied, will receive a map and summary of the change content between the objects. Structure is:
* changeMap: {Object/String} An isomorphic map of the object structures to values "ADD" or "DELETE" indicating
* that values have been added/removed at that location. Note that in the case the object structure differs at the root, <code>changeMap</code> will hold
* the plain String value "ADD" or "DELETE"
* changes: {Integer} Counts the number of changes between the objects - The two objects are identical iff <code>changes === 0</code>.
* unchanged: {Integer} Counts the number of leaf (primitive) values at which the two objects are identical. Note that the current implementation will
* double-count, this summary should be considered indicative rather than precise.
* @return <code>true</code> if the models are identical
*/
// TODO: This algorithm is quite inefficient in that both models will be copied once each
// supported, PUBLIC API function
fluid.model.diff = function (modela, modelb, options) {
options = options || {changeMap: {}, changes: 0}; // current algorithm can't avoid the expense of changeMap
options = options || {changes: 0, unchanged: 0, changeMap: {}}; // current algorithm can't avoid the expense of changeMap
var typea = fluid.typeCode(modela);
var typeb = fluid.typeCode(modelb);
var togo;
Expand All @@ -1124,6 +1126,8 @@ var fluid_2_0 = fluid_2_0 || {};
if (togo === false && options.changes === 0) { // catch all primitive cases
options.changes = 1;
options.changeMap = modelb === undefined ? "DELETE" : "ADD";
} else if (togo === true && options.unchanged === 0) {
options.unchanged = 1;
}
return togo;
};
Expand Down Expand Up @@ -1311,6 +1315,7 @@ var fluid_2_0 = fluid_2_0 || {};
trans.oldHolder = holder;
trans.newHolder = { model: fluid.copy(holder.model) };
trans.changeRecord.changes = 0;
trans.changeRecord.unchanged = 0; // just for type consistency - we don't use these values in the ChangeApplier
trans.changeRecord.changeMap = {};
},
commit: function (code) {
Expand Down
56 changes: 13 additions & 43 deletions src/framework/core/js/ModelTransformation.js
Expand Up @@ -134,48 +134,18 @@ var fluid = fluid || fluid_2_0;
return (val !== undefined) ? val : def;
};

// TODO: Incomplete implementation which only checks expected paths
fluid.deepEquals = function (expected, actual, stats) {
if (fluid.isPrimitive(expected)) {
if (expected === actual) {
++stats.matchCount;
} else {
++stats.mismatchCount;
stats.messages.push("Value mismatch at path " + stats.path + ": expected " + expected + " actual " + actual);
}
}
else {
if (typeof(expected) !== typeof(actual)) {
++stats.mismatchCount;
stats.messages.push("Type mismatch at path " + stats.path + ": expected " + typeof(expected) + " actual " + typeof(actual));
} else {
fluid.each(expected, function (value, key) {
stats.pathOp.push(key);
fluid.deepEquals(expected[key], actual[key], stats);
stats.pathOp.pop(key);
});
}
}
};

fluid.model.transform.matchValue = function (expected, actual) {
if (fluid.isPrimitive(expected)) {
return expected === actual ? 1 : 0;
} else {
var stats = {
matchCount: 0,
mismatchCount: 0,
messages: []
};
stats.pathOp = fluid.model.makePathStack(stats, "path");
fluid.deepEquals(expected, actual, stats);
return stats.matchCount;
}
};

// unsupported, NON-API function
fluid.model.transform.compareMatches = function (speca, specb) {
return specb.matchCount - speca.matchCount;
// Compute a "match score" between two pieces of model material, with 0 indicating a complete mismatch, and
// higher values indicating increasingly good matches
fluid.model.transform.matchValue = function (expected, actual, partialMatches) {
var stats = {changes: 0, unchanged: 0, changeMap: {}};
fluid.model.diff(expected, actual, stats);
// i) a pair with 0 matches counts for 0 in all cases
// ii) without "partial match mode" (the default), we simply count matches, with any mismatch giving 0
// iii) with "partial match mode", a "perfect score" in the top 24 bits is
// penalised for each mismatch, with a positive score of matches store in the bottom 24 bits
return stats.unchanged === 0 ? 0
: (partialMatches ? 0xffffff000000 - 0x1000000 * stats.changes + stats.unchanged :
(stats.changes ? 0 : 0xffffff000000 + stats.unchanged));
};

fluid.firstDefined = function (a, b) {
Expand Down Expand Up @@ -245,7 +215,7 @@ var fluid = fluid || fluid_2_0;
var expanded = fluid.model.transform.getValue(valueHolder.valuePath, valueHolder.value, transform);

transformArgs.unshift(expanded);
//if the function has no input, the result is considered undefined, and this is returned
// if the function has no input, the result is considered undefined, and this is returned
if (expanded === undefined) {
return undefined;
}
Expand Down

0 comments on commit 9323991

Please sign in to comment.