kojac 0.9.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +6 -14
  2. data/.gitignore +4 -0
  3. data/Gemfile +1 -1
  4. data/app/assets/javascripts/kojac.js +393 -125
  5. data/app/assets/javascripts/kojac_canjs.js +34 -34
  6. data/app/assets/javascripts/kojac_ember.js +110 -152
  7. data/app/controllers/{kojac_controller.rb → kojac_base_controller.rb} +18 -11
  8. data/app/policies/kojac_base_policy.rb +114 -0
  9. data/app/serializers/kojac_base_serializer.rb +35 -0
  10. data/kojac.gemspec +12 -10
  11. data/lib/kojac/app_serialize.rb +31 -29
  12. data/lib/kojac/concentric.rb +152 -0
  13. data/lib/kojac/kojac_policy.rb +70 -0
  14. data/lib/kojac/kojac_rails.rb +200 -49
  15. data/lib/kojac/version.rb +1 -1
  16. data/spec/can_cache_spec.js +19 -19
  17. data/spec/demo/.gitignore +16 -0
  18. data/spec/demo/.ruby-gemset +1 -0
  19. data/spec/demo/.ruby-version +1 -0
  20. data/spec/demo/Gemfile +59 -0
  21. data/spec/demo/Gemfile.lock +153 -0
  22. data/spec/demo/README.rdoc +15 -248
  23. data/spec/demo/Rakefile +25 -1
  24. data/spec/demo/app/{mailers/.gitkeep → assets/images/.keep} +0 -0
  25. data/spec/demo/app/assets/javascripts/application.js +3 -3
  26. data/spec/demo/app/controllers/application_controller.rb +6 -1
  27. data/spec/demo/app/{models/.gitkeep → controllers/concerns/.keep} +0 -0
  28. data/spec/demo/app/controllers/users_controller.rb +5 -0
  29. data/spec/demo/{lib/assets/.gitkeep → app/mailers/.keep} +0 -0
  30. data/spec/demo/{log/.gitkeep → app/models/.keep} +0 -0
  31. data/spec/demo/app/models/concerns/.keep +0 -0
  32. data/spec/demo/app/models/user.rb +36 -0
  33. data/spec/demo/app/policies/user_policy.rb +42 -0
  34. data/spec/demo/bin/bundle +3 -0
  35. data/spec/demo/bin/rails +4 -0
  36. data/spec/demo/bin/rake +4 -0
  37. data/spec/demo/config.ru +1 -1
  38. data/spec/demo/config/application.rb +14 -46
  39. data/spec/demo/config/application.yml +4 -0
  40. data/spec/demo/config/boot.rb +3 -9
  41. data/spec/demo/config/database.yml +6 -6
  42. data/spec/demo/config/environment.rb +4 -2
  43. data/spec/demo/config/environments/development.rb +11 -19
  44. data/spec/demo/config/environments/production.rb +40 -27
  45. data/spec/demo/config/environments/test.rb +13 -14
  46. data/spec/demo/config/initializers/concentric_config.rb +9 -0
  47. data/spec/demo/config/initializers/filter_parameter_logging.rb +4 -0
  48. data/spec/demo/config/initializers/inflections.rb +6 -5
  49. data/spec/demo/config/initializers/initialize_kojac.rb +16 -0
  50. data/spec/demo/config/initializers/secret_token.rb +7 -2
  51. data/spec/demo/config/initializers/session_store.rb +0 -5
  52. data/spec/demo/config/initializers/wrap_parameters.rb +6 -6
  53. data/spec/demo/config/locales/en.yml +20 -2
  54. data/spec/demo/config/routes.rb +24 -24
  55. data/spec/demo/db/migrate/20131212034312_add_user.rb +14 -0
  56. data/spec/demo/db/migrate/20140107085351_add_owner_id.rb +5 -0
  57. data/spec/demo/db/schema.rb +28 -0
  58. data/spec/demo/db/seeds.rb +7 -0
  59. data/spec/demo/lib/assets/.keep +0 -0
  60. data/spec/demo/lib/tasks/.keep +0 -0
  61. data/spec/demo/log/.keep +0 -0
  62. data/spec/demo/public/404.html +43 -11
  63. data/spec/demo/public/422.html +43 -11
  64. data/spec/demo/public/500.html +43 -11
  65. data/spec/demo/public/robots.txt +5 -0
  66. data/spec/demo/spec/controllers/allowed_fields_spec.rb +171 -0
  67. data/spec/demo/spec/factories/users.rb +9 -0
  68. data/spec/demo/spec/features/concentric_spec.rb +63 -0
  69. data/spec/demo/spec/features/serialization_spec.rb +86 -0
  70. data/spec/demo/spec/spec_helper.rb +133 -0
  71. data/spec/demo/spec/spec_utils.rb +42 -0
  72. data/spec/demo/vendor/assets/javascripts/.keep +0 -0
  73. data/spec/demo/vendor/assets/stylesheets/.keep +0 -0
  74. data/spec/ember_factory_spec.js +1 -1
  75. data/spec/ember_model_spec.js +13 -3
  76. data/spec/ember_tojsono_spec.js +105 -0
  77. data/spec/error_handling_spec.js +90 -0
  78. data/spec/external/underscore_plus.js +318 -9
  79. data/spec/kojac_caching_spec.js +3 -1
  80. data/spec/kojac_ember_cache_spec.js +9 -0
  81. data/spec/kojac_mock_spec.js +4 -4
  82. data/spec/kojac_operations_spec.js +4 -4
  83. data/spec/local_provider_spec.js +184 -0
  84. data/spec/model_ring_spec.rb +2 -2
  85. data/spec/operation_include_spec.js +2 -2
  86. data/spec/run.html +34 -24
  87. data/spec/type_conversion_spec.js +38 -0
  88. data/vendor/assets/javascripts/jstorage.js +950 -0
  89. metadata +115 -129
  90. data/Gemfile.lock +0 -157
  91. data/app/serializers/default_kojac_serializer.rb +0 -10
  92. data/lib/kojac/ring_strong_parameters.rb +0 -195
  93. data/spec/.DS_Store +0 -0
  94. data/spec/demo/script/rails +0 -6
  95. data/spec/external/.DS_Store +0 -0
