volt 0.9.3.pre1 → 0.9.3.pre2

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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +15 -1
  4. data/Gemfile +30 -3
  5. data/README.md +7 -2
  6. data/Rakefile +17 -0
  7. data/app/volt/models/user.rb +1 -1
  8. data/app/volt/tasks/live_query/live_query.rb +0 -1
  9. data/app/volt/tasks/live_query/live_query_pool.rb +8 -2
  10. data/app/volt/tasks/live_query/query_tracker.rb +2 -2
  11. data/app/volt/tasks/query_tasks.rb +10 -27
  12. data/app/volt/tasks/store_tasks.rb +6 -5
  13. data/app/volt/tasks/user_tasks.rb +2 -2
  14. data/docs/UPGRADE_GUIDE.md +14 -0
  15. data/lib/volt/boot.rb +1 -0
  16. data/lib/volt/cli/asset_compile.rb +25 -7
  17. data/lib/volt/cli/console.rb +6 -5
  18. data/lib/volt/cli/generate.rb +2 -2
  19. data/lib/volt/config.rb +2 -1
  20. data/lib/volt/controllers/http_controller.rb +4 -3
  21. data/lib/volt/controllers/model_controller.rb +41 -19
  22. data/lib/volt/controllers/template_helpers.rb +19 -0
  23. data/lib/volt/extra_core/array.rb +6 -0
  24. data/lib/volt/extra_core/hash.rb +8 -26
  25. data/lib/volt/extra_core/string.rb +1 -1
  26. data/lib/volt/models/array_model.rb +12 -4
  27. data/lib/volt/models/associations.rb +11 -13
  28. data/lib/volt/models/buffer.rb +1 -1
  29. data/lib/volt/models/model.rb +22 -13
  30. data/lib/volt/models/model_helpers/model_change_helpers.rb +0 -1
  31. data/lib/volt/models/model_helpers/model_helpers.rb +11 -0
  32. data/lib/volt/models/permissions.rb +9 -12
  33. data/lib/volt/models/persistors/array_store.rb +7 -7
  34. data/lib/volt/models/persistors/base.rb +9 -0
  35. data/lib/volt/models/persistors/cookies.rb +0 -4
  36. data/lib/volt/models/persistors/flash.rb +0 -4
  37. data/lib/volt/models/persistors/local_store.rb +0 -4
  38. data/lib/volt/models/persistors/model_store.rb +13 -21
  39. data/lib/volt/models/persistors/page.rb +22 -0
  40. data/lib/volt/models/persistors/params.rb +0 -4
  41. data/lib/volt/models/persistors/query/query_listener.rb +3 -2
  42. data/lib/volt/models/url.rb +2 -2
  43. data/lib/volt/models/validators/unique_validator.rb +1 -1
  44. data/lib/volt/models.rb +1 -0
  45. data/lib/volt/page/bindings/attribute_binding.rb +2 -2
  46. data/lib/volt/page/bindings/base_binding.rb +7 -3
  47. data/lib/volt/page/bindings/bindings.rb +9 -0
  48. data/lib/volt/page/bindings/content_binding.rb +2 -2
  49. data/lib/volt/page/bindings/each_binding.rb +16 -12
  50. data/lib/volt/page/bindings/event_binding.rb +4 -4
  51. data/lib/volt/page/bindings/if_binding.rb +3 -3
  52. data/lib/volt/page/bindings/view_binding.rb +4 -4
  53. data/lib/volt/page/bindings/yield_binding.rb +3 -3
  54. data/lib/volt/page/channel.rb +6 -0
  55. data/lib/volt/page/channel_stub.rb +1 -1
  56. data/lib/volt/page/page.rb +20 -54
  57. data/lib/volt/page/path_string_renderer.rb +5 -6
  58. data/lib/volt/page/string_template_renderer.rb +2 -2
  59. data/lib/volt/page/targets/attribute_section.rb +47 -0
  60. data/lib/volt/page/targets/base_section.rb +5 -5
  61. data/lib/volt/page/targets/binding_document/component_node.rb +6 -1
  62. data/lib/volt/page/template_renderer.rb +4 -4
  63. data/lib/volt/reactive/computation.rb +32 -3
  64. data/lib/volt/router/routes.rb +5 -5
  65. data/lib/volt/server/component_templates.rb +30 -2
  66. data/lib/volt/server/forking_server.rb +2 -2
  67. data/lib/volt/server/message_bus/base_message_bus.rb +52 -0
  68. data/lib/volt/server/message_bus/message_encoder.rb +64 -0
  69. data/lib/volt/server/message_bus/peer_to_peer/peer_connection.rb +186 -0
  70. data/lib/volt/server/message_bus/peer_to_peer/peer_server.rb +78 -0
  71. data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +57 -0
  72. data/lib/volt/server/message_bus/peer_to_peer/socket_with_timeout.rb +27 -0
  73. data/lib/volt/server/message_bus/peer_to_peer.rb +198 -0
  74. data/lib/volt/server/message_bus/redis.rb +1 -0
  75. data/lib/volt/server/rack/asset_files.rb +2 -2
  76. data/lib/volt/server/rack/component_paths.rb +1 -1
  77. data/lib/volt/server/rack/http_resource.rb +3 -2
  78. data/lib/volt/server/rack/opal_files.rb +6 -9
  79. data/lib/volt/server/websocket/websocket_handler.rb +0 -3
  80. data/lib/volt/server.rb +5 -3
  81. data/lib/volt/spec/setup.rb +11 -12
  82. data/lib/volt/tasks/dispatcher.rb +8 -12
  83. data/lib/volt/tasks/task_handler.rb +3 -2
  84. data/lib/volt/utils/csso_patch.rb +24 -0
  85. data/lib/volt/utils/promise_patch.rb +2 -0
  86. data/lib/volt/version.rb +1 -1
  87. data/lib/volt/volt/app.rb +73 -36
  88. data/lib/volt/volt/server_setup/app.rb +81 -0
  89. data/lib/volt.rb +22 -1
  90. data/spec/apps/kitchen_sink/Gemfile +1 -1
  91. data/spec/controllers/http_controller_spec.rb +5 -3
  92. data/spec/controllers/model_controller_spec.rb +2 -2
  93. data/spec/extra_core/hash_spec.rb +9 -0
  94. data/spec/integration/list_spec.rb +3 -3
  95. data/spec/models/associations_spec.rb +10 -2
  96. data/spec/models/dirty_spec.rb +7 -7
  97. data/spec/models/model_spec.rb +10 -2
  98. data/spec/models/permissions_spec.rb +9 -0
  99. data/spec/models/persistors/store_spec.rb +8 -0
  100. data/spec/page/bindings/content_binding_spec.rb +6 -2
  101. data/spec/page/bindings/each_binding_spec.rb +59 -0
  102. data/spec/page/bindings/if_binding_spec.rb +57 -0
  103. data/spec/page/path_string_renderer_spec.rb +5 -5
  104. data/spec/reactive/computation_spec.rb +65 -1
  105. data/spec/router/routes_spec.rb +1 -1
  106. data/spec/server/html_parser/sandlebars_parser_spec.rb +12 -22
  107. data/spec/server/message_bus/message_encoder_spec.rb +49 -0
  108. data/spec/server/message_bus/peer_to_peer/peer_connection_spec.rb +108 -0
  109. data/spec/server/message_bus/peer_to_peer/peer_server_spec.rb +66 -0
  110. data/spec/server/message_bus/peer_to_peer/socket_with_timeout_spec.rb +11 -0
  111. data/spec/server/message_bus/peer_to_peer_spec.rb +11 -0
  112. data/spec/server/rack/asset_files_spec.rb +1 -1
  113. data/spec/server/rack/http_resource_spec.rb +4 -4
  114. data/spec/spec_helper.rb +16 -3
  115. data/spec/tasks/dispatcher_spec.rb +17 -5
  116. data/spec/tasks/live_query_spec.rb +1 -1
  117. data/spec/tasks/query_tracker_spec.rb +34 -34
  118. data/spec/tasks/user_tasks_spec.rb +4 -2
  119. data/templates/project/Gemfile.tt +14 -3
  120. data/templates/project/config/app.rb.tt +27 -2
  121. data/volt.gemspec +3 -8
  122. metadata +32 -101
  123. data/docs/FAQ.md +0 -7
