volt 0.9.5 → 0.9.6.pre1

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