volt 0.7.4 → 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/app/volt/tasks/query_tasks.rb +11 -2
- data/app/volt/tasks/store_tasks.rb +1 -1
- data/lib/volt/models/array_model.rb +4 -4
- data/lib/volt/models/model.rb +7 -3
- data/lib/volt/models/persistors/array_store.rb +12 -6
- data/lib/volt/models/persistors/model_store.rb +1 -1
- data/lib/volt/models/persistors/query/query_listener.rb +1 -1
- data/lib/volt/models/persistors/store_state.rb +3 -3
- data/lib/volt/models/{validations/validations.rb → validations.rb} +22 -6
- data/lib/volt/models/validators/length_validator.rb +28 -0
- data/lib/volt/models/validators/presence_validator.rb +17 -0
- data/lib/volt/page/bindings/component_binding.rb +1 -33
- data/lib/volt/page/bindings/template_binding.rb +1 -1
- data/spec/models/validations_spec.rb +44 -7
- data/templates/project/app/home/config/routes.rb +1 -1
- data/templates/project/app/home/views/index/index.html +6 -6
- metadata +5 -5
- data/lib/volt/models/validations/errors.rb +0 -0
- data/lib/volt/models/validations/length.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6cb6fdeeaa6a10b0a3d1c81805a3feda5df1f60d
|
4
|
+
data.tar.gz: b833be5d63e7db1d7b8f9a1af8afee11d526e8d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29913c4b065abdc2960154fbace2edb83a8ea92e6f7955d538541b05227875770d327136d9d2e02e3d6c00642894545d0b917b63f085456dacbd5f1a37f11275
|
7
|
+
data.tar.gz: 1a73d3935e08f24fc64aa2f7dbca692d4cd27aeda930e9d1045c4e47938fea9ef47badd3ffeebbbea8b4fc004efd6d1a7d5e8dea69bc5a6496c06f0522df023e
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.5
|
@@ -22,8 +22,17 @@ class QueryTasks
|
|
22
22
|
puts "Load data on #{collection.inspect} - #{query.inspect}"
|
23
23
|
live_query.add_channel(@channel)
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
errors = {}
|
26
|
+
|
27
|
+
begin
|
28
|
+
# Get the initial data
|
29
|
+
initial_data = live_query.initial_data
|
30
|
+
rescue => exception
|
31
|
+
# Capture and pass up any exceptions
|
32
|
+
error = {:error => exception.message}
|
33
|
+
end
|
34
|
+
|
35
|
+
return initial_data, error
|
27
36
|
end
|
28
37
|
|
29
38
|
def initial_data
|
@@ -49,14 +49,14 @@ class ArrayModel < ReactiveArray
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
tag_method(:
|
52
|
+
tag_method(:then) do
|
53
53
|
destructive!
|
54
54
|
end
|
55
|
-
def
|
55
|
+
def then(*args, &block)
|
56
56
|
if @persistor
|
57
|
-
return @persistor.
|
57
|
+
return @persistor.then(*args, &block)
|
58
58
|
else
|
59
|
-
raise "this model's persistance layer does not support
|
59
|
+
raise "this model's persistance layer does not support then, try using store"
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
data/lib/volt/models/model.rb
CHANGED
@@ -3,7 +3,7 @@ require 'volt/models/array_model'
|
|
3
3
|
require 'volt/models/model_helpers'
|
4
4
|
require 'volt/reactive/object_tracking'
|
5
5
|
require 'volt/models/model_hash_behaviour'
|
6
|
-
require 'volt/models/validations
|
6
|
+
require 'volt/models/validations'
|
7
7
|
require 'volt/models/model_state'
|
8
8
|
|
9
9
|
|
@@ -60,7 +60,11 @@ class Model
|
|
60
60
|
trigger!('changed')
|
61
61
|
|
62
62
|
# Let the persistor know something changed
|
63
|
-
|
63
|
+
if @persistor
|
64
|
+
# the changed method on a persistor should return a promise that will
|
65
|
+
# be resolved when the save is complete, or fail with a hash of errors.
|
66
|
+
return @persistor.changed
|
67
|
+
end
|
64
68
|
end
|
65
69
|
end
|
66
70
|
alias_method :assign_attributes, :attributes=
|
@@ -306,7 +310,7 @@ class Model
|
|
306
310
|
if state == :loaded
|
307
311
|
setup_buffer(model)
|
308
312
|
else
|
309
|
-
self.parent.
|
313
|
+
self.parent.then do
|
310
314
|
setup_buffer(model)
|
311
315
|
end
|
312
316
|
end
|
@@ -106,18 +106,24 @@ module Persistors
|
|
106
106
|
return ReactiveValue.new(model)
|
107
107
|
end
|
108
108
|
|
109
|
-
#
|
110
|
-
# the
|
111
|
-
def
|
109
|
+
# Returns a promise that is resolved/rejected when the query is complete. Any
|
110
|
+
# passed block will be passed to the promises then. Then will be passed the model.
|
111
|
+
def then(&block)
|
112
|
+
promise = Promise.new
|
113
|
+
|
114
|
+
promise = promise.then(&block) if block
|
115
|
+
|
112
116
|
# puts "FETCH: #{@state.inspect}"
|
113
117
|
if @state == :loaded
|
114
|
-
|
118
|
+
promise.resolve(@model)
|
115
119
|
else
|
116
|
-
@
|
117
|
-
@
|
120
|
+
@fetch_promises ||= []
|
121
|
+
@fetch_promises << promise
|
118
122
|
|
119
123
|
load_data
|
120
124
|
end
|
125
|
+
|
126
|
+
return promise
|
121
127
|
end
|
122
128
|
|
123
129
|
# Called from backend
|
@@ -15,7 +15,7 @@ class QueryListener
|
|
15
15
|
|
16
16
|
def add_listener
|
17
17
|
@listening = true
|
18
|
-
@tasks.call('QueryTasks', 'add_listener', @collection, @query) do |results|
|
18
|
+
@tasks.call('QueryTasks', 'add_listener', @collection, @query) do |results, errors|
|
19
19
|
# When the initial data comes back, add it into the stores.
|
20
20
|
@stores.each do |store|
|
21
21
|
store.model.clear
|
@@ -17,10 +17,10 @@ module StoreState
|
|
17
17
|
# Trigger changed on the 'state' method
|
18
18
|
@model.trigger_for_methods!('changed', :state, :loaded?)
|
19
19
|
|
20
|
-
if @state == :loaded && @
|
20
|
+
if @state == :loaded && @fetch_promises
|
21
21
|
# Trigger each waiting fetch
|
22
|
-
@
|
23
|
-
@
|
22
|
+
@fetch_promises.compact.each {|fp| fp.resolve(@model) }
|
23
|
+
@fetch_promises = nil
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# require 'volt/models/validations/errors'
|
2
|
-
require 'volt/models/
|
2
|
+
require 'volt/models/validators/length_validator'
|
3
|
+
require 'volt/models/validators/presence_validator'
|
3
4
|
|
4
5
|
# Include in any class to get validation logic
|
5
6
|
module Validations
|
@@ -67,16 +68,31 @@ module Validations
|
|
67
68
|
options.each_pair do |validation, args|
|
68
69
|
# Call the specific validator, then merge the results back
|
69
70
|
# into one large errors hash.
|
70
|
-
|
71
|
-
|
72
|
-
|
71
|
+
klass = validation_class(validation, args)
|
72
|
+
|
73
|
+
if klass
|
74
|
+
validate_with(merge, klass, field_name, args)
|
75
|
+
else
|
76
|
+
raise "validtion type #{validation} is not specified."
|
73
77
|
end
|
74
78
|
end
|
75
79
|
end
|
76
80
|
end
|
77
81
|
|
78
|
-
# puts "ERROR: #{errors.inspect}"
|
79
|
-
|
80
82
|
return errors
|
81
83
|
end
|
84
|
+
|
85
|
+
private
|
86
|
+
# calls the validate method on the class, passing the right arguments.
|
87
|
+
def validate_with(merge, klass, field_name, args)
|
88
|
+
return merge.call(klass.validate(self, field_name, args))
|
89
|
+
end
|
90
|
+
|
91
|
+
def validation_class(validation, args)
|
92
|
+
begin
|
93
|
+
Object.const_get(:"#{validation.camelize}Validator")
|
94
|
+
rescue NameError => e
|
95
|
+
puts "Unable to find #{validation} validator"
|
96
|
+
end
|
97
|
+
end
|
82
98
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class LengthValidator
|
2
|
+
def self.validate(model, field_name, args)
|
3
|
+
errors = {}
|
4
|
+
value = model.send(field_name)
|
5
|
+
|
6
|
+
if args.is_a?(Fixnum)
|
7
|
+
min = args
|
8
|
+
max = nil
|
9
|
+
message = nil
|
10
|
+
elsif args.is_a?(Hash)
|
11
|
+
min = args[:length] || args[:minimum]
|
12
|
+
max = args[:maximum]
|
13
|
+
raise "length or minimum must be specified" unless min.is_a?(Fixnum)
|
14
|
+
|
15
|
+
message = args[:message]
|
16
|
+
else
|
17
|
+
raise "The arguments to length must be a number or a hash"
|
18
|
+
end
|
19
|
+
|
20
|
+
if !value || value.size < min
|
21
|
+
errors[field_name] = [message || "must be at least #{args} characters"]
|
22
|
+
elsif max && value.size > max
|
23
|
+
errors[field_name] = [message || "must be less than #{args} characters"]
|
24
|
+
end
|
25
|
+
|
26
|
+
return errors
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class PresenceValidator
|
2
|
+
def self.validate(model, field_name, args)
|
3
|
+
errors = {}
|
4
|
+
value = model.send(field_name)
|
5
|
+
if !value || value.blank?
|
6
|
+
if args.is_a?(Hash) && args[:message]
|
7
|
+
message = args[:message]
|
8
|
+
else
|
9
|
+
message = "must be specified"
|
10
|
+
end
|
11
|
+
|
12
|
+
errors[field_name] = [message]
|
13
|
+
end
|
14
|
+
|
15
|
+
return errors
|
16
|
+
end
|
17
|
+
end
|
@@ -1,37 +1,5 @@
|
|
1
1
|
require 'volt/page/bindings/template_binding'
|
2
2
|
|
3
|
-
# Component bindings are the same as template bindings, but handle components
|
4
|
-
# and do not pass their context through
|
3
|
+
# Component bindings are the same as template bindings, but handle components.
|
5
4
|
class ComponentBinding < TemplateBinding
|
6
|
-
# The context for a component binding can be either the controller, or the
|
7
|
-
# component arguments (@arguments), with the $page as the context. This gives
|
8
|
-
# components access to the page collections.
|
9
|
-
# def render_template(full_path, controller_path)
|
10
|
-
# # TODO: at the moment a :body section and a :title will both initialize different
|
11
|
-
# # controllers. Maybe we should have a way to tie them together?
|
12
|
-
# controller_class, action = get_controller(controller_path)
|
13
|
-
#
|
14
|
-
# model_with_parent = {parent: @context}.merge(@arguments || {})
|
15
|
-
#
|
16
|
-
# if controller_class
|
17
|
-
# # The user provided a controller, pass in the model as an argument (in a
|
18
|
-
# # sub-context)
|
19
|
-
# args = []
|
20
|
-
# args << SubContext.new(model_with_parent) if @arguments
|
21
|
-
#
|
22
|
-
# current_context = controller_class.new(*args)
|
23
|
-
# @controller = current_context
|
24
|
-
#
|
25
|
-
# # Trigger the action
|
26
|
-
# @controller.send(action) if @controller.respond_to?(action)
|
27
|
-
# else
|
28
|
-
# # There is not a controller
|
29
|
-
# current_context = SubContext.new(model_with_parent, @page)
|
30
|
-
# @controller = nil
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# @current_template = TemplateRenderer.new(@page, @target, current_context, @binding_name, full_path)
|
34
|
-
#
|
35
|
-
# call_ready
|
36
|
-
# end
|
37
5
|
end
|
@@ -12,7 +12,7 @@ class TemplateBinding < BaseBinding
|
|
12
12
|
@current_template = nil
|
13
13
|
|
14
14
|
# Find the source for the getter binding
|
15
|
-
@path, section = value_from_getter(getter)
|
15
|
+
@path, section, @options = value_from_getter(getter)
|
16
16
|
|
17
17
|
if section.is_a?(String)
|
18
18
|
# Render this as a section
|
@@ -2,11 +2,20 @@ require 'volt/models'
|
|
2
2
|
|
3
3
|
class TestModel < Model
|
4
4
|
validate :_name, length: 4
|
5
|
+
validate :_description, length: {message: 'needs to be longer', length: 50}
|
6
|
+
validate :_username, presence: true
|
5
7
|
end
|
6
8
|
|
9
|
+
|
7
10
|
describe Model do
|
8
11
|
it "should validate the name" do
|
9
|
-
expect(TestModel.new.errors).to eq(
|
12
|
+
expect(TestModel.new.errors).to eq(
|
13
|
+
{
|
14
|
+
:_name => ["must be at least 4 characters"],
|
15
|
+
:_description => ["needs to be longer"],
|
16
|
+
:_username => ["must be specified"]
|
17
|
+
}
|
18
|
+
)
|
10
19
|
end
|
11
20
|
|
12
21
|
it "should show marked validations once they are marked" do
|
@@ -18,7 +27,7 @@ describe Model do
|
|
18
27
|
|
19
28
|
expect(model.marked_errors).to eq(
|
20
29
|
{
|
21
|
-
:_name => ["must be at least 4
|
30
|
+
:_name => ["must be at least 4 characters"]
|
22
31
|
}
|
23
32
|
)
|
24
33
|
end
|
@@ -30,10 +39,38 @@ describe Model do
|
|
30
39
|
|
31
40
|
model.save!
|
32
41
|
|
33
|
-
expect(model.marked_errors).to eq(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
42
|
+
expect(model.marked_errors.keys).to eq([:_name, :_description, :_username])
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "length" do
|
46
|
+
it "should allow custom errors on length" do
|
47
|
+
model = TestModel.new
|
48
|
+
|
49
|
+
expect(model.marked_errors).to eq({})
|
50
|
+
|
51
|
+
model.mark_field!(:_description)
|
52
|
+
|
53
|
+
expect(model.marked_errors).to eq(
|
54
|
+
{
|
55
|
+
:_description => ["needs to be longer"]
|
56
|
+
}
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "presence" do
|
62
|
+
it "should validate presence" do
|
63
|
+
model = TestModel.new
|
64
|
+
|
65
|
+
expect(model.marked_errors).to eq({})
|
66
|
+
|
67
|
+
model.mark_field!(:_username)
|
68
|
+
|
69
|
+
expect(model.marked_errors).to eq(
|
70
|
+
{
|
71
|
+
:_username => ["must be specified"]
|
72
|
+
}
|
73
|
+
)
|
74
|
+
end
|
38
75
|
end
|
39
76
|
end
|
@@ -1,19 +1,19 @@
|
|
1
1
|
<:Title>
|
2
|
-
{#template params._controller.or('
|
2
|
+
{#template params._controller.or('index') + '/' + params._action.or('home'), "title"}
|
3
3
|
|
4
4
|
<:Body>
|
5
5
|
<div class="container">
|
6
6
|
<div class="header">
|
7
7
|
<ul class="nav nav-pills pull-right">
|
8
|
-
<:nav
|
9
|
-
<:nav
|
8
|
+
<:nav action="" text="Home" />
|
9
|
+
<:nav action="about" text="About" />
|
10
10
|
</ul>
|
11
11
|
<h3 class="text-muted">Project name</h3>
|
12
12
|
</div>
|
13
13
|
|
14
14
|
<:volt:notices />
|
15
15
|
|
16
|
-
{#template params._controller.or('
|
16
|
+
{#template params._controller.or('index') + '/' + params._action.or('home')}
|
17
17
|
|
18
18
|
<div class="footer">
|
19
19
|
<p>© Company 2014</p>
|
@@ -23,7 +23,7 @@
|
|
23
23
|
|
24
24
|
|
25
25
|
<:Nav>
|
26
|
-
<li class="{#if params.
|
27
|
-
<a href="/{@
|
26
|
+
<li class="{#if params._action.or('') == @action}active{/}">
|
27
|
+
<a href="/{@action}">{@text}</a>
|
28
28
|
</li>
|
29
29
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: volt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Stout
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -397,9 +397,9 @@ files:
|
|
397
397
|
- lib/volt/models/persistors/store_factory.rb
|
398
398
|
- lib/volt/models/persistors/store_state.rb
|
399
399
|
- lib/volt/models/url.rb
|
400
|
-
- lib/volt/models/validations
|
401
|
-
- lib/volt/models/
|
402
|
-
- lib/volt/models/
|
400
|
+
- lib/volt/models/validations.rb
|
401
|
+
- lib/volt/models/validators/length_validator.rb
|
402
|
+
- lib/volt/models/validators/presence_validator.rb
|
403
403
|
- lib/volt/page/bindings/attribute_binding.rb
|
404
404
|
- lib/volt/page/bindings/base_binding.rb
|
405
405
|
- lib/volt/page/bindings/component_binding.rb
|
File without changes
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module Validations
|
2
|
-
class Length
|
3
|
-
def self.validate(model, field_name, args)
|
4
|
-
errors = {}
|
5
|
-
value = model.send(field_name)
|
6
|
-
if !value || value.size < args
|
7
|
-
errors[field_name] = ["must be at least #{args} chars"]
|
8
|
-
end
|
9
|
-
|
10
|
-
return errors
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|