live_record 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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