volt 0.9.1.pre4 → 0.9.1.pre5

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +1 -0
  5. data/app/volt/tasks/query_tasks.rb +4 -3
  6. data/app/volt/tasks/store_tasks.rb +1 -1
  7. data/lib/volt/boot.rb +8 -7
  8. data/lib/volt/cli/asset_compile.rb +1 -1
  9. data/lib/volt/cli/console.rb +14 -3
  10. data/lib/volt/cli/new_gem.rb +3 -3
  11. data/lib/volt/cli.rb +3 -3
  12. data/lib/volt/config.rb +7 -1
  13. data/lib/volt/data_stores/base.rb +7 -0
  14. data/lib/volt/data_stores/data_store.rb +10 -3
  15. data/lib/volt/data_stores/mongo_driver.rb +58 -7
  16. data/lib/volt/models/associations.rb +2 -2
  17. data/lib/volt/models/persistors/array_store.rb +24 -6
  18. data/lib/volt/models/persistors/base.rb +4 -0
  19. data/lib/volt/models/persistors/model_store.rb +4 -15
  20. data/lib/volt/page/bindings/attribute_binding.rb +17 -15
  21. data/lib/volt/page/bindings/each_binding.rb +14 -17
  22. data/lib/volt/page/bindings/view_binding/controller_handler.rb +24 -0
  23. data/lib/volt/page/bindings/view_binding.rb +10 -30
  24. data/lib/volt/page/document_events.rb +7 -4
  25. data/lib/volt/page/page.rb +19 -13
  26. data/lib/volt/page/path_string_renderer.rb +41 -0
  27. data/lib/volt/page/targets/dom_section.rb +5 -2
  28. data/lib/volt/reactive/computation.rb +3 -1
  29. data/lib/volt/reactive/reactive_accessors.rb +8 -7
  30. data/lib/volt/reactive/reactive_array.rb +2 -0
  31. data/lib/volt/server/component_handler.rb +3 -3
  32. data/lib/volt/server/component_templates.rb +32 -6
  33. data/lib/volt/server/forking_server.rb +4 -2
  34. data/lib/volt/server/rack/asset_files.rb +5 -1
  35. data/lib/volt/server/rack/component_paths.rb +6 -4
  36. data/lib/volt/server/rack/opal_files.rb +16 -11
  37. data/lib/volt/server/rack/quiet_common_logger.rb +1 -1
  38. data/lib/volt/server.rb +1 -1
  39. data/lib/volt/spec/setup.rb +1 -1
  40. data/lib/volt/version.rb +5 -0
  41. data/lib/volt/volt/app.rb +12 -2
  42. data/spec/apps/kitchen_sink/app/main/views/mailers/welcome.email +12 -0
  43. data/spec/integration/http_endpoints_spec.rb +1 -3
  44. data/spec/integration/user_spec.rb +0 -10
  45. data/spec/models/associations_spec.rb +0 -3
  46. data/spec/models/model_spec.rb +13 -0
  47. data/spec/models/persistors/flash_spec.rb +45 -0
  48. data/spec/models/validators/phone_number_validator_spec.rb +2 -2
  49. data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +0 -5
  50. data/spec/page/path_string_renderer_spec.rb +23 -0
  51. data/spec/page/sub_context_spec.rb +1 -0
  52. data/spec/router/routes_spec.rb +24 -5
  53. data/spec/server/html_parser/view_handler_spec.rb +20 -0
  54. data/spec/server/rack/quite_common_logger_spec.rb +3 -3
  55. data/spec/spec_helper.rb +0 -4
  56. data/spec/tasks/query_tracker_spec.rb +30 -0
  57. data/templates/newgem/lib/newgem/version.rb.tt +7 -0
  58. data/templates/newgem/newgem.gemspec.tt +2 -4
  59. data/templates/project/Gemfile.tt +5 -2
  60. data/templates/project/config/app.rb.tt +49 -1
  61. data/volt.gemspec +12 -10
  62. metadata +24 -28
  63. data/VERSION +0 -1
  64. data/app/volt/tasks/live_query/data_store.rb +0 -33
  65. data/templates/newgem/VERSION +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 112adfde352ea21c2d38e0f6cc3e1f0974f12690
