robin-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e13a9eacc13a76cc09d33d925daabaa111012ac5
4
+ data.tar.gz: b95f6b46420a8842fab70c0246e2c8076d04976e
5
+ SHA512:
6
+ metadata.gz: f4e3cc7401e5fe5797a13ef78d1517193cf3f7e976369e5bf1bad2fbf4e07b91d0d7e022262a3e561590e7befd2c08744a1e84345b971a2a58c61260bda40cbf
7
+ data.tar.gz: 999148332f40ddf9a74ddb43cf8793b66ac484ae272fefe98d9238eff3c6225f4a85fb465c5093c1b131d05028b1d86d93f2dd0984aa32776c31de1c41ec782c
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby-19mode
6
+ - rbx-19mode
7
+ script: bundle exec rspec spec
8
+ notifications:
9
+ email: false
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in robin-rails.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'coveralls', :require => false
8
+
9
+ platforms :ruby do
10
+ gem 'sqlite3'
11
+ end
12
+
13
+ platforms :jruby do
14
+ gem 'json'
15
+ gem 'activerecord-jdbcsqlite3-adapter'
16
+ end
17
+ end
18
+
@@ -0,0 +1,7 @@
1
+ guard :rspec do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^bin/(.+)$}) { |m| [ "spec/bin/#{m[1]}_spec.rb" ] }
4
+ watch(%r{^lib/(.+)\.rb$}) { |m| [ "spec" ] }
5
+
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jonathan Martin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,10 @@
1
+ [![Gem Version](https://badge.fury.io/rb/robin-rails.png)](http://badge.fury.io/rb/robin-rails)
2
+ [![Dependency Status](https://gemnasium.com/nybblr/robin-rails.png)](https://gemnasium.com/nybblr/robin-rails)
3
+ [![Code Climate](https://codeclimate.com/github/nybblr/robin-rails.png)](https://codeclimate.com/github/nybblr/robin-rails)
4
+ [![Coverage Status](https://coveralls.io/repos/nybblr/robin-rails/badge.png?branch=master)](https://coveralls.io/r/nybblr/robin-rails)
5
+ [![Build Status](https://travis-ci.org/nybblr/robin-rails.png)](https://travis-ci.org/nybblr/robin-rails)
6
+
7
+ Robin.js on Rails
8
+ =================
9
+
10
+ Every Batman.js app on Rails needs a sidekick. Bring realtime to the fight with Robin.js.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,11 @@
1
+ require 'robin'
2
+ require 'robin/rails'
3
+ require 'robin/rails/version'
4
+ require 'rails/engine'
5
+
6
+ module Robin
7
+ module Rails
8
+ class Engine < ::Rails::Engine
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_support/core_ext/module/attribute_accessors'
2
+
3
+ module Robin
4
+ mattr_accessor :faye_url
5
+ @@faye_url = 'http://localhost:9292/faye'
6
+
7
+ class << self
8
+ def configure
9
+ yield self
10
+ end
11
+
12
+ def publish record, event, data
13
+ msg = {
14
+ channel: channel_for(record, event),
15
+ data: data
16
+ }
17
+
18
+ uri = URI.parse("http://localhost:9292/faye")
19
+ Net::HTTP.post_form(uri, message: msg.to_json)
20
+ end
21
+
22
+ def channel_for(record, event)
23
+ "/#{record.class.model_name.route_key}/#{event}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ require 'active_support/concern'
2
+ # require 'robin'
3
+
4
+ module Robin
5
+ module Rails
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ after_create do |record|
10
+ ::Robin.publish record, :created, record.attributes
11
+ end
12
+
13
+ after_update do |record|
14
+ ::Robin.publish record, :updated, record.attributes
15
+ end
16
+
17
+ after_destroy do |record|
18
+ ::Robin.publish record, :destroyed, id: record.id
19
+ end
20
+ end
21
+
22
+ module ClassMethods
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ module Robin
2
+ module Rails
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'robin/rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "robin-rails"
8
+ spec.version = Robin::Rails::VERSION
9
+ spec.authors = ["Jonathan Martin"]
10
+ spec.email = ["me@nybblr.com"]
11
+ spec.description = %q{Every Batman.js app on Rails needs a sidekick. Bring realtime to the fight with Robin.js.}
12
+ spec.summary = %q{Realtime updates are awesome and the future of web apps. But they're a pain to use from scatch for anything more complex than a couple models. We'd like things to just "autoupdate" and add functionality as desired to react to live updates. That's where Robin.js comes in.}
13
+ spec.homepage = "https://github.com/nybblr/robin-rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.required_ruby_version = '>= 1.9.3'
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "activesupport", ">= 4.0.0"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rails"
28
+ spec.add_development_dependency "rspec"
29
+ spec.add_development_dependency "guard"
30
+ spec.add_development_dependency "guard-rspec"
31
+ end
@@ -0,0 +1,4 @@
1
+ class DummyModel < ActiveRecord::Base
2
+ include Robin::Rails
3
+ end
4
+
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'robin-rails'
3
+ require 'active_record'
4
+
5
+ require_relative '../fixtures/dummy_model'
6
+
7
+ describe Robin::Rails do
8
+ before(:all) do
9
+ # Throw together a fake DB
10
+ ActiveRecord::Base.establish_connection(
11
+ :adapter => 'sqlite3',
12
+ :database => ':memory:'
13
+ )
14
+
15
+ ActiveRecord::Migration.verbose = false
16
+ ActiveRecord::Schema.define do
17
+ create_table :dummy_models, force: true
18
+ end
19
+ end
20
+
21
+ context 'included module' do
22
+ before do
23
+ Robin.stub(:publish)
24
+ end
25
+
26
+ it 'calls publish after create' do
27
+ Robin.should_receive(:publish).with(anything, :created, anything)
28
+
29
+ DummyModel.create
30
+ end
31
+
32
+ it 'calls publish after update' do
33
+ record = DummyModel.create
34
+ Robin.should_receive(:publish).with(anything, :updated, anything)
35
+ record.save
36
+ end
37
+
38
+ it 'calls publish after destroy' do
39
+ record = DummyModel.create
40
+ Robin.should_receive(:publish).with(anything, :destroyed, anything)
41
+ record.destroy
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'robin-rails'
3
+
4
+ describe Robin do
5
+ let(:data) { {id: 1, title: "hello"} }
6
+ let(:record) {
7
+ double(:record, class: double(model_name: double(route_key: 'records')))
8
+ }
9
+
10
+ context '#configure' do
11
+ it 'has reasonable defaults' do
12
+ Robin.faye_url.should == 'http://localhost:9292/faye'
13
+ end
14
+
15
+ it 'can override defaults' do
16
+ Robin.configure do |config|
17
+ config.faye_url = 'http://faye.local/faye'
18
+ end
19
+
20
+ Robin.faye_url.should == 'http://faye.local/faye'
21
+ end
22
+ end
23
+
24
+ context '#publish' do
25
+ it 'makes a properly formatted request' do
26
+ Net::HTTP.should_receive(:post_form).with(
27
+ anything, {message: {channel: "/records/created", data: data}.to_json}
28
+ )
29
+ Net::HTTP.stub(:post_form)
30
+
31
+ Robin.publish record, :created, data
32
+ end
33
+
34
+ it 'sends the request to the configured server' do
35
+
36
+ # URI.parse('http://localhost:9292/faye'),
37
+ end
38
+ end
39
+
40
+ context '#channel_for' do
41
+ it 'generates a path similar to a Rails route' do
42
+ Robin.channel_for(record, :busted).should == "/records/busted"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,2 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
@@ -0,0 +1,70 @@
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)
@@ -0,0 +1,44 @@
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()
19
+
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)
41
+
42
+ @Robin = Batman.Robin
43
+ @Robin.activeXhrCount = 0
44
+ $(document).ajaxSend(=> @Robin.activeXhrCount++).ajaxComplete(=> @Robin.activeXhrCount--)
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: robin-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Martin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Every Batman.js app on Rails needs a sidekick. Bring realtime to the
112
+ fight with Robin.js.
113
+ email:
114
+ - me@nybblr.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .gitignore
120
+ - .travis.yml
121
+ - Gemfile
122
+ - Guardfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - lib/robin-rails.rb
127
+ - lib/robin.rb
128
+ - lib/robin/rails.rb
129
+ - lib/robin/rails/version.rb
130
+ - robin-rails.gemspec
131
+ - spec/fixtures/dummy_model.rb
132
+ - spec/robin/rails_spec.rb
133
+ - spec/robin_spec.rb
134
+ - spec/spec_helper.rb
135
+ - vendor/assets/javascripts/robin/reactor.js.coffee
136
+ - vendor/assets/javascripts/robin/robin.js.coffee
137
+ homepage: https://github.com/nybblr/robin-rails
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - '>='
148
+ - !ruby/object:Gem::Version
149
+ version: 1.9.3
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.0.3
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Realtime updates are awesome and the future of web apps. But they're a pain
161
+ to use from scatch for anything more complex than a couple models. We'd like things
162
+ to just "autoupdate" and add functionality as desired to react to live updates.
163
+ That's where Robin.js comes in.
164
+ test_files:
165
+ - spec/fixtures/dummy_model.rb
166
+ - spec/robin/rails_spec.rb
167
+ - spec/robin_spec.rb
168
+ - spec/spec_helper.rb
169
+ has_rdoc: