Spec modification by diff object

https://fedorahosted.org/freeipa/ticket/3235
This commit is contained in:
Petr Vobornik
2013-05-06 16:22:23 +02:00
parent abdb5455d1
commit fcbf5cc411
7 changed files with 342 additions and 5 deletions
+17 -2
View File
@@ -21,8 +21,9 @@
define(['dojo/_base/declare',
'dojo/_base/array',
'dojo/_base/lang',
'./construct'
], function(declare, array, lang, construct) {
'./construct',
'./Spec_mod'
], function(declare, array, lang, construct, Spec_mod) {
var Builder = declare(null, {
/**
@@ -38,6 +39,11 @@ define(['dojo/_base/declare',
*/
registry: null,
/**
* Specification modifier
*/
spec_mod: null,
/**
* Build object based on spec.
*
@@ -152,6 +158,9 @@ define(['dojo/_base/declare',
if (preop_t === 'function') {
cs.spec = preop(cs.spec || {});
} else if (preop_t === 'object') {
var temp = lang.clone(preop);
this.spec_mod.mod(cs.spec, temp);
this.spec_mod.del_rules(temp);
lang.mixin(cs.spec, preop);
}
}
@@ -159,6 +168,10 @@ define(['dojo/_base/declare',
cs.spec = cs.spec || {};
// do we want following?, remove?
this.spec_mod.mod(cs.spec, cs.spec);
this.spec_mod.del_rules(cs.spec);
if (cs.factory && typeof cs.factory === 'function') {
obj = cs.factory(cs.spec);
} else if (cs.constructor && typeof cs.constructor === 'function') {
@@ -194,6 +207,8 @@ define(['dojo/_base/declare',
spec = spec || {};
if (spec.registry) this.registry = spec.registry;
if (spec.spec_mod) this.spec_mod = spec.spec_mod;
else this.spec_mod = new Spec_mod();
}
});
+177
View File
@@ -0,0 +1,177 @@
/* Authors:
* Petr Vobornik <pvoborni@redhat.com>
*
* Copyright (C) 2013 Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
define(['dojo/_base/declare',
'dojo/_base/lang'
], function(declare, lang) {
var Spec_mod = declare(null, {
/**
* Modifies spec according to rules defined in diff object.
*
* Diff should have following structure: {
* $add: array of add rules
* $del: array of del rules
* $set: array of set rules
* }
*
* The order of modification is del, add, set.
*
* @param {Object} spec
* @param {Object} diff
*/
mod: function(spec, diff) {
if (!diff) return spec;
this.del(spec, diff.$del);
this.add(spec, diff.$add);
this.set(spec, diff.$set);
return spec;
},
/**
* Adds objects according to rules to array.
*
* A rule is a triple of path and a object and position to add:
* ['path.to.spec.array', {}, position]
*
*/
add: function(spec, rules) {
return this._apply_rules(spec, rules, this._add);
},
/**
* Deletes objects according to rules from an array.
*
* A rule is a pair of path and delete conditions:
* ['path.to.spec.array', [ { name: 'foo'}, { name: 'baz'} ]]
*
* Deletes all objects with name 'baz' or 'foo'.
*/
del: function(spec, rules) {
return this._apply_rules(spec, rules, this._del);
},
/**
* A rule is a pair of path and a object to set.
* ['path.to.spec.property', {}]
*/
set: function(spec, rules) {
return this._apply_rules(spec, rules, this._set);
},
/**
* Removes all rule props
*/
del_rules: function(diff) {
delete diff.$add;
delete diff.$del;
delete diff.$set;
},
_apply_rules: function(spec, rules, method) {
if (!lang.isArrayLike(rules)) return spec;
for (var i=0; i<rules.length; i++) {
method.call(this, spec, rules[i]);
}
return spec;
},
_add: function(spec, rule) {
var path = rule[0];
var value = rule[1];
var pos = rule[2];
var arr = lang.getObject(path, false, spec);
if (!arr) {
arr = [];
lang.setObject(path, arr, spec);
}
if (typeof pos !== 'number') pos = arr.length;
else if (pos < 0) pos = 0;
else if (pos > arr.length) pos = arr.length;
arr.splice(pos, 0, value);
return spec;
},
_del: function(spec, rule) {
var path = rule[0];
var conds = rule[1];
var arr = lang.getObject(path, false, spec);
if (!arr) return spec;
var del = [];
var i,j;
for (i=0; i<arr.length; i++) {
for (j=0; j<conds.length; j++) {
if (this._match(arr[i], conds[j])) {
del.push(i);
break;
}
}
}
del.sort(function(a,b) {return b-a;});
for (i=0; i<del.length;i++) {
arr.splice(del[i], 1);
}
return spec;
},
_match: function(value, cond) {
var match = true;
if (typeof cond !== 'object') {
match = cond === value;
} else {
for (var prop in cond) {
if (cond.hasOwnProperty(prop) && cond[prop] !== value[prop]) {
match = false;
break;
}
}
}
return match;
},
_set: function(spec, rule) {
lang.setObject(rule[0], rule[1], spec);
return spec;
}
});
return Spec_mod;
});
+4 -2
View File
@@ -23,8 +23,9 @@
'test/aci_tests',
'test/widget_tests',
'test/ip_tests',
'test/utils_tests'
], function(om, ipa, details, entity, as, nav, cert, aci, wid, ip, ut){
'test/utils_tests',
'test/build_tests'
], function(om, ipa, details, entity, as, nav, cert, aci, wid, ip, ut, bt){
om();
ipa();
details();
@@ -36,6 +37,7 @@
wid();
ip();
ut();
bt();
});
</script>
</head>
+22
View File
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<title>IPA utils test suite</title>
<link rel="stylesheet" href="qunit.css" type="text/css" media="screen">
<script type="text/javascript" src="qunit.js"></script>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript" src="../js/dojo/dojo.js"></script>
<script type="text/javascript">
require(['test/build_tests'], function(tests){ tests() });
</script>
</head>
<body>
<h1 id="qunit-header">IPA Build test suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture"></div>
</body>
</html>
+119
View File
@@ -0,0 +1,119 @@
/* Authors:
* Petr Vobornik <pvoborni@redhat.com>
*
* Copyright (C) 2013 Red Hat
* see file 'COPYING' for use and warranty information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
define([
'freeipa/_base/Spec_mod'],
function(Spec_mod) { return function() {
module('build',{
setup: function() {
},
teardown: function() {
}
});
test('Testing builder', function() {
});
test('Testing Spec_mod', function() {
var sm = new Spec_mod();
var spec = {
foo: {
arr1: [
{ name: 'i1', a: 'b' },
{ name: 'i2', a: 'b' },
{ name: 'i3', a: 'c' },
{ name: 'i4', a: 'c' },
{ name: 'i5', a: 'a' }
],
arr2: ['item1']
},
baz: {
bar: 'a'
},
bar: 'b'
};
var diff = {
$add: [
['foo.arr1', { name: 'foo', a: 'c' }],
['foo.arr2', 'item2'],
['foo.arr2', { name: 'foo' }],
['arr3', 'a'] //creates new array
],
$del: [
[
'foo.arr1',
[
{ name: 'i1' }, //match
{ a: 'c'}, // 2 matches
{ name: 'i2', a:'c' }, //no match
{ name: 'i5', a:'a' } // match
]
],
[ 'foo.arr2', ['item1'] ] //match
],
$set: [
[ 'arr4', ['b'] ], // new array in spec
[ 'baz.bar', 'c'], //overwrite 'a'
[ 'baz.baz.baz', 'a'], // new property
[ 'bar', { foo: 'baz' }] // replace string by object
]
};
var ref = {
foo: {
arr1: [
{ name: 'i2', a: 'b' },
{ name: 'foo', a: 'c'}
],
arr2: [
'item2', { name: 'foo' }
]
},
arr3: [ 'a' ],
baz: {
bar: 'c',
baz: { baz: 'a' }
},
bar: { foo: 'baz' },
arr4: ['b']
};
sm.mod(spec, diff);
deepEqual(spec, ref, 'Complex Modification');
spec = {
a: [ 'a1', 'a2', 'a3' ]
};
var rules = [[ 'a', 'new', 1]];
sm.add(spec, rules);
deepEqual(spec, { a: ['a1', 'new', 'a2', 'a3'] }, 'Add on position');
});
};});
+1
View File
@@ -35,6 +35,7 @@
<li><a href="widget_tests.html">Widget Test Suite</a>
<li><a href="ip_tests.html">IP Addresses Test Suite</a>
<li><a href="utils_tests.html">Utils Test Suite</a>
<li><a href="build_tests.html">Build Test Suite</a>
</ul>
</div>
+2 -1
View File
@@ -148,4 +148,5 @@
+process ordered_map_tests.js
+process widget_tests.js
+process ip_tests.js
+process utils_tests.js
+process utils_tests.js
+process build_tests.js