volt 0.9.4.pre3 → 0.9.4.pre5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/CODE_OF_CONDUCT.md +15 -0
  4. data/README.md +2 -0
  5. data/app/volt/models/user.rb +6 -4
  6. data/lib/volt/boot.rb +0 -2
  7. data/lib/volt/cli/bundle.rb +29 -0
  8. data/lib/volt/cli/console.rb +2 -2
  9. data/lib/volt/cli/generate.rb +2 -0
  10. data/lib/volt/cli/new_gem.rb +23 -0
  11. data/lib/volt/cli.rb +15 -2
  12. data/lib/volt/controllers/collection_helpers.rb +34 -3
  13. data/lib/volt/controllers/http_controller.rb +1 -1
  14. data/lib/volt/controllers/model_controller.rb +9 -33
  15. data/lib/volt/helpers/time.rb +43 -0
  16. data/lib/volt/models/array_model.rb +96 -90
  17. data/lib/volt/models/buffer.rb +42 -7
  18. data/lib/volt/models/helpers/array_model.rb +15 -0
  19. data/lib/volt/models/helpers/base.rb +113 -0
  20. data/lib/volt/models/helpers/change_helpers.rb +91 -0
  21. data/lib/volt/models/helpers/dirty.rb +93 -0
  22. data/lib/volt/models/helpers/listener_tracker.rb +19 -0
  23. data/lib/volt/models/helpers/model.rb +15 -0
  24. data/lib/volt/models/model.rb +17 -12
  25. data/lib/volt/models/permissions.rb +1 -1
  26. data/lib/volt/models/persistors/array_store.rb +4 -0
  27. data/lib/volt/models/persistors/base.rb +10 -0
  28. data/lib/volt/models/persistors/cookies.rb +2 -0
  29. data/lib/volt/models/persistors/local_store.rb +3 -0
  30. data/lib/volt/models/persistors/model_store.rb +7 -0
  31. data/lib/volt/models/persistors/params.rb +4 -1
  32. data/lib/volt/models/persistors/query/query_listener.rb +1 -1
  33. data/lib/volt/models/url.rb +12 -7
  34. data/lib/volt/models/validators/unique_validator.rb +1 -1
  35. data/lib/volt/page/bindings/base_binding.rb +2 -2
  36. data/lib/volt/page/bindings/event_binding.rb +2 -2
  37. data/lib/volt/page/bindings/view_binding/controller_handler.rb +20 -0
  38. data/lib/volt/page/bindings/view_binding/view_lookup_for_path.rb +6 -4
  39. data/lib/volt/page/bindings/view_binding.rb +7 -7
  40. data/lib/volt/page/path_string_renderer.rb +2 -4
  41. data/lib/volt/page/targets/base_section.rb +3 -3
  42. data/lib/volt/page/targets/dom_template.rb +2 -2
  43. data/lib/volt/page/tasks.rb +6 -6
  44. data/lib/volt/page/template_renderer.rb +1 -1
  45. data/lib/volt/page/url_tracker.rb +4 -4
  46. data/lib/volt/reactive/reactive_array.rb +31 -20
  47. data/lib/volt/server/component_templates.rb +5 -5
  48. data/lib/volt/server/forking_server.rb +2 -2
  49. data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +3 -3
  50. data/lib/volt/server/message_bus/peer_to_peer.rb +7 -7
  51. data/lib/volt/server/rack/asset_files.rb +28 -8
  52. data/lib/volt/server/rack/component_paths.rb +4 -4
  53. data/lib/volt/server/rack/opal_files.rb +0 -1
  54. data/lib/volt/server/socket_connection_handler.rb +5 -2
  55. data/lib/volt/server.rb +0 -1
  56. data/lib/volt/spec/setup.rb +4 -5
  57. data/lib/volt/tasks/task.rb +2 -3
  58. data/lib/volt/utils/promise_extensions.rb +22 -6
  59. data/lib/volt/utils/time_patch.rb +12 -0
  60. data/lib/volt/utils/timers.rb +14 -2
  61. data/lib/volt/version.rb +1 -1
  62. data/lib/volt/volt/app.rb +44 -12
  63. data/lib/volt/volt/client_setup/browser.rb +113 -0
  64. data/lib/volt/volt/repos.rb +48 -0
  65. data/lib/volt/volt/server_setup/app.rb +1 -2
  66. data/lib/volt/volt/templates.rb +39 -0
  67. data/lib/volt/volt/users.rb +4 -4
  68. data/lib/volt.rb +1 -0
  69. data/spec/apps/file_loading/app/disable_auto/assets/css/test1.css.scss +0 -0
  70. data/spec/apps/file_loading/app/disable_auto/assets/css/test2.css.scss +0 -0
  71. data/spec/apps/file_loading/app/disable_auto/assets/js/test1.js +0 -0
  72. data/spec/apps/file_loading/app/disable_auto/assets/js/test2.js +0 -0
  73. data/spec/apps/file_loading/app/disable_auto/config/dependencies.rb +3 -0
  74. data/spec/apps/file_loading/app/main/assets/css/test3.css +0 -0
  75. data/spec/apps/file_loading/app/shared/config/dependencies.rb +1 -1
  76. data/spec/controllers/model_controller_spec.rb +7 -0
  77. data/spec/models/{model_helpers/model_helpers_spec.rb → helpers/base_spec.rb} +1 -1
  78. data/spec/models/helpers/model_spec.rb +26 -0
  79. data/spec/models/model_spec.rb +9 -0
  80. data/spec/models/persistors/params_spec.rb +1 -1
  81. data/spec/models/persistors/store_spec.rb +1 -0
  82. data/spec/page/bindings/content_binding_spec.rb +2 -4
  83. data/spec/page/bindings/each_binding_spec.rb +1 -4
  84. data/spec/page/bindings/if_binding_spec.rb +1 -4
  85. data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +17 -27
  86. data/spec/page/path_string_renderer_spec.rb +15 -4
  87. data/spec/server/rack/asset_files_spec.rb +88 -8
  88. data/spec/tasks/user_tasks_spec.rb +1 -1
  89. data/spec/utils/promise_extensions_spec.rb +22 -0
  90. data/spec/volt/repos_spec.rb +11 -0
  91. data/templates/newgem/CODE_OF_CONDUCT.md.tt +13 -0
  92. data/templates/project/app/main/config/routes.rb +4 -1
  93. metadata +34 -10
  94. data/lib/volt/models/model_helpers/dirty.rb +0 -88
  95. data/lib/volt/models/model_helpers/listener_tracker.rb +0 -15
  96. data/lib/volt/models/model_helpers/model_change_helpers.rb +0 -87
  97. data/lib/volt/models/model_helpers/model_helpers.rb +0 -110
  98. data/lib/volt/models/state_helpers.rb +0 -11
  99. data/lib/volt/page/page.rb +0 -190
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cbb8632dc480ad8c3e725df22fc50513d967aca8
4
- data.tar.gz: 7378a263f455ca95b60a04a75fa04409f9e0111f
3
+ metadata.gz: 336fa7176c4a60f3ea2757f0e78917d40f0faee7
4
+ data.tar.gz: 2911281e8bea55eca1fdc94568452f75012ee0aa
5
5
  SHA512:
6
- metadata.gz: 248aa3a47ef194d783dfd47c9ff794663170cccdd06aa66eb2bd4fb197ade72fac333f777d55134bc42d08fb65e25d525dbb9cf91ceb6c5ef53e20f25b7847af
7
- data.tar.gz: 09b7f6c57f8296c2079788e64372f3422b373d00b0ce9e64f351f36d640806961ec11df176ef302430d01e0cb9957e81a606fb2b1014a742d30ed7242d44a88d
6
+ metadata.gz: cb4724687642e194094184b6cd515da2fc1f78ff273ce2049d727dc1c3ea7f3fa07756827bb6b167545aea7f0cad83e40941cf0588a173c847901bd6359b7507
7
+ data.tar.gz: cb51999eb63a80ad0606e457457325a22fadcba5ec7453b1068d227885e65fec1de5fc4f063b6633fab8d310d92b6ae8976013526f2ec23afb6c0d276a2aeb73
data/CHANGELOG.md CHANGED
@@ -1,16 +1,29 @@
1
1
  # Change Log
2
2
 
3
3
  ## 0.9.4.pre1
4
+ ### Lingo Change
5
+ the base collections will now be called "Repositories" or "Repo's" for short. This will only matter directly for internal volt code, but for the data provider api, this will help.
6
+
4
7
  ### Added
5
8
  - ```root``` can now be called from a model to get the root model on the collection. (So if the model is on store, it will return ```store```)
6
9
  - ```store``` can now be called from inside of a model
