volt 0.9.3.pre1 → 0.9.3.pre2

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6e09afcd5fa1abe6f17a9c2912bc79cf4cf74aa
4
- data.tar.gz: f0ee7b0085bddf48461122bfccec1b21b06b2e3e
3
+ metadata.gz: 424f310e39b6096bf3372ff3dd5b90e6936718ef
4
+ data.tar.gz: fa76365d2cc587f7985e39008f13825f02c6515d
5
5
  SHA512:
6
- metadata.gz: ed02ac1418ee8f8ed50a67331dfb58eeabf933a55ecb60a2cb05052245164e851331fea5a5de8977a1fbfa31859bedea4dcaf8117b28258559c0954c5ff3f9e3
7
- data.tar.gz: 7069f1ac08014813da1501c252fed11031c248b479d7b7323ff49a69b17cdc5dc54e793f48b48b199a6e23fd56178ff6684b47151640ab321af3fd0cfcfe5d71
6
+ metadata.gz: c6371586b5afc5278951bf89478153b6e854edb444503ca8ea312071f74d350c2807aa67eede9f8d64a97bc8c8208649dafd46ae723f58c1cb4308566b3a0ce5
7
+ data.tar.gz: 86c5ef5a2b1da23d537103884ee7cdd840be23dae4a59ae22e0c2be0b3ac56652541fcbd5dd808b79c474cda6846e4847ef2839c9a91c5009da931952937c563
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.0
1
+ 2.2.0
data/CHANGELOG.md CHANGED
@@ -1,17 +1,31 @@
1
1
  # Change Log
2
2
 
3
- ## 0.9.3.pre1
3
+ ## 0.9.3.pre2
4
4
  ### Added
5
5
  - Added validations block for conditional validation runs
6
+ - you can now set the NO_FORKING=true ENV to prevent using the forking server in development.
7
+ - models without an assigned persistor now use the page persistor (which now can provide basic querying)
8
+ - Volt now pushes updates between mulitple app instances. Updates are pushed between any servers, clients, runners, etc.. that are connected to the same database via the MessageBus (see next)
9
+ - Volt now comes with a "MessageBus" built in. The message bus provides a pub/sub interface for the app "cluster". Volt provides a default message bus implementation using peer to peer sockets that are automatically managed via the database.
6
10
 
7
11
  ### Changed
8
12
  - All logic associated with mongo has been moved into the volt-mongo gem. If you are migrating from a previous version, be sure to add ```gem 'volt-mongo'``` to the Gemfile.
13
+ - models using the page or store persistor now auto-generate an id when created. This simplifies things since models always have an id. It makes association easier as well. (internally that is)
14
+ - models now use ```.id``` instead of ```._id``` Queries and saves are mapped to _id in the volt-mongo gem
15
+ - fixed issue where ```volt precompile``` would compile in extra assets from non-component gems.
16
+ - Lots of internal changes:
17
+ - bindings were refactored to pass around a Volt::App instead of a Volt::Page.
18
+ - controllers now take a Volt::App when created directly.
19
+ - You can now use .each in attribute bindings.
20
+ - We moved to csso as the css compressor because it does not require libv8, only an execjs runtime.
9
21
 
10
22
  ## 0.9.2
11
23
  ### Changed
12
24
  - We released 0.9.1 with a bug for destroy (doh!). Specs added and bug fixed.
13
25
 
14
26
  ## 0.9.1