@@ -6,8 +6,9 @@ require 'volt/server/rack/http_request'
6
6
  module Volt
7
7
  # Rack middleware for HttpController
8
8
  class HttpResource
9
- def initialize(app, router)
9
+ def initialize(app, volt_app, router)
10
10
  @app = app
11
+ @volt_app = volt_app
11
12
  @router = router
12
13
  end
13
14
 
@@ -38,7 +39,7 @@ module Volt
38
39
 
39
40
  namespace_module = Object.const_get(namespace.camelize.to_sym)
40
41
  klass = namespace_module.const_get(controller_name.camelize.to_sym)
41
- controller = klass.new(params, request)
42
+ controller = klass.new(@volt_app, params, request)
42
43
  controller.perform(action)
43
44
  end
44
45
  end
@@ -22,7 +22,8 @@ module Volt
22
22
  Opal.append_path(Volt.root + '/app')
23
23
  Opal.append_path(Volt.root + '/lib')
24
24
 
25
- Gem.loaded_specs.values.each do |gem|
25
+ Gem.loaded_specs.values.select {|gem| gem.name =~ /^volt/ }
26
+ .each do |gem|
26
27
  ['app', 'lib'].each do |folder|
27
28
  path = gem.full_gem_path + "/#{folder}"
28
29
 
