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 +4 -4
- data/README.md +58 -0
- data/lib/robin/rails/version.rb +1 -1
- data/vendor/assets/javascripts/robin/lib/queue.js +1 -0
- data/vendor/assets/javascripts/robin/robin.js.coffee +9 -42
- data/vendor/assets/javascripts/robin/robin/adapter.js.coffee +23 -0
- data/vendor/assets/javascripts/robin/robin/reactor.js.coffee +74 -0
- metadata +5 -3
- data/vendor/assets/javascripts/robin/reactor.js.coffee +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a53b2130e296798e0f9904424d22a7455c4718b
|
4
|
+
data.tar.gz: fbe629e0b2d28a38161ad5c789deef54724dbeac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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!
|
data/lib/robin/rails/version.rb
CHANGED
@@ -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
|
-
|
2
|
-
|
3
|
-
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
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.
|
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-
|
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/
|
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)
|