volt 0.9.5.pre3 → 0.9.5.pre4

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: 552337e005627aa06bff5950bcd94cbb5ab58684
4
- data.tar.gz: cf7e89e6862c51796186c9034a62e378e27abcfc
3
+ metadata.gz: 237e158164bd2f394e80998fa3314f52024fbebc
4
+ data.tar.gz: abd1d018ffd679afba929518326f0139cce4deb0
5
5
  SHA512:
6
- metadata.gz: 9c42d896c2c9cb881778a8a90dee2c2ff398213540bbaa4183f13c748106b7f8d0724cf50327ce090e7e1c30dcb7336d758f4a5d5ec61521420b53a33478593d
7
- data.tar.gz: ea0d96fa24038a6d45d99a3adb3ee59cd072adef219a48aa7c5543e63de9f52f7abf16fd6564aa4ed740e7cc137fcbd2c65220e38a76cf1e8ea7a664fb7ac868
6
+ metadata.gz: 48b5fa1a075beab16bbe901532b11e46e6ee4aa065d21db169bc425efc9def807d2d286f5ea4a2f6b569458b05fcb7052721ceb3df26aa7d585990a1d4fe6ffb
7
+ data.tar.gz: d18c325ef1f789d19a6ceaf2327452fd5b06dcefda74d0eeeca8e66b070599544ebf5176779d465a67bf641987f9af40de34a3eb7bbcffcd4b8d469910b17aea
data/CHANGELOG.md CHANGED
@@ -5,6 +5,8 @@
5
5
  - You can now disable auto-import of JS/CSS with ```disable_auto_import``` in a dependencies.rb file
6
6
  - Opal was upgraded to 0.8, which brings sourcemaps back (yah!)
7
7
  - Page load performance was improved, and more of sprockets was used for component loading.
8
+ - You can now return promises in permissions blocks. Also, can_read?, can_create?, and .can_delete?
9
+ - Anything in /public is now served via Rack::Static in the default middleware stack. (So you can put user uploaded images in there)
8
10
 
9
11
  ## 0.9.4
10
12
  ### Lingo Change
@@ -0,0 +1,6 @@
1
+ class ActiveVoltInstance < Volt::Model
2
+ field :server_id, String
3
+ field :ips, String
4
+ field :port, Fixnum
5
+ field :time, Time
6
+ end
@@ -37,7 +37,7 @@ class LiveQuery
37
37
  notify! do |channel|
38
38
  filtered_data = nil
39
39
  Volt.as_user(channel.user_id) do
40
- filtered_data = model.filtered_attributes
40
+ filtered_data = model.filtered_attributes.sync
41
41
  end
42
42
 
43
43
  channel.send_message('added', nil, @collection, @query, index, filtered_data)
@@ -57,7 +57,7 @@ class LiveQuery
57
57
  notify!(skip_channel) do |channel|
58
58
  filtered_data = nil
59
59
  Volt.as_user(channel.user_id) do
60
- filtered_data = model.filtered_attributes
60
+ filtered_data = model.filtered_attributes.sync
61
61
  end
62
62
  # puts "Changed: #{id}, #{data} to #{channel.inspect}"
63
63
  channel.send_message('changed', nil, @collection, @query, id, filtered_data)
@@ -26,7 +26,7 @@ class QueryTasks < Volt::Task
26
26
  if initial_data
27
27
  # Only send the filtered attributes for this user
28
28
  initial_data.map! do |data|
29
- [data[0], live_query.model_for_filter(data[1]).filtered_attributes]
29
+ [data[0], live_query.model_for_filter(data[1]).filtered_attributes.sync]
30
30
  end
31
31
  end
32
32
 
data/lib/volt/models.rb CHANGED
@@ -12,16 +12,14 @@ require 'volt/models/persistors/local_store'
12
12
  require 'volt/models/root_models/root_models'
13
13
  # require 'volt/models/root_models/store_root'
14
14
 
15
- # Fow now, we're keeping a volt copy of the promise library from opal 0.8,
16
- # since opal 0.7.x's version has some bugs.
17
- # if RUBY_PLATFORM == 'opal'
18
- # require 'promise'
19
- # else
20
- # # Opal doesn't expose its promise library directly
21
- # require 'opal'
15
+ # Requrie in opal's promise library
16
+ if RUBY_PLATFORM == 'opal'
17
+ require 'promise'
18
+ else
19
+ # Opal doesn't expose its promise library directly
20
+ require 'opal'
22
21
 