27
+ [0.9.1 Update Blog Post](http://blog.voltframework.com/post/118260814159/0-9-1-already-thats-how-we-roll)
28
+
15
29
  ### Added
16
30
  - Mailer! - volt now includes the volt-mailer gem out of the box. (you can remove it if you don't need/want it). See https://github.com/voltrb/volt-mailer for more info.
17
31
 
data/Gemfile CHANGED
@@ -5,6 +5,12 @@ gemspec
5
5
  # volt-mongo gem for testing
6
6
  gem 'volt-mongo'
7
7
 
8
+ # Use rbnacl for message bus encrpytion
9
+ # (optional, if you don't need encryption, disable in app.rb and remove)
10
+ gem 'rbnacl', require: false
11
+ gem 'rbnacl-libsodium', require: false
12
+
13
+
8
14
  group :development do
9
15
  # For testing the kitchen sink app
10
16
  # Twitter bootstrap
@@ -24,13 +30,34 @@ group :development do
24
30
  end
25
31
 
26
32
  group :development, :test do
27
- gem 'bson_ext'
33
+ platform :mri do
34
+ gem 'bson_ext'
28
35
 
29
- # For running tests
30
- gem 'thin'
36
+ # For running tests
37
+ gem 'thin'
38
+ end
39
+
40
+ platform :jruby do
41
+ # For running tests
42
+ gem 'puma'
43
+ end
31
44
  end
32
45
 
33
46
  platform :mri do
34
47
  # The implementation of ReadWriteLock in Volt uses concurrent ruby and ext helps performance.
35
48
  gem 'concurrent-ruby-ext'
49
+
50
+ # For debugging
51
+ gem 'pry-byebug', '~> 2.0.0', require: false
52
+
53
+ # For Yard Formatting, in MRI block because redcarpet doesn't install on jruby
54
+ gem 'redcarpet', '~> 3.2.2', require: false
55
+ gem 'github-markup', '~> 1.3.1', require: false
56
+
57
+ # Sauce has a dependency that doesn't run on ruby <= 2.0.0
58
+ # (which older jruby versions don't support)
59
+ # TODO: Move out of MRI block once jruby 9k is outs
60
+ gem 'sauce', '~> 3.5.3', require: false
61
+ gem 'sauce-connect', '~> 3.5.0', require: false
62
+
36
63
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Gratipay](http://img.shields.io/gratipay/voltframework.svg)](https://www.gratipay.com/voltframework/)
1
+ [![Pledgie](https://pledgie.com/campaigns/26731.png?skin_name=chrome)](https://pledgie.com/campaigns/26731)
2
2
  [![Gem Version](https://badge.fury.io/rb/volt.svg)](http://badge.fury.io/rb/volt)
3
3
  [![Code Climate](https://codeclimate.com/github/voltrb/volt/badges/gpa.svg)](https://codeclimate.com/github/voltrb/volt)
4
4
  [![Coverage Status](https://coveralls.io/repos/voltrb/volt/badge.svg?branch=master)](https://coveralls.io/r/voltrb/volt?branch=master)[![Build Status](http://img.shields.io/travis/voltrb/volt/master.svg?style=flat)](https://travis-ci.org/voltrb/volt)
@@ -36,5 +36,10 @@ There is also a [work in progress tutorial](https://github.com/rhgraysonii/volt_
36
36
 
37
37
  You want to contribute? Great! Thanks for being awesome! At the moment, we have a big internal todo list, hop on https://gitter.im/voltrb/volt so we don't duplicate work. Pull requests are always welcome, but asking about helping on Gitter should save some duplication.
38
38
 
39
+ # Support
39
40
 
40
- [![Gratipay](http://img.shields.io/gratipay/voltframework.svg)](https://www.gratipay.com/voltframework/)
41
+ VoltFramework is currently a labor of love mainly built by a small group of core developers. Donations are always welcome and will help Volt get to production faster :-) Also, if you or your company is interested in sponsoring Volt, please talk to @ryanstout in the [gitter](https://gitter.im/voltrb/volt)
42
+
43
+ [![Pledgie](https://pledgie.com/campaigns/26731.png?skin_name=chrome)](https://pledgie.com/campaigns/26731)
44
+
45
+ Bitcoins can also be sent to 1AYiL3MiSVe2QFyexzozUvFFH7uGCJgJMZ
data/Rakefile CHANGED
@@ -31,6 +31,23 @@ task :test do
31
31
  Rake::Task['ruby:rspec'].invoke
32
32
  end
33
33
 
34
+ task :opal_specs_in_browser do
35
+ require 'volt/server/websocket/rack_server_adaptor'
36
+ require 'rack/cascade'
37
+
38
+ server = Rack::Handler.get(RUNNING_SERVER)
39
+
40
+ Opal::Processor.source_map_enabled = false
41
+ app = Opal::Server.new { |s|
42
+ s.main = 'opal/rspec/sprockets_runner'
43
+ s.append_path 'spec'
44
+ s.append_path 'app'
45
+ s.debug = false
46
+ }
47
+
48
+ server.run(app, {})
49
+ end
50
+
34
51
  # Rubocop task
35
52
  RuboCop::RakeTask.new(:rubocop) do |task|
36
53
  task.options = ['--display-cop-names']
@@ -19,7 +19,7 @@ module Volt
19
19
  deny :hashed_password
20
20
 
21
21
  # Deny all if this isn't the owner
22
- deny if !_id == Volt.current_user_id && !new?
22
+ deny if !id == Volt.current_user_id && !new?
23
23
  end
24
24
 
25
25
  if RUBY_PLATFORM == 'opal'
@@ -68,7 +68,6 @@ class LiveQuery
68
68
  def initial_data
69
69
  @query_tracker.results.map.with_index do |data, index|
70
70
  data = data.dup
71
- data['_id'] = data['_id'].to_s
72
71
 
73
72
  [index, data]
74
73
  end
@@ -5,8 +5,9 @@ require 'volt/utils/generic_pool'
5
5
  # queries.
6
6
 
7
7
  class LiveQueryPool < Volt::GenericPool
8
- def initialize(data_store)
8
+ def initialize(data_store, volt_app)
9
9
  @data_store = data_store
10
+ @volt_app = volt_app
10
11
  super()
11
12
  end
12
13
 
@@ -17,11 +18,16 @@ class LiveQueryPool < Volt::GenericPool
17
18
  super(collection, query)
18
19
  end
19
20
 
20
- def updated_collection(collection, skip_channel)
21
+ def updated_collection(collection, skip_channel, from_message_bus=false)
21
22
  # collection = collection.to_sym
22
23
  lookup_all(collection).each do |live_query|
23
24
  live_query.run(skip_channel)
24
25
  end
26
+
27
+ msg_bus = @volt_app.message_bus
28
+ if !from_message_bus && collection != 'active_volt_instances' && msg_bus
29
+ msg_bus.publish('volt_collection_update', collection)
30
+ end
25
31
  end
26
32
 
27
33
  private
@@ -23,8 +23,8 @@ class QueryTracker
23
23
  @results = @data_store.query(@live_query.collection, @live_query.query)
24
24
 
25
25
  # Update the current_ids
26
- @current_ids = @results.map { |r| r['_id'] }
27
- @results_hash = Hash[@results.map { |r| [r['_id'], r] }]
26
+ @current_ids = @results.map { |r| r[:id] }
27
+ @results_hash = Hash[@results.map { |r| [r[:id], r] }]
28
28
 
29
29
  process_changes(skip_channel)
30
30
  end
@@ -1,29 +1,13 @@
1
- require_relative 'live_query/live_query_pool'
2
-
3
1
  class QueryTasks < Volt::Task
4
- @@channel_live_queries = {}
5
-
6
- def self.live_query_pool
7
- @@live_query_pool ||= LiveQueryPool.new(Volt::DataStore.fetch)
8
- end
9
-
10
2
  # The dispatcher passes its self in
11
- def initialize(channel, dispatcher = nil)
3
+ def initialize(volt_app, channel, dispatcher = nil)
4
+ @volt_app = volt_app
12
5
  @channel = channel
13
6
  @dispatcher = dispatcher
14
-
15
- # Load the query pool if not already setup
16
- self.class.live_query_pool
17
- end
18
-
19
- def self.reset!
20
- @@channel_live_queries = {}
21
- @@live_query_pool = nil
22
- live_query_pool
23
7
  end
24
8
 
25
9
  def add_listener(collection, query)
26
- live_query = @@live_query_pool.lookup(collection, query)
10
+ live_query = @volt_app.live_query_pool.lookup(collection, query)
27
11
  track_channel_in_live_query(live_query)
28
12
 
29
13
  if @channel
@@ -53,14 +37,12 @@ class QueryTasks < Volt::Task
53
37
  end
54
38
  end
55
39
 
56
- # @@live_query_pool.print
57
-
58
40
  [initial_data, error]
59
41
  end
60
42
 
61
43
  def initial_data
62
44
  data = live_query.initial_data
63
- data[:_id] = data[:_id].to_s
45
+ data[:id] = data[:id].to_s
64
46
 
65
47
  data
66
48
  end
@@ -68,13 +50,13 @@ class QueryTasks < Volt::Task
68
50
  # Remove a listening channel, the LiveQuery will automatically remove
69
51
  # itsself from the pool when there are no channels.
70
52
  def remove_listener(collection, query)
71
- live_query = @@live_query_pool.lookup(collection, query)
53
+ live_query = @volt_app.live_query_pool.lookup(collection, query)
72
54
  live_query.remove_channel(@channel)
73
55
  end
74
56
 
75
57
  # Removes a channel from all associated live queries
76
58
  def close!
77
- live_queries = @@channel_live_queries[@channel]
59
+ live_queries = @volt_app.channel_live_queries[@channel]
78
60
 
79
61
  if live_queries
80
62
  live_queries.each do |live_query|
@@ -82,14 +64,15 @@ class QueryTasks < Volt::Task
82
64
  end
83
65
  end
84
66
 
85
- @@channel_live_queries.delete(@channel)
67
+ @volt_app.channel_live_queries.delete(@channel)
86
68
  end
87
69
 
88
70
  private
89
71
 
90
72
  # Tracks that this channel will be notified from the live query.
91
73
  def track_channel_in_live_query(live_query)
92
- @@channel_live_queries[@channel] ||= []
93
- @@channel_live_queries[@channel] << live_query
74
+ channel_live_queries = @volt_app.channel_live_queries
75
+ channel_live_queries[@channel] ||= []
76
+ channel_live_queries[@channel] << live_query
94
77
  end
95
78
  end
@@ -2,7 +2,8 @@ require 'mongo'
2
2
  require 'volt/models'
3
3
 
4
4
  class StoreTasks < Volt::Task
5
- def initialize(channel = nil, dispatcher = nil)
5
+ def initialize(volt_app, channel = nil, dispatcher = nil)
6
+ @volt_app = volt_app
6
7
  @channel = channel
7
8
  @dispatcher = dispatcher
8
9
  end
@@ -18,7 +19,7 @@ class StoreTasks < Volt::Task
18
19
  collection = store.send(:"_#{path[-2]}")
19
20
 
20
21
  # See if the model has already been made
21
- collection.find(_id: data[:_id]).fetch_first do |model|
22
+ collection.where(id: data[:id]).fetch_first do |model|
22
23
  # Otherwise assign to the collection
23
24
  model ||= collection
24
25
 
@@ -70,18 +71,18 @@ class StoreTasks < Volt::Task
70
71
  query = nil
71
72
 
72
73
  Volt.skip_permissions do
73
- query = store.send(:"_#{collection}").where(_id: id)
74
+ query = store.get(collection).where(id: id)
74
75
  end
75
76
 
76
77
  query.fetch_first do |model|
77
78
  if model
78
79
  if model.can_delete?
79
- db.delete(collection, '_id' => id)
80
+ db.delete(collection, 'id' => id)
80
81
  else
81
82
  fail "Permissions did not allow #{collection} #{id} to be deleted."
82
83
  end
83
84
 
84
- QueryTasks.live_query_pool.updated_collection(collection, @channel)
85
+ @volt_app.live_query_pool.updated_collection(collection, @channel)
85
86
  else
86
87
  fail "Could not find #{id} in #{collection}"
87
88
  end
@@ -21,10 +21,10 @@ class UserTasks < Volt::Task
21
21
  # TODO: returning here should be possible, but causes some issues
22
22
  # Salt the user id with the app_secret so the end user can't
23
23
  # tamper with the cookie
24
- signature = Digest::SHA256.hexdigest(salty_user_id(user._id))
24
+ signature = Digest::SHA256.hexdigest(salty_user_id(user.id))
25
25
 
26
26
  # Return user_id:hash on user id
27
- next "#{user._id}:#{signature}"
27
+ next "#{user.id}:#{signature}"
28
28
  end
29
29
  end
30
30
  end
@@ -0,0 +1,14 @@
1
+ # 0.9.2 to 0.9.3
2
+
3
+ Add the following to your gemfile:
4
+
5
+ ```ruby
6
+ # Use rbnacl for message bus encrpytion
7
+ # (optional, if you don't need encryption, disable in app.rb and remove)
8
+ gem 'rbnacl', require: false
9
+ gem 'rbnacl-libsodium', require: false
10
+
11
+ # Asset compilation gems, they will be required when needed.
12
+ gem 'csso-rails', '~> 0.3.4', require: false
13
+ gem 'uglifier', '>= 2.4.0', require: false
14
+ ```
data/lib/volt/boot.rb CHANGED
@@ -16,6 +16,7 @@ else
16
16
  end
17
17
  require 'volt/volt/app'
18
18
 
19
+
19
20
  module Volt
20
21
  def self.boot(app_path)
21
22
  # Boot the app
@@ -9,7 +9,7 @@ module Volt
9
9
  private
10
10
 
11
11
  def compile
12
- print 'compiling project...'
12
+ puts 'compiling project...'
13
13
  require 'fileutils'
14
14
  ENV['SERVER'] = 'true'
15
15
 
@@ -38,20 +38,35 @@ module Volt
38
38
  @index_files = IndexFiles.new(@app, @component_paths, @opal_files)
39
39
  @component_handler = ComponentHandler.new(@component_paths)
40
40
 
41
+ puts 'Compile Opal for components'
41
42
  write_component_js
43
+ puts 'Copy assets'
42
44
  write_sprockets
45
+ puts 'Compile JS/CSS'
43
46
  write_js_and_css
47
+ puts 'Write index files'
44
48
  write_index
45
49
 
46
- puts "\rcompiled "
50
+ puts "compiled"
51
+ end
52
+
53
+ def logical_paths_and_full_paths
54
+ @opal_files.environment.each_file do |full_path|
55
+ logical_path = @opal_files.environment.send(:logical_path_for_filename, full_path, []).to_s
56
+
57
+ yield(logical_path, full_path.to_s)
58
+ end
59
+
47
60
  end
48
61
 
49
62
  def write_sprockets
50
63
  # Serve the opal files
51
- @opal_files.environment.each_logical_path do |logical_path|
52
- logical_path = logical_path.to_s
64
+ logical_paths_and_full_paths do |logical_path, full_path|
53
65
  # Only include files that aren't compiled elsewhere, like fonts
54
- if !logical_path[/[.](y|css|js|html|erb)$/] && File.extname(logical_path) != ''
66
+ if !logical_path[/[.](y|css|js|html|erb)$/] &&
67
+ File.extname(logical_path) != '' &&
68
+ # opal includes some node modules in the standard lib that we don't need to compile in
69
+ (full_path !~ /\/opal/ && full_path !~ /\/stdlib\// && logical_path !~ /^node_js\//)
55
70
  write_sprocket_file(logical_path)
56
71
  end
57
72
  end
@@ -70,8 +85,11 @@ module Volt
70
85
  path = "#{@root_path}/public/assets/#{logical_path}"
71
86
 
72
87
  begin
73
- content = @opal_files.environment[logical_path].to_s
74
- write_file(path, content)
88
+ # Only write out the assets
89
+ # if logical_path =~ /\/assets\//
90
+ content = @opal_files.environment[logical_path].to_s
91
+ write_file(path, content)
92
+ # end
75
93
  rescue Sprockets::FileNotFound, SyntaxError => e
76
94
  # ignore
77
95
  end
@@ -31,11 +31,11 @@ module Volt
31
31
  class Console
32
32
  module Helpers
33
33
  def store
34
- $page.store
34
+ @volt_app.page.store
35
35
  end
36
36
 
37
37
  def page
38
- $page.page
38
+ @volt_app.page.page
39
39
  end
40
40
  end
41
41
 
@@ -50,15 +50,16 @@ module Volt
50
50
  require 'volt/volt/core'
51
51
  require 'volt/server/socket_connection_handler_stub'
52
52
 
53
- SocketConnectionHandlerStub.dispatcher = Dispatcher.new
53
+ # Boot the volt app
54
+ volt_app = Volt.boot(Dir.pwd)
54
55
 
55
- Volt.boot(Dir.pwd)
56
+ SocketConnectionHandlerStub.dispatcher = Dispatcher.new(volt_app)
56
57
 
57
58
  Pry.config.prompt_name = 'volt'
58
59
 
60
+ Pry.main.instance_variable_set('@volt_app', volt_app)
59
61
  Pry.main.send(:include, Volt::Console::Helpers)
60
62
 
61
- # $page.pry
62
63
  Pry.start
63
64
  end
64
65
  end
@@ -62,7 +62,7 @@ class Generate < Thor
62
62
  method_option :name, type: :string, banner: 'The name of the model controller.'
63
63
  method_option :component, type: :string, default: 'main', banner: 'The component the controller should be created in.', required: false
64
64
  def controller(name, component = 'main')
65
- controller_name = name.underscore.singularize + '_controller' unless name =~ /_controller$/
65
+ controller_name = name.underscore.pluralize + '_controller' unless name =~ /_controller$/
66
66
  output_file = Dir.pwd + "/app/#{component.underscore}/controllers/#{controller_name}.rb"
67
67
  spec_file = Dir.pwd + "/spec/app/#{component.underscore}/integration/#{name.underscore.pluralize}_spec.rb"
68
68
 
@@ -85,7 +85,7 @@ class Generate < Thor
85
85
  method_option :name, type: :string, banner: 'The name of the view.'
86
86
  method_option :component, type: :string, default: 'main', banner: 'The component the view should be created in.', required: false
87
87
  def view(name, component = 'main')
88
- name = name.underscore.singularize
88
+ name = name.underscore.pluralize
89
89
  view_folder = Dir.pwd + "/app/#{component}/views/#{name}/"
90
90
  directory('view', view_folder, view_name: name, component: component)
91
91
  controller(name, component) unless controller_exists?(name, component)
data/lib/volt/config.rb CHANGED
@@ -59,7 +59,8 @@ else
59
59
  default_components: ['volt'],
60
60
 
61
61
  compress_javascript: Volt.env.production?,
62
- compress_css: Volt.env.production?
62
+ compress_css: Volt.env.production?,
63
+ abort_on_exception: true
63
64
  }
64
65
  end
65
66
 
@@ -8,11 +8,12 @@ module Volt
8
8
  attr_reader :params, :response_headers, :request
9
9
 
10
10
  # Initialzed with the params parsed from the route and the HttpRequest
11
- def initialize(params, request)
11
+ def initialize(volt_app, params, request)
12
+ @volt_app = volt_app
12
13
  @response_headers = HttpResponseHeader.new
13
14
  @response_body = []
14
15
  @request = request
15
- @params = Volt::Model.new(params.symbolize_keys.merge(request.params))
16
+ @params = Volt::Model.new(params.symbolize_keys.merge(request.params), persistor: Volt::Persistors::Params)
16
17
  end
17
18
 
18
19
  def perform(action)
@@ -25,7 +26,7 @@ module Volt
25
26
  private
26
27
 
27
28
  def store
28
- $page.store
29
+ @volt_app.page.store
29
30
  end
30
31
 
31
32
  def head(status, additional_headers = {})
@@ -1,11 +1,18 @@
1
1
  require 'volt/reactive/reactive_accessors'
2
2
  require 'volt/controllers/actions'
3
+ require 'volt/controllers/template_helpers'
3
4
 
4
5
  module Volt
5
6
  class ModelController
6
7
  include ReactiveAccessors
7
8
  include Actions
8
9
 
10
+ # A model controller will have its
11
+ # class VoltTemplates
12
+ # include TemplateHelpers
13
+ # end
14
+
15
+ class_attribute :default_model
9
16
  reactive_accessor :current_model
10
17
  reactive_accessor :last_promise
11
18
 
@@ -29,8 +36,7 @@ module Volt
29
36
  # ```yield_html``` and it will be run again when anything in the template changes.
30
37
  def yield_html
31
38
  if (template_path = attrs.content_template_path)
32
- # TODO: Don't use $page global
33
- @yield_renderer ||= StringTemplateRenderer.new($page, self, template_path)
39
+ @yield_renderer ||= StringTemplateRenderer.new(@volt_app, self, template_path)
34
40
  @yield_renderer.html
35
41
  else
36
42
  # no template, empty string
@@ -39,7 +45,7 @@ module Volt
39
45
  end
40
46
 
41
47
  def self.model(val)
42
- @default_model = val
48
+ self.default_model = val
43
49
  end
44
50
 
45
51
  # Sets the current model on this controller
@@ -85,20 +91,35 @@ module Volt
85
91
  model
86
92
  end
87
93
 
88
- def self.new(*args, &block)
94
+ def self.new(volt_app, *args, &block)
89
95
  inst = allocate
90
96
 
91
- inst.model = @default_model if @default_model
92
-
93
97
  # In MRI initialize is private for some reason, so call it with send
94
- inst.send(:initialize, *args, &block)
98
+ inst.send(:initialize, volt_app, *args, &block)
99
+
100
+ if inst.instance_variable_get('@__init_called')
101
+ inst.instance_variable_set('@__init_called', nil)
102
+ else
103
+ # Initialize was not called, we should warn since this is probably not
104
+ # the intended behavior.
105
+ Volt.logger.warn("super should be called when creating a custom initialize on class #{inst.class.to_s}")
106
+ end
95
107
 
96
108
  inst
97
109
  end
98
110
 
99
111
  attr_accessor :attrs
100
112
 
101
- def initialize(*args)
113
+ def initialize(volt_app, *args)
114
+ @volt_app = volt_app
115
+ @page = volt_app.page
116
+
117
+ # Track that the initialize was called
118
+ @__init_called = true
119
+
120
+ default_model = self.class.default_model
121
+ self.model = default_model if default_model
122
+
102
123
  if args[0]
103
124
  # Assign the first passed in argument to attrs
104
125
  self.attrs = args[0]
@@ -106,6 +127,7 @@ module Volt
106
127
  # If a model attribute is passed in, we assign it directly
107
128
  self.model = attrs.locals[:model] if attrs.respond_to?(:model)
108
129
  end
130
+
109
131
  end
110
132
 
111
133
  def go(url)
@@ -124,39 +146,39 @@ module Volt
124
146
  end
125
147
 
126
148
  def page
127
- $page.page
149
+ @page.page
128
150
  end
129
151
 
130
152
  def store
131
- $page.store
153
+ @page.store
132
154
  end
133
155
 
134
156
  def flash
135
- $page.flash
157
+ @page.flash
136
158
  end
137
159
 
138
160
  def params
139
- $page.params
161
+ @page.params
140
162
  end
141
163
 
142
164
  def local_store
143
- $page.local_store
165
+ @page.local_store
144
166
  end
145
167
 
146
168
  def cookies
147
- $page.cookies
169
+ @page.cookies
148
170
  end
149
171
 
150
172
  def url
151
- $page.url
173
+ @page.url
152
174
  end
153
175
 
154
176
  def channel
155
- $page.channel
177
+ @page.channel
156
178
  end
157
179
 
158
180
  def tasks
159
- $page.tasks
181
+ @page.tasks
160
182
  end
161
183
 
162
184
  def controller
@@ -164,11 +186,11 @@ module Volt
164
186
  end
165
187
 
166
188
  def url_for(params)
167
- $page.url.url_for(params)
189
+ @page.url.url_for(params)
168
190
  end
169
191
 
170
192
  def url_with(params)
171
- $page.url.url_with(params)
193
+ @page.url.url_with(params)
172
194
  end
173
195
 
174
196
  # loaded? is a quick way to see if the model for the controller is loaded