Class: Volt::ArrayModel

Inherits:
ReactiveArray show all
Includes:
ModelWrapper, Models::Helpers::ArrayModel, Models::Helpers::Base, StateManager
Defined in:
lib/volt/models/array_model.rb

Direct Known Subclasses

Cursor

Constant Summary

Constants included from Models::Helpers::Base

Models::Helpers::Base::ID_CHARS

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Helpers::ArrayModel

#loaded?, #loaded_state

Methods included from StateManager

#change_state_to

Methods included from Models::Helpers::Base

#deep_unwrap, #event_added, #event_removed, #generate_id, included, #root, #self_attributes, #setup_persistor, #store

Methods included from ModelWrapper

#wrap_value, #wrap_values

Methods inherited from ReactiveArray

#==, #[], #[]=, #all?, #any?, #clear, #delete_at, #each, #empty?, #insert, #method_missing, #respond_to_missing?, #size

Methods included from Eventable

#on, #remove_listener, #trigger!

Constructor Details

#initialize(array = [], options = {}) ⇒ ArrayModel

Returns a new instance of ArrayModel.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/volt/models/array_model.rb', line 89

def initialize(array = [], options = {})
  @options   = options
  @persistor = setup_persistor(options[:persistor])

  array = wrap_values(array)

  super(array)

  if @persistor
    @persistor.loaded
  else
    change_state_to(:loaded_state, :loaded, false)
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Volt::ReactiveArray

Instance Attribute Details

#arrayObject (readonly)

Returns the value of attribute array.



17
18
19
# File 'lib/volt/models/array_model.rb', line 17

def array
  @array
end

#optionsObject (readonly)

Returns the value of attribute options.



17
18
19
# File 'lib/volt/models/array_model.rb', line 17

def options
  @options
end

#parentObject

Returns the value of attribute parent.



17
18
19
# File 'lib/volt/models/array_model.rb', line 17

def parent
  @parent
end

#pathObject

Returns the value of attribute path.



17
18
19
# File 'lib/volt/models/array_model.rb', line 17

def path
  @path
end

#persistorObject (readonly)

Returns the value of attribute persistor.



17
18
19
# File 'lib/volt/models/array_model.rb', line 17

def persistor
  @persistor
end

Class Method Details

.process_class_name(name) ⇒ Object



306
307
308
# File 'lib/volt/models/array_model.rb', line 306

def self.process_class_name(name)
  name.pluralize
end

.proxy_to_persistor(*method_names) ⇒ Object

Some methods get passed down to the persistor.



75
76
77
78
79
80
81
82
83
84
85
# File 'lib/volt/models/array_model.rb', line 75

def self.proxy_to_persistor(*method_names)
  method_names.each do |method_name|
    define_method(method_name) do |*args, &block|
      if @persistor.respond_to?(method_name)
        @persistor.send(method_name, *args, &block)
      else
        fail "this model's persistance layer does not support #{method_name}, try using store"
      end
    end
  end
end

.proxy_with_load(*method_names) ⇒ Object

For many methods, we want to register a dependency on the root_dep as soon as the method is called, so it can begin loading. Also, some persistors need to have special loading logic (such as returning a promise instead of immediately returning). To accomplish this, we call the #run_once_loaded method on the persistor.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/volt/models/array_model.rb', line 24

def self.proxy_with_load(*method_names)
  imethods = instance_methods(false)
  method_names.each do |method_name|
    # Sometimes we want to alias a method_missing method, so we use super
    # instead to call it, if its not defined locally.
    if imethods.include?(method_name)
      imethod = true
      old_method_name = :"__old_#{method_name}"
      alias_method(old_method_name, method_name)
    else
      imethod = false
    end

    define_method(method_name) do |*args, &block|
      if imethod
        call_orig = proc do |*args|
          send(old_method_name, *args)
        end
      else
        call_orig = proc do |*args|
          super(*args)
        end
      end

      # track on the root dep
      persistor.try(:root_dep).try(:depend)

      if persistor.respond_to?(:run_once_loaded) &&
          !Volt.in_mode?(:no_model_promises)
        promise = persistor.run_once_loaded.then do
          # We are already loaded and the result is going to be wrapped
          Volt.run_in_mode(:no_model_promises) do
            call_orig.call(*args)
          end
        end

        if block
          promise = promise.then do |val|
            block.call(val)
          end
        end

        promise
      else
        call_orig.call(*args)
      end
    end
  end
end

Instance Method Details

#+(*args) ⇒ Object

Make sure it gets wrapped



232
233
234
235
# File 'lib/volt/models/array_model.rb', line 232

def +(*args)
  args = wrap_values(args)
  super(*args)
end

#<<(model) ⇒ Object

Make sure it gets wrapped



132
133
134
# File 'lib/volt/models/array_model.rb', line 132

def <<(model)
  create_new_model(model, :<<)
end

#allObject

Return the model, on store, .all is proxied to wait for load and return a promise.



215
216
217
# File 'lib/volt/models/array_model.rb', line 215

def all
  self
end

#append(model) ⇒ Object

Works like << except it always returns a promise



139
140
141
# File 'lib/volt/models/array_model.rb', line 139

def append(model)
  create_new_model(model, :append)
end

#attributesObject



120
121
122
# File 'lib/volt/models/array_model.rb', line 120

def attributes
  self
end

#buffer(attrs = {}) ⇒ Object



285
286
287
288
289
290
291
292
293
# File 'lib/volt/models/array_model.rb', line 285

