robin-rails 0.0.1 → 0.0.2

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
  SHA1:
3
- metadata.gz: e13a9eacc13a76cc09d33d925daabaa111012ac5
4
- data.tar.gz: b95f6b46420a8842fab70c0246e2c8076d04976e
3
+ metadata.gz: 7a53b2130e296798e0f9904424d22a7455c4718b
4
+ data.tar.gz: fbe629e0b2d28a38161ad5c789deef54724dbeac
5
5
  SHA512:
6
- metadata.gz: f4e3cc7401e5fe5797a13ef78d1517193cf3f7e976369e5bf1bad2fbf4e07b91d0d7e022262a3e561590e7befd2c08744a1e84345b971a2a58c61260bda40cbf
7
- data.tar.gz: 999148332f40ddf9a74ddb43cf8793b66ac484ae272fefe98d9238eff3c6225f4a85fb465c5093c1b131d05028b1d86d93f2dd0984aa32776c31de1c41ec782c
6
+ metadata.gz: 9dc6fced33d2e1560d57c824d19a4fd971457c7cfb2a609118fa1cdc9f78a8cc8a0560c759f620c099bc65297f520966fe29d24f38aa058a3734cd501481b2d1
7
+ data.tar.gz: c528834bc565005a810f823ceb8e902e4aa89e1d2da7cbb59933608cd1407ea9078adfa7742f4c3010a6d4bdbd7392347cf877d7393687fdcd737d6589716e18
data/README.md CHANGED
@@ -8,3 +8,61 @@ Robin.js on Rails
8
8
  =================
9
9
 
10
10
  Every Batman.js app on Rails needs a sidekick. Bring realtime to the fight with Robin.js.
