volt 0.7.4 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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