kojac 0.11.0 → 0.12.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.
@@ -8,6 +8,29 @@
8
8
  *
9
9
  *--------------------------------------------------------------------------*/
10
10
 
11
+ /* Ideas for future
12
+
13
+ stop using ids in collections, use full key instead
14
+
15
+ so then cache can be like :
16
+ {
17
+ allProducts: ['product__1','product__2'],
18
+ product__1: {
19
+ name: 'red toy'
20
+ },
21
+ product__2: {
22
+ name: 'blue toy'
23
+ }
24
+ productCol: Emberjac.modelCollection(
25
+ 'allProducts', // idCollection property, potentially path eg. 'App.cache.allProducts'. Binds to this and its contents
26
+ function(aArray){
27
+ // optionally filter and/or sort array here, return result leaving original unmodified
28
+ }
29
+ )
30
+ }
31
+
32
+ */
33
+
11
34
  // recommended http://www.cerebris.com/blog/2012/03/06/understanding-ember-object/
12
35
  //var Person = Ember.Object.extend({
13
36
  // chromosomes: null,
@@ -38,231 +61,146 @@
38
61
  // 2.
39
62
 
40
63
 
41
- Kojac.EmberObjectFactory = Kojac.Object.extend({
64
+ Kojac.EmberObjectFactory = Kojac.ObjectFactory.extend({
42
65
 
43
- matchers: null,
66
+ defaultClass: Ember.Object,
44
67
 
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
- },
68
+ createInstance: function(aClass,aProperties) {
69
+ aProperties = aProperties || {};
70
+ return aClass.create(aProperties);
71
+ }
53
72
 
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;
73
+ });
74
+
75
+ Kojac.EmberModel = Ember.Object.extend({
76
+
77
+ // set: function(k,v) {
78
+ // var def = this.constructor.getDefinitions();
79
+ // var t = (def && def[k]);
80
+ // if (t)
81
+ // v = Kojac.interpretValueAsType(v,t);
82
+ // return this._super(k,v);
83
+ // },
84
+ //
85
+ // setProperties: function(values) {
86
+ // values = Kojac.readTypedProperties({},values,this.constructor.getDefinitions());
87
+ // return this._super(values);
88
+ // },
89
+
90
+ // copy the property from source to dest
91
+ // this could be a static fn
92
+ toJsonoCopyFn: function(aDest,aSource,aProperty,aOptions) {
93
+ aDest[aProperty] = Kojac.Utils.toJsono(Ember.get(aSource,aProperty),aOptions);
69
94
  },
70
95
 
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 = newClass.create(aArray[i]);
76
- result.push(newv);
96
+ // return array of names, or an object and all keys will be used
97
+ // this could be a static fn
98
+ toPropListFn: function(aSource,aOptions) {
99
+ var p;
100
+ if (p = aSource && aSource.constructor && aSource.constructor.proto && aSource.constructor.proto()) {
101
+ if ((p = Ember.meta(p)) && (p = p.descs)) {
102
+ var result = [];
103
+ var m;
104
+ var d;
105
+ var k;
106
+ var keys = _.keys(p);
107
+ for (var i=0;i<keys.length;i++) {
108
+ k = keys[i];
109
+ if (!(d = p[k]))
110
+ continue;
111
+ if (!(m = d.meta()))
112
+ continue;
113
+ if (m.kemp)
114
+ result.push(k);
115
+ }
116
+ return result;
117
+ } else
118
+ return [];
119
+ } else {
120
+ return aSource;
77
121
  }
78
- return result;
79
122
  },
80
123
 
81
- manufacture: function(aObject,aKey) {
82
- var newClass = this.emberClassFromKey(aKey);
83
- var newv = newClass.create(aObject);
84
- return newv;
124
+ toJsono: function(aOptions) {
125
+ return Kojac.Utils.toJsono(this,aOptions,this.toPropListFn,this.toJsonoCopyFn)
85
126
  }
86
127
 
87
128
  });
88
129
 
89
- Kojac.EmberModel = Ember.Object.extend({});
90
-
91
- Kojac.EmberModel.TypedField = function() {
92
- this.get = function(obj,keyName) { // Here code was copied from Ember get to avoid endless recursion. This is more efficient but brittle for future Ember versions
93
- var meta = Ember.meta(obj),
94
- desc = (meta && meta.descs[keyName]),
95
- ret;
96
- if (Ember.ENV.MANDATORY_SETTER && meta && (meta.watching[keyName] > 0)) {
97
- ret = meta.values[keyName];
98
- } else {
99
- ret = obj[keyName];
100
- }
101
- if ((ret === undefined) &&
102
- ('object' === typeof obj) && !(keyName in obj) && ('function' === typeof obj.unknownProperty)) {
103
- return obj.unknownProperty(keyName);
104
- }
105
- return ret;
106
- }
107
- this.set = function(obj,keyName,aValue) { // here we call the standard method after removing the desc to prevent endless recursion, then put it back.
108
- var result;
109
- var def = obj.constructor.getDefinitions();
110
- var t = (def && def[keyName]);
111
- if (t)
112
- aValue = Kojac.interpretValueAsType(aValue,t);
113
- var meta = Ember.meta(obj),
114
- desc = (meta && meta.descs[keyName]);
115
- meta.descs[keyName] = undefined;
116
- try {
117
- result = Ember.set(obj,keyName,aValue);
118
- }
119
- finally {
120
- meta.descs[keyName] = desc;
121
- }
122
- return result;
123
- }
124
- };
125
- Kojac.EmberModel.TypedField.prototype = new Ember.Descriptor();
130
+ // in create, set cache with defaults merged with given values
131
+ // getter - use cacheFor
132
+ // setter - set cache with converted value
133
+ // in extend, generate with Ember.computed().cacheable(true)
134
+
135
+
136
+
126
137
 
127
138
  Kojac.EmberModel.reopenClass({
128
139
 
129
140
  extend: function() {
130
141
  var defs = arguments[0];
131
142
  var extender = {};
132
- var definitions = this.getDefinitions();
133
- var defaults = this.getDefaults();
134
143
 
135
144
  var _type;
136
145
  var _value;
137
- //var _init;
138
146
  if (defs) {
147
+ var destType;
148
+ var defaultValue;
139
149
  for (p in defs) {
140
150
  var pValue = defs[p];
151
+ destType = null;
152
+ defaultValue = null;
153
+
141
154
  if (Kojac.FieldTypes.indexOf(pValue)>=0) { // pValue is field type
142
- definitions[p] = pValue;
143
- defaults[p] = null;
144
- extender[p] = null;
155
+ destType = pValue;
156
+ defaultValue = null;
145
157
  } else {
146
158
  var ft=Kojac.getPropertyValueType(pValue);
147
159
  if (ft && (Kojac.SimpleTypes.indexOf(ft)>=0)) { // pValue is simple field value
148
- definitions[p] = ft;
149
- defaults[p] = pValue;
150
- extender[p] = pValue;
151
- } else { // pValue is something else
152
- //definitions[p] = _type;
153
- //defaults[p] = _value;
154
- extender[p] = pValue;
160
+ destType = ft;
161
+ defaultValue = pValue;
155
162
  }
156
163
  }
157
- }
158
- }
159
- var result = this._super(extender);
160
- result.setDefinitions(definitions);
161
- result.setDefaults(defaults);
162
- return result;
163
- },
164
-
165
- setDefinitions: function(aDefinitions) {
166
- this._definitions = (aDefinitions || {});
167
- },
168
164
 
169
- getDefinitions: function() {
170
- return this._definitions || {};
171
- },
172
-
173
- setDefaults: function(aDefaults) {
174
- this._defaults = (aDefaults || {});
175
- },
176
-
177
- getDefaults: function() {
178
- return this._defaults || {};
179
- },
180
-
181
- __addDescs: function(aNewInstance){
182
- var meta = Ember.meta(aNewInstance);
183
- var defs = this.getDefinitions();
184
- if (defs) {
185
- for (p in defs) {
186
- meta.descs[p] = new Kojac.EmberModel.TypedField(aNewInstance);
165
+ if (destType) {
166
+ extender[p] = Ember.computed(function(aKey,aValue){
167
+ // MyClass.metaForProperty('person');
168
+ var m = Ember.meta(this,false);
169
+ var d = m && m.descs[aKey];
170
+ var v;
171
+
172
+ if (arguments.length==2) { // set
173
+ var t = d && d._meta && d._meta.type;
174
+ if (t)
175
+ v = Kojac.interpretValueAsType(aValue,t);
176
+ else
177
+ v = aValue;
178
+ //cache[aKey] = v;
179
+ } else { // get
180
+ var cache = m.cache;
181
+ v = Ember.cacheFor(this,aKey);
182
+ if (cache && aKey in cache) {
183
+ return cache[aKey];
184
+ } else {
185
+ return d && d._meta && d._meta.value;
186
+ }
187
+ }
188
+ return v;
189
+ }).meta({
190
+ kemp: true, // Kojac Ember Model Property
191
+ type: destType,
192
+ value: defaultValue
193
+ })
194
+ } else {
195
+ extender[p] = pValue;
196
+ }
187
197
  }
188
198
  }
189
- },
190
-
191
-
192
- __createWithMixins: Kojac.EmberModel.createWithMixins,
193
- createWithMixins: function() {
194
- var inputs = arguments;
195
- if (inputs.length) {
196
- inputs[0] = Kojac.readTypedProperties({},inputs[0],this.getDefinitions());
197
- }
198
- var result = this.__createWithMixins.apply(this,inputs);
199
- this.__addDescs(result);
200
- return result;
201
- },
202
-
203
- __create: Kojac.EmberModel.create,
204
- create: function() {
205
- var inputs = arguments;
206
- if (inputs.length) {
207
- inputs[0] = Kojac.readTypedProperties({},inputs[0],this.getDefinitions());
208
- }
209
- var result = this.__create.apply(this,inputs);
210
- this.__addDescs(result);
199
+ var result = this._super(extender);
211
200
  return result;
212
201
  }
213
-
214
202
  });
215
203
 
216
- Kojac.EmberModel.reopen({
217
-
218
- ___set: Ember.set,
219
- set: function(k,v) {
220
- var def = this.constructor.getDefinitions();
221
- var t = (def && def[k]);
222
- if (t)
223
- v = Kojac.interpretValueAsType(v,t);
224
- return this.___set(this,k,v);
225
- },
226
-
227
- ___setProperties: Ember.setProperties,
228
- setProperties: function(values) {
229
- values = Kojac.readTypedProperties({},values,this.constructor.getDefinitions());
230
- return this.___setProperties(this,values);
231
- },
232
-
233
- // copy the property from source to dest
234
- // this could be a static fn
235
- toJsonoCopyFn: function(aDest,aSource,aProperty,aOptions) {
236
- aDest[aProperty] = Kojac.Utils.toJsono(Ember.get(aSource,aProperty),aOptions);
237
- },
238
-
239
- // return array of names, or an object and all keys will be used
240
- // this could be a static fn
241
- toPropListFn: function(aSource,aOptions) {
242
- if ("getDefinitions" in aSource.constructor)
243
- return aSource.constructor.getDefinitions(); // return an object to use all keys from
244
- else
245
- return aSource; // this is a simple object, so use all keys
246
- },
247
-
248
- toJsono: function(aOptions) {
249
- return Kojac.Utils.toJsono(this,aOptions,this.toPropListFn,this.toJsonoCopyFn)
250
- // for (var p in defs)
251
- // result[p] = this.get(p);
252
- // if (includes) {
253
- // includes = this.getProperties(includes);
254
- // var v;
255
- // for (var p in includes) {
256
- // v = includes[p];
257
- // if (v && (typeof(v)=="object") && ("toJsono" in v))
258
- // includes[p] = v.toJsono();
259
- // }
260
- // _.extend(result,includes);
261
- // }
262
- // return result;
263
- }
264
-
265
- });
266
204
 
267
205
  Kojac.EmberCache = Ember.Object.extend({
268
206
 
@@ -299,8 +237,10 @@ Kojac.EmberCache = Ember.Object.extend({
299
237
  this.endPropertyChanges();
300
238
  },
301
239
 
302
- collectIds: function(aPrefix, aIds) {
303
- return Kojac.collectIds(aPrefix,aIds,this);
240
+ collectIds: function(aPrefix, aIds, aFilterFn) {
241
+ if (!aIds)
242
+ aIds = this.get(aPrefix);
243
+ return Kojac.collectIds(aPrefix,aIds,this,aFilterFn);
304
244
  }
305
245
 
306
246
  });
@@ -322,7 +262,7 @@ Ember.computed.collectIds = function(aCollectionProperty,aPrefix,aModelCachePath
322
262
  if (!aPrefix)
323
263
  aPrefix = _.last(aCollectionProperty.split('.'));
324
264
 
325
- return Ember.computed(aCollectionProperty, function(){
265
+ var result = Ember.computed(aCollectionProperty, function(){
326
266
  var cache;
327
267
  if (aModelCachePath)
328
268
  cache = Ember.Handlebars.get(this,aModelCachePath); //(aModelCachePath && Ember.get(aModelCachePath));
@@ -331,15 +271,16 @@ Ember.computed.collectIds = function(aCollectionProperty,aPrefix,aModelCachePath
331
271
  var ids = Ember.Handlebars.get(this,aCollectionProperty);
332
272
  if (!ids)
333
273
  return [];
334
- var result = [];
274
+ var objects = [];
335
275
  var item;
336
276
  for (var i=0;i<ids.length;i++) {
337
277
  item = cache.get(aPrefix+'__'+ids[i]);
338
278
  if (!aFilterFn || aFilterFn(item))
339
- result.push(item);
279
+ objects.push(item);
340
280
  }
341
- return result;
342
- }).property(aModelCachePath,aCollectionProperty);
281
+ return objects;
282
+ });
283
+ return result.property.apply(result, _.compact([aModelCachePath,aCollectionProperty]));
343
284
  };
344
285
 
345
286
  Ember.computed.has_many = function(aResource,aForeignKey,aLocalPropertyPath,aModelCachePath,aFilterFn){
@@ -415,7 +356,3 @@ Ember.computed.modelByIdVersioned = function(aIdProperty,aVerProperty,aPrefix,aM
415
356
  }
416
357
  }).property(aModelCachePath,aIdProperty,aVerProperty);
417
358
  };
418
-
419
-
420
-
421
-
@@ -1,5 +1,8 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/kojac_front_methods.rb')
2
+
1
3
  class KojacBaseController < ApplicationController
2
4
 
5
+ include KojacFrontMethods
3
6
  respond_to :json
4
7
  protect_from_forgery :only => []
5
8
 
@@ -9,69 +12,11 @@ class KojacBaseController < ApplicationController
9
12
  current_user
10
13
  end
11
14
 
12
- def controller_for_key(aKey)
13
- resource = aKey.split('__').first
14
- controller_name = resource.camelize+'Controller'
15
- if controller = controller_name.constantize
16
- result = controller.new
17
- result.current_user = self.kojac_current_user
18
- result
19
- else
20
- nil
21
- end
22
- end
23
-
24
- def process_ops(aInput)
25
- result = { }
26
- if ops = aInput[:ops]
27
- result[:ops] = []
28
- ops.each do |op|
29
- method = "#{op[:verb].to_s.downcase}_op".to_sym
30
- ctrlr = self.controller_for_key(op[:key])
31
- if ctrlr.respond_to? method
32
- ctrlr.params = {op: op}
33
- output = ctrlr.send method
34
- result[:ops] << output
35
- else
36
- raise "Unsupported verb #{op[:verb]}"
37
- end
38
- end
39
- end
40
- result
41
- end
42
-
43
15
  public
44
16
 
45
17
  def receive
46
- input = nil
47
- output = nil
48
- status = :ok
49
-
50
- begin
51
- input = params[:kojac]
52
- output = process_ops(input)
53
- rescue => e
54
- raise e unless Rails.env.production?
55
- Rails.logger.debug e.message
56
- Rails.logger.debug e.backtrace.join("\n")
57
- handle_exception(e) if respond_to? :handle_exception
58
- output = {
59
- error: {
60
- format: 'KojacError',
61
- kind: 'Exception',
62
- errors: [{
63
- message: e.message,
64
- backtrace: e.backtrace
65
- }]
66
- }
67
- }
68
- end
69
- status = output[:error] ? :unprocessable_entity : :ok
70
- #output = ActiveModel::Serializer.new(output,current_user).to_json
71
- #sz = output.active_model_serializer.new(output)
72
- #jsons = sz.to_json(:scope => current_user, :root => false)
73
- jsono = KojacUtils.to_jsono(output,scope: kojac_current_user)
74
- render json: jsono, status: status
18
+ jsono,status = process_input(params[:kojac])
19
+ render json: jsono, status: status
75
20
  end
76
21
 
77
22
  end
@@ -0,0 +1,66 @@
1
+ module KojacFrontMethods
2
+
3
+ protected
4
+
5
+ def process_ops(aInput)
6
+ result = {}
7
+ if ops = aInput[:ops]
8
+ result[:ops] = []
9
+ ops.each do |op|
10
+ method = "#{op[:verb].to_s.downcase}_op".to_sym
11
+ ctrlr = self.controller_for_key(op[:key])
12
+ if ctrlr.respond_to? method
13
+ ctrlr.params = {op: op}
14
+ output = ctrlr.send method
15
+ result[:ops] << output
16
+ else
17
+ raise "Unsupported verb #{op[:verb]}"
18
+ end
19
+ end
20
+ end
21
+ result
22
+ end
23
+
24
+ def controller_for_key(aKey)
25
+ resource = aKey.split('__').first
26
+ controller_name = resource.camelize+'Controller'
27
+ if controller = controller_name.constantize
28
+ result = controller.new
29
+ result.current_user = self.kojac_current_user
30
+ result
31
+ else
32
+ nil
33
+ end
34
+ end
35
+
36
+ def process_input(aInputJson)
37
+ output = nil
38
+ status = :ok
39
+
40
+ begin
41
+ send(:before_process, [aInputJson]) if respond_to? :before_process
42
+ output = process_ops(aInputJson)
43
+ rescue => e
44
+ #raise e unless Rails.env.production?
45
+ Rails.logger.debug e.message
46
+ Rails.logger.debug e.backtrace.join("\n") unless Rails.env.production?
47
+ handle_exception(e) if respond_to? :handle_exception
48
+ output = {
49
+ error: {
50
+ format: 'KojacError',
51
+ kind: 'Exception',
52
+ errors: [{
53
+ message: e.message
54
+ }]
55
+ }
56
+ }
57
+ output[:error][:errors][0][:backtrace] = e.backtrace unless Rails.env.production?
58
+ output
59
+ end
60
+ send(:after_process, [aInputJson, output]) if respond_to? :after_process
61
+ status = output[:error] ? :unprocessable_entity : :ok
62
+ jsono = KojacUtils.to_jsono(output, scope: kojac_current_user)
63
+ [jsono,status]
64
+ end
65
+
66
+ end
@@ -0,0 +1,25 @@
1
+ require 'json'
2
+
3
+ class KojacMetalController < ActionController::Metal
4
+
5
+ include KojacFrontMethods
6
+
7
+ protected
8
+
9
+ def current_user
10
+ @current_user ||= env['warden'].user #User.find_by(id: session[:user])
11
+ end
12
+
13
+ def kojac_current_user
14
+ current_user
15
+ end
16
+
17
+ public
18
+
19
+ def index
20
+ input = JSON.parse(request.body.read)
21
+ jsono,status = process_input(input['kojac'])
22
+ self.response_body = jsono.to_json
23
+ self.status = status
24
+ end
25
+ end
@@ -30,6 +30,4 @@ class KojacBaseSerializer < ActiveModel::Serializer
30
30
  end
31
31
  result
32
32
  end
33
-
34
- alias_method :serializable_object, :serializable_hash
35
33
  end