23
- # gem_dir = File.join(Opal.gem_dir, '..')
24
- # require(gem_dir + '/stdlib/promise')
25
- # end
26
- # TODO: remove once https://github.com/opal/opal/pull/725 is released.
22
+ gem_dir = File.join(Opal.gem_dir, '..')
23
+ require(gem_dir + '/stdlib/promise')
24
+ end
27
25
  require 'volt/utils/promise_extensions'
@@ -22,21 +22,50 @@ module Volt
22
22
  # of immediately returning). To accomplish this, we call the
23
23
  # #run_once_loaded method on the persistor.
24
24
  def self.proxy_with_load(*method_names)
25
+ imethods = instance_methods(false)
25
26
  method_names.each do |method_name|
26
- old_method_name = :"__old_#{method_name}"
27
- alias_method(old_method_name, method_name)
27
+ # Sometimes we want to alias a method_missing method, so we use super
28
+ # instead to call it, if its not defined locally.
29
+ if imethods.include?(method_name)
30
+ imethod = true
31
+ old_method_name = :"__old_#{method_name}"
32
+ alias_method(old_method_name, method_name)
33
+ else
34
+ imethod = false
35
+ end
28
36
 
29
37
  define_method(method_name) do |*args, &block|
38
+ if imethod
39
+ call_orig = proc do |*args|
40
+ send(old_method_name, *args)
41
+ end
42
+ else
43
+ call_orig = proc do |*args|
44
+ super(*args)
45
+ end
46
+ end
47
+
30
48
  # track on the root dep
31
49
  persistor.try(:root_dep).try(:depend)
32
50
 
33
51
  if persistor.respond_to?(:run_once_loaded) &&
34
52
  !Volt.in_mode?(:no_model_promises)
35
- persistor.run_once_loaded(block) do
36
- send(old_method_name, *args)
53
+ promise = persistor.run_once_loaded.then do
54
+ # We are already loaded and the result is going to be wrapped
55
+ Volt.run_in_mode(:no_model_promises) do
56
+ call_orig.call(*args)
57
+ end
58
+ end
59
+
60
+ if block
61
+ promise = promise.then do |val|
62
+ block.call(val)
63
+ end
37
64
  end
65
+
66
+ promise
38
67
  else
39
- send(old_method_name, *args)
68
+ call_orig.call(*args)
40
69
  end
41
70
  end
42
71
  end
@@ -119,11 +148,17 @@ module Volt
119
148
 
120
149
  def delete(val)
121
150
  # Check to make sure the models are allowed to be deleted
122
- if !val.is_a?(Model) || val.can_delete?
123
- result = super
124
- Promise.new.resolve(result)
151
+ if !val.is_a?(Model)
152
+ # Not a model, return as a Promise
153
+ super(val).then
125
154
  else
126
- Promise.new.reject("permissions did not allow delete for #{val.inspect}.")
155
+ val.can_delete?.then do |can_delete|
156
+ if can_delete
157
+ super(val)
158
+ else
159
+ Promise.new.reject("permissions did not allow delete for #{val.inspect}.")
160
+ end
161
+ end
127
162
  end
128
163
  end
129
164
 
@@ -199,6 +234,10 @@ module Volt
199
234
  super(*args)
200
235
  end
201
236
 
237
+ def flatten(*args)
238
+ wrap_values(to_a.flatten(*args))
239
+ end
240
+
202
241
  def new_model(*args)
203
242
  Volt::Model.class_at_path(options[:path]).new(*args)
204
243
  end
@@ -285,34 +324,39 @@ module Volt
285
324
 
286
325
 
287
326
  if model.is_a?(Model)
288
- if !model.can_create?
289
- fail "permissions did not allow create for #{model.inspect}"
290
- end
291
-
292
- # Add it to the array and trigger any watches or on events.
293
- reactive_array_append(model)
294
-
295
- @persistor.added(model, @array.size - 1)
296
-
297
- # Validate and save
298
- promise = model.run_changed.then do
299
- # Mark the model as not new
300
- model.instance_variable_set('@new', false)
301
-
302
- # Mark the model as loaded
303
- model.change_state_to(:loaded_state, :loaded)
304
-
305
- end.fail do |err|
306
- # remove from the collection because it failed to save on the server
307
- # we don't need to call delete on the server.
308
- index = @array.index(model)
309
- delete_at(index, true)
327
+ promise = model.can_create?.then do |can_create|
328
+ unless can_create
329
+ fail "permissions did not allow create for #{model.inspect}"
330
+ end
331
+ end.then do
310
332
 
311
- # remove from the id list
312
- @persistor.try(:remove_tracking_id, model)
333
+ # Add it to the array and trigger any watches or on events.
334
+ reactive_array_append(model)
313
335
 
