kojac 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +7 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +158 -0
- data/MIT-LICENSE +20 -0
- data/README.md +69 -0
- data/Rakefile +27 -0
- data/app/assets/javascripts/can_extensions.js +45 -0
- data/app/assets/javascripts/kojac.js +1230 -0
- data/app/assets/javascripts/kojac_canjs.js +191 -0
- data/app/assets/javascripts/kojac_ember.js +463 -0
- data/app/controllers/kojac_controller.rb +70 -0
- data/app/serializers/default_kojac_serializer.rb +10 -0
- data/diagram.odg +0 -0
- data/kojac.gemspec +36 -0
- data/lib/kojac/app_serialize.rb +29 -0
- data/lib/kojac/kojac_rails.rb +432 -0
- data/lib/kojac/ring_strong_parameters.rb +195 -0
- data/lib/kojac/version.rb +3 -0
- data/lib/kojac.rb +8 -0
- data/lib/tasks/kojac_tasks.rake +4 -0
- data/notes.txt +48 -0
- data/spec/.DS_Store +0 -0
- data/spec/can_cache_spec.js +87 -0
- data/spec/can_factory_spec.js +144 -0
- data/spec/can_model_spec.js +127 -0
- data/spec/demo/README.rdoc +261 -0
- data/spec/demo/Rakefile +7 -0
- data/spec/demo/app/assets/javascripts/application.js +15 -0
- data/spec/demo/app/assets/stylesheets/application.css +13 -0
- data/spec/demo/app/controllers/application_controller.rb +3 -0
- data/spec/demo/app/helpers/application_helper.rb +2 -0
- data/spec/demo/app/mailers/.gitkeep +0 -0
- data/spec/demo/app/models/.gitkeep +0 -0
- data/spec/demo/app/views/layouts/application.html.erb +14 -0
- data/spec/demo/config/application.rb +65 -0
- data/spec/demo/config/boot.rb +10 -0
- data/spec/demo/config/database.yml +25 -0
- data/spec/demo/config/environment.rb +5 -0
- data/spec/demo/config/environments/development.rb +37 -0
- data/spec/demo/config/environments/production.rb +67 -0
- data/spec/demo/config/environments/test.rb +37 -0
- data/spec/demo/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/demo/config/initializers/inflections.rb +15 -0
- data/spec/demo/config/initializers/mime_types.rb +5 -0
- data/spec/demo/config/initializers/secret_token.rb +7 -0
- data/spec/demo/config/initializers/session_store.rb +8 -0
- data/spec/demo/config/initializers/wrap_parameters.rb +14 -0
- data/spec/demo/config/locales/en.yml +5 -0
- data/spec/demo/config/routes.rb +58 -0
- data/spec/demo/config.ru +4 -0
- data/spec/demo/lib/assets/.gitkeep +0 -0
- data/spec/demo/log/.gitkeep +0 -0
- data/spec/demo/public/404.html +26 -0
- data/spec/demo/public/422.html +26 -0
- data/spec/demo/public/500.html +25 -0
- data/spec/demo/public/favicon.ico +0 -0
- data/spec/demo/script/rails +6 -0
- data/spec/ember_factory_spec.js +157 -0
- data/spec/ember_model_spec.js +179 -0
- data/spec/external/.DS_Store +0 -0
- data/spec/external/ember/.DS_Store +0 -0
- data/spec/external/ember/ember-1.0.0-rc.6.js +30970 -0
- data/spec/external/ember/handlebars-1.0.0-rc.4.js +2239 -0
- data/spec/external/jasmine/MIT.LICENSE +20 -0
- data/spec/external/jasmine/jasmine-html.js +616 -0
- data/spec/external/jasmine/jasmine.css +81 -0
- data/spec/external/jasmine/jasmine.js +2529 -0
- data/spec/external/jasmine.async.js +51 -0
- data/spec/external/jquery/jquery-1.7.2.js +9404 -0
- data/spec/external/jquery/jquery-1.7.2.min.js +4 -0
- data/spec/external/jquery/jquery-1.9.1.js +9597 -0
- data/spec/external/json2.js +480 -0
- data/spec/external/steal/steal-121115.js +2747 -0
- data/spec/external/steal/steal-3.2.3.js +2098 -0
- data/spec/external/steal/steal-3.2.3.min.js +27 -0
- data/spec/external/steal/steal.js +2466 -0
- data/spec/external/steal/steal.min.js +32 -0
- data/spec/external/steal/stealconfig.js +19 -0
- data/spec/external/underscore.js +1223 -0
- data/spec/external/underscore_plus.js +261 -0
- data/spec/external.zip +0 -0
- data/spec/handler_stack_spec.js +143 -0
- data/spec/helpers/SpecHelper.js +10 -0
- data/spec/kojac_caching_spec.js +105 -0
- data/spec/kojac_mock_spec.js +230 -0
- data/spec/kojac_model_spec.js +126 -0
- data/spec/kojac_object_spec.js +171 -0
- data/spec/kojac_operations_spec.js +41 -0
- data/spec/mockjson/order_item.js +37 -0
- data/spec/mockjson/order_item__49.js +15 -0
- data/spec/mockjson/order_item__50.js +15 -0
- data/spec/mockjson/order_item__51.js +15 -0
- data/spec/mockjson/product.js +82 -0
- data/spec/mockjson/product__3.js +22 -0
- data/spec/model_ring_spec.rb +52 -0
- data/spec/operation_include_spec.js +77 -0
- data/spec/run.html +81 -0
- data/spec/spec.js +2 -0
- data/spec/support/jasmine.yml +86 -0
- metadata +380 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
// underscore_plus.js
|
|
2
|
+
// (c) 2012 Gary McGhee, Buzzware Solutions
|
|
3
|
+
// https://github.com/buzzware/underscore_plus
|
|
4
|
+
// Underscore may be freely distributed under the MIT license.
|
|
5
|
+
|
|
6
|
+
(function() {
|
|
7
|
+
|
|
8
|
+
//BEGIN copied from underscore
|
|
9
|
+
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
|
|
10
|
+
// Create quick reference variables for speed access to core prototypes.
|
|
11
|
+
var slice = ArrayProto.slice;
|
|
12
|
+
//END copied from underscore
|
|
13
|
+
|
|
14
|
+
_.stringify = function(aObject) {
|
|
15
|
+
if (_.isString(aObject))
|
|
16
|
+
return aObject;
|
|
17
|
+
if (aObject===null || aObject===undefined)
|
|
18
|
+
return '';
|
|
19
|
+
if (aObject.toString)
|
|
20
|
+
return aObject.toString();
|
|
21
|
+
return '';
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
//var MAX_DUMP_DEPTH = 10;
|
|
25
|
+
//
|
|
26
|
+
// function dumpObj(obj, name, indent, depth) {
|
|
27
|
+
// if (depth > MAX_DUMP_DEPTH) {
|
|
28
|
+
// return indent + name + ": <Maximum Depth Reached>\n";
|
|
29
|
+
// }
|
|
30
|
+
// if (typeof obj == "object") {
|
|
31
|
+
// var child = null;
|
|
32
|
+
// var output = indent + name + "\n";
|
|
33
|
+
// indent += "\t";
|
|
34
|
+
// for (var item in obj)
|
|
35
|
+
// {
|
|
36
|
+
// try {
|
|
37
|
+
// child = obj[item];
|
|
38
|
+
// } catch (e) {
|
|
39
|
+
// child = "<Unable to Evaluate>";
|
|
40
|
+
// }
|
|
41
|
+
// if (typeof child == "object") {
|
|
42
|
+
// output += dumpObj(child, item, indent, depth + 1);
|
|
43
|
+
// } else {
|
|
44
|
+
// output += indent + item + ": " + child + "\n";
|
|
45
|
+
// }
|
|
46
|
+
// }
|
|
47
|
+
// return output;
|
|
48
|
+
// } else {
|
|
49
|
+
// return obj;
|
|
50
|
+
// }
|
|
51
|
+
// }
|
|
52
|
+
|
|
53
|
+
_.concat = function(aArray,aAnotherArray) {
|
|
54
|
+
var result = [];
|
|
55
|
+
result.push.apply(result, aArray);
|
|
56
|
+
result.push.apply(result, aAnotherArray);
|
|
57
|
+
return result;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
_.nameValueString = function(aObject) {
|
|
61
|
+
return _.map(_.keys(aObject),function(k) { return k+'="'+_.stringify(aObject[k])+'"'}).join(' ');
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
_.classEnsure = function(aOrig,aNew) {
|
|
65
|
+
if (!aOrig)
|
|
66
|
+
return aNew;
|
|
67
|
+
if (!aNew)
|
|
68
|
+
return aOrig;
|
|
69
|
+
return _.union(aOrig.split(' '),aNew.split(' '));
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
_.getPath = function(aObject,aPath,aDefault) {
|
|
73
|
+
if ((typeof aObject)=='string') { // allow aObject to be left out and assume this
|
|
74
|
+
if (arguments.length==1) {
|
|
75
|
+
aPath = aObject;
|
|
76
|
+
aObject = window;
|
|
77
|
+
} else if (arguments.length==2) {
|
|
78
|
+
aDefault = aPath;
|
|
79
|
+
aPath = aObject;
|
|
80
|
+
aObject = window;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
var nodes = aPath.split('.');
|
|
84
|
+
var curr = aObject;
|
|
85
|
+
for (var i=0;i<nodes.length;i++) {
|
|
86
|
+
var name = nodes[i];
|
|
87
|
+
if ((curr===undefined)||(curr===null))
|
|
88
|
+
return aDefault;
|
|
89
|
+
if ((name in curr) || curr[name]) {
|
|
90
|
+
var val = curr[name];
|
|
91
|
+
if ((typeof val)=='function')
|
|
92
|
+
curr = val.call(curr);
|
|
93
|
+
else
|
|
94
|
+
curr = val;
|
|
95
|
+
} else {
|
|
96
|
+
return aDefault; // name doesn't exist
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return curr;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
_.moveKeys = function(aDest,aSource,aKeys) {
|
|
103
|
+
if (!aSource)
|
|
104
|
+
return aDest;
|
|
105
|
+
if (!aKeys)
|
|
106
|
+
aKeys = _.keys(aSource);
|
|
107
|
+
for (var i=0;i<aKeys.length;i++) {
|
|
108
|
+
var k = aKeys[i];
|
|
109
|
+
if (!(k in aSource))
|
|
110
|
+
continue;
|
|
111
|
+
aDest[k] = aSource[k];
|
|
112
|
+
delete aSource[k];
|
|
113
|
+
}
|
|
114
|
+
return aDest;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
_.removeKey = function(aObject,aKey) {
|
|
118
|
+
var result = aObject[aKey];
|
|
119
|
+
delete aObject[aKey];
|
|
120
|
+
return result;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// // find all dynamic objects in an array that have matching values for the contents of aAndCriteria
|
|
124
|
+
// public static function ObjectArrayFind(aArray:Array, aAndCriteria:Object):Array {
|
|
125
|
+
// return aArray.filter(
|
|
126
|
+
// function(item:*, index:int, array:Array):Boolean {
|
|
127
|
+
// // for all items in aAndCriteria, aItem has matching values
|
|
128
|
+
// for (var i:String in aAndCriteria) {
|
|
129
|
+
// if (aAndCriteria[i] != item[i])
|
|
130
|
+
// return false;
|
|
131
|
+
// }
|
|
132
|
+
// return true;
|
|
133
|
+
// }
|
|
134
|
+
// );
|
|
135
|
+
// }
|
|
136
|
+
//
|
|
137
|
+
// // like ObjectArrayFind except only returns one object. Could be optimised to quit searching when one is found
|
|
138
|
+
// // adds listener and removes on first occurrence
|
|
139
|
+
// public static function ObjectArrayFindOne(aArray:Array, aAndCriteria:Object):Object {
|
|
140
|
+
// var results:Array = ObjectArrayFind(aArray, aAndCriteria);
|
|
141
|
+
// return results[0];
|
|
142
|
+
// }
|
|
143
|
+
//
|
|
144
|
+
// public static function ObjectArrayLookup(aArray:Array, aAndCriteria:Object, aProperty:String):Object {
|
|
145
|
+
// var results:Array = ObjectArrayFind(aArray, aAndCriteria);
|
|
146
|
+
// var item:Object = results[0];
|
|
147
|
+
// if (!item)
|
|
148
|
+
// return null;
|
|
149
|
+
// return item[aProperty];
|
|
150
|
+
// }
|
|
151
|
+
|
|
152
|
+
_.hasMatchingProperties = function(aObject,aCriteria) {
|
|
153
|
+
for (var p in aCriteria) {
|
|
154
|
+
if (!(p in aObject) || (aObject[p]!==aCriteria[p]))
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// find one item matching object properties
|
|
161
|
+
_.findByCriteria = function(aArray,aCriteria) {
|
|
162
|
+
return _.find(aArray,function(obj){
|
|
163
|
+
return _.hasMatchingProperties(obj,aCriteria);
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// find one item matching object properties
|
|
168
|
+
_.filterByCriteria = function(aArray,aCriteria) {
|
|
169
|
+
return _.filter(aArray,function(obj){
|
|
170
|
+
return _.hasMatchingProperties(obj,aCriteria);
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
_.isObjectStrict = function(aSomething) {
|
|
175
|
+
return Object.prototype.toString.call(aSomething)==='[object Object]';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// create an object using key,value arguments eg. createObject('a',2) returns {a: 2}
|
|
179
|
+
_.createObject = function() {
|
|
180
|
+
var result = {};
|
|
181
|
+
result[arguments[0]] = arguments[1];
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
_.endsWith = function(aString, aSuffix) {
|
|
186
|
+
var i = aString.lastIndexOf(aSuffix);
|
|
187
|
+
return (i>=0 && i===aString.length-aSuffix.length);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
_.beginsWith = function(aString, aPrefix) {
|
|
191
|
+
var i = aString.indexOf(aPrefix);
|
|
192
|
+
return (i==0);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
_.chop = function(aString, aSuffix) {
|
|
196
|
+
var i = aString.lastIndexOf(aSuffix);
|
|
197
|
+
return (i===aString.length-aSuffix.length) ? aString.substring(0,i) : aString;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
_.bite = function(aString, aPrefix) {
|
|
201
|
+
var i = aString.indexOf(aPrefix);
|
|
202
|
+
return (i===0) ? aString.substring(aPrefix.length) : aString;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
_.typeOf = function(aSomething) {
|
|
206
|
+
if (aSomething===undefined)
|
|
207
|
+
return 'undefined';
|
|
208
|
+
if (aSomething===null)
|
|
209
|
+
return 'null';
|
|
210
|
+
|
|
211
|
+
var result = Object.prototype.toString.call(aSomething);
|
|
212
|
+
result = _.bite(result,'[object ');
|
|
213
|
+
result = _.chop(result,']');
|
|
214
|
+
return result.toLowerCase();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Clone properties that are objects or arrays, otherwise if aSource and aDestination are different, properties will be copied
|
|
219
|
+
* @param aDestination
|
|
220
|
+
* @param aSource (optional, defaults to aSource)
|
|
221
|
+
* @return aDestination
|
|
222
|
+
*/
|
|
223
|
+
_.cloneComplexValues = function (aDestination, aSource) {
|
|
224
|
+
if (!aSource)
|
|
225
|
+
aSource = aDestination;
|
|
226
|
+
for (var p in aSource) {
|
|
227
|
+
var t = _.typeOf(aSource[p]);
|
|
228
|
+
if (t==='array' || t==='object')
|
|
229
|
+
aDestination[p] = _.clone(aSource[p]);
|
|
230
|
+
else if (aDestination!==aSource)
|
|
231
|
+
aDestination[p] = aSource[p];
|
|
232
|
+
}
|
|
233
|
+
return aDestination;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// http://justtalkaboutweb.com/2008/01/06/javascript-object-extension/
|
|
237
|
+
|
|
238
|
+
_.originalClone = _.originalClone || _.clone;
|
|
239
|
+
// Create a copy (shallow or deep) of an object from https://github.com/cederberg/underscore/commits/feature-clone
|
|
240
|
+
_.clone = function(obj, deep) {
|
|
241
|
+
if (!deep)
|
|
242
|
+
return _.originalClone(obj);
|
|
243
|
+
if (!_.isObject(obj) || _.isFunction(obj)) return obj;
|
|
244
|
+
if (_.isDate(obj)) return new Date(obj.getTime());
|
|
245
|
+
if (_.isRegExp(obj)) return new RegExp(obj.source, obj.toString().replace(/.*\//, ""));
|
|
246
|
+
var isArr = (_.isArray(obj) || _.isArguments(obj));
|
|
247
|
+
if (deep) {
|
|
248
|
+
var func = function (memo, value, key) {
|
|
249
|
+
if (isArr)
|
|
250
|
+
memo.push(_.clone(value, true));
|
|
251
|
+
else
|
|
252
|
+
memo[key] = _.clone(value, true);
|
|
253
|
+
return memo;
|
|
254
|
+
};
|
|
255
|
+
return _.reduce(obj, func, isArr ? [] : {});
|
|
256
|
+
} else {
|
|
257
|
+
return isArr ? slice.call(obj) : _.extend({}, obj);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
}).call(this);
|
data/spec/external.zip
ADDED
|
Binary file
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
describe("HandlerStack", function() {
|
|
2
|
+
|
|
3
|
+
it("simple add", function() {
|
|
4
|
+
var hs = new HandlerStack();
|
|
5
|
+
var context = {text: 'A'};
|
|
6
|
+
|
|
7
|
+
hs.add(function(aContext) {
|
|
8
|
+
context.text += 'B';
|
|
9
|
+
});
|
|
10
|
+
hs.add(function(aContext) {
|
|
11
|
+
context.text += 'C';
|
|
12
|
+
});
|
|
13
|
+
runs(function() {
|
|
14
|
+
hs.run(context);
|
|
15
|
+
});
|
|
16
|
+
waitsFor(function() { return context.isResolved(); }, "request done", 3000);
|
|
17
|
+
runs(function() {
|
|
18
|
+
expect(context.text).toBe('ABC');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("add, push, then and done", function() {
|
|
23
|
+
var hs = new HandlerStack();
|
|
24
|
+
var context = {text: 'A'};
|
|
25
|
+
|
|
26
|
+
hs.add(function(aContext) {
|
|
27
|
+
context.text += 'B';
|
|
28
|
+
});
|
|
29
|
+
hs.add(function(aContext) {
|
|
30
|
+
context.text += 'C';
|
|
31
|
+
});
|
|
32
|
+
hs.push(function(aContext) {
|
|
33
|
+
context.text += 'X';
|
|
34
|
+
});
|
|
35
|
+
runs(function() {
|
|
36
|
+
hs.run(context);
|
|
37
|
+
context.then(function(aContext){
|
|
38
|
+
context.text += 'W';
|
|
39
|
+
});
|
|
40
|
+
context.done(function(aContext){
|
|
41
|
+
context.text += 'Z';
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
waitsFor(function() { return context.isResolved(); }, "request done", 3000);
|
|
45
|
+
runs(function() {
|
|
46
|
+
expect(context.text).toBe('AXBCWZ');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("error handling - stop processing handlers and set context.error and context.isRejected and call fail handler", function() {
|
|
51
|
+
var hs = new HandlerStack();
|
|
52
|
+
var context = {text: 'A'};
|
|
53
|
+
|
|
54
|
+
hs.add(function(aContext) {
|
|
55
|
+
context.text += 'B';
|
|
56
|
+
});
|
|
57
|
+
hs.add(function(aContext) {
|
|
58
|
+
throw new Error();
|
|
59
|
+
});
|
|
60
|
+
hs.add(function(aContext) {
|
|
61
|
+
context.text += 'X';
|
|
62
|
+
});
|
|
63
|
+
hs.run(context);
|
|
64
|
+
context.then(function(aContext){
|
|
65
|
+
context.text += 'W';
|
|
66
|
+
});
|
|
67
|
+
context.done(function(aContext){
|
|
68
|
+
context.text += 'Z';
|
|
69
|
+
});
|
|
70
|
+
context.fail(function(aContext){
|
|
71
|
+
context.text += 'F';
|
|
72
|
+
});
|
|
73
|
+
waitsFor(function() {
|
|
74
|
+
return context.isRejected();
|
|
75
|
+
}, "rejected", 3000);
|
|
76
|
+
runs(function() {
|
|
77
|
+
expect(context.text).toBe('ABF');
|
|
78
|
+
expect(context.error).toBeDefined();
|
|
79
|
+
expect(typeof(context.error)).toBe('object');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("reset and recall", function() {
|
|
84
|
+
var hs = new HandlerStack();
|
|
85
|
+
var context = {text: 'A'};
|
|
86
|
+
|
|
87
|
+
hs.add(function(aContext) {
|
|
88
|
+
context.text += 'B';
|
|
89
|
+
});
|
|
90
|
+
runs(function() {
|
|
91
|
+
hs.run(context);
|
|
92
|
+
context.then(function(aContext){
|
|
93
|
+
context.text += 'W';
|
|
94
|
+
});
|
|
95
|
+
context.done(function(aContext){
|
|
96
|
+
context.text += 'Z';
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
waitsFor(function() { return context.isResolved(); }, "resolved", 3000);
|
|
100
|
+
runs(function() {
|
|
101
|
+
expect(context.text).toBe('ABWZ');
|
|
102
|
+
expect(context.error).toBeUndefined();
|
|
103
|
+
hs.reset();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
runs(function() {
|
|
107
|
+
context = {text: 'G'};
|
|
108
|
+
hs.run(context);
|
|
109
|
+
context.then(function(aContext){
|
|
110
|
+
context.text += 'W';
|
|
111
|
+
});
|
|
112
|
+
context.done(function(aContext){
|
|
113
|
+
context.text += 'Z';
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
waitsFor(function() { return context.isResolved(); }, "resolved", 3000);
|
|
117
|
+
runs(function() {
|
|
118
|
+
expect(context.text).toBe('GBWZ');
|
|
119
|
+
expect(context.error).toBeUndefined();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("handler on an object", function() {
|
|
125
|
+
var hs = new HandlerStack();
|
|
126
|
+
var context = {text: 'A'};
|
|
127
|
+
var TestClass = function() {
|
|
128
|
+
this.text = 'B';
|
|
129
|
+
this.go = function(aContext) {
|
|
130
|
+
aContext.text += this.text;
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
var testClass = new TestClass();
|
|
134
|
+
hs.add(testClass.go,null,testClass); // note: using ability to specify this as third parameter
|
|
135
|
+
runs(function() {
|
|
136
|
+
hs.run(context);
|
|
137
|
+
});
|
|
138
|
+
waitsFor(function() { return context.isResolved(); }, "resolved", 3000);
|
|
139
|
+
runs(function() {
|
|
140
|
+
expect(context.text).toBe('AB');
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
describe("Kojac Caching", function() {
|
|
2
|
+
|
|
3
|
+
beforeEach(function () {
|
|
4
|
+
this.cache = new Kojac.Object();
|
|
5
|
+
this.kojac = new Kojac.Core({
|
|
6
|
+
cache: this.cache,
|
|
7
|
+
remoteProvider: new Kojac.RemoteProvider({useMockFileValues: true,mockFilePath: 'mockjson/'})
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("should return extra keys from a cacheRead that were returned from the server",function(){
|
|
12
|
+
var products_records = { // this is the normal data to return when requesting 'products'
|
|
13
|
+
products: [1,2,3],
|
|
14
|
+
products__1: {
|
|
15
|
+
id: 1,
|
|
16
|
+
name: "Product One"
|
|
17
|
+
},
|
|
18
|
+
products__2: {
|
|
19
|
+
id: 2,
|
|
20
|
+
name: "Product Two"
|
|
21
|
+
},
|
|
22
|
+
products__3: {
|
|
23
|
+
id: 3,
|
|
24
|
+
name: "Product Three"
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var products_server_response = _.clone(products_records); // the contents of this var will be returned by the mock server
|
|
28
|
+
this.kojac.remoteProvider.mockReadOperationHandler = function(aOp) { // this function acts as the server
|
|
29
|
+
switch (aOp.key) {
|
|
30
|
+
case 'products':
|
|
31
|
+
aOp.result_key = 'products';
|
|
32
|
+
aOp.results = _.extend(aOp.results,products_server_response);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var readReq = this.kojac.readRequest('products');
|
|
37
|
+
waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
|
|
38
|
+
runs(function() {
|
|
39
|
+
expect(readReq.results).toEqual(products_records); // should equal normal response
|
|
40
|
+
products_server_response = {}; // kill server response - non-cache reads should return empty now
|
|
41
|
+
readReq = this.kojac.readRequest('products',{cacheResults: false}); // read from server to check this, and don't store result in cache
|
|
42
|
+
});
|
|
43
|
+
waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
|
|
44
|
+
runs(function() {
|
|
45
|
+
expect(readReq.results).toEqual({}); // indeed, server now returns empty, but lets try cache
|
|
46
|
+
readReq = this.kojac.cacheReadRequest('products'); // read from cache
|
|
47
|
+
});
|
|
48
|
+
waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
|
|
49
|
+
runs(function() {
|
|
50
|
+
expect(readReq.results).toEqual(products_records); // should return original records - must be coming from cache not server
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("should return extra keys from a cacheRead that were returned from the server, using result_key",function(){
|
|
55
|
+
var products_records = { // this is the normal data to return when requesting 'products'
|
|
56
|
+
products: [1,2,3],
|
|
57
|
+
products__1: {
|
|
58
|
+
id: 1,
|
|
59
|
+
name: "Product One"
|
|
60
|
+
},
|
|
61
|
+
products__2: {
|
|
62
|
+
id: 2,
|
|
63
|
+
name: "Product Two"
|
|
64
|
+
},
|
|
65
|
+
products__3: {
|
|
66
|
+
id: 3,
|
|
67
|
+
name: "Product Three"
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var products_server_response = _.clone(products_records); // the contents of this var will be returned by the mock server
|
|
71
|
+
this.kojac.remoteProvider.mockReadOperationHandler = function(aOp) { // this function acts as the server
|
|
72
|
+
switch (aOp.key) {
|
|
73
|
+
case 'products':
|
|
74
|
+
if (aOp.result_key!==aOp.key)
|
|
75
|
+
products_server_response[aOp.result_key] = _.removeKey(products_server_response,aOp.key);
|
|
76
|
+
aOp.results = _.extend(aOp.results,products_server_response);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
expect(_.keys(this.kojac.cache)).toEqual([]);
|
|
81
|
+
var readReq = this.kojac.readRequest('products',{result_key: 'products_latest'});
|
|
82
|
+
waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
|
|
83
|
+
runs(function() {
|
|
84
|
+
var expected = _.clone(products_records);
|
|
85
|
+
expected.products_latest = _.removeKey(expected,'products');
|
|
86
|
+
expect(readReq.results).toEqual(expected); // should equal normal response
|
|
87
|
+
expect(_.keys(this.kojac.cache).sort()).toEqual(['products__1','products__2','products__3','products_latest']);
|
|
88
|
+
products_server_response = {}; // kill server response - non-cache reads should return empty now
|
|
89
|
+
readReq = this.kojac.readRequest('products',{cacheResults: false, result_key: 'products_latest'}); // read from server to check this, and don't store result in cache
|
|
90
|
+
});
|
|
91
|
+
waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
|
|
92
|
+
runs(function() {
|
|
93
|
+
expect(readReq.results).toEqual({}); // indeed, server now returns empty, but lets try cache
|
|
94
|
+
readReq = this.kojac.cacheReadRequest('products',{result_key: 'products_latest'}); // read from cache
|
|
95
|
+
});
|
|
96
|
+
waitsFor(function() { return readReq.isResolved(); }, "request done", 3000);
|
|
97
|
+
runs(function() {
|
|
98
|
+
var expected = _.clone(products_records);
|
|
99
|
+
expected.products_latest = _.removeKey(expected,'products');
|
|
100
|
+
expect(readReq.results).toEqual(expected); // should return original records - must be coming from cache not server
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
});
|
|
105
|
+
|