@@ -53,9 +54,10 @@ module Volt
53
54
  end
54
55
 
55
56
  if Volt.config.compress_css
56
- require 'ruby-clean-css'
57
- require 'ruby-clean-css/sprockets'
58
- RubyCleanCSS::Sprockets.register(environment)
57
+ # Use csso for css compression by default.
58
+ require 'volt/utils/csso_patch'
59
+ require 'csso'
60
+ Csso.install(environment)
59
61
  end
60
62
 
61
63
  server.append_path(app_path)
@@ -65,11 +67,6 @@ module Volt
65
67
 
66
68
  add_asset_folders(server)
67
69
 
68
- # Add the opal load paths
69
- Opal.paths.each do |path|
70
- server.append_path(path)
71
- end
72
-
73
70
  builder.map '/assets' do
74
71
  run server
75
72
  end
@@ -3,9 +3,6 @@ require 'volt/server/socket_connection_handler'
3
3
  require 'volt/server/websocket/rack_server_adaptor'
4
4
 
5
5
  module Volt
6
- # Setup the dispatcher for the socket connection handler.
7
- # SocketConnectionHandler.dispatcher = Dispatcher.new
8
-
9
6
  class WebsocketHandler
10
7
  def initialize(app)
11
8
  # Setup the rack server and adaptor
data/lib/volt/server.rb CHANGED
@@ -84,14 +84,16 @@ module Volt
84
84
  end
85
85
 
86
86
  # Only run ForkingServer if fork is supported in this env.
87
- if !can_fork || Volt.env.production? || Volt.env.test?
87
+ # NO_FORKING can be used to specify that you don't want to use the forking
88
+ # server.
89
+ if !can_fork || Volt.env.production? || Volt.env.test? || ENV['NO_FORKING']
88
90
  # In production/test, we boot the app and run the server
89
91
  #
90
92
  # Sometimes the app is already booted, so we can skip if it is
91
93
  boot_volt unless @volt_app
92
94
 
93
95
  # Setup the dispatcher (it stays this class during its run)
94
- SocketConnectionHandler.dispatcher = Dispatcher.new
96
+ SocketConnectionHandler.dispatcher = Dispatcher.new(@volt_app)
95
97
  app.run(new_server)
96
98
  else
97
99
  # In developer
@@ -133,7 +135,7 @@ module Volt
133
135
  # which JS/CSS files to serve.
134
136
  @rack_app.use IndexFiles, @volt_app.component_paths, opal_files
135
137
 
136
- @rack_app.use HttpResource, @volt_app.router
138
+ @rack_app.use HttpResource, @volt_app, @volt_app.router
137
139
 
138
140
  @rack_app.use Rack::Static,
139
141
  urls: ['/'],
@@ -10,7 +10,7 @@ module Volt
10
10
 
11
11
  require 'volt/boot'
12
12
 
13
- # Require in app
13
+ # Create a main volt app for tests
14
14
  volt_app = Volt.boot(app_path)
15
15
 
16
16
  unless RUBY_PLATFORM == 'opal'
@@ -32,11 +32,11 @@ module Volt
32
32
 
33
33
 
34
34
  cleanup_db = -> do
35
- Volt::DataStore.fetch.drop_database
35
+ volt_app.database.drop_database
36
36
 
37
37
  # Clear cached for a reset
