volt 0.9.5 → 0.9.6.pre1

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/app/volt/tasks/query_tasks.rb +1 -1
  4. data/app/volt/tasks/user_tasks.rb +6 -0
  5. data/docs/UPGRADE_GUIDE.md +19 -0
  6. data/lib/volt.rb +0 -1
  7. data/lib/volt/cli.rb +3 -0
  8. data/lib/volt/cli/destroy.rb +8 -0
  9. data/lib/volt/cli/generate.rb +1 -105
  10. data/lib/volt/cli/generators.rb +111 -0
  11. data/lib/volt/controllers/model_controller.rb +1 -1
  12. data/lib/volt/helpers/time.rb +5 -5
  13. data/lib/volt/models/array_model.rb +1 -1
  14. data/lib/volt/models/helpers/base.rb +28 -12
  15. data/lib/volt/models/persistors/page.rb +6 -6
  16. data/lib/volt/models/persistors/query/query_listener.rb +1 -1
  17. data/lib/volt/page/bindings/each_binding.rb +1 -1
  18. data/lib/volt/page/channel.rb +18 -7
  19. data/lib/volt/page/tasks.rb +10 -4
  20. data/lib/volt/reactive/computation.rb +20 -8
  21. data/lib/volt/reactive/dependency.rb +3 -1
  22. data/lib/volt/server/component_templates.rb +4 -3
  23. data/lib/volt/server/middleware/default_middleware_stack.rb +6 -6
  24. data/lib/volt/server/rack/index_files.rb +0 -12
  25. data/lib/volt/server/rack/opal_files.rb +1 -1
  26. data/lib/volt/server/socket_connection_handler.rb +40 -1
  27. data/lib/volt/server/template_handlers/sprockets_component_handler.rb +5 -2
  28. data/lib/volt/server/template_handlers/view_processor.rb +4 -4
  29. data/lib/volt/tasks/task.rb +2 -1
  30. data/lib/volt/utils/csso_patch.rb +1 -1
  31. data/lib/volt/version.rb +1 -1
  32. data/lib/volt/volt/app.rb +9 -0
  33. data/lib/volt/volt/server_setup/app.rb +19 -0
  34. data/lib/volt/volt/users.rb +4 -0
  35. data/spec/apps/kitchen_sink/app/main/config/routes.rb +1 -0
  36. data/spec/apps/kitchen_sink/app/main/controllers/main_controller.rb +3 -0
  37. data/spec/apps/kitchen_sink/app/main/models/user.rb +18 -0
  38. data/spec/apps/kitchen_sink/app/main/views/main/callbacks.html +7 -0
  39. data/spec/integration/bindings_spec.rb +1 -1
  40. data/spec/integration/callbacks_spec.rb +31 -0
  41. data/spec/integration/todos_spec.rb +2 -2
  42. data/spec/models/array_model_spec.rb +13 -0
  43. data/spec/models/associations_spec.rb +1 -1
  44. data/spec/models/field_helpers_spec.rb +1 -1
  45. data/spec/models/model_spec.rb +18 -0
  46. data/spec/models/permissions_spec.rb +1 -2
  47. data/spec/models/persistors/page_spec.rb +19 -0
  48. data/spec/reactive/computation_spec.rb +33 -0
  49. data/spec/server/socket_connection_handler_spec.rb +99 -0
  50. data/spec/tasks/dispatcher_spec.rb +1 -1
  51. data/spec/tasks/user_tasks_spec.rb +1 -1
  52. data/spec/utils/task_argument_filtererer_spec.rb +1 -1
  53. data/templates/project/Gemfile.tt +1 -1
  54. data/templates/project/README.md.tt +1 -1
  55. data/templates/project/config/app.rb.tt +10 -0
  56. data/templates/view/index.html.tt +1 -1
  57. metadata +14 -5
  58. data/lib/volt/utils/set_patch.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d8e569efc8f53ee1bf074fa627fe11363ecff05f
4
- data.tar.gz: 3cbd7a15e0ff177982e46ab072ff00de7397ccc0
3
+ metadata.gz: 29fb4233ac14f8c7e64e2989d8b35afef2ad5c46
4
+ data.tar.gz: 88a4befaffac7d6f0eeba74dcc8c8ca5d4f792ee
5
5
  SHA512:
6
- metadata.gz: 00cb9cee43f56ab6ff097bdd4ea449308927563099fb997a2f5d689c68f28e5bcf1dd03e85cf42eb6383db00ac844facce62947cd9db359bf085ca78e307ae43
7
- data.tar.gz: c9529a9c9d50431f1756257cbfafb72f6dcf7285a1ba27990f18b2fd2cd5afb09f250a1f4236c313b898366184ab7eca255c66c625d900eeaa28b900fbe86cc9
6
+ metadata.gz: 3bd5f4136741543d23af692202144ae62b6f2b4ca239149da6449901b1ef98d8fe4a9cb5b17f747c09cc9918d29ff73a176b6a72ab7e4e7329ee317273100b75
7
+ data.tar.gz: 608bfcaa76b62dc7e0a7fa085ade630b7dafb466568d6ac046a4f3a3fe205f04fabec87a33f98b0b987d97357f22ffefdbb468118460e6b609eb44e3afc51943
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.9.6
4
+ ### Added
5
+ - @merongivian was kind enough to add Spanish traslations to the docs: (http://docs.voltframework.com/es/index.html)
6
+
7
+ ### Changed
8
+ - Finally tracked down an illusive memory leak.
9
+ - Computations now raise an error on their inital run, then log errors (via Volt.logger.error(..)) when running again (since they update on next tick)
10
+
3
11
  ## 0.9.5
4
12
  ### Breaking Changes
5
13
  - previously, we mounted the asset folders in components at /assets, and we also mounted the /app folder (and any gem's app folders') at /assets. This allowed you to usually access what you wanted at /assets, but resulted in conflicts. To ensure better component isolation, we now only mount the ```app``` folders. To make things clear, instead of sprockets being mounted at /assets, it is now mounted at /app. So the url for something in /app/main/assets/css/something.css can be accessed at (you guessed it) /app/main/assets/css/something.css
@@ -19,6 +27,8 @@
19
27
  - The ```generate gem``` generator has been improved to setup a dummy app and integration specs out of the box.
20
28
  - Tasks can now set (only set, not read) cookies on the client using the ```cookies``` collection.
21
29
  - Added ```login_as(user)``` method to Tasks and HttpController's.
30
+ - [asset_url helper](http://docs.voltframework.com/en/deployment/README.html) in css/sass and html files
31
+ - Sourcemaps are enabled by default, you can disable them with ```MAPS=false``` env. By default Volt and Opal code is not sourcemapped. To enable sourcemaps for everything run with: ```MAPS=all``` (note this has a slight performance hit) [Read the docs](http://docs.voltframework.com/en/docs/debugging.html) for more.
22
32
 
23
33
  ### Changed
24
34
  - fix issue with ```raw``` and promises (#275)
@@ -7,7 +7,7 @@ class QueryTasks < Volt::Task
7
7
  # For requests from the client (with @channel), we track the channel
8
8
  # so we can send the results back. Server side requests don't stay live,
9
9
  # they simply return to :dirty once the query is issued.
10
- @channel.user_id = Volt.current_user_id
10
+ @channel.update_user_id(Volt.current_user_id)
11
11
 
12
12
  # live_query.add_channel(@channel)
13
13
  end
@@ -21,4 +21,10 @@ class UserTasks < Volt::Task
21
21
  end
22
22
  end
23
23
  end
24
+
25
+ def logout
26
+ # Remove user_id from user's channel
27
+ @channel.update_user_id(nil) if @channel
28
+ end
29
+
24
30
  end
@@ -4,6 +4,25 @@ CSS url's now should be referenced either 1) as relative paths from the css file
4
4
 
5
5
  On models, .can_delete?, .can_read?, and .can_create? now return promises.
6
6
 
7
+ replace /config/base/index.html with:
8
+
9
+ ```ruby
10
+ <!DOCTYPE html>
11
+ <html>
12
+ <%# IMPORTANT: Please read before changing! %>
13
+ <%# This file is rendered on the server using ERB, so it does NOT use Volt's %>
14
+ <%# normal template system. You can add to it, but keep in mind the template %>
15
+ <%# language difference. This file handles auto-loading all JS/Opal and CSS. %>
16
+ <head>
17
+ <meta charset="UTF-8" />
18
+ <%= javascript_tags %>
19
+ <%= css_tags %>
20
+ </head>
21
+ <body>
22
+
23
+ </body>
24
+ </html>
25
+ ```
7
26
  Check the CHANGELOG for more info.
8
27
 
9
28
  # 0.9.3 to 0.9.4
data/lib/volt.rb CHANGED
@@ -5,7 +5,6 @@ require 'volt/reactive/dependency'
5
5
  require 'volt/utils/modes'
6
6
  require 'volt/utils/volt_user_error'
7
7
  require 'volt/utils/boolean_patch'
8
- require 'volt/utils/set_patch'
9
8
  require 'volt/utils/time_patch'
10
9
 
11
10
  require 'volt/config'
data/lib/volt/cli.rb CHANGED
@@ -3,7 +3,9 @@ require 'bundler/setup'
3
3
 
4
4
  require 'thor'
5
5
  require 'volt/extra_core/extra_core'
6
+ require 'volt/cli/generators'
6
7
  require 'volt/cli/generate'
8
+ require 'volt/cli/destroy'
7
9
  require 'volt/version'
8
10
  require 'volt/cli/bundle'
9
11
 
@@ -13,6 +15,7 @@ module Volt
13
15
  include Volt::Bundle
14
16
 
15
17
  register(Generate, 'generate', 'generate GENERATOR [args]', 'Run a generator.')
18
+ register(Destroy, 'destroy', 'destroy GENERATOR [args]', 'Delete files created by a generator.')
16
19
 
17
20
  desc 'new PROJECT_NAME', 'generates a new project.'
18
21
 
@@ -0,0 +1,8 @@
1
+ class Destroy < Thor
2
+ include Generators
3
+
4
+ def initialize(*)
5
+ super
6
+ self.behavior = :revoke
7
+ end
8
+ end
@@ -1,107 +1,3 @@
1
1
  class Generate < Thor
2
- include Thor::Actions
3
-
4
- desc 'model NAME COMPONENT', 'Creates a model named NAME in the component named COMPONENT'
5
- method_option :name, type: :string, banner: 'The name of the model.'
6
- method_option :component, type: :string, default: 'main', banner: 'The component the model should be created in.', required: false
7
- def model(name, component = 'main')
8
- output_file = Dir.pwd + "/app/#{component.underscore}/models/#{name.underscore.singularize}.rb"
9
- spec_file = Dir.pwd + "/spec/app/#{component.underscore}/models/#{name.underscore.pluralize}_spec.rb"
10
- template('model/model.rb.tt', output_file, model_name: name.camelize.singularize)
11
- template('model/model_spec.rb.tt', spec_file, model_name: name.camelize.singularize)
12
- end
13
-
14
- desc 'component NAME', 'Creates a component named NAME in the app folder.'
15
- method_option :name, type: :string, banner: 'The name of the component.'
16
- def component(name)
17
- name = name.underscore
18
- component_folder = Dir.pwd + "/app/#{name}"
19
- component_spec_folder = Dir.pwd + '/spec/app/' + name
20
- @component_name = name
21
- directory('component', component_folder, component_name: name)
22
- directory('component_specs', component_spec_folder)
23
- end
24
-
25
- desc 'gem GEM', 'Creates a component gem where you can share a component'
26
- method_option :bin, type: :boolean, default: false, aliases: '-b', banner: 'Generate a binary for your library.'
27
- method_option :test, type: :string, lazy_default: 'rspec', aliases: '-t', banner: "Generate a test directory for your library: 'rspec' is the default, but 'minitest' is also supported."
28
- method_option :edit, type: :string, aliases: '-e',
29
- lazy_default: [ENV['BUNDLER_EDITOR'], ENV['VISUAL'], ENV['EDITOR']].find { |e| !e.nil? && !e.empty? },
30
- required: false, banner: '/path/to/your/editor',
31
- desc: 'Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)'
32
- method_option :coc, :type => :boolean, :desc => "Generate a code of conduct file. Set a default with `bundle config gem.coc true`."
33
- method_option :mit, :type => :boolean, :desc => "Generate an MIT license file"
34
-
35
- def gem(name)
36
- require 'volt/cli/new_gem'
37
-
38
- # remove prefixed volt-
39
- name = name.gsub(/^volt[-]/, '')
40
-
41
- if name =~ /[-]/
42
- require 'volt'
43
- require 'volt/extra_core/logger'
44
- Volt.logger.error('Gem names should use underscores for their names. Currently volt only supports a single namespace for a component.')
45
- return
46
- end
47
-
48
- NewGem.new(self, name, options)
49
- end
50
-
51
- def self.source_root
52
- File.expand_path(File.join(File.dirname(__FILE__), '../../../templates'))
53
- end
54
-
55
- desc 'http_controller NAME COMPONENT', 'Creates an HTTP Controller named NAME in the .'
56
- method_option :name, type: :string, banner: 'The name of the HTTP Controller.'
57
- method_option :component, type: :string, default: 'main', banner: 'The component the http_controller should be created in.', required: false
58
- def http_controller(name, component = 'main')
59
- name = name.underscore + '_controller' unless name =~ /_controller$/
60
-
61
- output_file = Dir.pwd + "/app/#{component}/controllers/server/#{name.underscore}.rb"
62
- spec_file = Dir.pwd + "/spec/app/#{component.underscore}/controllers/server/#{name}_spec.rb"
63
-
64
- template('controller/http_controller.rb.tt', output_file, component_module: component.camelize, http_controller_name: name.camelize)
65
- template('controller/http_controller_spec.rb.tt', spec_file, component_module: component.camelize, http_controller_name: name.camelize)
66
- end
67
-
68
- desc 'controller NAME COMPONENT', 'Creates a model controller named NAME in the app folder of the component named COMPONENT.'
69
- method_option :name, type: :string, banner: 'The name of the model controller.'
70
- method_option :component, type: :string, default: 'main', banner: 'The component the controller should be created in.', required: false
71
- def controller(name, component = 'main')
72
- controller_name = name.underscore + '_controller' unless name =~ /_controller$/
73
- output_file = Dir.pwd + "/app/#{component.underscore}/controllers/#{controller_name}.rb"
74
- spec_file = Dir.pwd + "/spec/app/#{component.underscore}/integration/#{name.underscore}_spec.rb"
75
-
76
- template('controller/model_controller.rb.tt', output_file, component_module: component.camelize, model_controller_name: controller_name.camelize)
77
- template('controller/model_controller_spec.rb.tt', spec_file, describe: name.underscore)
78
- end
79
-
80
- desc 'task NAME COMPONENT', 'Creates a task named NAME in the app folder of the component named COMPONENT.'
81
- method_option :name, type: :string, banner: 'The name of the task.'
82
- method_option :component, type: :string, default: 'main', banner: 'The component the task should be created in.', required: false
83
- def task(name, component = 'main')
84
- name = name.underscore.gsub(/_tasks$/, '').singularize.gsub('_task', '') + '_task'
85
- output_file = Dir.pwd + "/app/#{component}/tasks/#{name}.rb"
86
- spec_file = Dir.pwd + "/spec/app/#{component}/tasks/#{name}_spec.rb"
87
- template('task/task.rb.tt', output_file, task_name: name.camelize.singularize)
88
- template('task/task_spec.rb.tt', spec_file, task_name: name.camelize.singularize)
89
- end
90
-
91
- desc 'view NAME COMPONENT', 'Creates a view named NAME in the app folder of the component named COMPONENT.'
92
- method_option :name, type: :string, banner: 'The name of the view.'
93
- method_option :component, type: :string, default: 'main', banner: 'The component the view should be created in.', required: false
94
- def view(name, component = 'main')
95
- name = name.underscore.pluralize
96
- view_folder = Dir.pwd + "/app/#{component}/views/#{name}/"
97
- directory('view', view_folder, view_name: name, component: component)
98
- controller(name, component) unless controller_exists?(name, component)
99
- end
100
-
101
- private
102
-
103
- def controller_exists?(name, component = 'main')
104
- dir = Dir.pwd + "/app/#{component}/controllers/"
105
- File.exist?(dir + name.downcase.underscore.singularize + '.rb')
106
- end
2
+ include Generators
107
3
  end
@@ -0,0 +1,111 @@
1
+ module Generators
2
+ def self.included(base)
3
+ base.class_eval do
4
+ include Thor::Actions
5
+
6
+ desc 'model NAME COMPONENT', 'Creates a model named NAME in the component named COMPONENT'
7
+ method_option :name, type: :string, banner: 'The name of the model.'
8
+ method_option :component, type: :string, default: 'main', banner: 'The component the model should be created in.', required: false
9
+ def model(name, component = 'main')
10
+ output_file = Dir.pwd + "/app/#{component.underscore}/models/#{name.underscore.singularize}.rb"
11
+ spec_file = Dir.pwd + "/spec/app/#{component.underscore}/models/#{name.underscore.pluralize}_spec.rb"
12
+ template('model/model.rb.tt', output_file, model_name: name.camelize.singularize)
13
+ template('model/model_spec.rb.tt', spec_file, model_name: name.camelize.singularize)
14
+ end
15
+
16
+ desc 'component NAME', 'Creates a component named NAME in the app folder.'
17
+ method_option :name, type: :string, banner: 'The name of the component.'
18
+ def component(name)
19
+ name = name.underscore
20
+ component_folder = Dir.pwd + "/app/#{name}"
21
+ component_spec_folder = Dir.pwd + '/spec/app/' + name
22
+ @component_name = name
23
+ directory('component', component_folder, component_name: name)
24
+ directory('component_specs', component_spec_folder)
25
+ end
26
+
27
+ desc 'gem GEM', 'Creates a component gem where you can share a component'
28
+ method_option :bin, type: :boolean, default: false, aliases: '-b', banner: 'Generate a binary for your library.'
29
+ method_option :test, type: :string, lazy_default: 'rspec', aliases: '-t', banner: "Generate a test directory for your library: 'rspec' is the default, but 'minitest' is also supported."
30
+ method_option :edit, type: :string, aliases: '-e',
31
+ lazy_default: [ENV['BUNDLER_EDITOR'], ENV['VISUAL'], ENV['EDITOR']].find { |e| !e.nil? && !e.empty? },
32
+ required: false, banner: '/path/to/your/editor',
33
+ desc: 'Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)'
34
+ method_option :coc, type: :boolean, desc: "Generate a code of conduct file. Set a default with `bundle config gem.coc true`."
35
+ method_option :mit, type: :boolean, desc: "Generate an MIT license file"
36
+
37
+ def gem(name)
38
+ require 'volt/cli/new_gem'
39
+
40
+ # remove prefixed volt-
41
+ name = name.gsub(/^volt[-]/, '')
42
+
43
+ if name =~ /[-]/
44
+ require 'volt'
45
+ require 'volt/extra_core/logger'
46
+ Volt.logger.error('Gem names should use underscores for their names. Currently volt only supports a single namespace for a component.')
47
+ return
48
+ end
49
+
50
+ NewGem.new(self, name, options)
51
+ end
52
+
53
+ def self.source_root
54
+ File.expand_path(File.join(File.dirname(__FILE__), '../../../templates'))
55
+ end
56
+
57
+ desc 'http_controller NAME COMPONENT', 'Creates an HTTP Controller named NAME in the .'
58
+ method_option :name, type: :string, banner: 'The name of the HTTP Controller.'
59
+ method_option :component, type: :string, default: 'main', banner: 'The component the http_controller should be created in.', required: false
60
+ def http_controller(name, component = 'main')
61
+ name = name.underscore + '_controller' unless name =~ /_controller$/
62
+
63
+ output_file = Dir.pwd + "/app/#{component}/controllers/server/#{name.underscore}.rb"
64
+ spec_file = Dir.pwd + "/spec/app/#{component.underscore}/controllers/server/#{name}_spec.rb"
65
+
66
+ template('controller/http_controller.rb.tt', output_file, component_module: component.camelize, http_controller_name: name.camelize)
67
+ template('controller/http_controller_spec.rb.tt', spec_file, component_module: component.camelize, http_controller_name: name.camelize)
68
+ end
69
+
70
+ desc 'controller NAME COMPONENT', 'Creates a model controller named NAME in the app folder of the component named COMPONENT.'
71
+ method_option :name, type: :string, banner: 'The name of the model controller.'
72
+ method_option :component, type: :string, default: 'main', banner: 'The component the controller should be created in.', required: false
73
+ def controller(name, component = 'main')
74
+ controller_name = name.underscore + '_controller' unless name =~ /_controller$/
75
+ output_file = Dir.pwd + "/app/#{component.underscore}/controllers/#{controller_name}.rb"
76
+ spec_file = Dir.pwd + "/spec/app/#{component.underscore}/integration/#{name.underscore}_spec.rb"
77
+
78
+ template('controller/model_controller.rb.tt', output_file, component_module: component.camelize, model_controller_name: controller_name.camelize)
79
+ template('controller/model_controller_spec.rb.tt', spec_file, describe: name.underscore)
80
+ end
81
+
82
+ desc 'task NAME COMPONENT', 'Creates a task named NAME in the app folder of the component named COMPONENT.'
83
+ method_option :name, type: :string, banner: 'The name of the task.'
84
+ method_option :component, type: :string, default: 'main', banner: 'The component the task should be created in.', required: false
85
+ def task(name, component = 'main')
86
+ name = name.underscore.gsub(/_tasks$/, '').singularize.gsub('_task', '') + '_task'
87
+ output_file = Dir.pwd + "/app/#{component}/tasks/#{name}.rb"
88
+ spec_file = Dir.pwd + "/spec/app/#{component}/tasks/#{name}_spec.rb"
89
+ template('task/task.rb.tt', output_file, task_name: name.camelize.singularize)
90
+ template('task/task_spec.rb.tt', spec_file, task_name: name.camelize.singularize)
91
+ end
92
+
93
+ desc 'view NAME COMPONENT', 'Creates a view named NAME in the app folder of the component named COMPONENT.'
94
+ method_option :name, type: :string, banner: 'The name of the view.'
95
+ method_option :component, type: :string, default: 'main', banner: 'The component the view should be created in.', required: false
96
+ def view(name, component = 'main')
97
+ name = name.underscore.pluralize
98
+ view_folder = Dir.pwd + "/app/#{component}/views/#{name}/"
99
+ directory('view', view_folder, view_name: name, component: component)
100
+ controller(name, component) unless controller_exists?(name, component)
101
+ end
102
+
103
+ private
104
+
105
+ def controller_exists?(name, component = 'main')
106
+ dir = Dir.pwd + "/app/#{component}/controllers/"
107
+ File.exist?(dir + name.downcase.underscore.singularize + '.rb')
108
+ end
109
+ end
110
+ end
111
+ end
@@ -71,7 +71,7 @@ module Volt
71
71
  # ```yield_html``` and it will be run again when anything in the template changes.
72
72
  def yield_html
73
73
  if (template_path = attrs.content_template_path)
74
- @yield_renderer ||= StringTemplateRenderer.new(@volt_app, self, template_path)
74
+ @yield_renderer ||= StringTemplateRenderer.new(@volt_app, attrs.content_controller, template_path)
75
75
  @yield_renderer.html
76
76
  else
77
77
  # no template, empty string
@@ -28,16 +28,16 @@ class Time
28
28
 
29
29
  def beginning_of_day
30
30
  #(self - seconds_since_midnight).change(usec: 0)
31
- change(:hour => 0, :min => 0, :sec => 0)
31
+ change(hour: 0, min: 0, sec: 0)
32
32
  end
33
33
 
34
34
  # Returns a new Time representing the end of the day, 23:59:59.999999 (.999999999 in ruby1.9)
35
35
  def end_of_day
36
36
  change(
37
- :hour => 23,
38
- :min => 59,
39
- :sec => 59,
40
- # :usec => Rational(999999999, 1000)
37
+ hour: 23,
38
+ min: 59,
39
+ sec: 59,
40
+ # usec: Rational(999999999, 1000)
41
41
  )
42
42
  end
43
43
  end
@@ -323,7 +323,7 @@ module Volt
323
323
  end
324
324
 
325
325
  # Set the new path and the persistor.
326
- model.options = @options.merge(path: @options[:path] + [:[]])
326
+ model.options = @options.merge(parent: self, path: @options[:path] + [:[]])
327
327
  else
328
328
  model = wrap_values([model]).first
329
329
  end
@@ -74,27 +74,43 @@ module Volt
74
74
  # Gets the class for a model at the specified path.
75
75
  def class_at_path(path)
76
76
  if path
77
- begin
78
- # remove the _ and then singularize/pluralize
79
- if path.last == :[]
80
- index = -2
81
- else
82
- index = -1
83
- end
77
+ # remove the _ and then singularize/pluralize
78
+ if path.last == :[]
79
+ index = -2
80
+ else
81
+ index = -1
82
+ end
84
83
 
85
- # process_class_name is defined by Model/ArrayModel as
86
- # singularize/pluralize
87
- klass_name = process_class_name(klass_name = path[index]).camelize
84
+ # process_class_name is defined by Model/ArrayModel as
85
+ # singularize/pluralize
86
+ klass_name = process_class_name(klass_name = path[index]).camelize
88
87
 
88
+ begin
89
89
  # Lookup the class
90
90
  klass = Object.const_get(klass_name)
91
91
 
92
92
  # Use it if it is a model
93
- klass = self unless klass < self
93
+ return (klass < self ? klass : (klass = self))
94
94
  rescue NameError => e
95
95
  # Ignore exception, just means the model isn't defined
96
- klass = self
96
+ #
97
+ return klass = self if klass_name.singular?
98
+ end
99
+
100
+ # Checl for special case where we are subclassing a Volt::Model that has a custom Volt::ArrayModel
101
+ begin
102
+ # Get the pluralised name of the superclass of the model
103
+ super_klass_name = Object.const_get(klass_name.singularize).superclass.to_s.pluralize
104
+
105
+ # Get the class, rescue if not found
106
+ klass = Object.const_get(super_klass_name)
107
+
108
+ klass = self unless klass < self
109
+ rescue NameError => e
110
+ # Ignore exception, array model isn't defined.
111
+ return klass = self
97
112
  end
113
+
98
114
  else
99
115
  klass = self
100
116
  end
@@ -9,14 +9,14 @@ module Volt
9
9
 
10
10
  def where(query)
11
11
  @model.select do |model|
12
- # Filter through each part of the query and make sure it matches.
13
- query.each_pair do |key, value|
14
- next false unless model.get(key) == value
12
+ # Run through each key in the query and make sure the value matches.
13
+ # We use .all? because once one fails to match, we can return false,
14
+ # because it wouldn't match as a whole.
15
+ query.all? do |key, value|
16
+ model.get(key) == value
15
17
  end
16
-
17
- true
18
18
  end
19
19
  end
20
20
  end
21
21
  end
22
- end
22
+ end