live_record 0.3.4 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c5e459f1fd9627b4731cd59fcc25622317d2ecbeb1afe32b4d55328880ba7cf
4
- data.tar.gz: a2018fdbcfcdeef038c8a389bf3c5240a4ffa9b05884b6c8d9efb59a23d6c62c
3
+ metadata.gz: 509801a74ef9c87f3520ed9312e6cf8cb8c6861f4c250dc2075e7ba8822882c2
4
+ data.tar.gz: 220bc5c24e415c54c215b94b983b41bb7ced614090d82d89d347c4544c52ea95
5
5
  SHA512:
6
- metadata.gz: aba9f87dc58ad53ee987264795de0ba551c78888fc17725ed5176e036ae5294e50a5c50c84dc082425842eef3132fd48e49063930b6b65ded469e2376cc764cf
7
- data.tar.gz: 7a08ddb71528e48371c5406a7616dfcf19d9268adad369cbce537c21426020101d819421f6d1f2adc0418271b292e0140649113541ac1a2593ddec2dcbbe682a
6
+ metadata.gz: 949adea6b2fecd574a8fa9c69a4168f87c2231d3e4cf5b3e4920c6d19c155533d320b8bc0393fd93ca4eb2e8354a472c623f948eb199a836cacca041c7cdd4a0
7
+ data.tar.gz: 4822d238761d68875d963456ff7c11248368f9a91dfd40ea3f7f98e7d677104a7bc53166af8fcb05b0938bfebdd5f3d152329e44b9252d1e961ba2dc4530a6d4
@@ -0,0 +1,11 @@
1
+ load_paths:
2
+ - app/assets/javascripts
3
+
4
+ logical_paths:
5
+ - live_record.coffee
6
+
7
+ build:
8
+ logical_paths:
9
+ - live_record.js
10
+ path: lib/assets/compiled
11
+ clean: true
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ /tmp
1
2
  /.bundle
2
3
  *.sqlite
3
4
  *.sqlite-journal
