sync_bumper 0.1.0

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 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: []