volt 0.9.3.pre3 → 0.9.3.pre4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -2
  3. data/app/volt/models/user.rb +5 -0
  4. data/app/volt/tasks/store_tasks.rb +2 -2
  5. data/app/volt/tasks/user_tasks.rb +1 -1
  6. data/lib/volt/cli/asset_compile.rb +0 -2
  7. data/lib/volt/cli/generate.rb +8 -3
  8. data/lib/volt/cli.rb +3 -9
  9. data/lib/volt/controllers/actions.rb +6 -1
  10. data/lib/volt/controllers/http_controller.rb +16 -7
  11. data/lib/volt/controllers/model_controller.rb +21 -0
  12. data/lib/volt/models/array_model.rb +26 -3
  13. data/lib/volt/models/model.rb +18 -19
  14. data/lib/volt/models/persistors/array_store.rb +2 -10
  15. data/lib/volt/models/root_models/store_root.rb +17 -4
  16. data/lib/volt/models/validations/validations.rb +1 -1
  17. data/lib/volt/models/validators/unique_validator.rb +1 -1
  18. data/lib/volt/models.rb +1 -1
  19. data/lib/volt/page/bindings/attribute_binding.rb +5 -4
  20. data/lib/volt/page/bindings/base_binding.rb +17 -0
  21. data/lib/volt/page/bindings/content_binding.rb +7 -5
  22. data/lib/volt/page/bindings/each_binding.rb +62 -51
  23. data/lib/volt/page/bindings/event_binding.rb +14 -0
  24. data/lib/volt/page/bindings/view_binding.rb +1 -1
  25. data/lib/volt/reactive/computation.rb +22 -13
  26. data/lib/volt/reactive/dependency.rb +0 -24
  27. data/lib/volt/router/routes.rb +35 -0
  28. data/lib/volt/server/forking_server.rb +26 -3
  29. data/lib/volt/server/message_bus/peer_to_peer/peer_connection.rb +1 -1
  30. data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +1 -1
  31. data/lib/volt/server/message_bus/peer_to_peer.rb +28 -21
  32. data/lib/volt/server/middleware/default_middleware_stack.rb +67 -0
  33. data/lib/volt/server/middleware/middleware_stack.rb +58 -0
  34. data/lib/volt/server/rack/http_request.rb +1 -1
  35. data/lib/volt/server/rack/http_resource.rb +7 -0
  36. data/lib/volt/server/rack/keep_alive.rb +20 -0
  37. data/lib/volt/server/socket_connection_handler.rb +10 -1
  38. data/lib/volt/server.rb +6 -76
  39. data/lib/volt/utils/promise_extensions.rb +5 -1
  40. data/lib/volt/utils/set_patch.rb +25 -0
  41. data/lib/volt/utils/timers.rb +12 -0
  42. data/lib/volt/version.rb +1 -1
  43. data/lib/volt/volt/app.rb +13 -1
  44. data/lib/volt/volt/server_setup/app.rb +19 -1
  45. data/lib/volt/volt/users.rb +11 -22
  46. data/lib/volt.rb +1 -0
  47. data/spec/apps/kitchen_sink/Gemfile +1 -1
  48. data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -1
  49. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +22 -0
  50. data/spec/apps/kitchen_sink/app/main/views/main/bindings.html +10 -0
  51. data/spec/apps/kitchen_sink/app/main/views/main/store_demo.html +9 -0
  52. data/spec/controllers/http_controller_spec.rb +27 -0
  53. data/spec/integration/bindings_spec.rb +29 -0
  54. data/spec/integration/store_spec.rb +7 -7
  55. data/spec/models/associations_spec.rb +1 -1
  56. data/spec/models/model_spec.rb +10 -0
  57. data/spec/models/permissions_spec.rb +7 -4
  58. data/spec/reactive/computation_spec.rb +33 -5
  59. data/spec/router/routes_spec.rb +69 -0
  60. data/spec/server/middleware/middleware_handler.rb +24 -0
  61. data/spec/spec_helper.rb +1 -1
  62. data/spec/tasks/user_tasks_spec.rb +3 -2
  63. data/templates/project/Gemfile.tt +2 -2
  64. data/templates/project/config/base/index.html +5 -1
  65. metadata +10 -5
  66. data/spec/apps/kitchen_sink/app/main/views/main/store.html +0 -9
  67. data/templates/project/app/main/models/.empty_directory +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f07b58ba0668779997cda13fafd289b7c91451b6