314
- # re-raise, err might not be an Error object, so we use a rejected promise to re-raise
315
- Promise.new.reject(err)
336
+ @persistor.added(model, @array.size - 1)
337
+ end.then do
338
+ nil.then do
339
+ # Validate and save
340
+ model.run_changed
341
+ end.then do
342
+ # Mark the model as not new
343
+ model.instance_variable_set('@new', false)
344
+
345
+ # Mark the model as loaded
346
+ model.change_state_to(:loaded_state, :loaded)
347
+
348
+ end.fail do |err|
349
+ # remove from the collection because it failed to save on the server
350
+ # we don't need to call delete on the server.
351
+ index = @array.index(model)
352
+ delete_at(index, true)
353
+
354
+ # remove from the id list
355
+ @persistor.try(:remove_tracking_id, model)
356
+
357
+ # re-raise, err might not be an Error object, so we use a rejected promise to re-raise
358
+ Promise.new.reject(err)
359
+ end
316
360
  end
317
361
  else
318
362
  promise = nil.then do
@@ -337,7 +381,7 @@ module Volt
337
381
  end
338
382
 
339
383
  # We need to setup the proxy methods below where they are defined.
340
- proxy_with_load :[], :size, :last, :reverse, :all, :to_a, :empty?
384
+ proxy_with_load :[], :size, :last, :reverse, :all, :to_a, :empty?, :present?, :blank?
341
385
 
342
386
  end
343
387
  end
@@ -36,13 +36,16 @@ module FieldHelpers
36
36
  module ClassMethods
37
37
  # field lets you declare your fields instead of using the underscore syntax.
38
38
  # An optional class restriction can be passed in.
39
- def field(name, klass = nil, auto_cast = true)
39
+ def field(name, klass = nil, options = {})
40
40
  if klass && !VALID_FIELD_CLASSES.include?(klass)
41
41
  klass_names = VALID_FIELD_CLASSES.map(&:to_s).join(', ')
42
42
  msg = "valid field types is currently limited to #{klass_names}"
43
43
  fail FieldHelpers::InvalidFieldClass, msg
44
44
  end
45
45
 
46
+ self.fields_data ||= {}
47
+ self.fields_data[name] = [klass, options]
48
+
46
49
  if klass
47
50
  # Add type validation, execpt for String, since anything can be a string.
48
51
  unless klass == String
@@ -69,6 +72,7 @@ module FieldHelpers
69
72
  end
70
73
 
71
74
  def self.included(base)
75
+ base.class_attribute :fields_data
72
76
  base.send :extend, ClassMethods
73
77
  end
74
78
  end
@@ -106,41 +106,37 @@ module Volt
106
106
  !owner_id.nil? && owner_id == Volt.current_user_id
107
107
  end
108
108
 
109
- # Returns boolean if the model can be deleted
110
- def can_delete?
111
- action_allowed?(:delete)
112
- end
113
-
114
- # Checks the read permissions
115
- def can_read?
116
- action_allowed?(:read)
117
- end
118
-
119
- def can_create?
120
- action_allowed?(:create)
109
+ [:create, :update, :read, :delete].each do |action|
110
+ # Each can_action? (can_delete? for example) returns a promise that
111
+ # resolves to true or false if the user
112
+ define_method(:"can_#{action}?") do
113
+ action_allowed?(action)
114
+ end
121
115
  end
122
116
 
123
117
  # Checks if any denies are in place for an action (read or delete)
124
118
  def action_allowed?(action_name)
125
119
  # TODO: this does some unnecessary work
126
- compute_allow_and_deny(action_name)
120
+ compute_allow_and_deny(action_name).then do
127
121
 
128
- deny = @__deny_fields == true || (@__deny_fields && @__deny_fields.size > 0)
122
+ deny = @__deny_fields == true || (@__deny_fields && @__deny_fields.size > 0)
129
123
 
130
- clear_allow_and_deny
124
+ clear_allow_and_deny
131
125
 
132
- !deny
126
+ !deny
127
+ end
133
128
  end
134
129
 
135
130
  # Return the list of allowed fields
136
131
  def allow_and_deny_fields(action_name)
137
- compute_allow_and_deny(action_name)
132
+ compute_allow_and_deny(action_name).then do
138
133
 
139
- result = [@__allow_fields, @__deny_fields]
134
+ result = [@__allow_fields, @__deny_fields]
140
135
 
141
- clear_allow_and_deny
136
+ clear_allow_and_deny
142
137
 
143
- result
138
+ result
139
+ end
144
140
  end
145
141
 
146
142
  # Filter fields returns the attributes with any denied or not allowed fields
@@ -149,70 +145,80 @@ module Volt
149
145
  # Run with Volt.as_user(...) to change the user
150
146
  def filtered_attributes
151
147
  # Run the read permission check
