sync_bumper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eeb67b4ccf61e6b2c827757823f6c3409b204a0f
4
+ data.tar.gz: 1c00aeefec000c068ed4198c161fd84b9d1827a1
5
+ SHA512:
6
+ metadata.gz: 4a38eb4c7caa2151750ef0f6de38f2dbe0afb392a5e3f97fea70d1d691ab8eb3f4a8029238818773b719f0997275a2964e881d6ab104e624942c174d8d76796d
7
+ data.tar.gz: 6bf29354269289a5ee3836aeeeddfde38eb11bd3296df2128a74fcd3f8b2231878302438dbd58f53633190cc7582e9da342940cf2880f6422128d9cacff271c5
data/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ # Version 0.2.3 - June 30, 2013
2
+
3
+ - Fixed Turbolinks issue where `page:restore` events no longer evaluate script tags in the body. The workaround re-evaluates all sync sript tags on page restore.
4
+
5
+ # Version 0.2.1 - May 27, 2013
6
+
7
+ - Add ability to narrow scope to custom channel for sync_new publishes
8
+
9
+ Example Usage:
10
+
11
+ View:
12
+ ```erb
13
+ <%= sync_new partial: 'todo_list_row', resource: Todo.new, scope: [@project, :staff] %>
14
+ ```
15
+
16
+ Controller/Model:
17
+ ```ruby
18
+ sync_new @todo, scope: [@project, :staff]
19
+ ```
20
+
21
+
22
+ # Version 0.2.0 - May 26, 2013
23
+
24
+ - Add ability to refetch partial from server to render within session context, ref: https://github.com/chrismccord/sync/issues/44
25
+
26
+ This solves the issues of syncing partials across different users when the partial requires the session's context (ie. current_user).
27
+
28
+ Ex:
29
+ View: Add `refetch: true` to sync calls, and place partial file in a 'refetch'
30
+ subdirectory in the model's sync view folder:
31
+
32
+ The partial file would be located in `app/views/sync/todos/refetch/_list_row.html.erb`
33
+ ```erb
34
+ <% @project.todos.ordered.each do |todo| %>
35
+ <%= sync partial: 'list_row', resource: todo, refetch: true %>
36
+ <% end %>
37
+ <%= sync_new partial: 'list_row', resource: Todo.new, scope: @project, refetch: true %>
38
+ ```
39
+
40
+ *Notes*
41
+ While this approach works very well for the cases it's needed, syncing without refetching should be used unless refetching is absolutely necessary for performance reasons. For example,
42
+
43
+ A sync update request is triggered on the server for a 'regular' sync'd partial with 100 listening clients:
44
+ - number of http requests 1
45
+ - number of renders 1, pushed out to all 100 clients via pubsub server.
46
+
47
+
48
+ A sync update request is triggered on the server for a 'refetch' sync'd partial with 100 listening clients:
49
+ - number of http requests 100
50
+ - number of renders 100, rendering each request in clients session context.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Chris McCord
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ The Software shall be used for Good, not Evil.
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.
data/README.md ADDED
@@ -0,0 +1,408 @@
1
+ # Sync
2
+ > This started as a thought experiment that is growing into a viable option for realtime Rails apps without ditching
3
+ the standard rails stack that we love and are so productive with for a heavy client side MVC framework.
4
+
5
+
6
+ Real-time partials with Rails. Sync lets you render partials for models that, with minimal code,
7
+ update in realtime in the browser when changes occur on the server.
8
+
9
+ #### Watch a screencast to see it in action
10
+ [![See it in action](http://chrismccord.com/images/sync/video_thumb.png)](http://chrismccord.com/blog/2013/04/21/sync-realtime-rails-partials/)
11
+
12
+ In practice, one simply only needs to replace:
13
+
14
+ ```erb
15
+ <%= render partial: 'user_row', locals: {user: @user} %>
16
+ ```
17
+
18
+ with:
19
+
20
+ ```erb
21
+ <%= sync partial: 'user_row', resource: @user %>
22
+ ```
23
+
24
+ Then update views realtime automatically with the `sync` DSL or with a with a simple `sync_update(@user)` in the controller without any extra javascript or
25
+ configuration.
26
+
27
+ In addition to real-time updates, Sync also provides:
28
+
29
+ - Realtime removal of partials from the DOM when the sync'd model is destroyed in the controller via `sync_destroy(@user)`
30
+ - Realtime appending of newly created model's on scoped channels
31
+ - JavaScript/CoffeeScript hooks to override and extend element updates/appends/removes for partials
32
+ - Support for [Faye](http://faye.jcoglan.com/) and [Pusher](http://pusher.com)
33
+
34
+ ## Requirements
35
+
36
+ - Ruby >= 1.9.2
37
+ - Rails 3 >= 3.1 or Rails 4
38
+ - jQuery >= 1.9
39
+
40
+
41
+ ## Installation
42
+
43
+ #### 1) Add the gem to your `Gemfile`
44
+
45
+ #### Using Faye
46
+
47
+ ```ruby
48
+ gem 'faye'
49
+ gem 'thin', require: false
50
+ gem 'sync'
51
+ ```
52
+
53
+ #### Using Pusher
54
+
55
+ ```ruby
56
+ gem 'pusher'
57
+ gem 'sync'
58
+ ```
59
+
60
+ #### Install
61
+
62
+ ```bash
63
+ $ bundle
64
+ $ rails g sync:install
65
+ ```
66
+
67
+ #### 2) Require sync in your asset javascript manifest `app/assets/javascripts/application.js`:
68
+
69
+ ```javascript
70
+ //= require sync
71
+ ```
72
+
73
+ #### 3) Add the pubsub adapter's javascript to your application layout `app/views/layouts/application.html.erb`
74
+
75
+ ```erb
76
+ <%= javascript_include_tag Sync.adapter_javascript_url %>
77
+ ```
78
+
79
+ #### 4) Configure your pubsub server (Faye or Pusher)
80
+
81
+
82
+ #### Using [Faye](http://faye.jcoglan.com/) (self hosted)
83
+
84
+ Set your configuration in the generated `config/sync.yml` file, using the Faye adapter. Then run Faye alongside your app.
85
+
86
+ ```bash
87
+ rackup sync.ru -E production
88
+ ```
89
+
90
+ #### Using [Pusher](http://pusher.com) (SaaS)
91
+
92
+ Set your configuration in the generated `config/sync.yml` file, using the Pusher adapter. No extra process/setup.
93
+
94
+ ## Current Caveats
95
+ The current implementation uses a DOM range query (jQuery's `nextUntil`) to match your partial's "element" in
96
+ the DOM. The way this selector works requires your sync'd partial to be wrapped in a root level html tag for that partial file.
97
+ For example, this parent view/sync partial approach would *not* work:
98
+
99
+ Given the sync partial `_todo_row.html.erb`:
100
+
101
+ ```erb
102
+ Title:
103
+ <%= link_to todo.title, todo %>
104
+ ```
105
+
106
+ And the parent view:
107
+
108
+ ```erb
109
+ <table>
110
+ <tbody>
111
+ <tr>
112
+ <%= sync partial: 'todo_row', resource: @todo %>
113
+ </tr>
114
+ </tbody>
115
+ </table>
116
+ ```
117
+
118
+ ##### The markup *would need to change to*:
119
+
120
+
121
+ sync partial `_todo_row.html.erb`:
122
+
123
+ ```erb
124
+ <tr> <!-- root level container for the partial required here -->
125
+ Title:
126
+ <%= link_to todo.title, todo %>
127
+ </tr>
128
+ ```
129
+
130
+ And the parent view changed to:
131
+
132
+ ```erb
133
+ <table>
134
+ <tbody>
135
+ <%= sync partial: 'todo_row', resource: @todo %>
136
+ </tbody>
137
+ </table>
138
+ ```
139
+
140
+ I'm currently investigating true DOM ranges via the [Range](https://developer.mozilla.org/en-US/docs/DOM/range) object.
141
+
142
+
143
+ ## 'Automatic' syncing through the sync DSL
144
+
145
+ In addition to calling explicit sync actions within controller methods, a
146
+ `sync` and `enable_sync` DSL has been added to ActionController::Base and ActiveRecord::Base to automate the syncing
147
+ approach in a controlled, threadsafe way.
148
+
149
+ ### Example Controller/Model
150
+ ```ruby
151
+ class TodosController < ApplicationController
152
+
153
+ enable_sync only: [:create, :update, :destroy]
154
+ ...
155
+ end
156
+
157
+ class Todo < ActiveRecord::Base
158
+
159
+ belongs_to :project, counter_cache: true
160
+ has_many :comments, dependent: :destroy
161
+
162
+ sync :all, scope: :project
163
+
164
+ end
165
+ ```
166
+
167
+ ### Syncing outside of the controller
168
+
169
+ `Sync::Actions` can be included into any object wishing to perform sync
170
+ publishes for a given resource. Instead of using the the controller as
171
+ context for rendering, a Sync::Renderer instance is used. Since the Renderer
172
+ is not part of the request/response/session, it has no knowledge of the
173
+ current session (ie. current_user), so syncing from outside the controller
174
+ context will require some care that the partial can be rendered within a
175
+ sessionless context.
176
+
177
+ ### Example Syncing from a background worker or rails console
178
+ ```ruby
179
+ # Inside some script/worker
180
+ Sync::Model.enable do
181
+ Todo.first.update title: "This todo will be sync'd on save"
182
+ end
183
+ Todo.first.update title: "This todo will NOT be sync'd on save"
184
+
185
+ Sync::Model.enable!
186
+ Todo.first.update title: "This todo will be sync'd on save"
187
+ Todo.first.update title: "This todo will be sync'd on save"
188
+ Todo.first.update title: "This todo will be sync'd on save"
189
+ Sync::Model.disable!
190
+ Todo.first.update title: "This todo will NOT be sync'd on save"
191
+ ```
192
+
193
+ ## Custom Sync Views and javascript hooks
194
+
195
+ Sync allows you to hook into and override or extend all of the actions it performs when updating partials on the client side. When a sync partial is rendered, sync will instantiate a javascript View class based on the following order of lookup:
196
+
197
+ 1. The camelized version of the concatenated snake case resource
198
+ and partial names.
199
+ 2. The camelized version of the snake cased partial name.
200
+
201
+ #### Examples
202
+
203
+ partial name 'list_row', resource name 'todo', order of lookup:
204
+
205
+ 1. Sync.TodoListRow
206
+ 2. Sync.ListRow
207
+ 3. Sync.View (Default fallback)
208
+
209
+
210
+ For example, if you wanted to fade in/out a row in a sync'd todo list instead of the Sync.View default of instant insert/remove:
211
+
212
+ ```coffeescript
213
+ class Sync.TodoListRow extends Sync.View
214
+
215
+ beforeInsert: ($el) ->
216
+ $el.hide()
217
+ @insert($el)
218
+
219
+ afterInsert: -> @$el.fadeIn 'slow'
220
+
221
+ beforeRemove: -> @$el.fadeOut 'slow', => @remove()
222
+
223
+ ```
224
+
225
+ ## Narrowing sync_new scope
226
+
227
+ Sometimes, you do not want your page to update with every new record. With the `scope` option, you can limit what is being updated on a given page.
228
+
229
+ One way of using `scope` is by supplying a String or a Symbol. This is useful for example when you want to only show new records for a given locale:
230
+
231
+ View:
232
+ ```erb
233
+ <%= sync_new partial: 'todo_list_row', resource: Todo.new, scope: I18n.locale %>
234
+ ```
235
+
236
+ Controller/Model:
237
+ ```ruby
238
+ sync_new @todo, scope: @todo.locale
239
+ ```
240
+
241
+ Another use of `scope` is with a parent resource. This way you can for example update a project page with new todos for this single project:
242
+
243
+ View:
244
+ ```erb
245
+ <%= sync_new partial: 'todo_list_row', resource: Todo.new, scope: @project %>
246
+ ```
247
+
248
+ Controller/Model:
249
+ ```ruby
250
+ sync_new @todo, scope: @project
251
+ ```
252
+
253
+ Both approaches can be combined. Just supply an Array of Strings/Symbols and/or parent resources to the `scope` option. Note that the order of elements matters. Be sure to use the same order in your view and in your controller/model.
254
+
255
+ ## Refetching Partials
256
+
257
+ Refetching allows syncing partials across different users when the partial requires the session's context (ie. current_user).
258
+
259
+ Ex:
260
+ View: Add `refetch: true` to sync calls, and place partial file in a 'refetch'
261
+ subdirectory in the model's sync view folder:
262
+
263
+ The partial file would be located in `app/views/sync/todos/refetch/_list_row.html.erb`
264
+ ```erb
265
+ <% @project.todos.ordered.each do |todo| %>
266
+ <%= sync partial: 'list_row', resource: todo, refetch: true %>
267
+ <% end %>
268
+ <%= sync_new partial: 'list_row', resource: Todo.new, scope: @project, refetch: true %>
269
+ ```
270
+
271
+ *Notes*
272
+
273
+ While this approach works very well for the cases it's needed, syncing without refetching should be used unless refetching is absolutely necessary for performance reasons. For example,
274
+
275
+ A sync update request is triggered on the server for a 'regular' sync'd partial with 100 listening clients:
276
+ - number of http requests 1
277
+ - number of renders 1, pushed out to all 100 clients via pubsub server.
278
+
279
+
280
+ A sync update request is triggered on the server for a 'refetch' sync'd partial with 100 listening clients:
281
+ - number of http requests 100
282
+ - number of renders 100, rendering each request in clients session context.
283
+
284
+ ## Using with cache_digests (Russian doll caching)
285
+
286
+ Sync has a custom `DependencyTracker::ERBTracker` that can handle `sync` render calls.
287
+ Because the full partial name is not included, it has to guess the location of
288
+ your partial based on the name of the `resource` or `collection` passed to it.
289
+ See the tests to see how it works. If it doesn't work for you, you can always
290
+ use the [explicit "Template Dependency"
291
+ markers](https://github.com/rails/cache_digests).
292
+
293
+ To enable, add to `config/initializers/cache_digests.rb`:
294
+
295
+ #### Rails 4
296
+
297
+ ```ruby
298
+ require 'action_view/dependency_tracker'
299
+
300
+ ActionView::DependencyTracker.register_tracker :haml, Sync::ERBTracker
301
+ ActionView::DependencyTracker.register_tracker :erb, Sync::ERBTracker
302
+ ```
303
+
304
+ #### Rails 3 with [cache_digests](https://github.com/rails/cache_digests) gem
305
+
306
+ ```ruby
307
+ require 'cache_digests/dependency_tracker'
308
+
309
+ CacheDigests::DependencyTracker.register_tracker :haml, Sync::ERBTracker
310
+ CacheDigests::DependencyTracker.register_tracker :erb, Sync::ERBTracker
311
+ ```
312
+
313
+ **Note:** haml support is limited, but it seems to work in most cases.
314
+
315
+
316
+ ## Serving Faye over HTTPS (with Thin)
317
+
318
+ Create a thin configuration file `config/sync_thin.yml` similar to the following:
319
+
320
+ ```yaml
321
+ ---
322
+ port: 4443
323
+ ssl: true
324
+ ssl_key_file: /path/to/server.pem
325
+ ssl_cert_file: /path/to/certificate_chain.pem
326
+ environment: production
327
+ rackup: sync.ru
328
+ ```
329
+
330
+ The `certificate_chain.pem` file should contain your signed certificate, followed by intermediate certificates (if any) and the root certificate of the CA that signed the key.
331
+
332
+ Next reconfigure the `server` and `adapter_javascript_url` in `config/sync.yml` to look like `https://your.hostname.com:4443/faye` and `https://your.hostname.com:4443/faye/faye.js` respectively.
333
+
334
+ Finally start up Thin from the project root.
335
+
336
+ ```
337
+ thin -C config/sync_thin.yml start
338
+ ```
339
+
340
+
341
+ ## Brief Example or [checkout an example application](https://github.com/chrismccord/sync_example)
342
+
343
+ View `sync/users/_user_list_row.html.erb`
344
+
345
+ ```erb
346
+ <tr>
347
+ <td><%= link_to user.name, user %></td>
348
+ <td><%= link_to 'Edit', edit_user_path(user) %></td>
349
+ <td><%= link_to 'Destroy', user, method: :delete, remote: true, data: { confirm: 'Are you sure?' } %></td>
350
+ </tr>
351
+ ```
352
+
353
+ View `users/index.html.erb`
354
+
355
+ ```erb
356
+ <h1>Some Users</h1>
357
+ <table>
358
+ <tbody>
359
+ <%= sync partial: 'user_list_row', collection: @users %>
360
+ <%= sync_new partial: 'user_list_row', resource: User.new, direction: :append %>
361
+ </tbody>
362
+ </table>
363
+ ```
364
+
365
+
366
+ Controller
367
+
368
+ ```ruby
369
+ def UsersController < ApplicationController
370
+
371
+ def create
372
+ @user = User.new(user_params)
373
+ if @user.save
374
+ sync_new @user
375
+ end
376
+ respond_to do |format|
377
+ format.html { redirect_to users_url }
378
+ format.json { head :no_content }
379
+ end
380
+ end
381
+
382
+ def update
383
+ @user = User.find(params[:id])
384
+ if user.save
385
+
386
+ end
387
+
388
+ # Sync updates to any partials listening for this user
389
+ sync_update @user
390
+
391
+ redirect_to users_path, notice: "Saved!"
392
+ end
393
+
394
+ def destroy
395
+ @user = User.find(params[:id])
396
+ @user.destroy
397
+
398
+ # Sync destroy, telling client to remove all dom elements containing this user
399
+ sync_destroy @user
400
+
401
+ respond_to do |format|
402
+ format.html { redirect_to users_url }
403
+ format.json { head :no_content }
404
+ end
405
+ end
406
+ end
407
+ ```
408
+
data/Rakefile ADDED
File without changes
@@ -0,0 +1,13 @@
1
+ module SyncBumper
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ def self.source_root
5
+ File.dirname(__FILE__) + "/templates"
6
+ end
7
+
8
+ def copy_files
9
+ template "sync_bumper.rb", "config/initializers/sync_bumper.rb"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ SyncBumper.configure do |c|
2
+ c.url = case
3
+ when Rails.env.production?
4
+ lambda { |id| "http://example.com/todos/#{id}/bumper" }
5
+ when Rails.env.development?
6
+ lambda { |id| "http://example.com/todos/#{id}/bumper" }
7
+ else
8
+ lambda { |id| "http://example.com/todos/#{id}/bumper" }
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+
2
+ require 'digest/sha1'
3
+ require 'net/http'
4
+ require 'net/https'
5
+
6
+ require 'sync_bumper/model'
7
+
8
+ module SyncBumper
9
+
10
+ class << self
11
+ attr_accessor :url
12
+
13
+ def configure(&blk); class_eval(&blk); end
14
+
15
+ end
16
+ end
17
+
18
+
19
+ if defined? Rails
20
+ # path = Rails.root.join("config/sync_bumper.yml")
21
+ # SyncBumper.load_config(path, Rails.env) if path.exist?
22
+
23
+ ActiveRecord::Base.send :extend, SyncBumper::Model::ClassMethods
24
+ end
@@ -0,0 +1,93 @@
1
+ module SyncBumper
2
+ module Model
3
+
4
+ def self.enabled?
5
+ Thread.current["model_sync_enabled"]
6
+ end
7
+
8
+ def self.context
9
+ Thread.current["model_sync_context"]
10
+ end
11
+
12
+ def self.enable!(context = nil)
13
+ Thread.current["model_sync_enabled"] = true
14
+ Thread.current["model_sync_context"] = context
15
+ end
16
+
17
+ def self.disable!
18
+ Thread.current["model_sync_enabled"] = false
19
+ Thread.current["model_sync_context"] = nil
20
+ end
21
+
22
+ def self.enable(context = nil)
23
+ enable!(context)
24
+ yield
25
+ ensure
26
+ disable!
27
+ end
28
+
29
+ module ClassMethods
30
+ attr_accessor :sync_scope
31
+
32
+ def sync(*actions)
33
+ include ModelActions
34
+ if actions.last.is_a? Hash
35
+ @sync_scope = actions.last.fetch :scope
36
+ end
37
+ actions = [:create, :update, :destroy] if actions.include? :all
38
+ actions.flatten!
39
+
40
+ if actions.include? :create
41
+ after_create :publish_sync_create, :on => :create#, :if => lamda { Sync::Model.enabled? }
42
+ end
43
+ if actions.include? :update
44
+ after_update :publish_sync_update, :on => :update#, :if => lamda { Sync::Model.enabled? }
45
+ end
46
+ if actions.include? :destroy
47
+ after_destroy :publish_sync_destroy, :on => :destroy#, :if => lamda { Sync::Model.enabled? }
48
+ end
49
+ end
50
+ end
51
+
52
+ module ModelActions
53
+ def sync_scope
54
+ return nil unless self.class.sync_scope
55
+ send self.class.sync_scope
56
+ end
57
+
58
+ def publish_sync_create
59
+ Thread.new do
60
+ uri = URI(SyncBumper.url.call(id))
61
+ req = Net::HTTP::Post.new(uri.request_uri)
62
+
63
+ perform_request(req, uri)
64
+ end
65
+ end
66
+
67
+ def publish_sync_update
68
+ Thread.new do
69
+ uri = URI(SyncBumper.url.call(id))
70
+ req = Net::HTTP::Put.new(uri.request_uri)
71
+
72
+ perform_request(req, uri)
73
+ end
74
+ end
75
+
76
+ def publish_sync_destroy
77
+ Thread.new do
78
+ uri = URI(SyncBumper.url.call(id))
79
+ req = Net::HTTP::Delete.new(uri.request_uri)
80
+
81
+ perform_request(req, uri)
82
+ end
83
+ end
84
+
85
+ def perform_request(req, uri)
86
+ req["Content-Type"] = 'text/plain;charset=UTF-8'
87
+ req["Content-Length"] = '0'
88
+
89
+ res = Net::HTTP.start(uri.host, uri.port) { |http| http.request(req) }
90
+ end
91
+ end
92
+ end
93
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sync_bumper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexey Dubovskoy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: em-http-request
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.3.18
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 2.3.18
41
+ description: Bumper to involve Sync callbacks at external Rails App. Sync turns your
42
+ Rails partials realtime with automatic updates through Faye
43
+ email: dubovskoy.a@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/generators/sync/install_generator.rb
49
+ - lib/generators/sync/templates/sync_bumper.rb
50
+ - lib/sync_bumper/model.rb
51
+ - lib/sync_bumper.rb
52
+ - CHANGELOG.md
53
+ - Gemfile
54
+ - LICENSE
55
+ - Rakefile
56
+ - README.md
57
+ homepage: http://github.com/dubadub/sync_bumper
58
+ licenses: []
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - '>='
72
+ - !ruby/object:Gem::Version
73
+ version: 1.3.4
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.0.14
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Bumper to involve Sync callbacks at external Rails App
80
+ test_files: []