4
- data.tar.gz: b5b4d4a31d7b2ea898c6c1ce57ad6fa39373b03a
3
+ metadata.gz: 3a512670034e9289a6697c10ad2c3cc15c25c53e
4
+ data.tar.gz: 1bb81b98a09cc8d568803e76ecddd95cfcdfa3b6
5
5
  SHA512:
6
- metadata.gz: f8a220c588390c7c6a1f37199b8be4a56129339e8d6450ab18fd142bb9ff7b892465290e6efdd79524c538af793e3f5ef80226fbd1e009704fe656585c8722bf
7
- data.tar.gz: 5e89589d70e40122664207102c1e4abafb33fe58fcb6aa26827c2ef706a302ce83a1bca8d75f4e8989208d67a0690f2a2f3a4eac6d45cb73afbe1763e88e6a0f
6
+ metadata.gz: 0db33427235876fcd9d5f3f1c16ad38f3f0e30806febe59bce5da8d5516dbe7ee6c97163121b0f84de1c8e9fd8971d6cedd5bb1dbf27074b030c14fac90e5ab3
7
+ data.tar.gz: 5084fb2c133abb9a083964ef84cb63d3e338c2d1008a8b3636aedfac3f7a03fc3efffc91f4543574efa4b83779db8c3ebff364dd05a2c9a2418e622a0aaa710b
data/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- ## 0.9.3.pre2
3
+ ## 0.9.3.pre4
4
4
  ### Added
5
5
  - Added validations block for conditional validation runs
6
6
  - you can now set the NO_FORKING=true ENV to prevent using the forking server in development.
@@ -10,12 +10,14 @@
10
10
  - You can now nest models on store. Previously store was limited to only storing either values or ArrayModels (associations). You can now store directly, in mongo this will be stored as a nested value.
11
11
  - Promises got more awesome. Promises in volt can now proxy methods to their future resolved value. Something like: ```promise.then {|v| v.name }``` can now be written simply as: ```promise.name``` It will still return a promise, but to make life easier:
12
12
  - All bindings now support promises directly.
13
- - You can now set/get properties directly on ```store``` and they will be saved to a ```root_stores_models``` table.
14
13
  - All code in config/initializers is now run on app startup.