@@ -122,47 +122,47 @@
122
122
  // return value;
123
123
  // },
124
124
 
125
- get: function(k) {
125
+ retrieve: function(k) {
126
126
  return this.attr(k);
127
127
  },
128
- set: function(k,v) {
128
+ store: function(k,v) {
129
129
  return this.attr(k,v);
130
130
  },
131
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]);
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]);
162
149
  // }
163
150
  // }
164
- console.log('END cacheResults');
165
- },
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
166
 
167
167
  collectIds: function(aPrefix, aIds) {
168
168
  return Kojac.collectIds(aPrefix,aIds,this);
@@ -72,147 +72,89 @@ Kojac.EmberObjectFactory = Kojac.Object.extend({
72
72
  var newClass = this.emberClassFromKey(aKey);
73
73
  var result = [];
74
74
  for (var i=0; i<aArray.length; i++) {
75
- var newv = new newClass();
76
- newv.setProperties(aArray[i]);
75
+ var newv = newClass.create(aArray[i]);
77
76
  result.push(newv);
78
77
  }
79
78
  return result;
80
79
  },
81
80
 
82
- emberObjectFactory: function(aObject,aKey) {
81
+ manufacture: function(aObject,aKey) {
83
82
  var newClass = this.emberClassFromKey(aKey);
84
- var newv = new newClass();
85
- newv.setProperties(aObject);
83
+ var newv = newClass.create(aObject);
86
84
  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
85
  }
102
86
 
103
87
  });
104
88
 
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
89
  Kojac.EmberModel = Ember.Object.extend({});
166
90
 
167
- Kojac.EmberModel.reopenClass({
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();
168
126
 
169
- //_extend: Ember.Object.extend,
127
+ Kojac.EmberModel.reopenClass({
170
128
 
171
129
  extend: function() {
172
130
  var defs = arguments[0];
173
131
  var extender = {};
174
132
  var definitions = this.getDefinitions();
175
133
  var defaults = this.getDefaults();
134
+
176
135
  var _type;
177
136
  var _value;
178
137
  //var _init;
179
138
  if (defs) {
180
139
  for (p in defs) {
181
140
  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
- }
141
+ if (Kojac.FieldTypes.indexOf(pValue)>=0) { // pValue is field type
142
+ definitions[p] = pValue;
143
+ defaults[p] = null;
144
+ extender[p] = null;
145
+ } else {
146
+ var ft=Kojac.getPropertyValueType(pValue);
147
+ 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;
200
155
  }
201
- // }
156
+ }
202
157
  }
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
158
  }
217
159
  var result = this._super(extender);
218
160
  result.setDefinitions(definitions);
@@ -236,13 +178,26 @@ Kojac.EmberModel.reopenClass({
236
178
  return this._defaults || {};
237
179
  },
238
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);
187
+ }
188
+ }
189
+ },
190
+
191
+
239
192
  __createWithMixins: Kojac.EmberModel.createWithMixins,
240
193
  createWithMixins: function() {
241
194
  var inputs = arguments;
242
195
  if (inputs.length) {
243
196
  inputs[0] = Kojac.readTypedProperties({},inputs[0],this.getDefinitions());
244
197
  }
245
- return this.__createWithMixins.apply(this,inputs);
198
+ var result = this.__createWithMixins.apply(this,inputs);
199
+ this.__addDescs(result);
200
+ return result;
246
201
  },
247
202
 
248
203
  __create: Kojac.EmberModel.create,
@@ -251,7 +206,9 @@ Kojac.EmberModel.reopenClass({
251
206
  if (inputs.length) {
252
207
  inputs[0] = Kojac.readTypedProperties({},inputs[0],this.getDefinitions());
253
208
  }
254
- return this.__create.apply(this,inputs);
209
+ var result = this.__create.apply(this,inputs);
210
+ this.__addDescs(result);
211
+ return result;
255
212
  }
256
213
 
257
214
  });
@@ -273,28 +230,40 @@ Kojac.EmberModel.reopen({
273
230
  return this.___setProperties(this,values);
274
231
  },
275
232
 
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;
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;
293
263
  }
294
264
 
295
265
  });
296
266
 
297
-
298
267
  Kojac.EmberCache = Ember.Object.extend({
299
268
 
300
269
  generateKey: function(aPrefix) {
@@ -315,28 +284,17 @@ Kojac.EmberCache = Ember.Object.extend({
315
284
  return id;
316
285
  },
317
286
 
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();
287
+ retrieve: function(k) {
288
+ return this.get(k);
329
289
  },
330
290
 
331
- cacheResults: function(aRequest) {
291
+ store: function(k,v) {
332
292
  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);
293
+ if (v===undefined) {
294
+ this.set(k,v);
295
+ delete this[k];
296
+ } else {
297
+ this.set(k,v);
340
298
  }
341
299
  this.endPropertyChanges();
342
300
  },
@@ -1,16 +1,20 @@
1
- class KojacController < ApplicationController
1
+ class KojacBaseController < ApplicationController
2
2
 
3
3
  respond_to :json
4
4
  protect_from_forgery :only => []
5
5
 
6
6
  protected
7
7
 
8
+ def kojac_current_user
9
+ current_user
10
+ end
11
+
8
12
  def controller_for_key(aKey)
9
13
  resource = aKey.split('__').first
10
14
  controller_name = resource.camelize+'Controller'
11
15
  if controller = controller_name.constantize
12
16
  result = controller.new
13
- result.current_user = self.current_user
17
+ result.current_user = self.kojac_current_user
14
18
  result
15
19
  else
16
20
  nil
@@ -46,25 +50,28 @@ class KojacController < ApplicationController
46
50
  begin
47
51
  input = params[:kojac]
48
52
  output = process_ops(input)
49
- status = :ok
50
53
  rescue => e
51
54
  raise e unless Rails.env.production?
52
55
  Rails.logger.debug e.message
53
56
  Rails.logger.debug e.backtrace.join("\n")
57
+ handle_exception(e) if respond_to? :handle_exception
54
58
  output = {
55
- results: nil,
56
- errors: [{
57
- message: e.message,
58
- backtrace: e.backtrace
59
- }]
59
+ error: {
60
+ format: 'KojacError',
61
+ kind: 'Exception',
62
+ errors: [{
63
+ message: e.message,
64
+ backtrace: e.backtrace
65
+ }]
66
+ }
60
67
  }
61
- status = :unprocessable_entity
62
68
  end
69
+ status = output[:error] ? :unprocessable_entity : :ok
63
70
  #output = ActiveModel::Serializer.new(output,current_user).to_json
64
71
  #sz = output.active_model_serializer.new(output)
65
72
  #jsons = sz.to_json(:scope => current_user, :root => false)
66
- jsons = app_serialize(output,current_user)
67
- render json: jsons, status: status
73
+ jsono = KojacUtils.to_jsono(output,scope: kojac_current_user)
74
+ render json: jsono, status: status
68
75
  end
69
76
 
70
77
  end