38
- $page.instance_variable_set('@store', nil)
39
- QueryTasks.reset!
38
+ volt_app.page.instance_variable_set('@store', nil)
39
+ volt_app.reset_query_pool!
40
40
  end
41
41
 
42
42
  if RUBY_PLATFORM != 'opal'
@@ -44,6 +44,9 @@ module Volt
44
44
  cleanup_db.call
45
45
  end
46
46
 
47
+ # Run everything in the context of this app
48
+ Thread.current['volt_app'] = volt_app
49
+
47
50
  # Setup the spec collection accessors
48
51
  # RSpec.shared_context "volt collections", {} do
49
52
  RSpec.shared_examples_for 'volt collections', {} do
@@ -53,24 +56,20 @@ module Volt
53
56
  let(:the_page) { Model.new }
54
57
  let(:store) do
55
58
  @__store_accessed = true
56
- $page ||= Page.new
59
+ $page ||= volt_app.page
57
60
  $page.store
58
61
  end
62
+ let(:volt_app) { volt_app }
59
63
 
60
64
 
61
65
  if RUBY_PLATFORM != 'opal'
62
- after do
63
- if @__store_accessed
66
+ after do |example|
67
+ if @__store_accessed || example.metadata[:type] == :feature
64
68
  # Clear the database after each spec where we use store
65
69
  cleanup_db.call
66
70
  end
67
71
  end
68
72
 
69
- # Assume store is accessed in capyabara specs
70
- before(:context, {type: :feature}) do
71
- @__store_accessed = true
72
- end
73
-
74
73
  # Cleanup after integration tests also.
75
74
  before(:example, {type: :feature}) do
76
75
  @__store_accessed = true
@@ -9,6 +9,12 @@ module Volt
9
9
  # When we pass the dispatcher over DRb, don't send a copy, just proxy.
10
10
  include DRb::DRbUndumped
11
11
 
12
+ attr_reader :volt_app
13
+
14
+ def initialize(volt_app)
15
+ @volt_app = volt_app
16
+ end
17
+
12
18
  # Dispatch takes an incoming Task from the client and runs it on the
13
19
  # server, returning the result to the client.
14
20
  # Tasks returning a promise will wait to return.
@@ -31,17 +37,7 @@ module Volt
31
37
  # Init and send the method
32
38
  promise = promise.then do
33
39
  Thread.current['meta'] = meta_data
34
-
35
- # # Profile the code
36
- # RubyProf.start
37
-
38
- result = klass.new(channel, self).send(method_name, *args)
39
-
40
- # res = RubyProf.stop
41
- #
42
- # # Print a flat profile to text
43
- # printer = RubyProf::FlatPrinter.new(res)
44
- # printer.print(STDOUT)
40
+ result = klass.new(@volt_app, channel, self).send(method_name, *args)
45
41
 
46
42
  Thread.current['meta'] = nil
47
43
 
@@ -91,7 +87,7 @@ module Volt
91
87
  end
92
88
 
93
89
  def close_channel(channel)
94
- QueryTasks.new(channel).close!
90
+ QueryTasks.new(@volt_app, channel).close!
95
91
  end
96
92
  end
97
93
  end
@@ -14,7 +14,8 @@ module Volt
14
14
  $page.tasks.call(self.name, name, meta_data, *args, &block)
15
15
  end
16
16
  else
17
- def initialize(channel = nil, dispatcher = nil)
17
+ def initialize(volt_app, channel = nil, dispatcher = nil)
18
+ @volt_app = volt_app
18
19
  @channel = channel
19
20
  @dispatcher = dispatcher
20
21
  end
@@ -35,7 +36,7 @@ module Volt
35
36
  # TODO: optimize: this could run the inside first to see if it
36
37
  # returns a promise, so we don't have to wrap it.
37
38
  Promise.new.then do
38
- new(nil, nil).send(name, *args, &block)
39
+ new(Volt.current_app, nil, nil).send(name, *args, &block)
39
40
  end.resolve(nil)
40
41
  end
41
42
 
@@ -0,0 +1,24 @@
1
+ # CSSO complains when using node as an execJS runtime, but we currently have
2
+ # to due to a bug in therubyracer (or maybe execJS?)
3
+
4
+ require 'execjs'
5
+
6
+ module Csso
7
+ class JsLib
8
+
9
+ def initialize
10
+ spec = Gem::Specification.find_by_name("csso-rails")
11
+ path = spec.gem_dir
12
+
13
+ lib = File.read(File.expand_path(path + "/" + CSSO_JS_LIB, File.dirname(__FILE__)))
14
+ unless @csso = ExecJS.runtime.compile(lib)
15
+ raise 'cannot compile or what?'
16
+ end
17
+ end
18
+
19
+ def compress css, structural_optimization=true
20
+ @csso.call("do_compression", css, !structural_optimization)
21
+ end
22
+
23
+ end
24
+ end
@@ -47,6 +47,8 @@ class Promise
47
47
  # Waits for the promise to resolve (assuming it is blocking on
48
48
  # the server) and returns the result.
49
49
  def sync
50
+ raise ".sync can only be used on the client" if Volt.client?
51
+
50
52
  result = nil
51
53
  error = nil
52
54
 
data/lib/volt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Volt
2
2
  module Version
3
- STRING = '0.9.3.pre1'
3
+ STRING = '0.9.3.pre2'
4
4
  end
5
5
  end
data/lib/volt/volt/app.rb CHANGED
@@ -1,54 +1,91 @@
1
+ require 'opal'
2
+
3
+ # on the client, we want to include the main volt.rb file
4
+ require 'volt'
5
+ require 'volt/models'
6
+ require 'volt/controllers/model_controller'
7
+ require 'volt/tasks/task_handler'
8
+ require 'volt/page/bindings/bindings'
9
+ require 'volt/page/template_renderer'
10
+ require 'volt/page/string_template_renderer'
11
+ require 'volt/page/document_events'
12
+ require 'volt/page/sub_context'
13
+ require 'volt/page/targets/dom_target'
14
+ require 'volt/data_stores/base_adaptor_client'
15
+
16
+ if RUBY_PLATFORM == 'opal'
17
+ require 'volt/page/channel'
18
+ else
19
+ require 'volt/page/channel_stub'
20
+ end
21
+ require 'volt/router/routes'
22
+ require 'volt/models/url'
23
+ require 'volt/page/url_tracker'
24
+ require 'volt/benchmark/benchmark'
25
+ require 'volt/page/tasks'
26
+ require 'volt/page/page'
27
+
28
+ unless RUBY_PLATFORM == 'opal'
29
+ require 'volt/volt/server_setup/app'
30
+ end
31
+
1
32
  module Volt
2
33
  class App
3
- attr_reader :component_paths, :router, :page
34
+ if RUBY_PLATFORM != 'opal'
35
+ # Include server app setup
36
+ include Volt::ServerSetup::App
37
+ end
38
+
39
+ attr_reader :component_paths, :router, :page, :live_query_pool,
40
+ :channel_live_queries, :app_path, :database, :message_bus
41
+
42
+ def initialize(app_path=nil)
43
+ if Volt.server? && !app_path
44
+ raise "Volt::App.new requires an app path to boot"
45
+ end
46
+
47
+ @app_path = app_path
48
+ $volt_app = self
4
49
 
5
- def initialize(app_path)
6
50
  # Setup root path
7
51
  Volt.root = app_path
8
52
 
9
- # Run the app config to load all users config files
10
- unless RUBY_PLATFORM == 'opal'
11
- if Volt.server?
12
- @page = Page.new
53
+ setup_page
13
54
 
14
- # Setup a global for now
15
- $page = @page unless defined?($page)
55
+ if RUBY_PLATFORM != 'opal'
56
+ # Require in app and initializers
57
+ Volt.run_app_and_initializers unless RUBY_PLATFORM == 'opal'
58
+
59
+ # abort_on_exception is a useful debugging tool, and in my opinion something
60
+ # you probbaly want on. That said you can disable it if you need.
61
+ unless RUBY_PLATFORM == 'opal'
62
+ Thread.abort_on_exception = Volt.config.abort_on_exception
16
63
  end
17
- end
18
64
 
19
- # Require in app and initializers
20
- Volt.run_app_and_initializers unless RUBY_PLATFORM == 'opal'
65
+ load_app_code
21
66
 
22
- # Load component paths
23
- @component_paths = ComponentPaths.new(app_path)
24
- @component_paths.require_in_components(@page || $page)
67
+ reset_query_pool!
25
68
 
