kojac 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,191 @@
|
|
1
|
+
/*--------------------------------------------------------------------------
|
2
|
+
*
|
3
|
+
* Key Oriented JSON Application Cache (KOJAC)
|
4
|
+
* (c) 2011-12 Buzzware Solutions
|
5
|
+
* https://github.com/buzzware/KOJAC
|
6
|
+
*
|
7
|
+
* KOJAC is freely distributable under the terms of an MIT-style license.
|
8
|
+
*
|
9
|
+
*--------------------------------------------------------------------------*/
|
10
|
+
(function() {
|
11
|
+
|
12
|
+
// minimal plugin example
|
13
|
+
//(function(can, window, undefined){
|
14
|
+
// var oldSetup = can.Observe.setup;
|
15
|
+
// can.extend(can.Observe, {
|
16
|
+
// setup : function(superClass){
|
17
|
+
// oldSetup.apply(this, arguments);
|
18
|
+
// }
|
19
|
+
// });
|
20
|
+
//
|
21
|
+
//// can.extend(can.Observe.prototype, {
|
22
|
+
//// });
|
23
|
+
//
|
24
|
+
//})(this.can, this );
|
25
|
+
|
26
|
+
MODEL_FIELD_CONVERTERS = { // these are only used when you call .serialize()
|
27
|
+
'Int' : function( aValue ){
|
28
|
+
return Kojac.interpretValueAsType(aValue,Int);
|
29
|
+
},
|
30
|
+
'Number' : function( aValue ){
|
31
|
+
return Kojac.interpretValueAsType(aValue,Number);
|
32
|
+
},
|
33
|
+
'String' : function( aValue ){
|
34
|
+
return Kojac.interpretValueAsType(aValue,String);
|
35
|
+
},
|
36
|
+
'Boolean' : function( aValue ){
|
37
|
+
return Kojac.interpretValueAsType(aValue,Boolean);
|
38
|
+
},
|
39
|
+
'Date' : function( aValue ){
|
40
|
+
return Kojac.interpretValueAsType(aValue,Date);
|
41
|
+
},
|
42
|
+
'Array' : function( aValue ){
|
43
|
+
return Kojac.interpretValueAsType(aValue,Array);
|
44
|
+
},
|
45
|
+
'Object' : function( aValue ){
|
46
|
+
return Kojac.interpretValueAsType(aValue,Object);
|
47
|
+
}
|
48
|
+
};
|
49
|
+
|
50
|
+
Kojac.CanModel = can.Observe({
|
51
|
+
fullName: 'Kojac.CanModel',
|
52
|
+
extend: function(aFullName, aClass, aInstanceProps) {
|
53
|
+
if ( typeof aFullName != 'string' ) {
|
54
|
+
aInstanceProps = aClass;
|
55
|
+
aClass = aFullName;
|
56
|
+
aFullName = null;
|
57
|
+
}
|
58
|
+
if ( ! aInstanceProps ) {
|
59
|
+
aInstanceProps = aClass;
|
60
|
+
aClass = null;
|
61
|
+
}
|
62
|
+
aInstanceProps = aInstanceProps || {};
|
63
|
+
aClass = aClass || {};
|
64
|
+
|
65
|
+
if (aClass && (('attributes' in aClass) || ('defaults' in aClass) || ('serialize' in aClass) || ('convert' in aClass)))
|
66
|
+
throw new Error('attributes, defaults, serialize and convert not supported');
|
67
|
+
|
68
|
+
var attributes = {};
|
69
|
+
var defaults = {};
|
70
|
+
for (var p in aInstanceProps) {
|
71
|
+
var v = aInstanceProps[p];
|
72
|
+
var i = Kojac.FieldTypes.indexOf(v);
|
73
|
+
if (i >= 0) { // field type
|
74
|
+
v = null;
|
75
|
+
defaults[p] = v;
|
76
|
+
attributes[p] = Kojac.FieldTypeStrings[i];
|
77
|
+
delete aInstanceProps[p];
|
78
|
+
} else if (_.isFunction(v)) { // a method
|
79
|
+
// don't touch this
|
80
|
+
} else { // default value
|
81
|
+
i = Kojac.FieldTypes.indexOf(Kojac.getPropertyValueType(v));
|
82
|
+
if (i >= 0) {
|
83
|
+
attributes[p] = Kojac.FieldTypeStrings[i];
|
84
|
+
defaults[p] = v;
|
85
|
+
}
|
86
|
+
delete aInstanceProps[p];
|
87
|
+
}
|
88
|
+
}
|
89
|
+
_.extend(aClass,{
|
90
|
+
attributes: attributes,
|
91
|
+
defaults: defaults,
|
92
|
+
serialize : MODEL_FIELD_CONVERTERS, // these are only used when you call .serialize()
|
93
|
+
convert: MODEL_FIELD_CONVERTERS // these are only used when you set properties with attr
|
94
|
+
});
|
95
|
+
if (aFullName)
|
96
|
+
return can.Observe.extend.apply(this, [aFullName,aClass,aInstanceProps]);
|
97
|
+
else
|
98
|
+
return can.Observe.extend.apply(this, [aClass,aInstanceProps]);
|
99
|
+
}
|
100
|
+
},{
|
101
|
+
});
|
102
|
+
|
103
|
+
Kojac.CanObjectFactory = Kojac.ObjectFactory.extend({
|
104
|
+
|
105
|
+
defaultClass: can.Observe,
|
106
|
+
|
107
|
+
copyProperties: function(aDest,aSource) {
|
108
|
+
return CanUtils.copyProperties(aDest,aSource);
|
109
|
+
}
|
110
|
+
|
111
|
+
});
|
112
|
+
|
113
|
+
|
114
|
+
Kojac.CanCache = can.Observe({
|
115
|
+
// convert: {
|
116
|
+
// default: function(aValue) { return aValue; }
|
117
|
+
// }
|
118
|
+
},{
|
119
|
+
|
120
|
+
// __convert: function(prop, value){
|
121
|
+
// console.log('__convert');
|
122
|
+
// return value;
|
123
|
+
// },
|
124
|
+
|
125
|
+
get: function(k) {
|
126
|
+
return this.attr(k);
|
127
|
+
},
|
128
|
+
set: function(k,v) {
|
129
|
+
return this.attr(k,v);
|
130
|
+
},
|
131
|
+
|
132
|
+
cacheResults: function(aRequest) {
|
133
|
+
console.log('BEGIN cacheResults')
|
134
|
+
var results = {};
|
135
|
+
var deletes = [];
|
136
|
+
for (var i=0;i<aRequest.ops.length;i++) {
|
137
|
+
var op = aRequest.ops[i];
|
138
|
+
if (op.error)
|
139
|
+
break;
|
140
|
+
if (op.options.cacheResults===false)
|
141
|
+
continue;
|
142
|
+
for (p in op.results) {
|
143
|
+
var v = op.results[p];
|
144
|
+
results[p] = v;
|
145
|
+
if (v===undefined)
|
146
|
+
deletes.push(p);
|
147
|
+
else
|
148
|
+
deletes = _.without(deletes, [p]);
|
149
|
+
}
|
150
|
+
}
|
151
|
+
for (p in results) {
|
152
|
+
try {
|
153
|
+
this.attr(p,results[p]);
|
154
|
+
} catch (e) {
|
155
|
+
console.log('Error when caching '+p+' : '+ e.message);
|
156
|
+
}
|
157
|
+
}
|
158
|
+
// if (deletes.length) {
|
159
|
+
// for (var i=0;i<deletes.length;i++) {
|
160
|
+
// console.log('cacheResults remove');
|
161
|
+
// this.removeAttr(deletes[i]);
|
162
|
+
// }
|
163
|
+
// }
|
164
|
+
console.log('END cacheResults');
|
165
|
+
},
|
166
|
+
|
167
|
+
collectIds: function(aPrefix, aIds) {
|
168
|
+
return Kojac.collectIds(aPrefix,aIds,this);
|
169
|
+
},
|
170
|
+
|
171
|
+
collectionValues: function(aCollectionKey) {
|
172
|
+
return Kojac.collectionValues(aCollectionKey,this);
|
173
|
+
}
|
174
|
+
|
175
|
+
});
|
176
|
+
|
177
|
+
Kojac.collectIds = function(aPrefix,aIds,aCache) {
|
178
|
+
if (!aIds)
|
179
|
+
return [];
|
180
|
+
var result = [];
|
181
|
+
for (var i=0;i<aIds.length;i++)
|
182
|
+
result.push(aCache.get(aPrefix+'__'+aIds[i]));
|
183
|
+
return result;
|
184
|
+
};
|
185
|
+
|
186
|
+
Kojac.collectionValues = function(aCollectionKey,aCache) {
|
187
|
+
var ids = aCache.get(aCollectionKey);
|
188
|
+
return Kojac.collectIds(aCollectionKey,ids,aCache);
|
189
|
+
};
|
190
|
+
|
191
|
+
})();
|
@@ -0,0 +1,463 @@
|
|
1
|
+
/*--------------------------------------------------------------------------
|
2
|
+
*
|
3
|
+
* Key Oriented JSON Application Cache (KOJAC)
|
4
|
+
* (c) 2011-12 Buzzware Solutions
|
5
|
+
* https://github.com/buzzware/KOJAC
|
6
|
+
*
|
7
|
+
* KOJAC is freely distributable under the terms of an MIT-style license.
|
8
|
+
*
|
9
|
+
*--------------------------------------------------------------------------*/
|
10
|
+
|
11
|
+
// recommended http://www.cerebris.com/blog/2012/03/06/understanding-ember-object/
|
12
|
+
//var Person = Ember.Object.extend({
|
13
|
+
// chromosomes: null,
|
14
|
+
// init: function() {
|
15
|
+
// this._super();
|
16
|
+
// this.chromosomes = ["x"]; // everyone gets at least one X chromosome
|
17
|
+
// }
|
18
|
+
//});
|
19
|
+
|
20
|
+
// declaring property : {chromosomes: null}
|
21
|
+
// for values, generate function that calls this._super(); then loops thru setting values
|
22
|
+
|
23
|
+
// example :
|
24
|
+
//
|
25
|
+
//Product = Kojac.EmberModel.extend({
|
26
|
+
// name: String,
|
27
|
+
// purchases: Int,
|
28
|
+
// weight: Number,
|
29
|
+
// isMember: Boolean,
|
30
|
+
// init: function() {
|
31
|
+
// this._super();
|
32
|
+
// this.weight = 0.0;
|
33
|
+
// }
|
34
|
+
//});
|
35
|
+
//
|
36
|
+
//
|
37
|
+
// 1. Create extendObject with properties: null
|
38
|
+
// 2.
|
39
|
+
|
40
|
+
|
41
|
+
Kojac.EmberObjectFactory = Kojac.Object.extend({
|
42
|
+
|
43
|
+
matchers: null,
|
44
|
+
|
45
|
+
register: function(aPairs) {
|
46
|
+
if (!aPairs)
|
47
|
+
return;
|
48
|
+
if (this.matchers===null)
|
49
|
+
this.matchers = [];
|
50
|
+
for (var i = 0; i < aPairs.length; i++)
|
51
|
+
this.matchers.push(aPairs[i]);
|
52
|
+
},
|
53
|
+
|
54
|
+
emberClassFromKey: function(aKey) {
|
55
|
+
var pair;
|
56
|
+
var re;
|
57
|
+
var newClass;
|
58
|
+
for (var i = 0; i < this.matchers.length; i++) {
|
59
|
+
pair = this.matchers[i];
|
60
|
+
re = pair[0];
|
61
|
+
if (!re.test(aKey))
|
62
|
+
continue;
|
63
|
+
newClass = pair[1];
|
64
|
+
break;
|
65
|
+
}
|
66
|
+
if (newClass===undefined)
|
67
|
+
newClass = Ember.Object;
|
68
|
+
return newClass;
|
69
|
+
},
|
70
|
+
|
71
|
+
emberObjectFactoryArray: function(aArray,aKey) {
|
72
|
+
var newClass = this.emberClassFromKey(aKey);
|
73
|
+
var result = [];
|
74
|
+
for (var i=0; i<aArray.length; i++) {
|
75
|
+
var newv = new newClass();
|
76
|
+
newv.setProperties(aArray[i]);
|
77
|
+
result.push(newv);
|
78
|
+
}
|
79
|
+
return result;
|
80
|
+
},
|
81
|
+
|
82
|
+
emberObjectFactory: function(aObject,aKey) {
|
83
|
+
var newClass = this.emberClassFromKey(aKey);
|
84
|
+
var newv = new newClass();
|
85
|
+
newv.setProperties(aObject);
|
86
|
+
return newv;
|
87
|
+
},
|
88
|
+
|
89
|
+
transformResultsToValueObjects: function(aRequest) {
|
90
|
+
for (var i=0;i<aRequest.ops.length;i++) {
|
91
|
+
var op = aRequest.ops[i];
|
92
|
+
if (op.error)
|
93
|
+
break;
|
94
|
+
for (var k in op.results) {
|
95
|
+
var v = op.results[k];
|
96
|
+
if (!jQuery.isPlainObject(v))
|
97
|
+
continue;
|
98
|
+
op.results[k] = this.emberObjectFactory(v,k);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
});
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
//ExampleRemoteProvider = Ember.Object.extend({
|
108
|
+
//Kojac.RemoteProvider = Kojac.Object.extend({
|
109
|
+
//
|
110
|
+
// useMockFileValues: false,
|
111
|
+
// mockFilePath: '',
|
112
|
+
// mockReadOperationHandler: null,
|
113
|
+
// mockWriteOperationHandler: function(aOp) {
|
114
|
+
// log.debug(JSON.stringify(EmberUtils.copyProperties({},aOp,null,['request'])));
|
115
|
+
// },
|
116
|
+
//
|
117
|
+
// handleOperationFromFiles: function(aRequest) {
|
118
|
+
// var op = aRequest.handlers.parameter;
|
119
|
+
//
|
120
|
+
// if (op.verb==='READ' || op.verb==='EXECUTE') {
|
121
|
+
// if (this.mockReadOperationHandler) {
|
122
|
+
// this.mockReadOperationHandler(op);
|
123
|
+
// } else {
|
124
|
+
// aRequest.handlers.waitForCallNext = true;
|
125
|
+
// var fp = mockFilePath+op.key+'.js';
|
126
|
+
// var data = null;
|
127
|
+
// jQuery.ajax({url: fp, dataType: 'json', cache: false, data: data}).done(
|
128
|
+
// function( aData ) {
|
129
|
+
// for (p in aData)
|
130
|
+
// op[p] = aData[p];
|
131
|
+
// aRequest.handlers.callNext();
|
132
|
+
// }
|
133
|
+
// ).fail(
|
134
|
+
// function(jqXHR, textStatus) {
|
135
|
+
// aRequest.handlers.handleError(textStatus);
|
136
|
+
// }
|
137
|
+
// );
|
138
|
+
// }
|
139
|
+
// } else {
|
140
|
+
// if (this.mockWriteOperationHandler)
|
141
|
+
// this.mockWriteOperationHandler(op);
|
142
|
+
// }
|
143
|
+
// },
|
144
|
+
//
|
145
|
+
// handleAjaxRequest: function(aRequest) {
|
146
|
+
// var op = aRequest.parameter;
|
147
|
+
// aRequest.handlers.waitForCallNext = true;
|
148
|
+
// jQuery.ajax({},function(){
|
149
|
+
// aRequest.handlers.callNext();
|
150
|
+
// })
|
151
|
+
// },
|
152
|
+
//
|
153
|
+
// addRequestHandlers: function(aRequest) {
|
154
|
+
// if (this.useMockFileValues) {
|
155
|
+
// for (var i=0;i<aRequest.ops.length;i++)
|
156
|
+
// aRequest.handlers.add(this.handleOperationFromFiles,aRequest.ops[i],this);
|
157
|
+
// } else {
|
158
|
+
// aRequest.handlers.add(this.handleAjaxRequest,null,this);
|
159
|
+
// }
|
160
|
+
// }
|
161
|
+
//
|
162
|
+
//});
|
163
|
+
|
164
|
+
|
165
|
+
Kojac.EmberModel = Ember.Object.extend({});
|
166
|
+
|
167
|
+
Kojac.EmberModel.reopenClass({
|
168
|
+
|
169
|
+
//_extend: Ember.Object.extend,
|
170
|
+
|
171
|
+
extend: function() {
|
172
|
+
var defs = arguments[0];
|
173
|
+
var extender = {};
|
174
|
+
var definitions = this.getDefinitions();
|
175
|
+
var defaults = this.getDefaults();
|
176
|
+
var _type;
|
177
|
+
var _value;
|
178
|
+
//var _init;
|
179
|
+
if (defs) {
|
180
|
+
for (p in defs) {
|
181
|
+
var pValue = defs[p];
|
182
|
+
// if (p=='init') {
|
183
|
+
// _init = pValue;
|
184
|
+
// } else {
|
185
|
+
if (Kojac.FieldTypes.indexOf(pValue)>=0) { // pValue is field type
|
186
|
+
definitions[p] = pValue;
|
187
|
+
defaults[p] = null;
|
188
|
+
extender[p] = null;
|
189
|
+
} else {
|
190
|
+
var ft=Kojac.getPropertyValueType(pValue);
|
191
|
+
if (ft && (Kojac.SimpleTypes.indexOf(ft)>=0)) { // pValue is simple field value
|
192
|
+
definitions[p] = ft;
|
193
|
+
defaults[p] = pValue;
|
194
|
+
extender[p] = pValue;
|
195
|
+
} else { // pValue is something else
|
196
|
+
//definitions[p] = _type;
|
197
|
+
//defaults[p] = _value;
|
198
|
+
extender[p] = pValue;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
// }
|
202
|
+
}
|
203
|
+
// extender.init = function() { // we need to call the super init, then initialise default values, then call the given init
|
204
|
+
// this._super();
|
205
|
+
// //var defaults = this.constructor.getDefaults();
|
206
|
+
// //for (dp in defaults)
|
207
|
+
// // this[dp] = defaults[dp];
|
208
|
+
// if (_init) {
|
209
|
+
// var _super = this._super;
|
210
|
+
// this._super = function() {}; // temporarily disable _super to make init function work like normal ember init
|
211
|
+
// _init.call(this);
|
212
|
+
// if (_super)
|
213
|
+
// this._super = _super; // restore _super
|
214
|
+
// }
|
215
|
+
// };
|
216
|
+
}
|
217
|
+
var result = this._super(extender);
|
218
|
+
result.setDefinitions(definitions);
|
219
|
+
result.setDefaults(defaults);
|
220
|
+
return result;
|
221
|
+
},
|
222
|
+
|
223
|
+
setDefinitions: function(aDefinitions) {
|
224
|
+
this._definitions = (aDefinitions || {});
|
225
|
+
},
|
226
|
+
|
227
|
+
getDefinitions: function() {
|
228
|
+
return this._definitions || {};
|
229
|
+
},
|
230
|
+
|
231
|
+
setDefaults: function(aDefaults) {
|
232
|
+
this._defaults = (aDefaults || {});
|
233
|
+
},
|
234
|
+
|
235
|
+
getDefaults: function() {
|
236
|
+
return this._defaults || {};
|
237
|
+
},
|
238
|
+
|
239
|
+
__createWithMixins: Kojac.EmberModel.createWithMixins,
|
240
|
+
createWithMixins: function() {
|
241
|
+
var inputs = arguments;
|
242
|
+
if (inputs.length) {
|
243
|
+
inputs[0] = Kojac.readTypedProperties({},inputs[0],this.getDefinitions());
|
244
|
+
}
|
245
|
+
return this.__createWithMixins.apply(this,inputs);
|
246
|
+
},
|
247
|
+
|
248
|
+
__create: Kojac.EmberModel.create,
|
249
|
+
create: function() {
|
250
|
+
var inputs = arguments;
|
251
|
+
if (inputs.length) {
|
252
|
+
inputs[0] = Kojac.readTypedProperties({},inputs[0],this.getDefinitions());
|
253
|
+
}
|
254
|
+
return this.__create.apply(this,inputs);
|
255
|
+
}
|
256
|
+
|
257
|
+
});
|
258
|
+
|
259
|
+
Kojac.EmberModel.reopen({
|
260
|
+
|
261
|
+
___set: Ember.set,
|
262
|
+
set: function(k,v) {
|
263
|
+
var def = this.constructor.getDefinitions();
|
264
|
+
var t = (def && def[k]);
|
265
|
+
if (t)
|
266
|
+
v = Kojac.interpretValueAsType(v,t);
|
267
|
+
return this.___set(this,k,v);
|
268
|
+
},
|
269
|
+
|
270
|
+
___setProperties: Ember.setProperties,
|
271
|
+
setProperties: function(values) {
|
272
|
+
values = Kojac.readTypedProperties({},values,this.constructor.getDefinitions());
|
273
|
+
return this.___setProperties(this,values);
|
274
|
+
},
|
275
|
+
|
276
|
+
toObject: function(aOptions) {
|
277
|
+
var result = {};
|
278
|
+
var defs = this.constructor.getDefinitions();
|
279
|
+
var includes = aOptions && aOptions.include
|
280
|
+
for (var p in defs)
|
281
|
+
result[p] = this.get(p);
|
282
|
+
if (includes) {
|
283
|
+
includes = this.getProperties(includes);
|
284
|
+
var v;
|
285
|
+
for (var p in includes) {
|
286
|
+
v = includes[p];
|
287
|
+
if (v && (typeof(v)=="object") && ("toObject" in v))
|
288
|
+
includes[p] = v.toObject();
|
289
|
+
}
|
290
|
+
_.extend(result,includes);
|
291
|
+
}
|
292
|
+
return result;
|
293
|
+
}
|
294
|
+
|
295
|
+
});
|
296
|
+
|
297
|
+
|
298
|
+
Kojac.EmberCache = Ember.Object.extend({
|
299
|
+
|
300
|
+
generateKey: function(aPrefix) {
|
301
|
+
var key;
|
302
|
+
do {
|
303
|
+
key = aPrefix+'__'+(-_.random(1000000,2000000)).toString();
|
304
|
+
} while (key in this);
|
305
|
+
return key;
|
306
|
+
},
|
307
|
+
|
308
|
+
generateId: function(aPrefix) {
|
309
|
+
var key;
|
310
|
+
var id;
|
311
|
+
do {
|
312
|
+
id = -_.random(1000000,2000000)
|
313
|
+
key = aPrefix+'__'+id.toString();
|
314
|
+
} while (key in this);
|
315
|
+
return id;
|
316
|
+
},
|
317
|
+
|
318
|
+
store: function(aKeysValues) {
|
319
|
+
this.beginPropertyChanges();
|
320
|
+
for (p in aKeysValues) {
|
321
|
+
if (aKeysValues[p]===undefined) {
|
322
|
+
this.set(p,undefined);
|
323
|
+
delete this[p];
|
324
|
+
} else {
|
325
|
+
this.set(p,aKeysValues[p]);
|
326
|
+
}
|
327
|
+
}
|
328
|
+
this.endPropertyChanges();
|
329
|
+
},
|
330
|
+
|
331
|
+
cacheResults: function(aRequest) {
|
332
|
+
this.beginPropertyChanges();
|
333
|
+
for (var i=0;i<aRequest.ops.length;i++) {
|
334
|
+
var op = aRequest.ops[i];
|
335
|
+
if (op.error)
|
336
|
+
break;
|
337
|
+
if (op.options.cacheResults===false)
|
338
|
+
continue;
|
339
|
+
this.store(op.results);
|
340
|
+
}
|
341
|
+
this.endPropertyChanges();
|
342
|
+
},
|
343
|
+
|
344
|
+
collectIds: function(aPrefix, aIds) {
|
345
|
+
return Kojac.collectIds(aPrefix,aIds,this);
|
346
|
+
}
|
347
|
+
|
348
|
+
});
|
349
|
+
|
350
|
+
Kojac.collectIds = function(aPrefix,aIds,aCache,aFilterFn) {
|
351
|
+
if (!aIds)
|
352
|
+
return [];
|
353
|
+
var result = [];
|
354
|
+
var item;
|
355
|
+
for (var i=0;i<aIds.length;i++) {
|
356
|
+
item = aCache.get(aPrefix+'__'+aIds[i]);
|
357
|
+
if (!aFilterFn || aFilterFn(item))
|
358
|
+
result.push(item);
|
359
|
+
}
|
360
|
+
return result;
|
361
|
+
};
|
362
|
+
|
363
|
+
Ember.computed.collectIds = function(aCollectionProperty,aPrefix,aModelCachePath,aFilterFn){
|
364
|
+
if (!aPrefix)
|
365
|
+
aPrefix = _.last(aCollectionProperty.split('.'));
|
366
|
+
|
367
|
+
return Ember.computed(aCollectionProperty, function(){
|
368
|
+
var cache;
|
369
|
+
if (aModelCachePath)
|
370
|
+
cache = Ember.Handlebars.get(this,aModelCachePath); //(aModelCachePath && Ember.get(aModelCachePath));
|
371
|
+
else
|
372
|
+
cache = this;
|
373
|
+
var ids = Ember.Handlebars.get(this,aCollectionProperty);
|
374
|
+
if (!ids)
|
375
|
+
return [];
|
376
|
+
var result = [];
|
377
|
+
var item;
|
378
|
+
for (var i=0;i<ids.length;i++) {
|
379
|
+
item = cache.get(aPrefix+'__'+ids[i]);
|
380
|
+
if (!aFilterFn || aFilterFn(item))
|
381
|
+
result.push(item);
|
382
|
+
}
|
383
|
+
return result;
|
384
|
+
}).property(aModelCachePath,aCollectionProperty);
|
385
|
+
};
|
386
|
+
|
387
|
+
Ember.computed.has_many = function(aResource,aForeignKey,aLocalPropertyPath,aModelCachePath,aFilterFn){
|
388
|
+
|
389
|
+
return Ember.computed(function(){
|
390
|
+
var cache;
|
391
|
+
if (aModelCachePath)
|
392
|
+
cache = Ember.Handlebars.get(this,aModelCachePath); //(aModelCachePath && Ember.get(aModelCachePath));
|
393
|
+
else
|
394
|
+
cache = this;
|
395
|
+
var localValue = Ember.Handlebars.get(this,aLocalPropertyPath);
|
396
|
+
|
397
|
+
if (!_.endsWith(aResource,'__'))
|
398
|
+
aResource = aResource+'__';
|
399
|
+
|
400
|
+
var results = [];
|
401
|
+
// get all keys that begin with aPrefix
|
402
|
+
var keys = _.keys(cache);
|
403
|
+
for (var i=0;i<keys.length;i++) {
|
404
|
+
var k = keys[i];
|
405
|
+
if (!_.beginsWith(k,aResource))
|
406
|
+
continue;
|
407
|
+
var v = cache.get(k);
|
408
|
+
if (!v || (v.get(aForeignKey) != localValue))
|
409
|
+
continue;
|
410
|
+
if (aFilterFn && !aFilterFn(k,v))
|
411
|
+
continue;
|
412
|
+
results.push(v);
|
413
|
+
}
|
414
|
+
return results;
|
415
|
+
}).property(aModelCachePath,aLocalPropertyPath);
|
416
|
+
};
|
417
|
+
|
418
|
+
Ember.computed.modelById = function(aIdProperty,aPrefix,aModelCachePath) {
|
419
|
+
if (!aModelCachePath)
|
420
|
+
aModelCachePath = 'App.cache';
|
421
|
+
|
422
|
+
return Ember.computed(aIdProperty, function(){
|
423
|
+
var id = Ember.Handlebars.get(this,aIdProperty);
|
424
|
+
if (!id)
|
425
|
+
return null;
|
426
|
+
var cache = Ember.Handlebars.get(this,aModelCachePath);
|
427
|
+
var key = keyJoin(aPrefix,id);
|
428
|
+
if (!key || !cache)
|
429
|
+
return null;
|
430
|
+
return Ember.Handlebars.get(cache,key);
|
431
|
+
}).property(aModelCachePath,aIdProperty);
|
432
|
+
};
|
433
|
+
|
434
|
+
Ember.computed.modelByIdVersioned = function(aIdProperty,aVerProperty,aPrefix,aModelCachePath) {
|
435
|
+
if (!aModelCachePath)
|
436
|
+
aModelCachePath = 'App.cache';
|
437
|
+
|
438
|
+
return Ember.computed(aIdProperty, function(){
|
439
|
+
var id = Ember.Handlebars.get(this,aIdProperty);
|
440
|
+
var cache = Ember.Handlebars.get(this,aModelCachePath);
|
441
|
+
if (!id || !cache)
|
442
|
+
return null;
|
443
|
+
var key;
|
444
|
+
var ver = Ember.Handlebars.get(this,aVerProperty);
|
445
|
+
if (ver) {
|
446
|
+
id = [id,ver].join('_');
|
447
|
+
key = keyJoin(aPrefix,id);
|
448
|
+
return Ember.Handlebars.get(cache,key);
|
449
|
+
} else {
|
450
|
+
var versions = _.pickWithPrefix(cache,keyJoin(aPrefix,id)+'_');
|
451
|
+
var v,vi;
|
452
|
+
key = _.max(_.keys(versions), function(k){
|
453
|
+
vi = k.lastIndexOf('_');
|
454
|
+
return Number(k.substr(vi+1));
|
455
|
+
});
|
456
|
+
return key ? versions[key] : null;
|
457
|
+
}
|
458
|
+
}).property(aModelCachePath,aIdProperty,aVerProperty);
|
459
|
+
};
|
460
|
+
|
461
|
+
|
462
|
+
|
463
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
class KojacController < ApplicationController
|
2
|
+
|
3
|
+
respond_to :json
|
4
|
+
protect_from_forgery :only => []
|
5
|
+
|
6
|
+
protected
|
7
|
+
|
8
|
+
def controller_for_key(aKey)
|
9
|
+
resource = aKey.split('__').first
|
10
|
+
controller_name = resource.camelize+'Controller'
|
11
|
+
if controller = controller_name.constantize
|
12
|
+
result = controller.new
|
13
|
+
result.current_user = self.current_user
|
14
|
+
result
|
15
|
+
else
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_ops(aInput)
|
21
|
+
result = { }
|
22
|
+
if ops = aInput[:ops]
|
23
|
+
result[:ops] = []
|
24
|
+
ops.each do |op|
|
25
|
+
method = "#{op[:verb].to_s.downcase}_op".to_sym
|
26
|
+
ctrlr = self.controller_for_key(op[:key])
|
27
|
+
if ctrlr.respond_to? method
|
28
|
+
ctrlr.params = {op: op}
|
29
|
+
output = ctrlr.send method
|
30
|
+
result[:ops] << output
|
31
|
+
else
|
32
|
+
raise "Unsupported verb #{op[:verb]}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
result
|
37
|
+
end
|
38
|
+
|
39
|
+
public
|
40
|
+
|
41
|
+
def receive
|
42
|
+
input = nil
|
43
|
+
output = nil
|
44
|
+
status = :ok
|
45
|
+
|
46
|
+
begin
|
47
|
+
input = params[:kojac]
|
48
|
+
output = process_ops(input)
|
49
|
+
status = :ok
|
50
|
+
rescue => e
|
51
|
+
raise e unless Rails.env.production?
|
52
|
+
Rails.logger.debug e.message
|
53
|
+
Rails.logger.debug e.backtrace.join("\n")
|
54
|
+
output = {
|
55
|
+
results: nil,
|
56
|
+
errors: [{
|
57
|
+
message: e.message,
|
58
|
+
backtrace: e.backtrace
|
59
|
+
}]
|
60
|
+
}
|
61
|
+
status = :unprocessable_entity
|
62
|
+
end
|
63
|
+
#output = ActiveModel::Serializer.new(output,current_user).to_json
|
64
|
+
#sz = output.active_model_serializer.new(output)
|
65
|
+
#jsons = sz.to_json(:scope => current_user, :root => false)
|
66
|
+
jsons = app_serialize(output,current_user)
|
67
|
+
render json: jsons, status: status
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|