10
+ - all repos (```store```, ```page```, ```cookies```, ```params```, etc...) now can be accessed outside of controllers and tasks with ```Volt.current_app.{repository}``` (```Volt.current_app.store``` for example)
7
11
  - before_save was added to models.
8
12
  - added ```cookies``` model for HttpController
13
+ - added support for serializing Time objects
14
+ - Model's now have a saved_state and saved? method.
15
+ - Volt.current_app now has ```store``` and ```page``` collections accessable from it, and is the preferred way to access those collections outside of controllers and tasks.
16
+
17
+ ### Removed
18
+ - The $page global was removed. Use ```Volt.current_app``` to get access to repos.
9
19
 
10
20
  ### Changed
11
21
  - fixed bug with ReactiveHash#to_json
12
22
  - fixed bug with field Numeric coersion
13
23
  - fixed issue with initializers not loading on client sometimes.
24
+ - fixed issue with user password change
25
+ - fix issue storing Time in a hash
26
+ - fixed issue with local_store not persisting in some cases
14
27
 
15
28
  ## 0.9.3
16
29
  [0.9.3 Update Blog Post](http://blog.voltframework.com/post/121128931859/0-9-3-stuff-you-asked-for)
@@ -0,0 +1,15 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
12
+
13
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
14
+
15
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)
data/README.md CHANGED
@@ -41,6 +41,8 @@ Rick Carlino has been putting together some great volt tutorial videos also.
41
41
  - [Build a Realtime Chat App with Volt](http://datamelon.io/blog/2015/building-a-chat-app-in-volt.html)
42
42
  - [Understanding Volt Views](http://datamelon.io/blog/2015/understanding-views-in-volt-with-a-card-game.html)
43
43
 
44
+ @anhbizcad maintains a [playlist of Volt related videos](https://www.youtube.com/watch?v=McxtO8ybxy8&list=PLmQFeDKFCPXatHb-zEXwfeMH01DPiZjP7).
45
+
44
46
  # Getting Help
45
47
 
46
48
  Have a question and need help? The volt team watches [stackoverflow](http://stackoverflow.com/search?q=voltrb) for questions and will get back to you quickly. Be sure to post the question with the #voltrb tag. If you have something you'd like to discuss, drop into our [gitter room](https://gitter.im/voltrb/volt).
@@ -42,11 +42,13 @@ module Volt
42
42
  def hash_password
43
43
  password = get('password')
44
44
 
45
- # Clear the password
46
- set('password', nil)
45
+ if password.present?
46
+ # Clear the password
47
+ set('password', nil)
47
48
 
48
- # Set the hashed_password field instead
49
- set('hashed_password', BCrypt::Password.create(password))
49
+ # Set the hashed_password field instead
50
+ set('hashed_password', BCrypt::Password.create(password))
51
+ end
50
52
  end
51
53
  end
52
54
  end
data/lib/volt/boot.rb CHANGED
@@ -11,8 +11,6 @@ require 'volt/server/rack/component_paths'
11
11
 
12
12
  if RUBY_PLATFORM == 'opal'
13
13
  require 'volt'
14
- else
15
- require 'volt/page/page'
16
14
  end
17
15
  require 'volt/volt/app'
18
16
 
@@ -0,0 +1,29 @@
1
+ module Volt
2
+ module Bundle
3
+ # Run bundle from inside of cli, borrowed from rails:
4
+ # https://github.com/rails/rails/blob/21f7bcbaa7709ed072bb2e1273d25c09eeaa26d9/railties/lib/rails/generators/app_base.rb
5
+ def bundle_command(command)
6
+ say_status :run, "bundle #{command}"
7
+
8
+ # We are going to shell out rather than invoking Bundler::CLI.new(command)
9
+ # because `volt new` loads the Thor gem and on the other hand bundler uses
10
+ # its own vendored Thor, which could be a different version. Running both
11
+ # things in the same process is a recipe for a night with paracetamol.
12
+ #
13
+ # We unset temporary bundler variables to load proper bundler and Gemfile.
14
+ #
15
+ # Thanks to James Tucker for the Gem tricks involved in this call.
16
+ _bundle_command = Gem.bin_path('bundler', 'bundle')
17
+
18
+ require 'bundler'
19
+ Bundler.with_clean_env do
20
+ full_command = %Q["#{Gem.ruby}" "#{_bundle_command}" #{command}]
21
+ if options[:quiet]
22
+ system(full_command, out: File::NULL)
23
+ else
24
+ system(full_command)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -52,11 +52,11 @@ module Volt
52
52
  class Console
53
53
  module Helpers
54
54
  def store
55
- @volt_app.page.store
55
+ @volt_app.store
56
56
  end
57
57
 
58
58
  def page
59
- @volt_app.page.page
59
+ @volt_app.page
60
60
  end
61
61
  end
62
62
 
@@ -29,6 +29,8 @@ class Generate < Thor
29
29
  lazy_default: [ENV['BUNDLER_EDITOR'], ENV['VISUAL'], ENV['EDITOR']].find { |e| !e.nil? && !e.empty? },
30
30
  required: false, banner: '/path/to/your/editor',
31
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"
32
34
 
33
35
  def gem(name)
34
36
  require 'volt/cli/new_gem'
@@ -9,6 +9,7 @@ class NewGem
9
9
  @thor = thor
10
10
  @component_name = name.chomp('/')
11
11
  @name = 'volt-' + @component_name # remove trailing slash if present
12
+ @shell = Thor::Base.shell.new
12
13
 
13
14
  if gem_is_available?
14
15
  @thor.say("#{@name} is available! Making gem files.", :green)
@@ -56,6 +57,24 @@ class NewGem
56
57
  end
57
58
 
58
59
  def copy_options
60
+ if @options[:coc] or yes?("\nDo you want to include a code of conduct in this gem?\n\n\
61
+ Codes of conduct can increase contributions to your project by contributors who \
62
+ prefer collaborative, safe spaces. You can read more about the code of conduct at \
63
+ contributor-covenant.org. Having a code of conduct means agreeing to the responsibility \
64
+ of enforcing it, so be sure that you are prepared to do that. For suggestions about \
65
+ how to enforce codes of conduct, see bit.ly/coc-enforcement.\n\ny/(n):")
66
+
67
+ copy('newgem/CODE_OF_CONDUCT.md.tt', 'CODE_OF_CONDUCT.md')
68
+ end
69
+
70
+ if @options[:mit] or yes?("\nDo you want to license your code permissively under the MIT license?\n\n\
71
+ This means that any other developer or company will be legally allowed to use your code \
72
+ for free as long as they admit you created it. You can read more about the MIT license \
73
+ at choosealicense.com/licenses/mit.\n\ny/(n):")
74
+
75
+ copy('newgem/LICENSE.txt.tt', 'LICENSE.txt')
76
+ end
77
+
59
78
  copy('newgem/bin/newgem.tt', "bin/#{@name}") if @options[:bin]
60
79
  copy('newgem/rspec.tt', '.rspec')
61
80
  copy('newgem/spec/spec_helper.rb.tt', 'spec/spec_helper.rb')
@@ -105,4 +124,8 @@ class NewGem
105
124
 
106
125
  constant_name
107
126
  end
127
+
128
+ def yes?(msg)
129
+ @shell.yes?(msg)
130
+ end
108
131
  end
data/lib/volt/cli.rb CHANGED
@@ -5,10 +5,12 @@ require 'thor'
5
5
  require 'volt/extra_core/extra_core'
6
6
  require 'volt/cli/generate'
7
7
  require 'volt/version'
8
+ require 'volt/cli/bundle'
8
9
 
9
10
  module Volt
10
11
  class CLI < Thor
11
12
  include Thor::Actions
13
+ include Volt::Bundle
12
14
 
13
15
  register(Generate, 'generate', 'generate GENERATOR [args]', 'Run a generator.')
14
16
 
@@ -20,10 +22,21 @@ module Volt
20
22
  # Grab the current volt version
21
23
  directory('project', name, version: Volt::Version::STRING, name: name, domain: name.dasherize.downcase, app_name: name.capitalize)
22
24
 
23
- say 'Bundling Gems...'
24
- `cd #{name} && bundle`
25
+ # Move into the directory
26
+ Dir.chdir(name) do
27
+ # bundle
28
+ bundle_command('install')
29
+ end
30
+
31
+ say ""
32
+ say "Your app is now ready in the #{name} directory.", :green
33
+ say ""
34
+ say "To run your app: "
35
+ say " cd #{name}"
36
+ say " bundle exec volt server"
25
37
  end
26
38
 
39
+
27
40
  desc 'console', 'run the console on the project in the current directory'
28
41
 
29
42
  def console
@@ -2,17 +2,48 @@
2
2
  # @page is expected to be defined and a Volt::Page
3
3
  module Volt
4
4
  module CollectionHelpers
5
+ def url
6
+ Volt.current_app.url
7
+ end
5
8
 
6
9
  def url_for(params)
7
- @page.url.url_for(params)
10
+ Volt.current_app.url.url_for(params)
8
11
  end
9
12
 
10
13
  def url_with(params)
11
- @page.url.url_with(params)
14
+ Volt.current_app.url.url_with(params)
12
15
  end
13
16
 
14
17
  def store
15
- @page.store
18
+ Volt.current_app.store
19
+ end
20
+
21
+ def page
22
+ Volt.current_app.page
23
+ end
24
+
25
+ def flash
26
+ Volt.current_app.flash
27
+ end
28
+
29
+ def params
30
+ Volt.current_app.params
31
+ end
32
+
33
+ def local_store
34
+ Volt.current_app.local_store
35
+ end
36
+
37
+ def cookies
38
+ Volt.current_app.cookies
39
+ end
40
+
41
+ def channel
42
+ Volt.current_app.channel
43
+ end
44
+
45
+ def tasks
46
+ Volt.current_app.tasks
16
47
  end
17
48
  end
18
49
  end
@@ -43,7 +43,7 @@ module Volt
43
43
  attr_reader :response_headers, :request
44
44
 
45
45
  def store
46
- @volt_app.page.store
46
+ @volt_app.store
47
47
  end
48
48
 
49
49
  def head(status, additional_headers = {})
@@ -55,6 +55,15 @@ module Volt
55
55
  return nil
56
56
  end
57
57
 
58
+ # the u method provides an easy helper to render an unbonud binding. This
59
+ # means that the binding will not reactively update. If no bindings are
60
+ # bound on any model's from a query, the query will not be reactively
61
+ # listened to.
62
+ def u
63
+ raise "the 'u' method requires a block" unless block_given?
64
+ Volt::Computation.run_without_tracking { yield }
65
+ end
66
+
58
67
  # yield_html renders the content passed into a tag as a string. You can ```.watch!```
59
68
  # ```yield_html``` and it will be run again when anything in the template changes.
60
69
  def yield_html
@@ -135,7 +144,6 @@ module Volt
135
144
 
136
145
  def initialize(volt_app, *args)
137
146
  @volt_app = volt_app
138
- @page = volt_app.page
139
147
 
140
148
  # Track that the initialize was called
141
149
  @__init_called = true
@@ -168,38 +176,6 @@ module Volt
168
176
  end
169
177
  end
170
178
 
171
- def page
172
- @page.page
173
- end
174
-
175
- def flash
176
- @page.flash
177
- end
178
-
179
- def params
180
- @page.params
181
- end
182
-
183
- def local_store
184
- @page.local_store
185
- end
186
-
187
- def cookies
188
- @page.cookies
189
- end
190
-
191
- def url
192
- @page.url
193
- end
194
-
195
- def channel
196
- @page.channel
197
- end
198
-
199
- def tasks
200
- @page.tasks
201
- end
202
-
203
179
  def controller
204
180
  @controller ||= Model.new
205
181
  end
@@ -0,0 +1,43 @@
1
+ # Much of this class was borrowed from ActiveSupport:
2
+ # https://github.com/rails/rails/blob/ca9736e78ca9348e785a5c78c8cc085c0c2d4731/activesupport/lib/active_support/core_ext/time/calculations.rb
3
+
4
+ class Time
5
+ # Returns a new Time where one or more of the elements have been changed according
6
+ # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
7
+ # <tt>:sec</tt>, <tt>:usec</tt>) reset cascadingly, so if only the hour is passed,
8
+ # then minute, sec, and usec is set to 0. If the hour and minute is passed, then
9
+ # sec and usec is set to 0. The +options+ parameter takes a hash with any of these
10
+ # keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>,
11
+ # <tt>:sec</tt>, <tt>:usec</tt>.
12
+ #
13
+ # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
14
+ # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
15
+ # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
16
+ def change(options)
17
+ new_year = options.fetch(:year, year)
18
+ new_month = options.fetch(:month, month)
19
+ new_day = options.fetch(:day, day)
20
+ new_hour = options.fetch(:hour, hour)
21
+ new_min = options.fetch(:min, options[:hour] ? 0 : min)
22
+ new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
23
+ # new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
24
+
25
+ # TODO: Opal doesn't have rational yet, so usec's don't get added in right yet
26
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
27
+ end
28
+
29
+ def beginning_of_day
30
+ #(self - seconds_since_midnight).change(usec: 0)
31
+ change(:hour => 0, :min => 0, :sec => 0)
32
+ end
33
+
34
+ # Returns a new Time representing the end of the day, 23:59:59.999999 (.999999999 in ruby1.9)
35
+ def end_of_day
36
+ change(
37
+ :hour => 23,
38
+ :min => 59,
39
+ :sec => 59,
40
+ # :usec => Rational(999999999, 1000)
41
+ )
42
+ end
43
+ end
@@ -1,8 +1,8 @@
1
1
  require 'volt/reactive/reactive_array'
2
2
  require 'volt/models/model_wrapper'
3
- require 'volt/models/model_helpers/model_helpers'
3
+ require 'volt/models/helpers/base'
4
4
  require 'volt/models/state_manager'
5
- require 'volt/models/state_helpers'
5
+ require 'volt/models/helpers/array_model'
6
6
  require 'volt/data_stores/data_store'
7
7
 
8
8
  module Volt
@@ -10,9 +10,9 @@ module Volt
10
10
 
11
11
  class ArrayModel < ReactiveArray
12
12
  include ModelWrapper
13
- include ModelHelpers
13
+ include Models::Helpers::Base
14
14
  include StateManager
15
- include StateHelpers
15
+ include Models::Helpers::ArrayModel
16
16
 
17
17
  attr_reader :parent, :path, :persistor, :options, :array
18
18
 
@@ -87,72 +87,22 @@ module Volt
87
87
 
88
88
  # Make sure it gets wrapped
89
89
  def <<(model)
90
- if model.is_a?(Model)
91
- # Set the new path and the persistor.
92
- model.options = @options.merge(path: @options[:path] + [:[]])
93
- else
94
- model = wrap_values([model]).first
95
- end
96
-
97
-
98
- if model.is_a?(Model)
99
- if !model.can_create?
100
- fail "permissions did not allow create for #{model.inspect}"
101
- end
102
-
103
- # Add it to the array and trigger any watches or on events.
104
- super(model)
105
-
106
- @persistor.added(model, @array.size - 1)
107
-
108
- # Validate and save
109
- promise = model.run_changed.then do
110
- # Mark the model as not new
111
- model.instance_variable_set('@new', false)
112
-
113
- # Mark the model as loaded
114
- model.change_state_to(:loaded_state, :loaded)
115
-
116
- end.fail do |err|
117
- # remove from the collection because it failed to save on the server
118
- # we don't need to call delete on the server.
119
- index = @array.index(model)
120
- delete_at(index, true)
121
-
122
- # remove from the id list
123
- @persistor.try(:remove_tracking_id, model)
124
-
125
- # re-raise, err might not be an Error object, so we use a rejected promise to re-raise
126
- Promise.new.reject(err)
127
- end
128
- else
129
- promise = nil.then do
130
- # Add it to the array and trigger any watches or on events.
131
- super(model)
132
-
133
- @persistor.added(model, @array.size - 1)
134
- end
135
- end
136
-
137
- promise.then do
138
- # resolve the model
139
- model
140
- end
90
+ create_new_model(model, :<<)
141
91
  end
142
92
 
93
+ # Alias append for use inside of child append
94
+ alias_method :reactive_array_append, :append
143
95
  # Works like << except it always returns a promise
144
96
  def append(model)
145
- # Wrap results in a promise
146
- Promise.new.resolve(nil).then do
147
- send(:<<, model)
148
- end
97
+ create_new_model(model, :append)
149
98
  end
150
99
 
151
100
  # Create does append with a default empty model
152
101
  def create(model={})
153
- append(model)
102
+ create_new_model(model, :create)
154
103
  end
155
104
 
105
+
156
106
  def delete(val)
157
107
  # Check to make sure the models are allowed to be deleted
158
108
  if !val.is_a?(Model) || val.can_delete?
@@ -219,24 +169,8 @@ module Volt
219
169
 
220
170
  # returns a promise to fetch the first instance
221
171
  def fetch_first(&block)
222
- persistor = self.persistor
223
-
224
- if persistor && persistor.is_a?(Persistors::ArrayStore)
225
- # On array store, we wait for the result to be loaded in.
226
- promise = limit(1).fetch do |res|
227
- result = res.first
228
-
229
- result
230
- end
231
- else
232
- # On all other persistors, it should be loaded already
233
- promise = Promise.new.resolve(first)
234
- end
235
-
236
- # Run any passed in blocks after fetch
237
- promise = promise.then(&block) if block
238
-
239
- promise
172
+ Volt.logger.warn('.fetch_first is deprecated in favor of .first')
173
+ first
240
174
  end
241
175
 
242
176
  # Make sure it gets wrapped
@@ -256,7 +190,7 @@ module Volt
256
190
  end
257
191
 
258
192
  def new_array_model(*args)
259
- ArrayModel.new(*args)
193
+ Volt::ArrayModel.class_at_path(options[:path]).new(*args)
260
194
  end
261
195
 
262
196
  # Convert the model to an array all of the way down
@@ -283,17 +217,15 @@ module Volt
283
217
 
284
218
 
285
219
  def inspect
286
- Computation.run_without_tracking do
287
- # Track on size
288
- @size_dep.depend
289
- str = "#<#{self.class}"
290
- # str += " state:#{loaded_state}"
291
- # str += " path:#{path.join('.')}" if path
292
- # str += " persistor:#{persistor.inspect}" if persistor
293
- str += " #{@array.inspect}>"
294
-
295
- str
296
- end
220
+ # Track on size
221
+ @size_dep.depend
222
+ str = "#<#{self.class}"
223
+ # str += " state:#{loaded_state}"
224
+ # str += " path:#{path.join('.')}" if path
225
+ # str += " persistor:#{persistor.inspect}" if persistor
226
+ str += " #{@array.inspect}>"
227
+
228
+ str
297
229
  end
298
230
 
299
231
  def buffer(attrs = {})
@@ -317,6 +249,80 @@ module Volt
317
249
  end
318
250
  end
319
251
 
252
+ def self.process_class_name(name)
253
+ name.pluralize
254
+ end
255
+
256
+ private
257
+ # called form <<, append, and create. If a hash is passed in, it converts
258
+ # it to a model. Then it takes the model and inserts it into the ArrayModel
259
+ # then persists it.
260
+ def create_new_model(model, from_method)
261
+ if model.is_a?(Model)
262
+ if model.buffer?
263
+ fail "The #{from_method} does not take a buffer. Call .save! on buffer's to persist them."
264
+ end
265
+
266
+ # Set the new path and the persistor.
267
+ model.options = @options.merge(path: @options[:path] + [:[]])
268
+ else
269
+ model = wrap_values([model]).first
270
+ end
271
+
272
+
273
+ if model.is_a?(Model)
274
+ if !model.can_create?
275
+ fail "permissions did not allow create for #{model.inspect}"
276
+ end
277
+
278
+ # Add it to the array and trigger any watches or on events.
279
+ reactive_array_append(model)
280
+
281
+ @persistor.added(model, @array.size - 1)
282
+
283
+ # Validate and save
284
+ promise = model.run_changed.then do
285
+ # Mark the model as not new
286
+ model.instance_variable_set('@new', false)
287
+
288
+ # Mark the model as loaded
289
+ model.change_state_to(:loaded_state, :loaded)
290
+
291
+ end.fail do |err|
292
+ # remove from the collection because it failed to save on the server
293
+ # we don't need to call delete on the server.
294
+ index = @array.index(model)
295
+ delete_at(index, true)
296
+
297
+ # remove from the id list
298
+ @persistor.try(:remove_tracking_id, model)
299
+
300
+ # re-raise, err might not be an Error object, so we use a rejected promise to re-raise
301
+ Promise.new.reject(err)
302
+ end
303
+ else
304
+ promise = nil.then do
305
+ # Add it to the array and trigger any watches or on events.
306
+ reactive_array_append(model)
307
+
308
+ @persistor.added(model, @array.size - 1)
309
+ end
310
+ end
311
+
312
+ promise = promise.then do
313
+ # resolve the model
314
+ model
315
+ end
316
+
317
+ # unwrap the promise if the persistor is synchronus.
318
+ # This will return the value or raise the exception.
319
+ promise = promise.unwrap unless @persistor.async?
320
+
321
+ # return
322
+ promise
323
+ end
324
+
325
+
320
326
  # We need to setup the proxy methods below where they are defined.
321
327
  proxy_with_load :[], :size, :last, :reverse, :all, :to_a
322
328