26
- unless RUBY_PLATFORM == 'opal'
27
- setup_router
28
- require_http_controllers
69
+ start_message_bus
29
70
  end
30
71
  end
31
72
 
32
- unless RUBY_PLATFORM == 'opal'
33
- def setup_router
34
- # Find the route file
35
- home_path = @component_paths.component_paths('main').first
36
- routes = File.read("#{home_path}/config/routes.rb")
37
- @router = Routes.new.define do
38
- eval(routes)
39
- end
40
- end
41
73
 
42
- def require_http_controllers
43
- @component_paths.app_folders do |app_folder|
44
- # Sort so we get consistent load order across platforms
45
- Dir["#{app_folder}/*/controllers/server/*.rb"].each do |ruby_file|
46
- # path = ruby_file.gsub(/^#{app_folder}\//, '')[0..-4]
47
- # require(path)
48
- require(ruby_file)
49
- end
50
- end
51
- end
74
+ # Setup a Page instance.
75
+ def setup_page
76
+ # Run the app config to load all users config files
77
+ @page = Page.new(self)
78
+
79
+ # Setup a global for now
80
+ $page = @page unless defined?($page)
52
81
  end
53
82
  end
54
83
  end
84
+
85
+ if Volt.client?
86
+ $volt_app = Volt::App.new
87
+
88
+ `$(document).ready(function() {`
89
+ $volt_app.page.start
90
+ `});`
91
+ end
@@ -0,0 +1,81 @@
1
+ # The following setup handles setting up the app on the server.
2
+ unless RUBY_PLATFORM == 'opal'
3
+ require 'volt/server/message_bus/peer_to_peer'
4
+ end
5
+
6
+ module Volt
7
+ module ServerSetup
8
+ module App
9
+ def load_app_code
10
+ # Load component paths
11
+ @component_paths = ComponentPaths.new(@app_path)
12
+ @component_paths.require_in_components(@page || $page)
13
+
14
+ setup_router
15
+ require_http_controllers
16
+ end
17
+
18
+ def setup_router
19
+ # Find the route file
20
+ home_path = @component_paths.component_paths('main').first
21
+ routes = File.read("#{home_path}/config/routes.rb")
22
+ @router = Routes.new.define do
23
+ eval(routes)
24
+ end
25
+ end
26
+
27
+ def require_http_controllers
28
+ @component_paths.app_folders do |app_folder|
29
+ # Sort so we get consistent load order across platforms
30
+ Dir["#{app_folder}/*/controllers/server/*.rb"].each do |ruby_file|
31
+ # path = ruby_file.gsub(/^#{app_folder}\//, '')[0..-4]
32
+ # require(path)
33
+ require(ruby_file)
34
+ end
35
+ end
36
+ end
37
+
38
+ def reset_query_pool!
39
+ if RUBY_PLATFORM != 'opal'
40
+ # The load path isn't setup at the top of app.rb, so we wait to require
41
+ require 'volt/tasks/live_query/live_query_pool'
42
+
43
+ # Setup LiveQueryPool for the app
44
+ @database = Volt::DataStore.fetch
45
+ @live_query_pool = LiveQueryPool.new(@database, self)
46
+ @channel_live_queries = {}
47
+ end
48
+ end
49
+
50
+ def start_message_bus
51
+ unless RUBY_PLATFORM == 'opal'
52
+
53
+ # Don't run in test env, since you probably only have one set of tests
54
+ # running at a time, and even if you have multiple, they shouldn't be
55
+ # updating each other.
56
+ unless Volt.env.test?
57
+ # Start the message bus
58
+ bus_name = Volt.config.message_bus.try(:bus_name) || 'peer_to_peer'
59
+ begin
60
+ message_bus_class = MessageBus.const_get(bus_name.camelize)
61
+ rescue NameError => e
62
+ raise "message bus name #{bus_name} was not found, be sure its "
63
+ + "gem is included in the gemfile."
64
+ end
65
+
66
+ @message_bus = message_bus_class.new(self)
67
+
68
+ Thread.new do
69
+ # Handle incoming messages in a new thread
70
+ @message_bus.subscribe('volt_collection_update') do |collection_name|
71
+ # update a collection, don't resend since we're coming from
72
+ # the message bus.
73
+ live_query_pool.updated_collection(collection_name, nil, true)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
data/lib/volt.rb CHANGED
@@ -12,7 +12,9 @@ require 'volt/volt/users'
12
12
 