15
14
  - All code in any components config/initializers (app/main/config/initializers/*.rb) is now run on the server during app startup. On the client, only the included components initializers will be run.
16
15
  - all initializers folders now support a ```client``` and ```server``` folder.
17
16
  - has_one is now supported.
18
17
  - You can now use .create to make a new item on a collection.
18
+ - .inspect for models is now cleaner
19
+ - Volt.current_user now works in HttpController's
20
+ - You can now add your own middleware to the middleware stack. (see docs)
19
21
 
20
22
  ### Changed
21
23
  - All methods on ArrayModel's under the store collection now return a Promise.
@@ -30,6 +32,8 @@
30
32
  - You can now use .each in attribute bindings.
31
33
  - We moved to csso as the css compressor because it does not require libv8, only an execjs runtime.
32
34
  - Each bindings now support promises.
35
+ - Volt.fetch_current_user has been deprecated and Volt.current_user now returns a promise.
36
+ - Volt.current_user? now returns a promise that yields a boolean
33
37
 
34
38
  ## 0.9.2
35
39
  ### Changed
@@ -2,6 +2,11 @@ require 'bcrypt' unless RUBY_PLATFORM == 'opal'
2
2
 
3
3
  module Volt
4
4
  class User < Model
5
+ field :username
6
+ field :email
7
+ field :name
8
+ field :password
9
+
5
10
  # returns login field name depending on config settings
6
11
  def self.login_field
7
12
  if Volt.config.try(:public).try(:auth).try(:use_username)
@@ -13,7 +13,7 @@ class StoreTasks < Volt::Task
13
13
  collection = store.send(:"_#{path[-2]}")
14
14
 
15
15
  # See if the model has already been made
16
- collection.where(id: data[:id]).fetch_first do |model|
16
+ collection.where(id: data[:id]).first.then do |model|
17
17
  # Otherwise assign to the collection
18
18
  model ||= collection
19
19
 
@@ -68,7 +68,7 @@ class StoreTasks < Volt::Task
68
68
  query = store.get(collection).where(id: id)
69
69
  end
70
70
 
71
- query.fetch_first do |model|
71
+ query.first.then do |model|
72
72
  if model
73
73
  if model.can_delete?
74
74
  db.delete(collection, 'id' => id)
@@ -11,7 +11,7 @@ class UserTasks < Volt::Task
11
11
 
12
12
  # During login we need access to the user's info even though we aren't the user
13
13
  Volt.skip_permissions do
14
- store._users.where(query).fetch_first do |user|
14
+ store._users.where(query).first.then do |user|
15
15
  fail VoltUserError, 'User could not be found' unless user
16
16
 
17
17
  match_pass = BCrypt::Password.new(user._hashed_password)
@@ -26,8 +26,6 @@ module Volt
26
26
 
27
27
  require 'volt/server/rack/component_paths'
28
28
  require 'volt/server/rack/component_code'
29
- require 'volt/server/rack/opal_files'
30
- require 'volt/server/rack/index_files'
31
29
  require 'volt/server/component_handler'
32
30
 
33
31
  @app_path = File.expand_path(File.join(@root_path, 'app'))
@@ -33,7 +33,12 @@ class Generate < Thor
33
33
  def gem(name)
34
34
  require 'volt/cli/new_gem'
35
35
 
36
+ # remove prefixed volt-
37
+ name = name.gsub(/^volt[-]/, '')
38
+
36
39
  if name =~ /[-]/
40
+ require 'volt'
41
+ require 'volt/extra_core/logger'
37
42
  Volt.logger.error('Gem names should use underscores for their names. Currently volt only supports a single namespace for a component.')
38
43
  return
39
44
  end
@@ -62,12 +67,12 @@ class Generate < Thor
62
67
  method_option :name, type: :string, banner: 'The name of the model controller.'
63
68
  method_option :component, type: :string, default: 'main', banner: 'The component the controller should be created in.', required: false
64
69
  def controller(name, component = 'main')
65
- controller_name = name.underscore.pluralize + '_controller' unless name =~ /_controller$/
70
+ controller_name = name.underscore + '_controller' unless name =~ /_controller$/
66
71
  output_file = Dir.pwd + "/app/#{component.underscore}/controllers/#{controller_name}.rb"
67
- spec_file = Dir.pwd + "/spec/app/#{component.underscore}/integration/#{name.underscore.pluralize}_spec.rb"
72
+ spec_file = Dir.pwd + "/spec/app/#{component.underscore}/integration/#{name.underscore}_spec.rb"
68
73
 
69
74
  template('controller/model_controller.rb.tt', output_file, component_module: component.camelize, model_controller_name: controller_name.camelize)
70
- template('controller/model_controller_spec.rb.tt', spec_file, describe: name.underscore.pluralize)
75
+ template('controller/model_controller_spec.rb.tt', spec_file, describe: name.underscore)
71
76
  end
72
77
 
73
78
  desc 'task NAME COMPONENT', 'Creates a task named NAME in the app folder of the component named COMPONENT.'
data/lib/volt/cli.rb CHANGED
@@ -87,21 +87,15 @@ module Volt
87
87
 
88
88
  def drop_collection(collection)
89
89
  ENV['SERVER'] = 'true'
90
- require 'mongo'
91
90
  require 'volt/boot'
92
91
 
93
92
  Volt.boot(Dir.pwd)
94
93
 
95
- host = Volt.config.db_host || 'localhost'
96
- port = Volt.config.db_port || Mongo::MongoClient::DEFAULT_PORT
97
- name = Volt.config.db_name
98
-
99
- say("Connecting to #{host}:#{port}", :yellow)
100
- db = Mongo::MongoClient.new(host, port).db(name)
94
+ db = Volt::DataStore.fetch
101
95
  drop = db.drop_collection(collection)
102
96
 
103
- say("Collection #{collection} on #{name} couldn't be dropped", :red) if drop == false
104
- say("Collection #{collection} on #{name} dropped", :green) if drop == true
97
+ say("Collection #{collection} could not be dropped", :red) if drop == false
98
+ say("Collection #{collection} dropped", :green) if drop == true
105
99
  end
106
100
 
107
101
  def self.source_root
@@ -62,7 +62,12 @@ module Volt
62
62
 
63
63
  begin
64
64
  filtered_callbacks.each do |callback|
65
- instance_eval(&callback)
65
+ case callback
66
+ when Symbol
67
+ send(callback)
68
+ when Proc
69
+ instance_eval(&callback)
70
+ end
66
71
  end
67
72
 
68
73
  return false
@@ -1,11 +1,17 @@
1
1
  require 'volt/server/rack/http_response_header'
2
2
  require 'volt/server/rack/http_response_renderer'
3
+ require 'volt/controllers/actions'
3
4
 
4
5
  module Volt
5
6
  # Allow you to create controllers that act as http endpoints
6
7
  class HttpController
7
- attr_accessor :response_body
8
- attr_reader :params, :response_headers, :request
8
+ include Actions
9
+
10
+ #TODO params is only public for testing
11
+ attr_accessor :params
12
+
13
+ # Setup before_action and after_action
14
+ setup_action_helpers_in_class(:before, :after)
9
15
 
10
16
  # Initialzed with the params parsed from the route and the HttpRequest
11
17
  def initialize(volt_app, params, request)
@@ -13,18 +19,21 @@ module Volt
13
19
  @response_headers = HttpResponseHeader.new
14
20
  @response_body = []
15
21
  @request = request
16
- @params = Volt::Model.new(params.symbolize_keys.merge(request.params), persistor: Volt::Persistors::Params)
22
+ @params = Volt::Model.new(request.params.symbolize_keys.merge(params), persistor: Volt::Persistors::Params)
17
23
  end
18
24
 
19
25
  def perform(action)
20
- # TODO: before actions
21
- send(action.to_sym)
22
- # TODO: after actions / around actions
26
+ filtered = run_actions(:before, action)
27
+ send(action.to_sym) unless filtered
28
+ run_actions(:after, action) unless filtered
23
29
  respond
24
30
  end
25
31
 
26
32
  private
27
33
 
34
+ attr_accessor :response_body
35
+ attr_reader :response_headers, :request
36
+
28
37
  def store
29
38
  @volt_app.page.store
30
39
  end
@@ -49,7 +58,7 @@ module Volt
49
58
  Rack::Response.new(response_body, response_status, response_headers)
50
59
  end
51
60
 
52
- # Get the http status code as integer
61
+ # Returns the http status code as integer
53
62
  def response_status
54
63
  if @response_status.is_a?(Symbol)
55
64
  Rack::Utils::SYMBOL_TO_STATUS_CODE[@response_status]
@@ -34,6 +34,27 @@ module Volt
34
34
  section.range
35
35
  end
36
36
 
37
+ # Walks the dom_nodes range until it finds an element. Typically this will
38
+ # be the container element without the whitespace text nodes.
39
+ def first_element
40
+ range = dom_nodes
41
+ nodes = `range.startContainer.childNodes`
42
+
43
+ start_index = `range.startOffset`
44
+ end_index = `range.endOffset`
45
+
46
+ start_index.upto(end_index) do |index|
47
+ node = `nodes[index]`
48
+
49
+ # Return if an element
50
+ if `node.nodeType === 1`
51
+ return node
52
+ end
53
+ end
54
+
55
+ return nil
56
+ end
57
+
37
58
  # yield_html renders the content passed into a tag as a string. You can ```.watch!```
38
59
  # ```yield_html``` and it will be run again when anything in the template changes.
39
60
  def yield_html
@@ -154,7 +154,11 @@ module Volt
154
154
  end
155
155
 
156
156
  def first
157
- self[0]
157
+ if persistor.is_a?(Persistors::ArrayStore)
158
+ limit(1)[0]
159
+ else
160
+ self[0]
161
+ end
158
162
  end
159
163
 
160
164
  # Return the first item in the collection, or create one if one does not
@@ -174,7 +178,21 @@ module Volt
174
178
  end
175
179
 
176
180
  def reverse
177
- super
181
+ @size_dep.depend
182
+ @array.reverse
183
+ end
184
+
185
+ # Array#select, with reactive notification
186
+ def select
187
+ new_array = []
188
+ @array.size.times do |index|
189
+ value = @array[index]
190
+ if yield(value)
191
+ new_array << value
192
+ end
193
+ end
194
+
195
+ new_array
178
196
  end
179
197
 
180
198
  # Return the model, on store, .all is proxied to wait for load and return
@@ -237,6 +255,11 @@ module Volt
237
255
  array
238
256
  end
239
257
 
258
+ def to_json
259
+ to_a.to_json
260
+ end
261
+
262
+
240
263
  def inspect
241
264
  Computation.run_without_tracking do
242
265
  # Track on size
@@ -262,7 +285,7 @@ module Volt
262
285
  end
263
286
 
264
287
  # We need to setup the proxy methods below where they are defined.
265
- proxy_with_load :first, :[], :size, :last, :reverse, :all, :to_a
288
+ proxy_with_load :[], :size, :last, :reverse, :all, :to_a
266
289
 
267
290
  end
268
291
  end
@@ -72,7 +72,7 @@ module Volt
72
72
  # model. That information is relayed to the ArrayModel so it knows when it can
73
73
  # stop subscribing.
74
74
  # @root_dep = Dependency.new(@listener_event_counter.method(:add), @listener_event_counter.method(:remove))
75
- @root_dep = Dependency.new(-> { add_list }, -> { remove_list })
75
+ @root_dep = Dependency.new(-> { retain }, -> { release })
76
76
 
77
77
  @deps = HashDependency.new
78
78
  @size_dep = Dependency.new
@@ -94,11 +94,11 @@ module Volt
94
94
  trigger!(:new, :new)
95
95
  end
96
96
 
97
- def add_list
97
+ def retain
98
98
  @listener_event_counter.add
99
99
  end
100
100
 
101
- def remove_list
101
+ def release
102
102
  @listener_event_counter.remove
103
103
  end
104
104
 
@@ -308,28 +308,23 @@ module Volt
308
308
 
309
309
  def inspect
310
310
  Computation.run_without_tracking do
311
- str = "<#{self.class}"
311
+ str = "#<#{self.class}"
312
+ # str += ":#{object_id}"
312
313
 
313
- # Get path, loaded_state, and persistor, but cache in local var
314
- # path = self.path
315
- # str += " path:#{path}" if path
316
-
317
- # loaded_state = self.loaded_state
318
- # str += " state:#{loaded_state}" if loaded_state
319
-
320
- # persistor = self.persistor
321
- # str += " persistor:#{persistor.inspect}" if persistor
314
+ # First, select all of the non-ArrayModel values
315
+ attrs = attributes.reject {|key, val| val.is_a?(ArrayModel) }.to_h
322
316
 
323
317
  # Show the :id first, then sort the rest of the attributes
324
- attrs = attributes.dup
325
-
326
318
  id = attrs.delete(:id)
319
+ id = id[0..3] + '..' + id[-4..-1] if id
327
320
 
328
321
  attrs = attrs.sort
329
- attrs.insert(0, [:id, id])
330
-
331
- str += " #{attrs.to_h.inspect}>"
322
+ attrs.insert(0, [:id, id]) if id
332
323
 
324
+ str += attrs.map do |key, value|
325
+ " #{key}: #{value.inspect}"
326
+ end.join(',')
327
+ str += '>'
333
328
  str
334
329
  end
335
330
  end
@@ -352,6 +347,10 @@ module Volt
352
347
  end
353
348
  end
354
349
 
350
+ def to_json
351
+ to_h.to_json
352
+ end
353
+
355
354
  private
356
355
  def run_initial_setup(initial_setup)
357
356
  # Save the changes
@@ -405,7 +404,7 @@ module Volt
405
404
 
406
405
  # Make an id if there isn't one yet
407
406
  if @attributes[:id].nil? && persistor.try(:auto_generate_id)
408
- self.id = generate_id
407
+ @attributes[:id] = generate_id
409
408
  end
410
409
  end
411
410
 
@@ -79,7 +79,7 @@ module Volt
79
79
  # sync with the database. The data is kept in memory and the model's
80
80
  # loaded_state is marked as "dirty" meaning it may not be in sync.
81
81
  def stop_listening
82
- Timers.next_tick do
82
+ Timers.client_set_timeout(5000) do
83
83
  Computation.run_without_tracking do
84
84
  if @listener_event_counter.count == 0
85
85
  if @added_to_query
@@ -210,6 +210,7 @@ module Volt
210
210
  # Returns a promise that is resolved/rejected when the query is complete. Any
211
211
  # passed block will be passed to the promises then. Then will be passed the model.
212
212
  def fetch(&block)
213
+ Volt.logger.warn('Deprication warning: in 0.9.3.pre4, all query methods on store now return Promises, so you can juse use .all or .first instead of .first')
213
214
  promise = Promise.new
214
215
 
215
216
  # Run the block after resolve if a block is passed in
@@ -230,15 +231,6 @@ module Volt
230
231
  promise
231
232
  end
232
233
 
233
- # A combination of .fetch and .each. Returns the fetch promise
234
- def fetch_each
235
- fetch do |items|
236
- items.each do |item|
237
- yield(item)
238
- end
239
- end
240
- end
241
-
242
234
  # Alias then for now
243
235
  # TODO: Deprecate
244
236
  alias_method :then, :fetch
@@ -9,28 +9,41 @@ require 'volt/models/root_models/root_models'
9
9
  module Volt
10
10
  module StoreRootHelpers
11
11
  def model_for_root
12
- root = get(:root_store_models).first_or_create
12
+ root = nil
13
+ Volt::Computation.run_without_tracking do
14
+ root = get(:root_store_models).first_or_create
15
+ end
13
16
 
14
17
  root
15
18
  end
16
19
 
17
20
 
18
21
  def get(attr_name, expand = false)
19
- if attr_name.singular? && attr_name.to_sym != :id
22
+ res = if attr_name.singular? && attr_name.to_sym != :id
23
+ puts "GET: #{attr_name}"
20
24
  model_for_root.get(attr_name, expand)
21
25
  else
22
26
  super
23
27
  end
28
+
29
+ # puts "GOT: #{res.inspect}"
30
+ res
24
31
  end
25
32
 
26
33
  def set(attr_name, value, &block)
27
34
  if attr_name.singular? && attr_name.to_sym != :id
28
- model_for_root.set(attr_name, value, &block)
35
+ puts "SET ATTR NAME: #{attr_name.inspect}: #{value.inspect}"
36
+ Volt::Computation.run_without_tracking do
37
+ model_for_root.then do |model|
38
+ model.set(attr_name, value, &block)
39
+ end
40
+ end
29
41
  else
30
42
  super
31
43
  end
44
+ # puts "SET---"
32
45
  end
33
46
  end
34
47
  end
35
48
 
36
- StoreRoot.send(:include, Volt::StoreRootHelpers)
49
+ # StoreRoot.send(:include, Volt::StoreRootHelpers)
@@ -217,7 +217,7 @@ module Volt
217
217
  def validation_class(validation, args)
218
218
  Volt.const_get(:"#{validation.camelize}Validator")
219
219
  rescue NameError => e
220
- puts "Unable to find #{validation} validator"
220
+ Volt.logger.error "Unable to find #{validation} validator"
221
221
  end
222
222
  end
223
223
  end
@@ -12,7 +12,7 @@ module Volt
12
12
 
13
13
  # Check if the value is taken
14
14
  # TODO: need a way to handle scope for unique
15
- return $page.store.get(model.path[-2]).where(query).first do |item|
15
+ return $page.store.get(model.path[-2]).where(query).first.then do |item|
16
16
  if item
17
17
  message = (args.is_a?(Hash) && args[:message]) || 'is already taken'
18
18
 
data/lib/volt/models.rb CHANGED
@@ -10,7 +10,7 @@ require 'volt/models/persistors/cookies' if RUBY_PLATFORM == 'opal'
10
10
  require 'volt/models/persistors/flash'
11
11
  require 'volt/models/persistors/local_store'
12
12
  require 'volt/models/root_models/root_models'
13
- require 'volt/models/root_models/store_root'
13
+ # require 'volt/models/root_models/store_root'
14
14
 
15
15
  # Fow now, we're keeping a volt copy of the promise library from opal 0.8,
16
16
  # since opal 0.7.x's version has some bugs.
@@ -19,12 +19,13 @@ module Volt
19
19
  begin
20
20
  @context.instance_eval(&@getter)
21
21
  rescue => e
22
- Volt.logger.error("AttributeBinding Error: #{e.inspect}")
22
+ getter_fail(e)
23
23
  ''
24
24
  end
25
- end.watch_and_resolve! do |result|
26
- update(result)
27
- end
25
+ end.watch_and_resolve!(
26
+ method(:update),
27
+ method(:getter_fail)
28
+ )
28
29
 
29
30
  @is_select = `#{element}.is('select')`
30
31
  @is_hidden = `#{element}.is('[type=hidden]')`
@@ -41,5 +41,22 @@ module Volt
41
41
  def remove_anchors
42
42
  @dom_section.remove_anchors if @dom_section
43
43
  end
44
+
45
+ # log out a message about a failed computation or Promise.
46
+ def getter_fail(error)
47
+ message = "#{self.class.to_s} Error: #{error.inspect}"
48
+
49
+ if RUBY_PLATFORM == 'opal'
50
+ if `#{@getter}`
51
+ message += "\n" + `#{@getter}.toString()`
52
+ end
53
+ else
54
+ if error.respond_to?(:backtrace)
55
+ message += "\n" + error.backtrace.join("\n")
56
+ end
57
+ end
58
+
59
+ Volt.logger.error(message)
60
+ end
44
61
  end
45
62
  end
@@ -8,18 +8,20 @@ module Volt
8
8
 
9
9
  def initialize(volt_app, target, context, binding_name, getter)
10
10
  super(volt_app, target, context, binding_name)
11
+ @getter = getter
11
12
 
12
13
  # Listen for changes
13
14
  @computation = lambda do
14
15
  begin
15
- res = @context.instance_eval(&getter)
16
+ @context.instance_eval(&getter)
16
17
  rescue => e
17
- Volt.logger.error("ContentBinding Error: #{e.inspect}")
18
+ getter_fail(e)
18
19
  ''
19
20
  end
20
- end.watch_and_resolve! do |result|
21
- update(result)
22
- end
21
+ end.watch_and_resolve!(
22
+ method(:update),
23
+ method(:getter_fail)
24
+ )
23
25
  end
24
26
 
25
27
  def update(value)