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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/CODE_OF_CONDUCT.md +15 -0
- data/README.md +2 -0
- data/app/volt/models/user.rb +6 -4
- data/lib/volt/boot.rb +0 -2
- data/lib/volt/cli/bundle.rb +29 -0
- data/lib/volt/cli/console.rb +2 -2
- data/lib/volt/cli/generate.rb +2 -0
- data/lib/volt/cli/new_gem.rb +23 -0
- data/lib/volt/cli.rb +15 -2
- data/lib/volt/controllers/collection_helpers.rb +34 -3
- data/lib/volt/controllers/http_controller.rb +1 -1
- data/lib/volt/controllers/model_controller.rb +9 -33
- data/lib/volt/helpers/time.rb +43 -0
- data/lib/volt/models/array_model.rb +96 -90
- data/lib/volt/models/buffer.rb +42 -7
- data/lib/volt/models/helpers/array_model.rb +15 -0
- data/lib/volt/models/helpers/base.rb +113 -0
- data/lib/volt/models/helpers/change_helpers.rb +91 -0
- data/lib/volt/models/helpers/dirty.rb +93 -0
- data/lib/volt/models/helpers/listener_tracker.rb +19 -0
- data/lib/volt/models/helpers/model.rb +15 -0
- data/lib/volt/models/model.rb +17 -12
- data/lib/volt/models/permissions.rb +1 -1
- data/lib/volt/models/persistors/array_store.rb +4 -0
- data/lib/volt/models/persistors/base.rb +10 -0
- data/lib/volt/models/persistors/cookies.rb +2 -0
- data/lib/volt/models/persistors/local_store.rb +3 -0
- data/lib/volt/models/persistors/model_store.rb +7 -0
- data/lib/volt/models/persistors/params.rb +4 -1
- data/lib/volt/models/persistors/query/query_listener.rb +1 -1
- data/lib/volt/models/url.rb +12 -7
- data/lib/volt/models/validators/unique_validator.rb +1 -1
- data/lib/volt/page/bindings/base_binding.rb +2 -2
- data/lib/volt/page/bindings/event_binding.rb +2 -2
- data/lib/volt/page/bindings/view_binding/controller_handler.rb +20 -0
- data/lib/volt/page/bindings/view_binding/view_lookup_for_path.rb +6 -4
- data/lib/volt/page/bindings/view_binding.rb +7 -7
- data/lib/volt/page/path_string_renderer.rb +2 -4
- data/lib/volt/page/targets/base_section.rb +3 -3
- data/lib/volt/page/targets/dom_template.rb +2 -2
- data/lib/volt/page/tasks.rb +6 -6
- data/lib/volt/page/template_renderer.rb +1 -1
- data/lib/volt/page/url_tracker.rb +4 -4
- data/lib/volt/reactive/reactive_array.rb +31 -20
- data/lib/volt/server/component_templates.rb +5 -5
- data/lib/volt/server/forking_server.rb +2 -2
- data/lib/volt/server/message_bus/peer_to_peer/server_tracker.rb +3 -3
- data/lib/volt/server/message_bus/peer_to_peer.rb +7 -7
- data/lib/volt/server/rack/asset_files.rb +28 -8
- data/lib/volt/server/rack/component_paths.rb +4 -4
- data/lib/volt/server/rack/opal_files.rb +0 -1
- data/lib/volt/server/socket_connection_handler.rb +5 -2
- data/lib/volt/server.rb +0 -1
- data/lib/volt/spec/setup.rb +4 -5
- data/lib/volt/tasks/task.rb +2 -3
- data/lib/volt/utils/promise_extensions.rb +22 -6
- data/lib/volt/utils/time_patch.rb +12 -0
- data/lib/volt/utils/timers.rb +14 -2
- data/lib/volt/version.rb +1 -1
- data/lib/volt/volt/app.rb +44 -12
- data/lib/volt/volt/client_setup/browser.rb +113 -0
- data/lib/volt/volt/repos.rb +48 -0
- data/lib/volt/volt/server_setup/app.rb +1 -2
- data/lib/volt/volt/templates.rb +39 -0
- data/lib/volt/volt/users.rb +4 -4
- data/lib/volt.rb +1 -0
- data/spec/apps/file_loading/app/disable_auto/assets/css/test1.css.scss +0 -0
- data/spec/apps/file_loading/app/disable_auto/assets/css/test2.css.scss +0 -0
- data/spec/apps/file_loading/app/disable_auto/assets/js/test1.js +0 -0
- data/spec/apps/file_loading/app/disable_auto/assets/js/test2.js +0 -0
- data/spec/apps/file_loading/app/disable_auto/config/dependencies.rb +3 -0
- data/spec/apps/file_loading/app/main/assets/css/test3.css +0 -0
- data/spec/apps/file_loading/app/shared/config/dependencies.rb +1 -1
- data/spec/controllers/model_controller_spec.rb +7 -0
- data/spec/models/{model_helpers/model_helpers_spec.rb → helpers/base_spec.rb} +1 -1
- data/spec/models/helpers/model_spec.rb +26 -0
- data/spec/models/model_spec.rb +9 -0
- data/spec/models/persistors/params_spec.rb +1 -1
- data/spec/models/persistors/store_spec.rb +1 -0
- data/spec/page/bindings/content_binding_spec.rb +2 -4
- data/spec/page/bindings/each_binding_spec.rb +1 -4
- data/spec/page/bindings/if_binding_spec.rb +1 -4
- data/spec/page/bindings/template_binding/view_lookup_for_path_spec.rb +17 -27
- data/spec/page/path_string_renderer_spec.rb +15 -4
- data/spec/server/rack/asset_files_spec.rb +88 -8
- data/spec/tasks/user_tasks_spec.rb +1 -1
- data/spec/utils/promise_extensions_spec.rb +22 -0
- data/spec/volt/repos_spec.rb +11 -0
- data/templates/newgem/CODE_OF_CONDUCT.md.tt +13 -0
- data/templates/project/app/main/config/routes.rb +4 -1
- metadata +34 -10
- data/lib/volt/models/model_helpers/dirty.rb +0 -88
- data/lib/volt/models/model_helpers/listener_tracker.rb +0 -15
- data/lib/volt/models/model_helpers/model_change_helpers.rb +0 -87
- data/lib/volt/models/model_helpers/model_helpers.rb +0 -110
- data/lib/volt/models/state_helpers.rb +0 -11
- data/lib/volt/page/page.rb +0 -190
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 336fa7176c4a60f3ea2757f0e78917d40f0faee7
|
4
|
+
data.tar.gz: 2911281e8bea55eca1fdc94568452f75012ee0aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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)
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -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).
|
data/app/volt/models/user.rb
CHANGED
@@ -42,11 +42,13 @@ module Volt
|
|
42
42
|
def hash_password
|
43
43
|
password = get('password')
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
if password.present?
|
46
|
+
# Clear the password
|
47
|
+
set('password', nil)
|
47
48
|
|
48
|
-
|
49
|
-
|
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
@@ -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
|
data/lib/volt/cli/console.rb
CHANGED
data/lib/volt/cli/generate.rb
CHANGED
@@ -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'
|
data/lib/volt/cli/new_gem.rb
CHANGED
@@ -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
|
-
|
24
|
-
|
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
|
-
|
10
|
+
Volt.current_app.url.url_for(params)
|
8
11
|
end
|
9
12
|
|
10
13
|
def url_with(params)
|
11
|
-
|
14
|
+
Volt.current_app.url.url_with(params)
|
12
15
|
end
|
13
16
|
|
14
17
|
def store
|
15
|
-
|
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
|
@@ -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/
|
3
|
+
require 'volt/models/helpers/base'
|
4
4
|
require 'volt/models/state_manager'
|
5
|
-
require 'volt/models/
|
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
|
13
|
+
include Models::Helpers::Base
|
14
14
|
include StateManager
|
15
|
-
include
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
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
|
|