@@ -5,4 +6,6 @@
5
6
  /spec/internal/tmp/*
6
7
  .byebug_history
7
8
  *.gem
8
- Gemfile.lock
9
+ Gemfile.lock
10
+ .DS_Store
11
+ /node_modules
File without changes
data/Gemfile CHANGED
@@ -8,4 +8,6 @@ group :development, :test do
8
8
  gem 'factory_girl_rails', '~> 4.8', require: false
9
9
  # do not require to prevent Capybara deprecation warning on rspec run
10
10
  gem 'capybara', '~> 3.1', require: false
11
+
12
+ gem 'sprockets-export', '~> 1.0.0', require: false
11
13
  end
data/README.md CHANGED
@@ -157,7 +157,7 @@
157
157
  1. Add the following to your `Gemfile`:
158
158
 
159
159
  ```ruby
160
- gem 'live_record', '~> 0.3.4'
160
+ gem 'live_record', '~> 0.3.6'
161
161
  ```
162
162
 
163
163
  2. Run:
@@ -779,7 +779,12 @@ end
779
779
  ## License
780
780
  * MIT
781
781
 
782
+ ## Developer Guide
783
+ * see [developer_guide.md](developer_guide.md)
784
+
782
785
  ## Changelog
786
+ * 0.3.6
787
+ * set up as a Node module
783
788
  * 0.3.4
784
789
  * now supports Rails `~> 5.2` after being tested to work
785
790
  * update dependency to Rails (and other dev gems) to use semantic versioning: `~> 5.0`, instead of `>= 5.0, < 5.3`
@@ -1,3 +1,4 @@
1
+ #= export LiveRecord
1
2
  #= require_self
2
3
  #= require_directory ./live_record/
3
4
 
@@ -1,4 +1,4 @@
1
1
  #= require_self
2
2
  #= require_directory ./helpers/
3
3
 
4
- LiveRecord.helpers ||= {}
4
+ this.LiveRecord.helpers ||= {}
@@ -1,6 +1,6 @@
1
1
  # ref: https://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
2
2
 
3
- LiveRecord.helpers.caseConverter =
3
+ this.LiveRecord.helpers.caseConverter =
4
4
  toCamel: (string) ->
5
5
  string.replace(
6
6
  /(\-[a-z])/g,
@@ -1,4 +1,4 @@
1
- LiveRecord.helpers.loadRecords = (args) ->
1
+ this.LiveRecord.helpers.loadRecords = (args) ->
2
2
  args['modelName'] || throw new Error(':modelName argument required')
3
3
  throw new Error(':modelName is not defined in LiveRecord.Model.all') if LiveRecord.Model.all[args['modelName']] == undefined
4
4
 
@@ -1,6 +1,6 @@
1
1
  # ref: https://stackoverflow.com/questions/34852855/combined-comparison-spaceship-operator-in-javascript
2
2
 
3
- LiveRecord.helpers.spaceship = (val1, val2) ->
3
+ this.LiveRecord.helpers.spaceship = (val1, val2) ->
4
4
  if val1 == null or val2 == null or typeof val1 != typeof val2
5
5
  return null
6
6
  if typeof val1 == 'string'
@@ -1,4 +1,4 @@
1
1
  #= require_self
2
2
  #= require_directory ./model/
3
3
 
4
- LiveRecord.Model ||= {}
4
+ this.LiveRecord.Model ||= {}
@@ -1 +1 @@
1
- LiveRecord.Model.all = {}
1
+ this.LiveRecord.Model.all = {}
@@ -1,4 +1,4 @@
1
- LiveRecord.Model.create = (config) ->
1
+ this.LiveRecord.Model.create = (config) ->
2
2
  config.modelName != undefined || throw new Error('missing :modelName argument')
3
3
  config.callbacks != undefined || config.callbacks = {}
4
4
  config.plugins != undefined || config.callbacks = {}
@@ -1,3 +1,3 @@
1
1
  #= require_self
2
2
 
3
- LiveRecord.plugins ||= {}
3
+ this.LiveRecord.plugins ||= {}
@@ -1,7 +1,7 @@
1
1
  #= require_self
2
2
  #= require_directory ./live_dom/
3
3
 
4
- LiveRecord.plugins.LiveDOM ||= {}
4
+ this.LiveRecord.plugins.LiveDOM ||= {}
5
5
 
6
- if window.jQuery == undefined
6
+ if window.jQuery == undefined
7
7
  throw new Error('jQuery is not loaded yet, and is a dependency of LiveRecord')
@@ -1,4 +1,4 @@
1
- LiveRecord.plugins.LiveDOM.applyToModel = (Model, pluginValue) ->
1
+ this.LiveRecord.plugins.LiveDOM.applyToModel = (Model, pluginValue) ->
2
2
  return if pluginValue != true
3
3
 
4
4
  # DOM callbacks
@@ -0,0 +1,24 @@
1
+ ## Development
2
+
3
+ ### Publishing as Ruby Gem
4
+
5
+ ```bash
6
+ # [increment gem VERSION]
7
+ gem build live_record
8
+ gem push live_record-X.X.X.gem
9
+ ```
10
+
11
+ ### Publishing as Node Module
12
+
13
+ ```bash
14
+ # [increment gem VERSION]
15
+ bundle exec blade build
16
+ # see .blade.yml: which will sprockets-compile app/assets/javascripts/live_record.coffee into lib/assets/compile/live_record.js
17
+ npm publish --access=public
18
+ ```
19
+
20
+ ## Test
21
+
22
+ ```bash
23
+ bundle exec rspec
24
+ ```
@@ -0,0 +1,603 @@
1
+ (function() {
2
+ this.LiveRecord || (this.LiveRecord = {});
3
+
4
+ }).call(this);
5
+ (function() {
6
+ var base;
7
+
8
+ (base = this.LiveRecord).helpers || (base.helpers = {});
9
+
10
+ }).call(this);
11
+ (function() {
12
+ this.LiveRecord.helpers.caseConverter = {
13
+ toCamel: function(string) {
14
+ return string.replace(/(\-[a-z])/g, function($1) {
15
+ return $1.toUpperCase().replace('-', '');
16
+ });
17
+ },
18
+ toUnderscore: function(string) {
19
+ return string.replace(/([A-Z])/g, function($1) {
20
+ return "_" + $1.toLowerCase();
21
+ });
22
+ }
23
+ };
24
+
25
+ }).call(this);
26
+ (function() {
27
+ this.LiveRecord.helpers.loadRecords = function(args) {
28
+ args['modelName'] || (function() {
29
+ throw new Error(':modelName argument required');
30
+ })();
31
+ if (LiveRecord.Model.all[args['modelName']] === void 0) {
32
+ throw new Error(':modelName is not defined in LiveRecord.Model.all');
33
+ }
34
+ args['url'] || (args['url'] = window.location.href);
35
+ return $.getJSON(args['url']).done(function(data) {
36
+ var i, len, record, record_attributes, record_or_records, records, records_attributes;
37
+ record_or_records = void 0;
38
+ if ($.isArray(data)) {
39
+ records_attributes = data;
40
+ records = [];
41
+ for (i = 0, len = records_attributes.length; i < len; i++) {
42
+ record_attributes = records_attributes[i];
43
+ record = new LiveRecord.Model.all[args['modelName']](record_attributes);
44
+ record.create();
45
+ records.push(record);
46
+ }
47
+ record_or_records = records;
48
+ } else if (data) {
49
+ record_attributes = data;
50
+ record = new LiveRecord.Model.all[args['modelName']](record_attributes);
51
+ record.create();
52
+ record_or_records = record;
53
+ }
54
+ if (args['onLoad']) {
55
+ return args['onLoad'].call(this, record_or_records);
56
+ }
57
+ }).fail(function(jqxhr, textStatus, error) {
58
+ if (args['onError']) {
59
+ return args['onError'].call(this, jqxhr, textStatus, error);
60
+ }
61
+ });
62
+ };
63
+
64
+ }).call(this);
65
+ (function() {
66
+ this.LiveRecord.helpers.spaceship = function(val1, val2) {
67
+ if (val1 === null || val2 === null || typeof val1 !== typeof val2) {
68
+ return null;
69
+ }
70
+ if (typeof val1 === 'string') {
71
+ return val1.localeCompare(val2);
72
+ } else {
73
+ if (val1 > val2) {
74
+ return 1;
75
+ } else if (val1 < val2) {
76
+ return -1;
77
+ }
78
+ return 0;
79
+ }
80
+ };
81
+
82
+ }).call(this);
83
+ (function() {
84
+ var base;
85
+
86
+ (base = this.LiveRecord).Model || (base.Model = {});
87
+
88
+ }).call(this);
89
+ (function() {
90
+ this.LiveRecord.Model.all = {};
91
+
92
+ }).call(this);
93
+ (function() {
94
+ this.LiveRecord.Model.create = function(config) {
95
+ var Model, callbackFunction, callbackFunctions, callbackKey, i, index, len, methodKey, methodValue, pluginKey, pluginValue, ref, ref1, ref2, ref3;
96
+ config.modelName !== void 0 || (function() {
97
+ throw new Error('missing :modelName argument');
98
+ })();
99
+ config.callbacks !== void 0 || (config.callbacks = {});
100
+ config.plugins !== void 0 || (config.callbacks = {});
101
+ Model = function(attributes) {
102
+ if (attributes == null) {
103
+ attributes = {};
104
+ }
105
+ this.attributes = attributes;
106
+ Object.keys(this.attributes).forEach(function(attribute_key) {
107
+ if (Model.prototype[attribute_key] === void 0) {
108
+ return Model.prototype[attribute_key] = function() {
109
+ return this.attributes[attribute_key];
110
+ };
111
+ }
112
+ });
113
+ this._callbacks = {
114
+ 'on:connect': [],
115
+ 'on:disconnect': [],
116
+ 'on:responseError': [],
117
+ 'before:create': [],
118
+ 'after:create': [],
119
+ 'before:update': [],
120
+ 'after:update': [],
121
+ 'before:destroy': [],
122
+ 'after:destroy': []
123
+ };
124
+ return this;
125
+ };
126
+ Model.modelName = config.modelName;
127
+ Model.associations = {
128
+ hasMany: config.hasMany,
129
+ belongsTo: config.belongsTo
130
+ };
131
+ if (Model.associations.hasMany) {
132
+ Object.keys(Model.associations.hasMany).forEach(function(key, index) {
133
+ var associationConfig, associationName;
134
+ associationName = key;
135
+ associationConfig = Model.associations.hasMany[associationName];
136
+ return Model.prototype[associationName] = function() {
137
+ var associatedModel, associatedRecords, id, isAssociated, record, ref, self;
138
+ self = this;
139
+ associatedModel = LiveRecord.Model.all[associationConfig.modelName];
140
+ if (!associatedModel) {
141
+ throw new Error('No defined model for "' + associationConfig.modelName + '"');
142
+ }
143
+ associatedRecords = [];
144
+ ref = associatedModel.all;
145
+ for (id in ref) {
146
+ record = ref[id];
147
+ isAssociated = record[associationConfig.foreignKey]() === self.id();
148
+ if (isAssociated) {
149
+ associatedRecords.push(record);
150
+ }
151
+ }
152
+ return associatedRecords;
153
+ };
154
+ });
155
+ }
156
+ if (Model.associations.belongsTo) {
157
+ Object.keys(Model.associations.belongsTo).forEach(function(key, index) {
158
+ var associationConfig, associationName;
159
+ associationName = key;
160
+ associationConfig = Model.associations.belongsTo[associationName];
161
+ return Model.prototype[associationName] = function() {
162
+ var associatedModel, belongsToID, self;
163
+ self = this;
164
+ associatedModel = LiveRecord.Model.all[associationConfig.modelName];
165
+ if (!associatedModel) {
166
+ throw new Error('No defined model for "' + associationConfig.modelName + '"');
167
+ }
168
+ belongsToID = self[associationConfig.foreignKey]();
169
+ return associatedModel.all[belongsToID];
170
+ };
171
+ });
172
+ }
173
+ Model.all = {};
174
+ Model.subscriptions = [];
175
+ Model.autoload = function(config) {
176
+ var subscription;
177
+ if (config == null) {
178
+ config = {};
179
+ }
180
+ config.callbacks || (config.callbacks = {});
181
+ config.reload || (config.reload = false);
182
+ if (config.callbacks.afterReload && !config.reload) {
183
+ throw new Error('`afterReload` callback only works with `reload: true`');
184
+ }
185
+ subscription = App.cable.subscriptions.create({
186
+ channel: 'LiveRecord::AutoloadsChannel',
187
+ model_name: Model.modelName,
188
+ where: config.where
189
+ }, {
190
+ connected: function() {
191
+ if (config.reload) {
192
+ config.reload = false;
193
+ this.syncRecords();
194
+ }
195
+ if (this.liveRecord._staleSince !== void 0) {
196
+ this.syncRecords();
197
+ }
198
+ if (config.callbacks['on:connect']) {
199
+ return config.callbacks['on:connect'].call(this);
200
+ }
201
+ },
202
+ disconnected: function() {
203
+ if (!this.liveRecord._staleSince) {
204
+ this.liveRecord._staleSince = (new Date()).toISOString();
205
+ }
206
+ if (config.callbacks['on:disconnect']) {
207
+ return config.callbacks['on:disconnect'].call(this);
208
+ }
209
+ },
210
+ received: function(data) {
211
+ if (data.error) {
212
+ if (!this.liveRecord._staleSince) {
213
+ this.liveRecord._staleSince = (new Date()).toISOString();
214
+ }
215
+ return this.onError[data.error.code].call(this, data);
216
+ } else {
217
+ return this.onAction[data.action].call(this, data);
218
+ }
219
+ },
220
+ onAction: {
221
+ createOrUpdate: function(data) {
222
+ var doesRecordAlreadyExist, record;
223
+ record = Model.all[data.attributes.id];
224
+ if (record) {
225
+ doesRecordAlreadyExist = true;
226
+ } else {
227
+ record = new Model(data.attributes);
228
+ doesRecordAlreadyExist = false;
229
+ }
230
+ if (config.callbacks['before:createOrUpdate']) {
231
+ config.callbacks['before:createOrUpdate'].call(this, record);
232
+ }
233
+ if (doesRecordAlreadyExist) {
234
+ record.update(data.attributes);
235
+ } else {
236
+ record.create();
237
+ }
238
+ if (config.callbacks['after:createOrUpdate']) {
239
+ return config.callbacks['after:createOrUpdate'].call(this, record);
240
+ }
241
+ },
242
+ afterReload: function(data) {
243
+ if (config.callbacks['after:reload']) {
244
+ return config.callbacks['after:reload'].call(this, data.recordIds);
245
+ }
246
+ }
247
+ },
248
+ onError: {
249
+ forbidden: function(data) {
250
+ return console.error('[LiveRecord Response Error]', data.error.code, ':', data.error.message, 'for', this);
251
+ },
252
+ bad_request: function(data) {
253
+ return console.error('[LiveRecord Response Error]', data.error.code, ':', data.error.message, 'for', this);
254
+ }
255
+ },
256
+ syncRecords: function() {
257
+ this.perform('sync_records', {
258
+ model_name: Model.modelName,
259
+ where: config.where,
260
+ stale_since: this.liveRecord._staleSince
261
+ });
262
+ return this.liveRecord._staleSince = void 0;
263
+ }
264
+ });
265
+ subscription.liveRecord = {};
266
+ subscription.liveRecord.modelName = Model.modelName;
267
+ subscription.liveRecord.where = config.where;
268
+ subscription.liveRecord.callbacks = config.callbacks;
269
+ this.subscriptions.push(subscription);
270
+ return subscription;
271
+ };
272
+ Model.subscribe = function(config) {
273
+ var subscription;
274
+ if (config == null) {
275
+ config = {};
276
+ }
277
+ config.callbacks || (config.callbacks = {});
278
+ config.reload || (config.reload = false);
279
+ if (config.callbacks.afterReload && !config.reload) {
280
+ throw new Error('`afterReload` callback only works with `reload: true`');
281
+ }
282
+ subscription = App.cable.subscriptions.create({
283
+ channel: 'LiveRecord::PublicationsChannel',
284
+ model_name: Model.modelName,
285
+ where: config.where
286
+ }, {
287
+ connected: function() {
288
+ if (config.reload) {
289
+ config.reload = false;
290
+ this.syncRecords();
291
+ }
292
+ if (this.liveRecord._staleSince !== void 0) {
293
+ this.syncRecords();
294
+ }
295
+ if (config.callbacks['on:connect']) {
296
+ return config.callbacks['on:connect'].call(this);
297
+ }
298
+ },
299
+ disconnected: function() {
300
+ if (!this.liveRecord._staleSince) {
301
+ this.liveRecord._staleSince = (new Date()).toISOString();
302
+ }
303
+ if (config.callbacks['on:disconnect']) {
304
+ return config.callbacks['on:disconnect'].call(this);
305
+ }
306
+ },
307
+ received: function(data) {
308
+ if (data.error) {
309
+ if (!this.liveRecord._staleSince) {
310
+ this.liveRecord._staleSince = (new Date()).toISOString();
311
+ }
312
+ return this.onError[data.error.code].call(this, data);
313
+ } else {
314
+ return this.onAction[data.action].call(this, data);
315
+ }
316
+ },
317
+ onAction: {
318
+ create: function(data) {
319
+ var record;
320
+ record = new Model(data.attributes);
321
+ if (config.callbacks['before:create']) {
322
+ config.callbacks['before:create'].call(this, record);
323
+ }
324
+ record.create();
325
+ if (config.callbacks['after:create']) {
326
+ return config.callbacks['after:create'].call(this, record);
327
+ }
328
+ },
329
+ afterReload: function(data) {
330
+ if (config.callbacks['after:reload']) {
331
+ return config.callbacks['after:reload'].call(this, data.recordIds);
332
+ }
333
+ }
334
+ },
335
+ onError: {
336
+ forbidden: function(data) {
337
+ return console.error('[LiveRecord Response Error]', data.error.code, ':', data.error.message, 'for', this);
338
+ },
339
+ bad_request: function(data) {
340
+ return console.error('[LiveRecord Response Error]', data.error.code, ':', data.error.message, 'for', this);
341
+ }
342
+ },
343
+ syncRecords: function() {
344
+ this.perform('sync_records', {
345
+ model_name: Model.modelName,
346
+ where: config.where,
347
+ stale_since: this.liveRecord._staleSince
348
+ });
349
+ return this.liveRecord._staleSince = void 0;
350
+ }
351
+ });
352
+ subscription.liveRecord = {};
353
+ subscription.liveRecord.modelName = Model.modelName;
354
+ subscription.liveRecord.where = config.where;
355
+ subscription.liveRecord.callbacks = config.callbacks;
356
+ this.subscriptions.push(subscription);
357
+ return subscription;
358
+ };
359
+ Model.unsubscribe = function(subscription) {
360
+ var index;
361
+ index = this.subscriptions.indexOf(subscription);
362
+ if (index === -1) {
363
+ throw new Error('`subscription` argument does not exist in ' + this.modelName + ' subscriptions list');
364
+ }
365
+ App.cable.subscriptions.remove(subscription);
366
+ this.subscriptions.splice(index, 1);
367
+ return subscription;
368
+ };
369
+ ref = config.classMethods;
370
+ for (methodKey in ref) {
371
+ methodValue = ref[methodKey];
372
+ if (Model[methodKey] !== void 0) {
373
+ throw new Error('Cannot use reserved name as class method: ', methodKey);
374
+ }
375
+ Model[methodKey] = methodValue;
376
+ }
377
+ Model.prototype.subscribe = function(config) {
378
+ var subscription;
379
+ if (config == null) {
380
+ config = {};
381
+ }
382
+ if (this.subscription !== void 0) {
383
+ return this.subscription;
384
+ }
385
+ config.reload || (config.reload = false);
386
+ subscription = App['live_record_' + this.modelName() + '_' + this.id()] = App.cable.subscriptions.create({
387
+ channel: 'LiveRecord::ChangesChannel',
388
+ model_name: this.modelName(),
389
+ record_id: this.id()
390
+ }, {
391
+ record: function() {
392
+ var identifier;
393
+ if (this._record) {
394
+ return this._record;
395
+ }
396
+ identifier = JSON.parse(this.identifier);
397
+ return this._record = Model.all[identifier.record_id];
398
+ },
399
+ connected: function() {
400
+ if (config.reload) {
401
+ config.reload = false;
402
+ this.syncRecord(this.record());
403
+ }
404
+ if (this.record()._staleSince !== void 0) {
405
+ this.syncRecord(this.record());
406
+ }
407
+ return this.record()._callCallbacks('on:connect', void 0);
408
+ },
409
+ disconnected: function() {
410
+ if (!this.record()._staleSince) {
411
+ this.record()._staleSince = (new Date()).toISOString();
412
+ }
413
+ return this.record()._callCallbacks('on:disconnect', void 0);
414
+ },
415
+ received: function(data) {
416
+ if (data.error) {
417
+ if (!this.record()._staleSince) {
418
+ this.record()._staleSince = (new Date()).toISOString();
419
+ }
420
+ this.onError[data.error.code].call(this, data);
421
+ this.record()._callCallbacks('on:responseError', [data.error.code]);
422
+ return delete this.record()['subscription'];
423
+ } else {
424
+ return this.onAction[data.action].call(this, data);
425
+ }
426
+ },
427
+ onAction: {
428
+ update: function(data) {
429
+ this.record()._setChangesFrom(data.attributes);
430
+ this.record().update(data.attributes);
431
+ return this.record()._unsetChanges();
432
+ },
433
+ destroy: function(data) {
434
+ return this.record().destroy();
435
+ }
436
+ },
437
+ onError: {
438
+ forbidden: function(data) {
439
+ return console.error('[LiveRecord Response Error]', data.error.code, ':', data.error.message, 'for', this.record());
440
+ },
441
+ bad_request: function(data) {
442
+ return console.error('[LiveRecord Response Error]', data.error.code, ':', data.error.message, 'for', this.record());
443
+ }
444
+ },
445
+ syncRecord: function() {
446
+ this.perform('sync_record', {
447
+ model_name: this.record().modelName(),
448
+ record_id: this.record().id(),
449
+ stale_since: this.record()._staleSince
450
+ });
451
+ return this.record()._staleSince = void 0;
452
+ }
453
+ });
454
+ return this.subscription = subscription;
455
+ };
456
+ Model.prototype.model = function() {
457
+ return Model;
458
+ };
459
+ Model.prototype.modelName = function() {
460
+ return Model.modelName;
461
+ };
462
+ Model.prototype.unsubscribe = function() {
463
+ if (this.subscription === void 0) {
464
+ return;
465
+ }
466
+ App.cable.subscriptions.remove(this.subscription);
467
+ return delete this['subscription'];
468
+ };
469
+ Model.prototype.isSubscribed = function() {
470
+ return this.subscription !== void 0;
471
+ };
472
+ Model.prototype.create = function(options) {
473
+ if (Model.all[this.attributes.id]) {
474
+ throw new Error(Model.modelName + '(' + this.id() + ') is already in the store');
475
+ }
476
+ this._callCallbacks('before:create', void 0);
477
+ Model.all[this.attributes.id] = this;
478
+ this.subscribe({
479
+ reload: true
480
+ });
481
+ this._callCallbacks('after:create', void 0);
482
+ return this;
483
+ };
484
+ Model.prototype.update = function(attributes) {
485
+ var self;
486
+ self = this;
487
+ Object.keys(attributes).forEach(function(attribute_key) {
488
+ if (Model.prototype[attribute_key] === void 0) {
489
+ return Model.prototype[attribute_key] = function() {
490
+ return this.attributes[attribute_key];
491
+ };
492
+ }
493
+ });
494
+ this._callCallbacks('before:update', void 0);
495
+ Object.keys(attributes).forEach(function(attribute_key) {
496
+ return self.attributes[attribute_key] = attributes[attribute_key];
497
+ });
498
+ this._callCallbacks('after:update', void 0);
499
+ return true;
500
+ };
501
+ Model.prototype.destroy = function() {
502
+ this._callCallbacks('before:destroy', void 0);
503
+ this.unsubscribe();
504
+ delete Model.all[this.attributes.id];
505
+ this._callCallbacks('after:destroy', void 0);
506
+ return this;
507
+ };
508
+ Model._callbacks = {
509
+ 'on:connect': [],
510
+ 'on:disconnect': [],
511
+ 'on:responseError': [],
512
+ 'before:create': [],
513
+ 'after:create': [],
514
+ 'before:update': [],
515
+ 'after:update': [],
516
+ 'before:destroy': [],
517
+ 'after:destroy': []
518
+ };
519
+ Model.prototype.addCallback = Model.addCallback = function(callbackKey, callbackFunction) {
520
+ var index;
521
+ index = this._callbacks[callbackKey].indexOf(callbackFunction);
522
+ if (index === -1) {
523
+ this._callbacks[callbackKey].push(callbackFunction);
524
+ return callbackFunction;
525
+ }
526
+ };
527
+ Model.prototype.removeCallback = Model.removeCallback = function(callbackKey, callbackFunction) {
528
+ var index;
529
+ index = this._callbacks[callbackKey].indexOf(callbackFunction);
530
+ if (index !== -1) {
531
+ this._callbacks[callbackKey].splice(index, 1);
532
+ return callbackFunction;
533
+ }
534
+ };
535
+ Model.prototype._callCallbacks = function(callbackKey, args) {
536
+ var callback, i, j, len, len1, ref1, ref2, results;
537
+ ref1 = Model._callbacks[callbackKey];
538
+ for (i = 0, len = ref1.length; i < len; i++) {
539
+ callback = ref1[i];
540
+ callback.apply(this, args);
541
+ }
542
+ ref2 = this._callbacks[callbackKey];
543
+ results = [];
544
+ for (j = 0, len1 = ref2.length; j < len1; j++) {
545
+ callback = ref2[j];
546
+ results.push(callback.apply(this, args));
547
+ }
548
+ return results;
549
+ };
550
+ Model.prototype._setChangesFrom = function(attributes) {
551
+ var attributeName, attributeValue, results;
552
+ this.changes = {};
553
+ results = [];
554
+ for (attributeName in attributes) {
555
+ attributeValue = attributes[attributeName];
556
+ if (this.attributes[attributeName] !== attributeValue) {
557
+ results.push(this.changes[attributeName] = [this.attributes[attributeName], attributeValue]);
558
+ } else {
559
+ results.push(void 0);
560
+ }
561
+ }
562
+ return results;
563
+ };
564
+ Model.prototype._unsetChanges = function() {
565
+ return delete this['changes'];
566
+ };
567
+ ref1 = config.instanceMethods;
568
+ for (methodKey in ref1) {
569
+ methodValue = ref1[methodKey];
570
+ if (Model.prototype[methodKey] !== void 0) {
571
+ throw new Error('Cannot use reserved name as instance method: ', methodKey);
572
+ }
573
+ Model.prototype[methodKey] = methodValue;
574
+ }
575
+ ref2 = config.callbacks;
576
+ for (callbackKey in ref2) {
577
+ callbackFunctions = ref2[callbackKey];
578
+ for (i = 0, len = callbackFunctions.length; i < len; i++) {
579
+ callbackFunction = callbackFunctions[i];
580
+ Model.addCallback(callbackKey, callbackFunction);
581
+ }
582
+ }
583
+ ref3 = config.plugins;
584
+ for (pluginKey in ref3) {
585
+ pluginValue = ref3[pluginKey];
586
+ if (LiveRecord.plugins) {
587
+ index = Object.keys(LiveRecord.plugins).indexOf(pluginKey);
588
+ if (index !== -1) {
589
+ LiveRecord.plugins[pluginKey].applyToModel(Model, pluginValue);
590
+ }
591
+ }
592
+ }
593
+ LiveRecord.Model.all[config.modelName] = Model;
594
+ return Model;
595
+ };
596
+
597
+ }).call(this);
598
+ (function() {
599
+ var base;
600
+
601
+ (base = this.LiveRecord).plugins || (base.plugins = {});
602
+
603
+ }).call(this);
@@ -1,3 +1,3 @@
1
1
  module LiveRecord
2
- VERSION = '0.3.4'.freeze
2
+ VERSION = '0.3.6'.freeze
3
3
  end
@@ -22,9 +22,11 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency 'byebug', '~> 9.0'
23
23
 
24
24
  s.add_development_dependency 'sprockets-rails', '~> 3.2'
25
+ s.add_development_dependency 'sprockets-export', '~> 1.0'
25
26
  s.add_development_dependency 'coffee-rails', '~> 4.2'
26
27
  s.add_development_dependency 'jquery-rails', '~> 4.3'
27
28
  s.add_development_dependency 'jbuilder', '~> 2.7'
29
+ s.add_development_dependency 'blade', '~> 0.7'
28
30
 
29
31
  s.add_development_dependency 'sqlite3', '~> 1.3'
30
32
  s.add_development_dependency 'redis', '~> 3.3'
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "@jrpolidario/live_record",
3
+ "version": "0.3.6",
4
+ "lockfileVersion": 1,
5
+ "requires": true,
6
+ "dependencies": {
7
+ "actioncable": {
8
+ "version": "5.2.0",
9
+ "resolved": "https://registry.npmjs.org/actioncable/-/actioncable-5.2.0.tgz",
10
+ "integrity": "sha512-5o0wKTz2egSGDf7SubQLqoew/lGJhkjyJSdbMiaAfci/vNMjs7xjL2X+ELhstJmaN5tY17O3Wx6c5q2GgQE/JQ=="
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@jrpolidario/live_record",
3
+ "version": "0.3.6",
4
+ "description": "Auto-syncs records in client-side JS (through a Model DSL) from changes (updates/destroy) in the backend Rails server through ActionCable.\\n Also supports streaming newly created records to client-side JS.\\n Supports lost connection restreaming for both new records (create), and record-changes (updates/destroy).\\n Auto-updates DOM elements mapped to a record attribute, from changes (updates/destroy).",
5
+ "main": "lib/assets/compiled/live_record.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/jrpolidario/live_record.git"
9
+ },
10
+ "author": "Jules Roman B. Polidario",
11
+ "license": "MIT",
12
+ "bugs": {
13
+ "url": "https://github.com/jrpolidario/live_record/issues"
14
+ },
15
+ "homepage": "https://github.com/jrpolidario/live_record#readme",
16
+ "dependencies": {
17
+ "actioncable": "^5.0.0"
18
+ }
19
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: live_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jules Roman B. Polidario
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-25 00:00:00.000000000 Z
11
+ date: 2018-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '3.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sprockets-export
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: coffee-rails
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +150,20 @@ dependencies:
136
150
  - - "~>"
137
151
  - !ruby/object:Gem::Version
138
152
  version: '2.7'
153
+ - !ruby/object:Gem::Dependency
154
+ name: blade
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.7'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.7'
139
167
  - !ruby/object:Gem::Dependency
140
168
  name: sqlite3
141
169
  requirement: !ruby/object:Gem::Requirement
@@ -272,7 +300,9 @@ executables: []
272
300
  extensions: []
273
301
  extra_rdoc_files: []
274
302
  files:
303
+ - ".blade.yml"
275
304
  - ".gitignore"
305
+ - ".npmignore"
276
306
  - ".rspec"
277
307
  - ".travis.yml"
278
308
  - Gemfile
@@ -297,6 +327,8 @@ files:
297
327
  - app/channels/live_record/publications_channel.rb
298
328
  - config.ru
299
329
  - config/puma.rb
330
+ - developer_guide.md
331
+ - lib/assets/compiled/live_record.js
300
332
  - lib/live_record.rb
301
333
  - lib/live_record/action_view_extensions/view_helper.rb
302
334
  - lib/live_record/configure.rb
@@ -313,6 +345,8 @@ files:
313
345
  - lib/live_record/model/callbacks.rb
314
346
  - lib/live_record/version.rb
315
347
  - live_record.gemspec
348
+ - package-lock.json
349
+ - package.json
316
350
  - spec/factories/categories.rb
317
351
  - spec/factories/posts.rb
318
352
  - spec/factories/users.rb