def buffer(attrs = {})
  model_path  = options[:path] + [:[]]
  model_klass = Volt::Model.class_at_path(model_path)

  new_options = options.merge(path: model_path, save_to: self, buffer: true).reject { |k, _| k.to_sym == :persistor }
  model       = model_klass.new(attrs, new_options)

  model
end

#count(&block) ⇒ Object



311
312
313
# File 'lib/volt/models/array_model.rb', line 311

def count(&block)
  all.reactive_count(&block)
end

#create(model = {}) ⇒ Object

Create does append with a default empty model



144
145
146
# File 'lib/volt/models/array_model.rb', line 144

def create(model={})
  create_new_model(model, :create)
end

#delete(val) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/volt/models/array_model.rb', line 149

def delete(val)
  # Check to make sure the models are allowed to be deleted
  if !val.is_a?(Model)
    # Not a model, return as a Promise
    super(val).then
  else
    val.can_delete?.then do |can_delete|
      if can_delete
        super(val)
      else
       Promise.new.reject("permissions did not allow delete for #{val.inspect}.")
      end
    end
  end
end

#fail_not_found_if_nil(promise) ⇒ Object

Raise a RecordNotFoundException if the promise returns a nil.



296
297
298
299
300
301
302
303
304
# File 'lib/volt/models/array_model.rb', line 296

def fail_not_found_if_nil(promise)
  promise.then do |val|
    if val
      val
    else
      raise RecordNotFoundException.new
    end
  end
end

#fetch_first(&block) ⇒ Object

returns a promise to fetch the first instance



220
221
222
223
# File 'lib/volt/models/array_model.rb', line 220

def fetch_first(&block)
  Volt.logger.warn('.fetch_first is deprecated in favor of .first')
  first
end

#firstObject



165
166
167
168
169
170
171
# File 'lib/volt/models/array_model.rb', line 165

def first
  if persistor.is_a?(Persistors::ArrayStore)
    limit(1)[0]
  else
    self[0]
  end
end

#first!Object

Same as first, except it returns a promise (even on page collection), and it fails with a RecordNotFoundException if no result is found.



175
176
177
# File 'lib/volt/models/array_model.rb', line 175

def first!
  fail_not_found_if_nil(first)
end

#first_or_createObject

Return the first item in the collection, or create one if one does not exist yet.



181
182
183
184
185
186
187
188
189
# File 'lib/volt/models/array_model.rb', line 181

def first_or_create
  first.then do |item|
    if item
      item
    else
      create
    end
  end
end

#flatten(*args) ⇒ Object



237
238
239
# File 'lib/volt/models/array_model.rb', line 237

def flatten(*args)
  wrap_values(to_a.flatten(*args))
end

#inject(*args) ⇒ Object

Make sure it gets wrapped



226
227
228
229
# File 'lib/volt/models/array_model.rb', line 226

def inject(*args)
  args = wrap_values(args)
  super(*args)
end

#inspectObject



273
274
275
276
277
278
279
280
281
282
283
# File 'lib/volt/models/array_model.rb', line 273

def inspect
  # Track on size
  @size_dep.depend
  str = "#<#{self.class}"
  # str += " state:#{loaded_state}"
  # str += " path:#{path.join('.')}" if path
  # str += " persistor:#{persistor.inspect}" if persistor
  str += " #{@array.inspect}>"

  str
end

#lastObject



191
192
193
# File 'lib/volt/models/array_model.rb', line 191

def last
  self[-1]
end

#new_array_model(*args) ⇒ Object



246
247
248
# File 'lib/volt/models/array_model.rb', line 246

def new_array_model(*args)
  Volt::ArrayModel.class_at_path(options[:path]).new(*args)
end

#new_model(*args) ⇒ Object Also known as: new



241
242
243
# File 'lib/volt/models/array_model.rb', line 241

def new_model(*args)
  Volt::Model.class_at_path(options[:path]).new(*args)
end

#reactive_array_appendObject

Alias append for use inside of child append



137
# File 'lib/volt/models/array_model.rb', line 137

alias_method :reactive_array_append, :append

#reactive_countObject



310
# File 'lib/volt/models/array_model.rb', line 310

alias_method :reactive_count, :count

#reverseObject



195
196
197
198
# File 'lib/volt/models/array_model.rb', line 195

def reverse
  @size_dep.depend
  @array.reverse
end

#selectObject

Array#select, with reactive notification



201
202
203
204
205
206
207
208
209
210
211
# File 'lib/volt/models/array_model.rb', line 201

def select
  new_array = []
  @array.size.times do |index|
    value = @array[index]
    if yield(value)
      new_array << value
    end
  end

  new_array
end

#state_for(*args) ⇒ Object



124
125
126
127
128
129
# File 'lib/volt/models/array_model.rb', line 124

def state_for(*args)
  # Track on root dep
  persistor.try(:root_dep).try(:depend)

  super
end

#to_aObject

Convert the model to an array all of the way down



251
252
253
254
255
256
257
258
259
260
# File 'lib/volt/models/array_model.rb', line 251

def to_a
  @size_dep.depend
  array = []
  Volt.run_in_mode(:no_model_promises) do
    attributes.size.times do |index|
      array << deep_unwrap(self[index])
    end
  end
  array
end

#to_jsonObject



262
263
264
265
266
267
268
269
270
# File 'lib/volt/models/array_model.rb', line 262

def to_json
  array = to_a

  if array.is_a?(Promise)
    array.then(&:to_json)
  else
    array.to_json
  end
end