volt 0.9.1.pre4 → 0.9.1.pre5

Sign up to get free protection for your applications and to get access to all the features.
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