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
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