13
13
  module Volt
14
14
  @in_browser = if RUBY_PLATFORM == 'opal'
15
- `!!document && !window.OPAL_SPEC_PHANTOM`
15
+ # When testing with opal-rspec, it technically is in a browser
16
+ # but its not setup with our own app code.
17
+ `!!document && !window.OPAL_SPEC_PHANTOM && window.$`
16
18
  else
17
19
  false
18
20
  end
@@ -52,5 +54,24 @@ module Volt
52
54
  def in_browser?
53
55
  @in_browser
54
56
  end
57
+
58
+ # When we use something like a Task, we don't specify an app, so we use
59
+ # a thread local or global to lookup the current app. This lets us run
60
+ # more than one app at once, giving deference to a global app.
61
+ def current_app
62
+ Thread.current['volt_app'] || $volt_app
63
+ end
64
+
65
+ # Runs code in the context of this app.
66
+ def in_app
67
+ previous_app = Thread.current['volt_app']
68
+ Thread.current['volt_app'] = self
69
+
70
+ begin
71
+ yield
72
+ ensure
73
+ Thread.current['volt_app'] = previous_app
74
+ end
75
+ end
55
76
  end
56
77
  end
@@ -14,7 +14,7 @@ gem 'volt-fields'
14
14
  gem 'volt-user_templates'
15
15
 
16
16
  # use mongo for data store while testing
17
- gem 'volt-mongo'
17
+ gem 'volt-mongo', path: '/Users/ryanstout/Sites/volt/apps/volt-mongo'
18
18
 
19
19
  gem 'opal'
20
20
 
@@ -1,3 +1,5 @@
1
+ require 'spec_helper'
2
+
1
3
  if RUBY_PLATFORM != 'opal'
2
4
  require 'volt/controllers/http_controller'
3
5
  require 'volt/server/rack/http_request'
@@ -53,13 +55,13 @@ if RUBY_PLATFORM != 'opal'
53
55
  'CONTENT_TYPE' => 'text/plain;charset=utf-8'))
54
56
  end
55
57
 
56
- let(:controller) { TestHttpController.new({}, request) }
58
+ let(:controller) { TestHttpController.new(volt_app, {}, request) }
57
59
 
58
60
  it 'should merge the request params and the url params' do
59
61
  request = Volt::HttpRequest.new(
60
62
  Rack::MockRequest.env_for('http://example.com/test.html?this=is_a&test=param'))
61
63
  controller = TestHttpController.new(
62
- { another: 'params', 'and_a' => 'string' }, request)
64
+ volt_app, { another: 'params', 'and_a' => 'string' }, request)
63
65
  expect(controller.params.size).to eq(4)
64
66
  expect(controller.params._and_a).to eq('string')
65
67
  expect(controller.params._this).to eq('is_a')
@@ -117,7 +119,7 @@ if RUBY_PLATFORM != 'opal'
117
119
  end
118
120
 
119
121
  it 'should have access to the body' do
120
- http_app = Volt::HttpResource.new(app, nil)
122
+ http_app = Volt::HttpResource.new(app, volt_app, nil)
121
123
  allow(http_app).to receive(:routes_match?)
122
124
  .and_return(controller: 'test_http',
123
125
  action: 'access_body')
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  if RUBY_PLATFORM != 'opal'
4
4
  describe Volt::ModelController do
5
5
  it 'should accept a promise as a model and resolve it' do
6
- controller = Volt::ModelController.new
6
+ controller = Volt::ModelController.new(volt_app)
7
7
 
8
8
  promise = Promise.new
9
9
 
@@ -17,7 +17,7 @@ if RUBY_PLATFORM != 'opal'
17
17
  end
18
18
 
19
19
  it 'should not return true from loaded until the promise is resolved' do
20
- controller = Volt::ModelController.new
20
+ controller = Volt::ModelController.new(volt_app)
21
21
 
22
22
  promise = Promise.new
23
23
  controller.model = promise
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash do
4
+ it 'should return a hash without the speicified keys' do
5
+ a = {one: 1, two: 2, three: 3}
6
+
7
+ expect(a.without(:one, :three)).to eq({two: 2})
8
+ end
9
+ end
@@ -12,7 +12,7 @@ if ENV['BROWSER'] == 'firefox'
12
12
  fill_in('newtodo', with: "Item 3\n")