152
- allow, deny = allow_and_deny_fields(:read)
153
-
154
- result = nil
155
-
156
- if allow && allow != true && allow.size > 0
157
- # always keep id
158
- allow << :id
159
-
160
- # Only keep fields in the allow list
161
- result = @attributes.select { |key| allow.include?(key) }
162
- elsif deny == true
163
- # Only keep id
164
- # TODO: Should this be a full reject?
165
- result = @attributes.reject { |key| key != :id }
166
- elsif deny && deny.size > 0
167
- # Reject any in the deny list
168
- result = @attributes.reject { |key| deny.include?(key) }
169
- else
170
- result = @attributes
171
- end
172
-
173
- # Deeply filter any nested models
174
- return result.map do |key, value|
175
- if value.is_a?(Model)
176
- value = value.filtered_attributes
148
+ allow_and_deny_fields(:read).then do |allow, deny|
149
+
150
+ result = nil
151
+
152
+ if allow && allow != true && allow.size > 0
153
+ # always keep id
154
+ allow << :id
155
+
156
+ # Only keep fields in the allow list
157
+ result = @attributes.select { |key| allow.include?(key) }
158
+ elsif deny == true
159
+ # Only keep id
160
+ # TODO: Should this be a full reject?
161
+ result = @attributes.reject { |key| key != :id }
162
+ elsif deny && deny.size > 0
163
+ # Reject any in the deny list
164
+ result = @attributes.reject { |key| deny.include?(key) }
165
+ else
166
+ result = @attributes
177
167
  end
178
168
 
179
- [key, value]
180
- end.to_h
169
+ # Deeply filter any nested models
170
+ result.then do |res|
171
+ keys = []
172
+ values = []
173
+ res.each do |key, value|
174
+ if value.is_a?(Model)
175
+ value = value.filtered_attributes
176
+ end
177
+ keys << key
178
+ values << value
179
+ end
180
+
181
+ Promise.when(*values).then do |values|
182
+ keys.zip(values).to_h
183
+ end
184
+ end
185
+ end
181
186
  end
182
187
 
183
188
  private
184
189
 
185
190
  def run_permissions(action_name = nil)
186
- compute_allow_and_deny(action_name)
187
-
188
- errors = {}
189
-
190
- if @__allow_fields == true
191
- # Allow all fields
192
- elsif @__allow_fields && @__allow_fields.size > 0
193
- # Deny all not specified in the allow list
194
- changed_attributes.keys.each do |field_name|
195
- unless @__allow_fields.include?(field_name)
196
- add_error_if_changed(errors, field_name)
191
+ compute_allow_and_deny(action_name).then do
192
+
193
+ errors = {}
194
+
195
+ if @__allow_fields == true
196
+ # Allow all fields
197
+ elsif @__allow_fields && @__allow_fields.size > 0
198
+ # Deny all not specified in the allow list
199
+ changed_attributes.keys.each do |field_name|
200
+ unless @__allow_fields.include?(field_name)
201
+ add_error_if_changed(errors, field_name)
202
+ end
197
203
  end
198
204
  end
199
- end
200
205
 
201
- if @__deny_fields == true
202
- # Don't allow any field changes
203
- changed_attributes.keys.each do |field_name|
204
- add_error_if_changed(errors, field_name)
205
- end
206
- elsif @__deny_fields
207
- # Allow all except the denied
208
- @__deny_fields.each do |field_name|
209
- add_error_if_changed(errors, field_name) if changed?(field_name)
206
+ if @__deny_fields == true
207
+ # Don't allow any field changes
208
+ changed_attributes.keys.each do |field_name|
209
+ add_error_if_changed(errors, field_name)
210
+ end
211
+ elsif @__deny_fields
212
+ # Allow all except the denied
213
+ @__deny_fields.each do |field_name|
214
+ add_error_if_changed(errors, field_name) if changed?(field_name)
215
+ end
210
216
  end
211
- end
212
217
 
213
- clear_allow_and_deny
218
+ clear_allow_and_deny
214
219
 
215
- errors
220
+ errors
221
+ end
216
222
  end
217
223
 
218
224
  def clear_allow_and_deny
@@ -235,10 +241,13 @@ module Volt
235
241
  # Run each of the permission blocks for this action
236
242
  permissions = self.class.__permissions__
237
243
  if permissions && (blocks = permissions[action_name])
238
- blocks.each do |block|
244
+ results = blocks.map do |block|
239
245
  # Call the block, pass the action name
240
246
  instance_exec(action_name, &block)
241
247
  end
248
+
249
+ # Wait for any promises returned
250
+ Promise.when(*results)
242
251
  end
243
252
  end
244
253