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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e66c91c0fc530f8c0bfe7ab8f309fdf5873a3d39
4
- data.tar.gz: f9ed6aecc1e258b23cbe59e9d99ab64a54da72d1
3
+ metadata.gz: 6cb6fdeeaa6a10b0a3d1c81805a3feda5df1f60d
4
+ data.tar.gz: b833be5d63e7db1d7b8f9a1af8afee11d526e8d5
5
5
  SHA512:
6
- metadata.gz: 17882cc80fad10785f995d654f6f127eba2e11dffa5b19965785f50aa262cb2e3950d62fdfdcecfc86099ebc47e33a12937f3dd506845d4e60577ac1f8d3b414
7
- data.tar.gz: 4821c56302f0b4e649162dba8e6f07e3a629d7b3ff43e9cc970bb3d37304460d29d846b649190a306d67b20ab282042ecb47f3334c6aff915f2dfccde95a89a7
6
+ metadata.gz: 29913c4b065abdc2960154fbace2edb83a8ea92e6f7955d538541b05227875770d327136d9d2e02e3d6c00642894545d0b917b63f085456dacbd5f1a37f11275
7
+ data.tar.gz: 1a73d3935e08f24fc64aa2f7dbca692d4cd27aeda930e9d1045c4e47938fea9ef47badd3ffeebbbea8b4fc004efd6d1a7d5e8dea69bc5a6496c06f0522df023e
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.4
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
- # Return the initial data
26
- return live_query.initial_data
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
@@ -52,7 +52,7 @@ class StoreTasks
52
52
  update_data.delete(:_id)
53
53
  @@db[collection].update({:_id => id}, update_data)
54
54
  else
55
- raise
55
+ return {:error => error.message}
56
56
  end
57
57
  end
58
58
 
@@ -49,14 +49,14 @@ class ArrayModel < ReactiveArray
49
49
  end
50
50
  end
51
51
 
52
- tag_method(:fetch) do
52
+ tag_method(:then) do
53
53
  destructive!
54
54
  end
55
- def fetch(*args, &block)
55
+ def then(*args, &block)
56
56
  if @persistor
57
- return @persistor.fetch(*args, &block)
57
+ return @persistor.then(*args, &block)
58
58
  else
59
- raise "this model's persistance layer does not support fetch, try using store"
59
+ raise "this model's persistance layer does not support then, try using store"
60
60
  end
61
61
  end
62
62
 
@@ -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/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
- @persistor.changed if @persistor
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.fetch do
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
- # Fetch does a one time load of the data on an unloaded model and returns
110
- # the result.
111
- def fetch(&block)
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
- block.call(@model)
118
+ promise.resolve(@model)
115
119
  else
116
- @fetch_callbacks ||= []
117
- @fetch_callbacks << block
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
@@ -64,7 +64,7 @@ module Persistors
64
64
  end
65
65
 
66
66
  @tasks.call('StoreTasks', 'save', collection, self_attributes) do |errors|
67
- # puts "SAVE GOT: #{errors.inspect}"
67
+ puts "SAVE GOT: #{errors.inspect}"
68
68
  if errors.size == 0
69
69
  promise.resolve
70
70
  else
@@ -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 && @fetch_callbacks
20
+ if @state == :loaded && @fetch_promises
21
21
  # Trigger each waiting fetch
22
- @fetch_callbacks.compact.each {|fc| fc.call(@model) }
23
- @fetch_callbacks = nil
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/validations/length'
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
- case validation
71
- when :length
72
- merge.call(Length.validate(self, field_name, args))
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({:_name => ["must be at least 4 chars"]})
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 chars"]
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
- :_name => ["must be at least 4 chars"]
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,4 +1,4 @@
1
- get "/about", _controller: 'about'
1
+ get "/about", _action: 'about'
2
2
 
3
3
  # The main route
4
4
  get '/'
@@ -1,19 +1,19 @@
1
1
  <:Title>
2
- {#template params._controller.or('home') + '/' + params._action.or(''), "title"}
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 controller="" text="Home" />
9
- <:nav controller="about" text="About" />
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('home') + '/' + params._action.or('')}
16
+ {#template params._controller.or('index') + '/' + params._action.or('home')}
17
17
 
18
18
  <div class="footer">
19
19
  <p>&copy; Company 2014</p>
@@ -23,7 +23,7 @@
23
23
 
24
24
 
25
25
  <:Nav>
26
- <li class="{#if params._controller.or('') == @controller}active{/}">
27
- <a href="/{@controller}">{@text}</a>
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
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-13 00:00:00.000000000 Z
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/errors.rb
401
- - lib/volt/models/validations/length.rb
402
- - lib/volt/models/validations/validations.rb
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