13
13
  end
14
14
 
15
- it 'should add items to the list' do
15
+ it 'should add items to the list', type: :feature do
16
16
  expect(find('#todos-table')).to have_content('Item 1')
17
17
  end
18
18
 
@@ -28,7 +28,7 @@ if ENV['BROWSER'] == 'firefox'
28
28
  expect(find('#todos-table')).to_not have_css('td.name.complete')
29
29
  end
30
30
 
31
- it 'should delete items' do
31
+ it 'should delete items', type: :feature do
32
32
  expect(find('#todos-table')).to have_content('Item 1')
33
33
  expect(find('#todos-table')).to have_content('Item 2')
34
34
  expect(find('#todos-table')).to have_content('Item 3')
@@ -41,7 +41,7 @@ if ENV['BROWSER'] == 'firefox'
41
41
  expect(find('#todos-table')).to have_content('Item 3')
42
42
  end
43
43
 
44
- it 'should track the number of todos and the numbers that are complete' do
44
+ it 'should track the number of todos and the numbers that are complete', type: :feature do
45
45
  count = find('#count')
46
46
 
47
47
  expect(count).to have_content('0 of 3')
@@ -20,7 +20,7 @@ describe Volt::Associations do
20
20
  it 'should associate via belongs_to' do
21
21
  address = store._addresses!.fetch_first.sync
22
22
 
23
- expect(address.person.sync._id).to eq(@person._id)
23
+ expect(address.person.sync.id).to eq(@person.id)
24
24
  end
25
25
 
26
26
  it 'should associate via has_many' do
@@ -35,8 +35,16 @@ describe Volt::Associations do
35
35
  store = Volt::Model.new({}, persistor: Volt::Persistors::Flash)
36
36
  expect do
37
37
  store.send(:association_with_root_model, :blah)
38
- end.to raise_error("blah currently only works on the store collection "\
38
+ end.to raise_error("blah currently only works on the store and page collection "\
39
39
  "(support for other collections coming soon)")
40
40
  end
41
+
42
+ # it 'should assign the reference_id for has_many' do
43
+ # bob = Person.new
44
+ # bob.addresses << {:street => '1234 awesome street'}
45
+ # puts "Bob: #{bob.inspect} - #{bob.addresses.size}"
46
+ # expect(bob.addresses[0].person_id).to eq(bob.id)
47
+ # expect(bob.id).to_not eq(nil)
48
+ # end
41
49
  end
42
50
  end
@@ -79,27 +79,27 @@ describe 'Volt::Dirty' do
79
79
  end
80
80
 
81
81
  it 'should revert changes' do
82
- expect(model.attributes).to eq({})
82
+ expect(model.attributes.without(:id)).to eq({})
83
83
  model.attributes = { first: 'Bob', last: 'Smith' }
84
- expect(model.attributes).to eq(first: 'Bob', last: 'Smith')
84
+ expect(model.attributes.without(:id)).to eq(first: 'Bob', last: 'Smith')
85
85
 
86
86
  model.revert_changes!
87
- expect(model.attributes).to eq(first: nil, last: nil)
87
+ expect(model.attributes.without(:id)).to eq(first: nil, last: nil)
88
88
  end
89
89
 
90
90
  it 'should revert changes after a clear_tracked_changed!' do
91
- expect(model.attributes).to eq({})
91
+ expect(model.attributes.without(:id)).to eq({})
92
92
  model.attributes = { first: 'Bob', last: 'Smith' }
93
- expect(model.attributes).to eq(first: 'Bob', last: 'Smith')
93
+ expect(model.attributes.without(:id)).to eq(first: 'Bob', last: 'Smith')
94
94
 
95
95
  model.clear_tracked_changes!
96
96
  expect(model.changed_attributes).to eq({})
97
97
 
98
98
  model._first = 'Jimmy'
99
99
  model._last = 'Dean'
100
- expect(model.attributes).to eq(first: 'Jimmy', last: 'Dean')
100
+ expect(model.attributes.without(:id)).to eq(first: 'Jimmy', last: 'Dean')
101
101
 
102
102
  model.revert_changes!
103
- expect(model.attributes).to eq(first: 'Bob', last: 'Smith')
103
+ expect(model.attributes.without(:id)).to eq(first: 'Bob', last: 'Smith')
104
104
  end
105
105
  end