11
+
12
+ Usage
13
+ =====
14
+
15
+ For client-side info on Robin.js, [checkout the CoffeeScript source.](https://github.com/nybblr/robin)
16
+
17
+ Vendoring
18
+ ---------
19
+
20
+ The latest version of the client-side Robin.js source is available through the asset pipeline under the `robin` namespace.
21
+
22
+ ~~~coffeescript
23
+ # app/assets/javascripts/application.js.coffee
24
+ #
25
+ #= require batman/es5-shim
26
+ #= require batman/batman
27
+ #= require batman/batman.rails
28
+ #= require batman/batman.jquery
29
+ #
30
+ #= require robin/robin
31
+ ~~~
32
+
33
+ Make sure you load Robin after the Batman source files. To get things working on the frontend, [checkout the setup details for Robin.js.](https://github.com/nybblr/robin)
34
+
35
+ Realtime
36
+ --------
37
+
38
+ The easiest way to get started is to add Robin to your Gemfile:
39
+
40
+ ~~~ruby
41
+ gem 'robin-rails' # Robin.js vendor and Rails events
42
+ gem 'faye' # websocket backend
43
+ ~~~
44
+
45
+ For every model you want to update in realtime, include the `Robin::Rails` module.
46
+
47
+ ~~~ruby
48
+ class Post < ActiveRecord::Base
49
+ include Robin::Rails
50
+ end
51
+ ~~~
52
+
53
+ You can configure the Faye endpoint in an initializer.
54
+
55
+ ~~~ruby
56
+ # config/initializers/robin.rb
57
+ Robin.configure do |config|
58
+ config.faye_url = 'http://localhost:9292/faye' # the default
59
+ end
60
+ ~~~
61
+
62
+ That's it! Anytime a record is created, updated, or destroyed, the event will immediately be pushed to Robin.js subscribers via Faye. If you've got Faye running correctly (e.g. make sure you use Thin or another EventMachine friendly server), you should now be able to open several browser clients, edit models in the JS console, then watch the events propagate to other subscribed clients!
63
+
64
+ Contributing
65
+ ============
66
+ This project is (obviously) in its infancy with just the basics. TODO lists a bunch of features I hope to get implemented, but this is GitHub: if you add a feature on your own, give me a hand and contribute!
67
+
68
+ No guidelines yet other than your basics: fork it, submit a pull request with relevant tests, and try to follow the conventions already in the code. Any and all quality contributions welcome!
@@ -1,5 +1,5 @@
1
1
  module Robin
2
2
  module Rails
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
@@ -0,0 +1 @@
1
+ (function(){function n(n){function t(){for(;f=a<c.length&&n>p;){var u=a++,t=c[u],r=l.call(t,1);r.push(e(u)),++p,t[0].apply(null,r)}}function e(n){return function(u,l){--p,null==d&&(null!=u?(d=u,a=s=0/0,r()):(c[n]=l,--s?f||t():r()))}}function r(){null!=d?v(d):i?v(d,c):v.apply(null,[d].concat(c))}var o,f,i,c=[],a=0,p=0,s=0,d=null,v=u;return n||(n=1/0),o={defer:function(){return d||(c.push(arguments),++s,t()),o},await:function(n){return v=n,i=!1,s||r(),o},awaitAll:function(n){return v=n,i=!0,s||r(),o}}}function u(){}"undefined"==typeof module?self.queue=n:module.exports=n,n.version="1.0.4";var l=[].slice})();
@@ -1,44 +1,11 @@
1
- # Push-persistence backed by Faye.
2
- class Batman.Robin extends Batman.Object
3
- @_nest: []
4
- @_verbs: ["updated", "created", "destroyed", "flushed", "batched"]
5
-
6
- @on 'socket:ready', ->
7
- @socket = Batman.currentApp.socket
8
- bird() for bird in @_nest
9
-
10
- constructor: (@model) ->
11
- if @socket
12
- # Go ahead and subscribe.
13
- @subscribe()
14
- else
15
- # Add it to the nest.
16
- Batman.Robin._nest.push =>
17
- @socket = Batman.Robin.socket
18
- @subscribe()
1
+ #= require_self
2
+ #= require ./robin/reactor
3
+ #= require ./robin/adapter
19
4
 
20
- subscribe: ->
21
- channel = @model.storageKey
22
- Batman.developer.log "Subscribing to /#{channel}..."
23
- for verb in @constructor._verbs
24
- do (verb) =>
25
- @socket.subscribe "/#{channel}/#{verb}", (data) => @delayIfXhrRequests(verb, data)
26
-
27
- delayIfXhrRequestsWithoutDecompress: (method, data) ->
28
- if Batman.Robin.activeXhrCount == 0
29
- setTimeout =>
30
- Batman.developer.log("Processing #{method} with data #{JSON.stringify(data)}")
31
- Batman.Reactor.process(method, @model, data)
32
- , 0
33
- else
34
- Batman.developer.log("Delaying #{method}")
35
- setTimeout =>
36
- @delayIfXhrRequestsWithoutDecompress(method, data)
37
- , 500
38
-
39
- delayIfXhrRequests: (method, data) ->
40
- @delayIfXhrRequestsWithoutDecompress(method, data)
5
+ # Push-persistence backed by Faye.
6
+ class @Robin extends Batman.Object
7
+ @connect: (socket) ->
8
+ @set 'socket', socket
9
+ @fire('socket:ready')
41
10
 
42
- @Robin = Batman.Robin
43
- @Robin.activeXhrCount = 0
44
- $(document).ajaxSend(=> @Robin.activeXhrCount++).ajaxComplete(=> @Robin.activeXhrCount--)
11
+ window.Robin = Robin
@@ -0,0 +1,23 @@
1
+ Robin.AdapterMethods =
2
+ subscribe: ->
3
+ Robin.observeAndFire 'socket', (newVal, oldVal) =>
4
+ if newVal?
5
+ @socket = newVal
6
+ @_subscribeNow()
7
+
8
+ _subscribeNow: ->
9
+ channel = @model.storageKey
10
+ Batman.developer.log "Subscribing to /#{channel}..."
11
+ for verb in Robin.Reactor._verbs
12
+ do (verb) =>
13
+ @socket.subscribe "/#{channel}/#{verb}", (data) => @_react(verb, data)
14
+
15
+ _react: (verb, data) ->
16
+ Robin.Reactor.process(verb, @model, data)
17
+
18
+ class Robin.Adapter extends Batman.RailsStorage
19
+ Batman.mixin @::, Robin.AdapterMethods
20
+
21
+ constructor: (model) ->
22
+ super(model)
23
+ @subscribe()
@@ -0,0 +1,74 @@
1
+ #= require ../lib/queue
2
+ #= require_self
3
+
4
+ # Utility class for updating models in memory.
5
+ Robin.Reactor =
6
+ # Private queue for batching
7
+ _q: queue(1)
8
+
9
+ # Valid batch operations
10
+ _verbs: ["updated", "created", "destroyed", "flushed", "batched"]
11
+
12
+ # Public interface for updating objects in Batman in a bulk/one off fashion
13
+ process: (verb, model, data) ->
14
+ if @_verbs.indexOf(verb) > -1
15
+ if verb is 'batched'
16
+ @_batched(model, data)
17
+ else
18
+ @_enqueue(verb, model, data)
19
+ else
20
+ Batman.developer.warn("unrecognized verb: " + verb)
21
+
22
+ _execute: (verb, model, data) ->
23
+ Batman.developer.log("#{verb} #{model.name} => #{JSON.stringify(data)}")
24
+ @['_'+verb](model, data)
25
+
26
+ _enqueue: (verb, model, data) ->
27
+ @_q.defer (next) =>
28
+ @_execute(verb, model, data)
29
+ next()
30
+
31
+ _removeRecord: (model, record) ->
32
+ model.get('loaded').remove(record)
33
+ record.get('lifecycle').destroyed()
34
+
35
+ _initOrUpdateRecord: (model, data) ->
36
+ model._makeOrFindRecordFromData(data)
37
+
38
+ _findRecord: (model, data) ->
39
+ model._loadIdentity(data['id'])
40
+
41
+ # Flush every record of a model matching the criterion.
42
+ # Makes Batman request updates.
43
+ _flushed: (model, data) ->
44
+ key = data.key
45
+ value = data.value
46
+
47
+ recordsToRemove = model.get('loaded').indexedBy(key).get(value).toArray()
48
+ for record in recordsToRemove
49
+ @_removeRecord(model, record)
50
+ if key is model.get('primaryKey')
51
+ model.find value, ->
52
+ else
53
+ options = {}
54
+ options["#{key}"] = value
55
+ model.load options
56
+
57
+ _batched: (model, batch) ->
58
+ return unless batch?
59
+ Batman.developer.log("batched (#{batch.length})")
60
+
61
+ for item in batch
62
+ @_enqueue(item[0], model, item[1])
63
+
64
+ _created: (model, data) ->
65
+ @_initOrUpdateRecord(model, data)
66
+
67
+ _updated: (model, data) ->
68
+ record = @_findRecord(model, data)
69
+ @_initOrUpdateRecord(model, data) if record?
70
+
71
+ _destroyed: (model, data) ->
72
+ record = @_findRecord(model, data)
73
+ @_removeRecord(model, record) if record?
74
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: robin-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Martin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-16 00:00:00.000000000 Z
11
+ date: 2013-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -132,8 +132,10 @@ files:
132
132
  - spec/robin/rails_spec.rb
133
133
  - spec/robin_spec.rb
134
134
  - spec/spec_helper.rb
135
- - vendor/assets/javascripts/robin/reactor.js.coffee
135
+ - vendor/assets/javascripts/robin/lib/queue.js
136
136
  - vendor/assets/javascripts/robin/robin.js.coffee
137
+ - vendor/assets/javascripts/robin/robin/adapter.js.coffee
138
+ - vendor/assets/javascripts/robin/robin/reactor.js.coffee
137
139
  homepage: https://github.com/nybblr/robin-rails
138
140
  licenses:
139
141
  - MIT
@@ -1,70 +0,0 @@
1
- # Utility class for updating models in memory.
2
- Batman.Reactor =
3
- # Private queue for jQuery
4
- _q: $({})
5
-
6
- # Valid batch operations
7
- _verbs: ["updated", "created", "destroyed", "flushed", "batched"]
8
-
9
- # Public interface for updating objects in Batman in a bulk/one off fashion
10
- process: (verb, model, data) ->
11
- if _.contains @_verbs, verb
12
- @['_'+verb](model, data)
13
- else
14
- Batman.developer.warn("unrecognized batch operation: " + verb)
15
-
16
- _enqueue: (model, batch_item) ->
17
- @_q.queue (next) =>
18
- @process(batch_item[0], model, batch_item[1])
19
- next()
20
-
21
- _getObject: (model, data) ->
22
- # model = Batman.currentApp[pushed_data.model_name]
23
- # data = pushed_data.model_data
24
- obj = new model()
25
- obj._withoutDirtyTracking -> obj.fromJSON(data)
26
- return obj
27
-
28
- # Flush every object of a certain model that matches the criterion (all comments for a post)
29
- # used when you have too much data to pass through Pusher but want Batman to request updates
30
- _flushed: (model, data) ->
31
- # model = Batman.currentApp[reload_data.model_name]
32
- match_key = data.match_key
33
- match_value = data.match_value
34
- Batman.developer.log("FLUSH #{model.name} - #{match_key} => #{match_value}")
35
- recordsToRemove = model.get('loaded').indexedBy(match_key).get(match_value).toArray()
36
- recordsToRemove.forEach (existing) =>
37
- model.get('loaded').remove(existing)
38
- if match_key == 'id'
39
- model.find match_value, ->
40
- else
41
- options = {}
42
- options["#{match_key}"] = match_value
43
- model.load options
44
-
45
- _batched: (model, batch) ->
46
- return if batch == undefined
47
- Batman.developer.log("BATCH: " + batch.length)
48
- for batched_item in batch
49
- @_enqueue(model, batched_item)
50
-
51
- _created: (model, data) ->
52
- Batman.developer.log("created: #{JSON.stringify(data)}")
53
- obj = model.get('loaded.indexedByUnique.id').get(data["id"])
54
- if obj # If object already in memory, update it
55
- obj._withoutDirtyTracking -> obj.fromJSON(data)
56
- else # create object in memory
57
- obj = @_getObject(model, data)
58
- model._mapIdentity(obj)
59
-
60
- _updated: (model, data) ->
61
- Batman.developer.log("updated #{JSON.stringify(data)}")
62
- obj = model.get('loaded.indexedByUnique.id').get(data["id"])
63
- if obj
64
- obj._withoutDirtyTracking -> obj.fromJSON(data)
65
-
66
- _destroyed: (model, data) ->
67
- Batman.developer.log("destroyed #{JSON.stringify(data)}")
68
- existing = model.get('loaded.indexedByUnique.id').get(data["id"])
69
- if existing
70
- model.get('loaded').remove(existing)