4
- data.tar.gz: 0fa53b549be59a3edf910dd28397c07148297a36
3
+ metadata.gz: 2f83c12e036d4b26d94015e199d1721c7bec82cf
4
+ data.tar.gz: a6475a6f6e230f0f7d411f17a03a3bc7e15ecc3f
5
5
  SHA512:
6
- metadata.gz: d50022986eb78ea62fecf9c75465d0839a40c4d5bf2debbda31e469c04d36b14e774813192479482f7bb6cb3ede05ece3fc8b77bd0afc3bf25f4000d582886ee
7
- data.tar.gz: 464c2c73e009e3a3edcce0d2ea70c42023a6e832878652263a462b6ddf917ec440bf95441766bcac440d8f81a4539e33277272940aab3b3b34be5450aae6009d
6
+ metadata.gz: 09519287d313bb3bbcdb4fc5190e67a7ab3f7d2152ddbf4a13ffecaa81fdf63043bbb2ef62d6def2fd5c28e17b048f3008e67629e12ad7b49b63c882d4c45a8d
7
+ data.tar.gz: bf82e809508689cf4fc749f7dc1c6a23690e4eff81db652d6dc21ced81971195b396bfe75b5d0f6522534a63d4c480359cab8f27f6cb88058ca18b0ced74a749
data/CHANGELOG.md CHANGED
@@ -10,6 +10,9 @@
10
10
  - made it so <:SectionName> can be accessed by <:section_name /> tag
11
11
  - fixed issue with if bindings not resolving some promises.
12
12
  - fixed issue with require's in controllers.
