render_sync 0.5.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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +153 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +22 -0
  5. data/README.md +521 -0
  6. data/Rakefile +9 -0
  7. data/app/assets/javascripts/sync.coffee +355 -0
  8. data/app/controllers/sync/refetches_controller.rb +56 -0
  9. data/app/helpers/render_sync/config_helper.rb +15 -0
  10. data/config/routes.rb +3 -0
  11. data/config/sync.yml +21 -0
  12. data/lib/generators/render_sync/install_generator.rb +14 -0
  13. data/lib/generators/render_sync/templates/sync.ru +14 -0
  14. data/lib/generators/render_sync/templates/sync.yml +34 -0
  15. data/lib/render_sync.rb +174 -0
  16. data/lib/render_sync/action.rb +39 -0
  17. data/lib/render_sync/actions.rb +114 -0
  18. data/lib/render_sync/channel.rb +23 -0
  19. data/lib/render_sync/clients/dummy.rb +22 -0
  20. data/lib/render_sync/clients/faye.rb +104 -0
  21. data/lib/render_sync/clients/pusher.rb +77 -0
  22. data/lib/render_sync/controller_helpers.rb +33 -0
  23. data/lib/render_sync/engine.rb +24 -0
  24. data/lib/render_sync/erb_tracker.rb +49 -0
  25. data/lib/render_sync/faye_extension.rb +45 -0
  26. data/lib/render_sync/model.rb +174 -0
  27. data/lib/render_sync/model_actions.rb +60 -0
  28. data/lib/render_sync/model_change_tracking.rb +97 -0
  29. data/lib/render_sync/model_syncing.rb +65 -0
  30. data/lib/render_sync/model_touching.rb +35 -0
  31. data/lib/render_sync/partial.rb +112 -0
  32. data/lib/render_sync/partial_creator.rb +47 -0
  33. data/lib/render_sync/reactor.rb +48 -0
  34. data/lib/render_sync/refetch_model.rb +21 -0
  35. data/lib/render_sync/refetch_partial.rb +43 -0
  36. data/lib/render_sync/refetch_partial_creator.rb +21 -0
  37. data/lib/render_sync/renderer.rb +19 -0
  38. data/lib/render_sync/resource.rb +115 -0
  39. data/lib/render_sync/scope.rb +113 -0
  40. data/lib/render_sync/scope_definition.rb +30 -0
  41. data/lib/render_sync/view_helpers.rb +106 -0
  42. data/test/dummy/README.rdoc +28 -0
  43. data/test/dummy/Rakefile +6 -0
  44. data/test/dummy/app/assets/javascripts/application.js +13 -0
  45. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  46. data/test/dummy/app/controllers/application_controller.rb +5 -0
  47. data/test/dummy/app/helpers/application_helper.rb +2 -0
  48. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  49. data/test/dummy/app/views/sync/users/_show.html.erb +1 -0
  50. data/test/dummy/app/views/sync/users/refetch/_show.html.erb +1 -0
  51. data/test/dummy/bin/bundle +3 -0
  52. data/test/dummy/bin/rails +4 -0
  53. data/test/dummy/bin/rake +4 -0
  54. data/test/dummy/config.ru +4 -0
  55. data/test/dummy/config/application.rb +22 -0
  56. data/test/dummy/config/boot.rb +5 -0
  57. data/test/dummy/config/database.yml +8 -0
  58. data/test/dummy/config/environment.rb +5 -0
  59. data/test/dummy/config/environments/development.rb +29 -0
  60. data/test/dummy/config/environments/production.rb +80 -0
  61. data/test/dummy/config/environments/test.rb +36 -0
  62. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  63. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  64. data/test/dummy/config/initializers/inflections.rb +16 -0
  65. data/test/dummy/config/initializers/mime_types.rb +5 -0
  66. data/test/dummy/config/initializers/secret_token.rb +12 -0
  67. data/test/dummy/config/initializers/session_store.rb +3 -0
  68. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  69. data/test/dummy/config/locales/en.yml +23 -0
  70. data/test/dummy/config/routes.rb +56 -0
  71. data/test/dummy/log/test.log +626 -0
  72. data/test/dummy/public/404.html +58 -0
  73. data/test/dummy/public/422.html +58 -0
  74. data/test/dummy/public/500.html +57 -0
  75. data/test/dummy/public/favicon.ico +0 -0
  76. data/test/em_minitest_spec.rb +100 -0
  77. data/test/fixtures/sync_auth_token_missing.yml +6 -0
  78. data/test/fixtures/sync_erb.yml +7 -0
  79. data/test/fixtures/sync_faye.yml +7 -0
  80. data/test/fixtures/sync_pusher.yml +8 -0
  81. data/test/models/group.rb +3 -0
  82. data/test/models/project.rb +2 -0
  83. data/test/models/todo.rb +8 -0
  84. data/test/models/user.rb +82 -0
  85. data/test/sync/abstract_controller.rb +3 -0
  86. data/test/sync/action_test.rb +82 -0
  87. data/test/sync/channel_test.rb +15 -0
  88. data/test/sync/config_test.rb +25 -0
  89. data/test/sync/erb_tracker_test.rb +72 -0
  90. data/test/sync/faye_extension_test.rb +87 -0
  91. data/test/sync/message_test.rb +159 -0
  92. data/test/sync/model_test.rb +315 -0
  93. data/test/sync/partial_creator_test.rb +35 -0
  94. data/test/sync/partial_test.rb +107 -0
  95. data/test/sync/protected_attributes_test.rb +39 -0
  96. data/test/sync/reactor_test.rb +18 -0
  97. data/test/sync/refetch_model_test.rb +26 -0
  98. data/test/sync/refetch_partial_creator_test.rb +16 -0
  99. data/test/sync/refetch_partial_test.rb +74 -0
  100. data/test/sync/renderer_test.rb +19 -0
  101. data/test/sync/resource_test.rb +181 -0
  102. data/test/sync/scope_definition_test.rb +39 -0
  103. data/test/sync/scope_test.rb +113 -0
  104. data/test/test_helper.rb +66 -0
  105. data/test/travis/sync.ru +14 -0
  106. data/test/travis/sync.yml +21 -0
  107. metadata +317 -0
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/404.html -->
52
+ <div class="dialog">
53
+ <h1>The page you were looking for doesn't exist.</h1>
54
+ <p>You may have mistyped the address or the page may have moved.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/422.html -->
52
+ <div class="dialog">
53
+ <h1>The change you wanted was rejected.</h1>
54
+ <p>Maybe you tried to change something you didn't have access to.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/500.html -->
52
+ <div class="dialog">
53
+ <h1>We're sorry, but something went wrong.</h1>
54
+ </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
56
+ </body>
57
+ </html>
File without changes
@@ -0,0 +1,100 @@
1
+ # Copyright (c) 2011 Pete Higgins
2
+ # https://github.com/phiggins/em-minitest-spec
3
+ #
4
+ require 'eventmachine'
5
+
6
+ module EM # :nodoc:
7
+ module MiniTest # :nodoc:
8
+ module Spec # :nodoc
9
+ VERSION = '1.1.0' # :nodoc:
10
+
11
+ ##
12
+ # +wait+ indicates that the spec is not expected to be completed when
13
+ # the block is finished running. A call to +done+ is required when using
14
+ # +wait+.
15
+ #
16
+ # # setup my spec to use EM::MiniTest::Spec
17
+ # describe MyClass do
18
+ # include EM::MiniTest::Spec
19
+ #
20
+ # # The call to defer will return immediately, so the spec code
21
+ # # needs to keep running until callback is called.
22
+ # it "does some async things" do
23
+ # defer_me = lambda do
24
+ # # some async stuff
25
+ # end
26
+ #
27
+ # callback = lambda do
28
+ # done!
29
+ # end
30
+ #
31
+ # EM.defer defer_me, callback
32
+ #
33
+ # wait!
34
+ # end
35
+ def wait
36
+ @wait = true
37
+ end
38
+ alias wait! wait
39
+
40
+ ##
41
+ # Indicates that an async spec is finished. See +wait+ for example usage.
42
+ def done
43
+ EM.cancel_timer(@timeout)
44
+ EM.stop
45
+ end
46
+ alias done! done
47
+
48
+ ##
49
+ # A helper method for the use case of waiting for some operation to
50
+ # complete that is not necessarily under the control of the spec code.
51
+ #
52
+ # # These are exactly equivalent
53
+ # it "waits with the helper" do
54
+ # wait_for do
55
+ # assert true
56
+ # end
57
+ # end
58
+ #
59
+ # it "waits manually" do
60
+ # EM.next_tick do
61
+ # assert true
62
+ # done!
63
+ # end
64
+ #
65
+ # wait!
66
+ # end
67
+ def wait_for
68
+ EM.next_tick do
69
+ yield
70
+ done!
71
+ end
72
+
73
+ wait!
74
+ end
75
+
76
+ def self.included base # :nodoc:
77
+ base.extend(ClassMethods)
78
+ end
79
+
80
+ module ClassMethods # :nodoc:
81
+ def it *args, &block # :nodoc:
82
+ return super unless block_given?
83
+
84
+ super do
85
+ @wait = false
86
+
87
+ EM.run do
88
+ @timeout = EM.add_timer(0.1) do
89
+ flunk "test timed out!"
90
+ end
91
+
92
+ instance_eval(&block)
93
+ done! unless @wait
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,6 @@
1
+ # Faye
2
+ test:
3
+ server: "http://localhost:9292/faye"
4
+ adapter_javascript_url: "http://localhost:9292/faye/faye.js"
5
+ adapter: "Faye"
6
+ async: false
@@ -0,0 +1,7 @@
1
+ # Faye
2
+ test:
3
+ server: "http://localhost:9292/faye"
4
+ adapter_javascript_url: "http://localhost:9292/faye/faye.js"
5
+ auth_token: <%= "erb secret" %>
6
+ adapter: "Faye"
7
+ async: false
@@ -0,0 +1,7 @@
1
+ # Faye
2
+ test:
3
+ server: "http://localhost:9292/faye"
4
+ adapter_javascript_url: "http://localhost:9292/faye/faye.js"
5
+ auth_token: "secret"
6
+ adapter: "Faye"
7
+ async: false
@@ -0,0 +1,8 @@
1
+ # Pusher
2
+ test:
3
+ adapter_javascript_url: "http://js.pusher.com/2.0/pusher.min.js"
4
+ app_id: "YOUR_PUSHER_APP_ID"
5
+ api_key: "YOUR_PUSHER_API_KEY"
6
+ auth_token: "YOUR_PUSHER_SECRET"
7
+ adapter: "Pusher"
8
+ async: false
@@ -0,0 +1,3 @@
1
+ class Group < ActiveRecord::Base
2
+
3
+ end
@@ -0,0 +1,2 @@
1
+ class Project < ActiveRecord::Base
2
+ end
@@ -0,0 +1,8 @@
1
+ class Todo < ActiveRecord::Base
2
+ belongs_to :user
3
+
4
+ sync :all
5
+ sync_scope :complete, -> { where(complete: true) }
6
+ sync_scope :by_user, ->(user) { where(user_id: user.id) }
7
+ sync_scope :with_user_id, ->(user_id) { where(user_id: user_id) }
8
+ end
@@ -0,0 +1,82 @@
1
+ class User < ActiveRecord::Base
2
+ belongs_to :group
3
+
4
+ def id
5
+ 1
6
+ end
7
+
8
+ sync :all
9
+ sync_scope :cool, -> { where(cool: true) }
10
+ sync_scope :in_group, ->(group) { where(group_id: group.id)}
11
+ sync_scope :with_group_id, ->(group_id) { where(group_id: group_id)}
12
+ sync_scope :with_min_age_in_group, ->(age, group_id) { where(group_id: group_id).where(["age >= ?", age])}
13
+ end
14
+
15
+ class UserWithoutScopes < ActiveRecord::Base
16
+ self.table_name = :users
17
+
18
+ def id
19
+ 1
20
+ end
21
+
22
+ sync :all
23
+ end
24
+
25
+ class UserWithDefaultScope < ActiveRecord::Base
26
+ self.table_name = :users
27
+ belongs_to :group
28
+
29
+ sync :all, default_scope: :group
30
+ end
31
+
32
+ class UserWithSimpleScope < ActiveRecord::Base
33
+ self.table_name = :users
34
+
35
+ sync :all
36
+ sync_scope :old, -> { where(["users.age >= ?", 90]) }
37
+ end
38
+
39
+ class UserWithAdvancedScope < ActiveRecord::Base
40
+ self.table_name = :users
41
+ belongs_to :group
42
+
43
+ sync :all
44
+ sync_scope :in_group, ->(group) { where(group_id: group.id) }
45
+ end
46
+
47
+ class UserTouchingGroup < ActiveRecord::Base
48
+ self.table_name = :users
49
+ belongs_to :group
50
+
51
+ sync :all
52
+ sync_touch :group
53
+ end
54
+
55
+ class UserJustTouchingGroup < ActiveRecord::Base
56
+ self.table_name = :users
57
+ belongs_to :group
58
+
59
+ sync_touch :group
60
+ end
61
+
62
+ class UserTouchingGroupAndProject < ActiveRecord::Base
63
+ self.table_name = :users
64
+ belongs_to :group
65
+ belongs_to :project
66
+
67
+ sync :all
68
+ sync_touch :group, :project
69
+ end
70
+
71
+ # Setup test user with protected attributes (only allow cool)
72
+ # if Rails < 4 or Rails > 4 with gem protected_attributes
73
+ class UserWithProtectedAttributes < ActiveRecord::Base
74
+ attr_accessible :cool if Rails.version < "4"
75
+ self.table_name = :users
76
+ sync :all
77
+ end
78
+
79
+ if Rails.version < "4"
80
+ UserWithProtectedAttributes.mass_assignment_sanitizer = :strict
81
+ end
82
+
@@ -0,0 +1,3 @@
1
+ class ActionController::Base
2
+ prepend_view_path 'test/sync/views'
3
+ end
@@ -0,0 +1,82 @@
1
+ require_relative '../test_helper'
2
+ require 'mocha/setup'
3
+ require 'rails/all'
4
+
5
+ describe RenderSync::Action do
6
+ include TestHelper
7
+
8
+ describe '#initialize' do
9
+ it 'sets instance variables on initialize without scopes' do
10
+ action = RenderSync::Action.new("record", :new)
11
+ assert_equal "record", action.record
12
+ assert_equal :new, action.name
13
+ assert_equal [], action.scope
14
+ end
15
+
16
+ it 'sets instance variables on initialize with scope' do
17
+ action = RenderSync::Action.new("record", :new, scope: "scope")
18
+ assert_equal ["scope"], action.scope
19
+ end
20
+
21
+ it 'sets instance variables on initialize with default_scope' do
22
+ action = RenderSync::Action.new("record", :new, default_scope: "scope")
23
+ assert_equal ["scope"], action.scope
24
+ end
25
+
26
+ it 'sets instance variables on initialize with scope and default_scope' do
27
+ action = RenderSync::Action.new("record", :new, scope: "scope", default_scope: "default")
28
+ assert_equal ["default", "scope"], action.scope
29
+ end
30
+
31
+ it 'sets instance variables on initialize with default_scope' do
32
+ user = User.create!
33
+ scope = User.cool
34
+ action = RenderSync::Action.new(user, :new, scope: scope, default_scope: :group)
35
+ assert_equal [:group, scope], action.scope
36
+ end
37
+
38
+
39
+ it 'sets instance variables on initialize with nested scopes' do
40
+ action = RenderSync::Action.new("record", :new, scope: ["nested", "scopes"], default_scope: ["my", "cool"])
41
+ assert_equal [["my", "cool"], ["nested", "scopes"]], action.scope
42
+ end
43
+ end
44
+
45
+ describe "#perform" do
46
+
47
+ it 'calls different actions without scope' do
48
+ record = User.new name: "Foo"
49
+
50
+ action = RenderSync::Action.new(record, :new)
51
+ action.expects(:sync_new).with(record, scope: [])
52
+ action.perform
53
+
54
+ action = RenderSync::Action.new(record, :update)
55
+ action.expects(:sync_update).with(record, scope: [])
56
+ action.perform
57
+
58
+ action = RenderSync::Action.new(record, :destroy)
59
+ action.expects(:sync_destroy).with(record, scope: [])
60
+ action.perform
61
+ end
62
+
63
+ it 'calls different actions with scope' do
64
+ record = User.new name: "Foo"
65
+
66
+ action = RenderSync::Action.new(record, :new, scope: "scope", default_scope: "default")
67
+ action.expects(:sync_new).with(record, scope: ["default", "scope"])
68
+ action.perform
69
+
70
+ action = RenderSync::Action.new(record, :update, scope: "scope", default_scope: "default")
71
+ action.expects(:sync_update).with(record, scope: ["default", "scope"])
72
+ action.perform
73
+
74
+ action = RenderSync::Action.new(record, :destroy, scope: "scope", default_scope: "default")
75
+ action.expects(:sync_destroy).with(record, scope: ["default", "scope"])
76
+ action.perform
77
+ end
78
+
79
+
80
+ end
81
+
82
+ end