Class: Volt::ReactiveArray

Inherits:
Object show all
Includes:
Eventable
Defined in:
lib/volt/reactive/reactive_array.rb

Direct Known Subclasses

ArrayModel

Instance Method Summary collapse

Methods included from Eventable

#on, #remove_listener, #trigger!

Constructor Details

#initialize(array = []) ⇒ ReactiveArray

Returns a new instance of ReactiveArray.



7
8
9
10
11
12
# File 'lib/volt/reactive/reactive_array.rb', line 7

def initialize(array = [])
  @array      = array
  @array_deps = []
  @size_dep   = Dependency.new
  @old_size   = 0
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object

Forward any missing methods to the array



19
20
21
22
23
24
25
# File 'lib/volt/reactive/reactive_array.rb', line 19

def method_missing(method_name, *args, &block)
  # Long term we should probably handle all Enum methods
  # directly for smarter updating.  For now, just depend on size
  # so updates retrigger the whole method call.
  @size_dep.depend
  @array.send(method_name, *args, &block)
end

Instance Method Details

#+(array) ⇒ Object



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/volt/reactive/reactive_array.rb', line 203

def +(array)
  fail 'not implemented yet'
  old_size = @array.size

  # TODO: += is funky here, might need to make a .plus! method
  result   = ReactiveArray.new(@array.dup + array)

  old_size.upto(result.size - 1) do |index|
    trigger_for_index!('changed', index)
    trigger_added!(old_size + index)
  end

  trigger_size_change!

  result
end

#<<(*args) ⇒ Object

alias :__old_append :<<



189
190
191
# File 'lib/volt/reactive/reactive_array.rb', line 189

def <<(*args)
  append(*args)
end

#==(*args) ⇒ Object



27
28
29
# File 'lib/volt/reactive/reactive_array.rb', line 27

def ==(*args)
  @array.==(*args)
end

#[](index) ⇒ Object

TODO: Handle a range



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/volt/reactive/reactive_array.rb', line 101

def [](index)
  # Handle a negative index, depend on size
  if index < 0
    # Depend on size by calling .size, since we are looking up reverse
    # indexes

    # cache size lookup
    size = self.size

    index = size + index

    # In this case, we're looking back past 0 (going backwards), so we get
    # nil.  Since we're depending on @size_dep (because we called .size),
    # it will invalidate when the size changes.
    return nil if index < 0
  end

  # Get or create the dependency
  dep   = (@array_deps[index] ||= Dependency.new)

  # Track the dependency
  dep.depend

  # Return the index
  @array[index]
end

#[]=(index, value) ⇒ Object



128
129
130
131
132
133
134
135
# File 'lib/volt/reactive/reactive_array.rb', line 128

def []=(index, value)
  # Assign the new value
  @array[index] = value

  trigger_for_index!(index)

  trigger_size_change!
end

#all?Boolean

Returns:



82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/volt/reactive/reactive_array.rb', line 82

def all?
  if block_given?
    size.times do |index|
      val = self[index]

      return false unless yield(val)
    end

    true
  else
    @array.all?
  end
end

#any?Boolean

Returns:



68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/volt/reactive/reactive_array.rb', line 68

def any?
  if block_given?
    size.times do |index|
      val = self[index]

      return true if yield(val)
    end

    false
  else
    @array.any?
  end
end

#append(value) ⇒ Object



193
194
195
196
197
198
199
200
201
# File 'lib/volt/reactive/reactive_array.rb', line 193

def append(value)
  result = (@array << value)

  trigger_for_index!(@array.size - 1)
  trigger_added!(@array.size - 1)
  trigger_size_change!

  result
end

#clearObject



182
183
184
185
186
# File 'lib/volt/reactive/reactive_array.rb', line 182

def clear
  __clear

  @persistor.clear if @persistor
end

#count(&block) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/volt/reactive/reactive_array.rb', line 41

def count(&block)
  if block
    count = 0

    Volt.run_in_mode(:no_model_promises) do
      size.times do |index|
        count += 1 if block.call(self[index])
      end
    end

    # return as a promise
    count.then
  else
    size
  end
end

#delete(val) ⇒ Object



171
172
173
174
175
176
177
178
179
180
# File 'lib/volt/reactive/reactive_array.rb', line 171

def delete(val)
  index = @array.index(val)
  if index
    delete_at(index)
  else
    # Sometimes the model isn't loaded at the right state yet, so we
    # just remove it from the persistor
    @persistor.removed(val) if @persistor
  end
end

#delete_at(index, skip_persistor = false) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/volt/reactive/reactive_array.rb', line 145

def delete_at(index, skip_persistor=false)
  size = @array.size
  # Handle a negative index
  index = size + index if index < 0

  model = @array.delete_at(index)

  # Remove the dependency for that cell, and #remove it
  index_deps = @array_deps.delete_at(index)
  index_deps.remove if index_deps

  trigger_removed!(index)

  # Trigger a changed event for each element in the zone where the
  # delete would change
  index.upto(size + 1) do |position|
    trigger_for_index!(position)
  end

  trigger_size_change!

  @persistor.removed(model) if @persistor && !skip_persistor

  model
end

#each(&block) ⇒ Object

At the moment, each just passes through.



32
33
34
# File 'lib/volt/reactive/reactive_array.rb', line 32

def each(&block)
  @array.each(&block)
end

#empty?Boolean

Returns:



36
37
38
39
# File 'lib/volt/reactive/reactive_array.rb', line 36

def empty?
  @size_dep.depend
  @array.empty?
end

#insert(index, *objects) ⇒ Object



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/volt/reactive/reactive_array.rb', line 220

def insert(index, *objects)
  result = @array.insert(index, *objects)

  # All objects from index to the end have "changed"
  index.upto(result.size) do |index|
    trigger_for_index!(index)
  end

  objects.size.times do |count|
    trigger_added!(index + count)
  end

  trigger_size_change!

  result
end

#inspectObject



237
238
239
240
241
# File 'lib/volt/reactive/reactive_array.rb', line 237

def inspect
  # TODO: should also depend on items in array
  @size_dep.depend
  "#<#{self.class}:#{object_id} #{@array.inspect}>"
end

#lastObject



96
97
98
# File 'lib/volt/reactive/reactive_array.rb', line 96

def last
  self[-1]
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:



14
15
16
# File 'lib/volt/reactive/reactive_array.rb', line 14

def respond_to_missing?(method_name, include_private = false)
  @array.respond_to?(method_name, include_private) || super
end

#selectObject



58
59
60
61
62
63
64
65
66
# File 'lib/volt/reactive/reactive_array.rb', line 58

def select
  result = []
  size.times do |index|
    val = self[index]
    result << val if yield(val)
  end

  result
end

#sizeObject Also known as: length



137
138
139
140
141
# File 'lib/volt/reactive/reactive_array.rb', line 137

def size
  @size_dep.depend

  @array.size
end