volt 0.4.9 → 0.4.10
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 +4 -4
- data/VERSION +1 -1
- data/app/volt/tasks/channel_tasks.rb +2 -2
- data/lib/volt/console.rb +0 -1
- data/lib/volt/controllers/model_controller.rb +20 -2
- data/lib/volt/models.rb +4 -2
- data/lib/volt/models/array_model.rb +19 -5
- data/lib/volt/models/model.rb +51 -9
- data/lib/volt/models/model_wrapper.rb +2 -2
- data/lib/volt/models/persistors/array_store.rb +79 -0
- data/lib/volt/models/persistors/base.rb +24 -0
- data/lib/volt/models/persistors/model_store.rb +140 -0
- data/lib/volt/models/persistors/params.rb +26 -0
- data/lib/volt/models/persistors/store.rb +44 -0
- data/lib/volt/models/persistors/store_factory.rb +15 -0
- data/lib/volt/models/url.rb +2 -1
- data/lib/volt/page/bindings/each_binding.rb +2 -2
- data/lib/volt/page/channel.rb +0 -2
- data/lib/volt/page/page.rb +2 -3
- data/lib/volt/page/tasks.rb +28 -7
- data/lib/volt/reactive/reactive_array.rb +14 -1
- data/lib/volt/tasks/dispatcher.rb +8 -2
- data/spec/models/model_spec.rb +32 -2
- data/spec/models/persistors/params_spec.rb +16 -0
- data/spec/models/persistors/store_spec.rb +29 -0
- data/spec/models/store_spec.rb +16 -16
- data/spec/router/routes_spec.rb +1 -1
- data/templates/project/app/home/controllers/index_controller.rb +2 -1
- metadata +12 -8
- data/lib/volt/models/params.rb +0 -72
- data/lib/volt/models/params_array.rb +0 -9
- data/lib/volt/models/store.rb +0 -183
- data/lib/volt/models/store_array.rb +0 -82
- data/spec/models/params_spec.rb +0 -16
data/lib/volt/models/params.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'volt/models/params_array'
|
2
|
-
|
3
|
-
# All url related data is stored in params. This includes the main uri
|
4
|
-
# in addition to any query parameters. The router is responsible for
|
5
|
-
# converting any uri sections into params. Sections in the uri will
|
6
|
-
# override any specified parameters.
|
7
|
-
#
|
8
|
-
# The params value can be updated the same way a model would be, only
|
9
|
-
# the updates will trigger an updated url via the browser history api.
|
10
|
-
# TODO: Support # for browsers without the history api.
|
11
|
-
class Params < Model
|
12
|
-
def initialize(*args)
|
13
|
-
super(*args)
|
14
|
-
end
|
15
|
-
|
16
|
-
def deep_clone
|
17
|
-
new_obj = clone
|
18
|
-
|
19
|
-
new_obj.attributes = new_obj.attributes.dup
|
20
|
-
|
21
|
-
new_obj
|
22
|
-
end
|
23
|
-
|
24
|
-
tag_method(:delete) do
|
25
|
-
destructive!
|
26
|
-
end
|
27
|
-
def delete(*args)
|
28
|
-
super
|
29
|
-
|
30
|
-
value_updated
|
31
|
-
end
|
32
|
-
|
33
|
-
def method_missing(method_name, *args, &block)
|
34
|
-
result = super
|
35
|
-
|
36
|
-
if method_name[0] == '_' && method_name[-1] == '='
|
37
|
-
# Trigger value updated after an assignment
|
38
|
-
self.value_updated
|
39
|
-
end
|
40
|
-
|
41
|
-
return result
|
42
|
-
end
|
43
|
-
|
44
|
-
def value_updated
|
45
|
-
# Once the initial url has been parsed and set into the attributes,
|
46
|
-
# start triggering updates on change events.
|
47
|
-
# TODO: This is a temp solution, we need to make it so value_updated
|
48
|
-
# is called after the reactive_value has been updated.
|
49
|
-
if RUBY_PLATFORM == 'opal'
|
50
|
-
%x{
|
51
|
-
if (window.setTimeout && this.$run_update.bind) {
|
52
|
-
if (window.paramsUpdateTimer) {
|
53
|
-
clearTimeout(window.paramsUpdateTimer);
|
54
|
-
}
|
55
|
-
window.paramsUpdateTimer = setTimeout(this.$run_update.bind(this), 0);
|
56
|
-
}
|
57
|
-
}
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def run_update
|
62
|
-
$page.params.trigger!('child_changed') if Volt.client?
|
63
|
-
end
|
64
|
-
|
65
|
-
def new_model(*args)
|
66
|
-
Params.new(*args)
|
67
|
-
end
|
68
|
-
|
69
|
-
def new_array_model(*args)
|
70
|
-
ParamsArray.new(*args)
|
71
|
-
end
|
72
|
-
end
|
data/lib/volt/models/store.rb
DELETED
@@ -1,183 +0,0 @@
|
|
1
|
-
require 'volt/models/store_array'
|
2
|
-
|
3
|
-
class Store < Model
|
4
|
-
ID_CHARS = [('a'..'z'), ('A'..'Z'), ('0'..'9')].map {|v| v.to_a }.flatten
|
5
|
-
|
6
|
-
@@identity_map = {}
|
7
|
-
|
8
|
-
attr_reader :state
|
9
|
-
|
10
|
-
def initialize(tasks=nil, *args)
|
11
|
-
@tasks = tasks
|
12
|
-
@state = :not_loaded
|
13
|
-
|
14
|
-
super(*args)
|
15
|
-
|
16
|
-
track_in_identity_map if attributes && attributes[:_id]
|
17
|
-
|
18
|
-
value_updated
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.from_id(id)
|
22
|
-
@@identity_map[id]
|
23
|
-
end
|
24
|
-
|
25
|
-
def event_added(event, scope_provider, first)
|
26
|
-
if first && event == :changed
|
27
|
-
# Start listening
|
28
|
-
ensure_id
|
29
|
-
change_channel_connection("add")
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def event_removed(event, no_more_events)
|
34
|
-
if no_more_events && event == :changed
|
35
|
-
# Stop listening
|
36
|
-
change_channel_connection("remove")
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def change_channel_connection(add_or_remove)
|
41
|
-
if attributes && path.size > 1
|
42
|
-
channel_name = "#{path[-2]}##{attributes[:_id]}"
|
43
|
-
puts "Event Added: #{channel_name} -- #{attributes.inspect}"
|
44
|
-
@tasks.call('ChannelTasks', "#{add_or_remove}_listener", channel_name)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.update(model_id, data)
|
49
|
-
model = @@identity_map[model_id]
|
50
|
-
|
51
|
-
if model
|
52
|
-
data.each_pair do |key, value|
|
53
|
-
if key != '_id'
|
54
|
-
model.send(:"#{key}=", value)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def generate_id
|
61
|
-
id = []
|
62
|
-
12.times { id << ID_CHARS.sample }
|
63
|
-
|
64
|
-
return id.join
|
65
|
-
end
|
66
|
-
|
67
|
-
def method_missing(method_name, *args, &block)
|
68
|
-
if method_name[-1] == ']'
|
69
|
-
# Load the model
|
70
|
-
self.load!
|
71
|
-
end
|
72
|
-
|
73
|
-
result = super
|
74
|
-
|
75
|
-
if method_name[0] == '_' && method_name[-1] == '='
|
76
|
-
# Trigger value updated after an assignment
|
77
|
-
self.value_updated
|
78
|
-
end
|
79
|
-
|
80
|
-
return result
|
81
|
-
end
|
82
|
-
|
83
|
-
def track_in_identity_map
|
84
|
-
@@identity_map[attributes[:_id]] = self
|
85
|
-
end
|
86
|
-
|
87
|
-
# When called, will setup an id if there is not one
|
88
|
-
def ensure_id
|
89
|
-
# No id yet, lets create one
|
90
|
-
if attributes && !attributes[:_id]
|
91
|
-
self.attributes[:_id] = generate_id
|
92
|
-
track_in_identity_map
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def value_updated
|
97
|
-
path_size = path.size
|
98
|
-
if !(defined?($loading_models) && $loading_models) && @tasks && path_size > 0 && !nil?
|
99
|
-
|
100
|
-
ensure_id
|
101
|
-
|
102
|
-
if path_size > 3 && parent && source = parent.parent
|
103
|
-
self.attributes[:"#{path[-4].singularize}_id"] = source._id
|
104
|
-
end
|
105
|
-
|
106
|
-
# puts "Save: #{collection} - #{attrs.inspect}"
|
107
|
-
@tasks.call('StoreTasks', 'save', collection, self_attributes)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# Return the attributes that are only for this store, not any sub-associations.
|
112
|
-
def self_attributes
|
113
|
-
# Don't store any sub-stores, those will do their own saving.
|
114
|
-
attrs = attributes.reject {|k,v| v.is_a?(Model) || v.is_a?(ArrayModel) }
|
115
|
-
end
|
116
|
-
|
117
|
-
def collection(path=nil)
|
118
|
-
path ||= self.path
|
119
|
-
|
120
|
-
collection_name = path.last
|
121
|
-
collection_name = path[-2] if collection_name == :[]
|
122
|
-
|
123
|
-
return collection_name
|
124
|
-
end
|
125
|
-
|
126
|
-
# On stores, we store the model so we don't have to look it up
|
127
|
-
# every time we do a read.
|
128
|
-
def read_new_model(method_name)
|
129
|
-
# On stores, plural associations are automatically assumed to be
|
130
|
-
# collections.
|
131
|
-
if method_name.plural?
|
132
|
-
model = new_array_model([], self, path + [method_name])
|
133
|
-
else
|
134
|
-
model = new_model(nil, self, path + [method_name])
|
135
|
-
end
|
136
|
-
|
137
|
-
self.attributes ||= {}
|
138
|
-
attributes[method_name] = model
|
139
|
-
|
140
|
-
if model.is_a?(StoreArray)# && model.state == :not_loaded
|
141
|
-
model.load!
|
142
|
-
end
|
143
|
-
|
144
|
-
return model
|
145
|
-
end
|
146
|
-
|
147
|
-
|
148
|
-
# When called, this model is deleted from its current parent collection
|
149
|
-
# and from the database
|
150
|
-
def delete!
|
151
|
-
if path.size == 0
|
152
|
-
raise "Not in a collection"
|
153
|
-
end
|
154
|
-
|
155
|
-
# TEMP: Find this model in the parent's collection
|
156
|
-
parent.each_with_index do |child,index|
|
157
|
-
puts "CHECK #{child.inspect} vs #{self.inspect}"
|
158
|
-
if child._id == self._id
|
159
|
-
puts "FOUND AT: #{index}"
|
160
|
-
parent.delete_at(index)
|
161
|
-
break
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
# Send to the DB that we got deleted
|
166
|
-
unless $loading_models
|
167
|
-
puts "delete #{collection} - #{attributes[:_id]}"
|
168
|
-
@tasks.call('StoreTasks', 'delete', collection, attributes[:_id])
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
def inspect
|
173
|
-
"<#{self.class.to_s}-#{@state} #{attributes.inspect}>"
|
174
|
-
end
|
175
|
-
|
176
|
-
def new_model(attributes={}, parent=nil, path=nil, class_paths=nil)
|
177
|
-
return Store.new(@tasks, attributes, parent, path, class_paths)
|
178
|
-
end
|
179
|
-
|
180
|
-
def new_array_model(*args)
|
181
|
-
StoreArray.new(@tasks, *args)
|
182
|
-
end
|
183
|
-
end
|
@@ -1,82 +0,0 @@
|
|
1
|
-
class StoreArray < ArrayModel
|
2
|
-
attr_reader :state
|
3
|
-
|
4
|
-
def initialize(tasks=nil, array=[], parent=nil, path=nil)
|
5
|
-
@tasks = tasks
|
6
|
-
@state = :not_loaded
|
7
|
-
|
8
|
-
super(array, parent, path)
|
9
|
-
|
10
|
-
# TEMP: TODO: Setup the listeners right away
|
11
|
-
change_channel_connection('add', 'added')
|
12
|
-
change_channel_connection('add', 'removed')
|
13
|
-
end
|
14
|
-
|
15
|
-
# def event_added(event, scope_provider, first)
|
16
|
-
# puts "New event1: #{event.inspect} - #{first}"
|
17
|
-
# if first && [:added, :removed].include?(event)
|
18
|
-
# # Start listening for added items on the collection
|
19
|
-
#
|
20
|
-
# change_channel_connection('add', event)
|
21
|
-
# end
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# def event_removed(event, no_more_events)
|
25
|
-
# if no_more_events && [:added, :removed].include?(event)
|
26
|
-
# # Stop listening
|
27
|
-
# change_channel_connection("remove", event)
|
28
|
-
# end
|
29
|
-
# end
|
30
|
-
|
31
|
-
|
32
|
-
def load!
|
33
|
-
if @state == :not_loaded
|
34
|
-
@state = :loading
|
35
|
-
|
36
|
-
if @tasks && path.last.plural?
|
37
|
-
# Check to see the parents scope so we can only lookup associated
|
38
|
-
# models.
|
39
|
-
scope = {}
|
40
|
-
|
41
|
-
# Scope to the parent
|
42
|
-
if path.size > 1 && attributes && attributes[:_id].true?
|
43
|
-
scope[:"#{path[-2].singularize}_id"] = _id
|
44
|
-
end
|
45
|
-
|
46
|
-
puts "Load At Scope: #{scope.inspect}"
|
47
|
-
|
48
|
-
load_child_models(scope)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
return self
|
53
|
-
end
|
54
|
-
|
55
|
-
def load_child_models(scope)
|
56
|
-
# puts "FIND: #{collection(path).inspect} at #{scope.inspect}"
|
57
|
-
@tasks.call('StoreTasks', 'find', path.last, scope) do |results|
|
58
|
-
# TODO: Globals evil, replace
|
59
|
-
$loading_models = true
|
60
|
-
results.each do |result|
|
61
|
-
self << Store.new(@tasks, result, self, path + [:[]], @class_paths)
|
62
|
-
end
|
63
|
-
$loading_models = false
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def change_channel_connection(add_or_remove, event)
|
68
|
-
if @tasks && parent.attributes && path.size != 0
|
69
|
-
channel_name = "#{path[-1]}-#{event}"
|
70
|
-
puts "Listen on #{channel_name} - #{add_or_remove}"
|
71
|
-
@tasks.call('ChannelTasks', "#{add_or_remove}_listener", channel_name)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def new_model(*args)
|
76
|
-
Store.new(@tasks, *args)
|
77
|
-
end
|
78
|
-
|
79
|
-
def new_array_model(*args)
|
80
|
-
StoreArray.new(@tasks, *args)
|
81
|
-
end
|
82
|
-
end
|
data/spec/models/params_spec.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'volt/models'
|
2
|
-
|
3
|
-
describe Params do
|
4
|
-
it "should stay as params classes when used" do
|
5
|
-
a = Params.new
|
6
|
-
expect(a._test.class).to eq(Params)
|
7
|
-
|
8
|
-
expect(a._test._cool.class).to eq(Params)
|
9
|
-
|
10
|
-
a._items << {_name: 'Test'}
|
11
|
-
|
12
|
-
expect(a._items.class).to eq(ParamsArray)
|
13
|
-
expect(a._items[0].class).to eq(Params)
|
14
|
-
expect(a._items[0]._name.class).to eq(String)
|
15
|
-
end
|
16
|
-
end
|