13
+ - fix class formatting issue with Pry.
14
+ - Bundler.require is now called for the correct env when 'volt/boot' is included. (We weren't planning to do this, but it does make life so much easier)
15
+ - opal-jquery was removed as a dependency. If you want to use it again, add ```gem 'opal-jquery'``` to your Gemfile and add ```require 'opal/jquery'` to your MainController.
13
16
 
14
17
 
15
18
  ## 0.9.0
data/CONTRIBUTING.md CHANGED
@@ -58,7 +58,7 @@ BROWSER=firefox bundle exec rake
58
58
 
59
59
  #### Write Tests
60
60
 
61
- Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [spec/volt](spec/volt).
61
+ Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [specs](https://github.com/voltrb/volt/tree/master/spec).
62
62
 
63
63
  We definitely appreciate pull requests that highlight or reproduce a problem, even without a fix.
64
64
 
data/README.md CHANGED
@@ -3,6 +3,7 @@
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)
5
5
  [![Inline docs](http://inch-ci.org/github/voltrb/volt.svg?branch=master)](http://inch-ci.org/github/voltrb/volt)
6
+ [![License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](http://opensource.org/licenses/MIT)
6
7
 
7
8
  For the current status of Volt, read: http://voltframework.com/blog
8
9
 
@@ -1,18 +1,19 @@
1
- require_relative 'live_query/data_store'
2
1
  require_relative 'live_query/live_query_pool'
3
2
 
4
3
  class QueryTasks < Volt::Task
5
- @@live_query_pool = LiveQueryPool.new(DataStore.new)
6
4
  @@channel_live_queries = {}
7
5
 
8
6
  def self.live_query_pool
9
- @@live_query_pool
7
+ @@live_query_pool ||= LiveQueryPool.new(Volt::DataStore.fetch)
10
8
  end
11
9
 
12
10
  # The dispatcher passes its self in
13
11
  def initialize(channel, dispatcher = nil)
14
12
  @channel = channel
15
13
  @dispatcher = dispatcher
14
+
15
+ # Load the query pool if not already setup
16
+ self.class.live_query_pool
16
17
  end
17
18
 
18
19
  def add_listener(collection, query)
@@ -77,7 +77,7 @@ class StoreTasks < Volt::Task
77
77
  query.fetch_first do |model|
78
78
  if model
79
79
  if model.can_delete?
80
- db[collection].remove('_id' => id)
80
+ db.delete('_id' => id)
81
81
  else
82
82
  raise "Permissions did not allow #{collection} #{id} to be deleted."
83
83
  end
data/lib/volt/boot.rb CHANGED
@@ -1,3 +1,11 @@
1
+ unless RUBY_PLATFORM == 'opal'
2
+ # An option to skip requiring.
3
+ unless ENV['SKIP_BUNDLER_REQUIRE']
4
+ # Require in gems
5
+ Bundler.require((ENV['VOLT_ENV'] || ENV['RACK_ENV'] || :development).to_sym)
6
+ end
7
+ end
8
+
1
9
  require 'volt/models'
2
10
  require 'volt/server/rack/component_paths'
3
11
 
@@ -10,13 +18,6 @@ require 'volt/volt/app'
10
18
 
11
19
  module Volt
12
20
  def self.boot(app_path)
13
- # Run the app config to load all users config files
14
- unless RUBY_PLATFORM == 'opal'
15
- if Volt.server?
16
- $page = Page.new
17
- end
18
- end
19
-
20
21
  # Boot the app
21
22
  App.new(app_path)
22
23
  end
@@ -80,7 +80,7 @@ module Volt
80
80
  end
81
81
 
82
82
  def write_component_js
83
- javascript_code = @component_handler.compile_for_component('main')
83
+ javascript_code = @component_handler.compile_for_component('main', true)
84
84
 
85
85
  path = File.join(Volt.root, '/public/components/main.js')
86
86
  write_file(path, javascript_code)
@@ -29,6 +29,17 @@ end
29
29
 
30
30
  module Volt
31
31
  class Console
32
+ module Helpers
33
+ def store
34
+ $page.store
35
+ end
36
+
37
+ def page
38
+ $page.page
39
+ end
40
+ end
41
+
42
+
32
43
  def self.start
33
44
  require 'pry'
34
45
 
@@ -46,10 +57,10 @@ module Volt
46
57
 
47
58
  Pry.config.prompt_name = 'volt'
48
59
 
49
- # start a REPL session
50
- # Pry.start
60
+ Pry.main.send(:include, Volt::Console::Helpers)
51
61
 
52
- $page.pry
62
+ # $page.pry
63
+ Pry.start
53
64
  end
54
65
  end
55
66
  end
@@ -51,8 +51,8 @@ class NewGem
51
51
  copy('newgem/gitignore.tt', '.gitignore')
52
52
  copy('newgem/newgem.gemspec.tt', "#{@name}.gemspec")
53
53
  copy('newgem/lib/newgem.rb.tt', "lib/#{@namespaced_path}.rb")
54
- copy('newgem/VERSION', 'VERSION')
55
54
  FileUtils.mkdir_p(File.join(@target, "lib/#{@namespaced_path}"))
55
+ copy('newgem/lib/newgem/version.rb.tt', "lib/#{@namespaced_path}/version.rb")
56
56
  end
57
57
 
58
58
  def copy_options
@@ -103,8 +103,8 @@ class NewGem
103
103
  end
104
104
 
105
105
  def volt_version_base
106
- version_path = File.join(File.dirname(__FILE__), '../../../VERSION')
107
- File.read(version_path).split('.').tap { |v| v[v.size - 1] = 0 }.join('.')
106
+ require 'volt/version'
107
+ Volt::Version::STRING.split('.').tap { |v| v[v.size - 1] = 0 }.join('.')
108
108
  end
109
109
 
110
110
  def get_constant_name
data/lib/volt/cli.rb CHANGED
@@ -4,6 +4,7 @@ require 'bundler/setup'
4
4
  require 'thor'
5
5
  require 'volt/extra_core/extra_core'
6
6
  require 'volt/cli/generate'
7
+ require 'volt/version'
7
8
 
8
9
  module Volt
9
10
  class CLI < Thor
@@ -17,8 +18,7 @@ module Volt
17
18
  require 'securerandom'
18
19
 
19
20
  # Grab the current volt version
20
- version = File.read(File.join(File.dirname(__FILE__), '../../VERSION'))
21
- directory('project', name, version: version, name: name)
21
+ directory('project', name, version: Volt::Version::STRING, name: name, domain: name.dasherize.downcase, app_name: name.capitalize)
22
22
 
23
23
  say 'Bundling Gems...'
24
24
  `cd #{name} && bundle`
@@ -114,5 +114,5 @@ end
114
114
  # Add in more features
115
115
  require 'volt/cli/asset_compile'
116
116
 
117
- puts "Volt #{File.read(File.join(File.dirname(__FILE__), '../../VERSION'))}"
117
+ puts "Volt #{Volt::Version::STRING}"
118
118
  Volt::CLI.start(ARGV)
data/lib/volt/config.rb CHANGED
@@ -51,7 +51,13 @@ else
51
51
  db_name: (ENV['DB_NAME'] || (app_name + '_' + Volt.env.to_s)).gsub('.', '_'),
52
52
  db_host: ENV['DB_HOST'] || 'localhost',
53
53
  db_port: (ENV['DB_PORT'] || 27_017).to_i,
54
- db_driver: ENV['DB_DRIVER'] || 'mongo'
54
+ db_driver: ENV['DB_DRIVER'] || 'mongo',
55
+
56
+ # a list of components which should be included in all components
57
+ default_components: ['volt'],
58
+
59
+ compress_javascript: Volt.env.production?,
60
+ compress_css: Volt.env.production?
55
61
  }
56
62
  end
57
63
 
@@ -0,0 +1,7 @@
1
+ module Volt
2
+ class DataStore
3
+ class Base
4
+
5
+ end
6
+ end
7
+ end
@@ -3,9 +3,16 @@ require 'volt/data_stores/mongo_driver'
3
3
  module Volt
4
4
  class DataStore
5
5
  def self.fetch
6
- if Volt.config.db_driver == 'mongo'
7
- MongoDriver.fetch
8
- else
6
+ # Cache the driver
7
+ return @driver if @driver
8
+
9
+ database_name = Volt.config.db_driver
10
+ driver_name = database_name.camelize + 'Driver'
11
+
12
+ begin
13
+ driver = self.const_get(driver_name)
14
+ @driver = MongoDriver.new
15
+ rescue NameError => e
9
16
  fail "#{database_name} is not a supported database"
10
17
  end
11
18
  end
@@ -1,17 +1,68 @@
1
+ require 'volt/data_stores/base'
1
2
  require 'mongo'
2
3
 
3
4
  module Volt
4
5
  class DataStore
5
- class MongoDriver
6
- def self.fetch
6
+ class MongoDriver < Base
7
+ attr_reader :db, :mongo_db
8
+
9
+ def initialize
7
10
  if Volt.config.db_uri.present?
8
- @@mongo_db ||= Mongo::MongoClient.from_uri(Volt.config.db_uri)
9
- @@db ||= @@mongo_db.db(Volt.config.db_uri.split('/').last || Volt.config.db_name)
11
+ @mongo_db ||= Mongo::MongoClient.from_uri(Volt.config.db_uri)
12
+ @db ||= @mongo_db.db(Volt.config.db_uri.split('/').last || Volt.config.db_name)
10
13
  else
11
- @@mongo_db ||= Mongo::MongoClient.new(Volt.config.db_host, Volt.config.db_path)
12
- @@db ||= @@mongo_db.db(Volt.config.db_name)
14
+ @mongo_db ||= Mongo::MongoClient.new(Volt.config.db_host, Volt.config.db_path)
15
+ @db ||= @mongo_db.db(Volt.config.db_name)
16
+ end
17
+ end
18
+
19
+ def insert(collection, values)
20
+ @db[collection].insert(values)
21
+ end
22
+
23
+ def update(collection, values)
24
+ # TODO: Seems mongo is dumb and doesn't let you upsert with custom id's
25
+ begin
26
+ @db[collection].insert(values)
27
+ rescue Mongo::OperationFailure => error
28
+ # Really mongo client?
29
+ if error.message[/^11000[:]/]
30
+ # Update because the id already exists
31
+ update_values = values.dup
32
+ id = update_values.delete(:_id)
33
+ @db[collection].update({ _id: id }, update_values)
34
+ else
35
+ return { error: error.message }
36
+ end
13
37
  end
14
- @@db
38
+
39
+ return nil
40
+ end
41
+
42
+ def query(collection, query)
43
+ allowed_methods = ['find', 'skip', 'limit']
44
+
45
+ cursor = @db[collection]
46
+
47
+ query.each do |query_part|
48
+ method_name, *args = query_part
49
+
50
+ unless allowed_methods.include?(method_name.to_s)
51
+ raise "`#{method_name}` is not part of a valid query"
52
+ end
53
+
54
+ cursor = cursor.send(method_name, *args)
55
+ end
56
+
57
+ cursor.to_a
58
+ end
59
+
60
+ def delete(collection, query)
61
+ @db[collection].remove(query)
62
+ end
63
+
64
+ def drop_database
65
+ db.connection.drop_database(Volt.config.db_name)
15
66
  end
16
67
  end
17
68
  end
@@ -36,7 +36,7 @@ module Volt
36
36
  # Currently the has_many and belongs_to associations only work on the store collection,
37
37
  # this method checks to make sure we are on store and returns the root reference to it.
38
38
  def association_with_root_model(method_name)
39
- persistor = self.persistor || (respond_to(:save_to) && save_to.persistor)
39
+ persistor = self.persistor || (respond_to?(:save_to) && save_to.persistor)
40
40
 
41
41
  # Check if we are on the store collection
42
42
  if persistor.is_a?(Volt::Persistors::ModelStore)
@@ -51,4 +51,4 @@ module Volt
51
51
  end
52
52
  end
53
53
  end
54
- end
54
+ end
@@ -18,6 +18,9 @@ module Volt
18
18
  end
19
19
 
20
20
  def initialize(model, tasks = nil)
21
+ # Keep a hash of all ids in this collection
22
+ @ids = {}
23
+
21
24
  super
22
25
 
23
26
  # The listener event counter keeps track of how many things are listening
@@ -226,15 +229,16 @@ module Volt
226
229
  # TODO: Deprecate
227
230
  alias_method :then, :fetch
228
231
 
229
- # Called from backend
232
+ # Called from backend when an item is added
230
233
  def add(index, data)
231
234
  $loading_models = true
232
235
 
233
236
  Model.no_validate do
234
237
  data_id = data['_id'] || data[:_id]
235
238
 
236
- # Don't add if the model is already in the ArrayModel
237
- unless @model.array.find { |v| v._id == data_id }
239
+ # Don't add if the model is already in the ArrayModel (from the client already)
240
+ unless @ids[data_id]
241
+ @ids[data_id] = true
238
242
  # Find the existing model, or create one
239
243
  new_model = @@identity_map.find(data_id) do
240
244
  new_options = @model.options.merge(path: @model.path + [:[]], parent: @model)
@@ -248,12 +252,14 @@ module Volt
248
252
  $loading_models = false
249
253
  end
250
254
 
255
+ # Called from the server when it removes an item.
251
256
  def remove(ids)
252
257
  $loading_models = true
253
258
  ids.each do |id|
254
259
  # TODO: optimize this delete so we don't need to loop
255
260
  @model.each_with_index do |model, index|
256
261
  if model._id == id
262
+ @ids.delete(id)
257
263
  del = @model.delete_at(index)
258
264
  break
259
265
  end
@@ -263,23 +269,35 @@ module Volt
263
269
  $loading_models = false
264
270
  end
265
271
 
272
+ # Called when all models are removed
273
+ def clear
274
+ @ids = {}
275
+ end
276
+
266
277
  def channel_name
267
278
  @model.path[-1]
268
279
  end
269
280
 
270
- # When a model is added to this collection, we call its "changed"
271
- # method. This should trigger a save.
281
+ # Called when the client adds an item.
272
282
  def added(model, index)
273
283
  if model.persistor
274
284
  # Tell the persistor it was added, return the promise
275
- model.persistor.add_to_collection
285
+ promise = model.persistor.add_to_collection
286
+
287
+ # Track the the model got added
288
+ @ids[model._id] = true
289
+
290
+ promise
276
291
  end
277
292
  end
278
293
 
294
+ # Called when the client removes an item
279
295
  def removed(model)
280
296
  if model.persistor
281
297
  # Tell the persistor it was removed
282
298
  model.persistor.remove_from_collection
299
+
300
+ @ids.delete(model._id)
283
301
  end
284
302
 
285
303
  if defined?($loading_models) && $loading_models
@@ -17,6 +17,10 @@ module Volt
17
17
  changed(attribute_name)
18
18
  end
19
19
 
20
+ # Called when the model is cleared (all child models removed)
21
+ def clear
22
+ end
23
+
20
24
  def event_added(event, first, first_for_event)
21
25
  end
22
26
 
@@ -195,21 +195,10 @@ module Volt
195
195
  id = values[:_id]
196
196
 
197
197
  # Try to create
198
- # TODO: Seems mongo is dumb and doesn't let you upsert with custom id's
199
- begin
200
- # values['_id'] = BSON::ObjectId('_id') if values['_id']
201
- db[collection].insert(values)
202
- rescue Mongo::OperationFailure => error
203
- # Really mongo client?
204
- if error.message[/^11000[:]/]
205
- # Update because the id already exists
206
- update_values = values.dup
207
- update_values.delete(:_id)
208
- db[collection].update({ _id: id }, update_values)
209
- else
210
- return { error: error.message }
211
- end
212
- end
198
+ update_result = db.update(collection, values)
199
+
200
+ # An error hash will be returned if the update doesn't work
201
+ return update_result if update_result
213
202
 
214
203
  QueryTasks.live_query_pool.updated_collection(collection.to_s, Thread.current['in_channel'])
215
204
  {}
@@ -26,26 +26,28 @@ module Volt
26
26
  update(result)
27
27
  end
28
28
 
29
- @is_radio = element.is('[type=radio]')
29
+ @is_radio = `#{element}.is('[type=radio]')`
30
30
  if @is_radio
31
- @selected_value = element.attr('value')
31
+ @selected_value = `#{element}.attr('value') || ''`
32
32
  end
33
33
 
34
34
  # Bind so when this value updates, we update
35
35
  case @attribute_name
36
36
  when 'value'
37
- element.on('input.attrbind') { changed }
37
+ changed_event = Proc.new { changed }
38
+ `#{element}.on('input.attrbind', #{changed_event})`
38
39
  when 'checked'
39
- element.on('change.attrbind') { |event| changed(event) }
40
+ changed_event = Proc.new { |event| changed(event) }
41
+ `#{element}.on('change.attrbind', #{changed_event})`
40
42
  end
41
43
  end
42
44
 
43
45
  def changed(event = nil)
44
46
  case @attribute_name
45
47
  when 'value'
46
- current_value = element.value
48
+ current_value = `#{element}.val() || ''`
47
49
  else
48
- current_value = element.is(':checked')
50
+ current_value = `#{element}.is(':checked')`
49
51
  end
50
52
 
51
53
  if @is_radio
@@ -59,7 +61,7 @@ module Volt
59
61
  end
60
62
 
61
63
  def element
62
- Element.find('#' + binding_name)
64
+ @element ||= `$('#' + #{binding_name})`
63
65
  end
64
66
 
65
67
  def update(new_value)
@@ -94,20 +96,20 @@ module Volt
94
96
  when 'value'
95
97
  # TODO: only update if its not the same, this keeps it from moving the
96
98
  # cursor in text fields.
97
- if val != element.value
98
- element.value = val
99
+ if val != `(#{element}.val() || '')`
100
+ `#{element}.val(#{val})`
99
101
  end
100
102
  when 'disabled'
101
103
  # Disabled is handled specially, you can either return a boolean:
102
104
  # (true being disabled, false not disabled), or you can optionally
103
105
  # include the "disabled" string. (or any string)
104
106
  if val != false && val.present?
105
- element.attr('disabled', 'disabled')
107
+ `#{element}.attr('disabled', 'disabled')`
106
108
  else
107
- element.remove_attr('disabled')
109
+ `#{element}.removeAttr('disabled')`
108
110
  end
109
111
  else
110
- element[@attribute_name] = val
112
+ `#{element}.attr(#{@attribute_name}, #{val})`
111
113
  end
112
114
  end
113
115
 
@@ -120,7 +122,7 @@ module Volt
120
122
  value = (@selected_value == value)
121
123
  end
122
124
 
123
- element.prop('checked', value)
125
+ `#{element}.prop('checked', #{value})`
124
126
  end
125
127
 
126
128
  def remove
@@ -128,9 +130,9 @@ module Volt
128
130
  # aren't responsible for it being there.
129
131
  case @attribute_name
130
132
  when 'value'
131
- element.off('input.attrbind', nil)
133
+ `#{element}.off('input.attrbind', #{nil})`
132
134
  when 'checked'
133
- element.off('change.attrbind', nil)
135
+ `#{element}.off('change.attrbind', #{nil})`
134
136
  end
135
137
 
136
138
  if @computation
@@ -31,16 +31,10 @@ module Volt
31
31
  Computation.run_without_tracking do
32
32
  # Adjust to the new size
33
33
  values = current_values(value)
34
+
34
35
  @value = values
35
36
 
36
- if @added_listener
37
- @added_listener.remove
38
- @added_listener = nil
39
- end
40
- if @removed_listener
41
- @removed_listener.remove
42
- @removed_listener = nil
43
- end
37
+ remove_listeners
44
38
 
45
39
  if @value.respond_to?(:on)
46
40
  @added_listener = @value.on('added') { |position| item_added(position) }
@@ -141,6 +135,17 @@ module Volt
141
135
  values
142
136
  end
143
137
 
138
+ def remove_listeners
139
+ if @added_listener
140
+ @added_listener.remove
141
+ @added_listener = nil
142
+ end
143
+ if @removed_listener
144
+ @removed_listener.remove
145
+ @removed_listener = nil
146
+ end
147
+ end
148
+
144
149
  # When this each_binding is removed, cleanup.
145
150
  def remove
146
151
  @computation.stop
@@ -151,15 +156,7 @@ module Volt
151
156
 
152
157
  @getter = nil
153
158
 
154
- if @added_listener
155
- @added_listener.remove
156
- @added_listener = nil
157
- end
158
-
159
- if @removed_listener
160
- @removed_listener.remove
161
- @removed_listener = nil
162
- end
159
+ remove_listeners
163
160
 
164
161
  if @templates
165
162
  template_count = @templates.size
@@ -40,5 +40,29 @@ module Volt
40
40
  # before_action chain was not stopped
41
41
  return false
42
42
  end
43
+
44
+ # Fetch the controller class
45
+ def self.get_controller_and_action(controller_path)
46
+ raise "Invalid controller path: #{controller_path.inspect}" unless controller_path && controller_path.size > 0
47
+
48
+ action = controller_path[-1]
49
+
50
+ # Get the constant parts
51
+ parts = controller_path[0..-2].map { |v| v.tr('-', '_').camelize }
52
+
53
+ # Do const lookups starting at object and working our way down.
54
+ # So Volt::ProgressBar would lookup Volt, then ProgressBar on Volt.
55
+ obj = Object
56
+ parts.each do |part|
57
+ if obj.const_defined?(part)
58
+ obj = obj.const_get(part)
59
+ else
60
+ # return a blank ModelController
61
+ return [ModelController, nil]
62
+ end
63
+ end
64
+
65
+ [obj, action]
66
+ end
43
67
  end
44
68
  end