Class: ReactiveManager

Inherits:
Object show all
Includes:
Events
Defined in:
lib/volt/reactive/reactive_value.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Events

#event_chain, #listeners, #on, #remove_listener, #trigger!, #trigger_by_scope!

Constructor Details

#initialize(getter, setter = nil, scope = nil) ⇒ ReactiveManager

When created, ReactiveValue’s get a getter (a proc)



185
186
187
188
189
190
191
# File 'lib/volt/reactive/reactive_value.rb', line 185

def initialize(getter, setter=nil, scope=nil)
  @getter = getter
  @setter = setter
  @scope = scope
  
  @parents = []
end

Instance Attribute Details

#parentsObject (readonly)

Returns the value of attribute parents.



182
183
184
# File 'lib/volt/reactive/reactive_value.rb', line 182

def parents
  @parents
end

#scopeObject (readonly)

Returns the value of attribute scope.



182
183
184
# File 'lib/volt/reactive/reactive_value.rb', line 182

def scope
  @scope
end

Instance Method Details

#add_parent!(parent) ⇒ Object



347
348
349
350
# File 'lib/volt/reactive/reactive_value.rb', line 347

def add_parent!(parent)
  @parents << parent
  event_chain.add_object(parent)
end

#check_tag(method_name, tag_name, current_obj) ⇒ Object

Method calls can be tagged so the reactive value knows how to handle them. This lets you check the state of the tags.



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/volt/reactive/reactive_value.rb', line 274

def check_tag(method_name, tag_name, current_obj)
  if current_obj.respond_to?(:reactive_method_tag)
    tag = current_obj.reactive_method_tag(method_name, tag_name)
    
    unless tag
      # Get the tag from the all methods if its not directly specified
      tag = current_obj.reactive_method_tag(:__all_methods, tag_name)
    end
    
    # Evaluate now if its a proc
    tag = tag.call(method_name) if tag.class == ::Proc
    
    return tag
  end
  
  return nil
end

#curObject

Fetch the current value



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/volt/reactive/reactive_value.rb', line 224

def cur
  # @@cur_count ||= 0
  # @@cur_count += 1
  # puts "Cur: #{@@cur_count}"# if @@cur_count % 100 == 0
  # if ObjectTracker.cache_version == @cached_version
  #   return @cached_obj
  # end
  
  if @getter.class == ::Proc
    # Get the current value, capture any errors
    begin
      result = @getter.call
    rescue => e
      result = e
    end
  else
    # getter is just an object, return it
    result = @getter
  end
  
  if result.reactive?
    # Unwrap any stored reactive values
    result = result.cur
  end
  
  # if ObjectTracker.cache_enabled
  #   @cached_obj = result
  #   @cached_version = ObjectTracker.cache_version
  # end
  
  return result
end

#cur=(val) ⇒ Object



257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/volt/reactive/reactive_value.rb', line 257

def cur=(val)
  if @setter
    @setter.call(val)
  elsif @scope == nil
    @getter = val
    @setter = nil
    
    trigger!('changed')
  else
    raise "Value can not be updated"
  end
end

#event_added(event, scope, first) ⇒ Object



206
207
208
209
210
# File 'lib/volt/reactive/reactive_value.rb', line 206

def event_added(event, scope, first)
  # When the first event is registered, we need to start listening on our current object
  # for it to publish events.
  object_tracker.enable! if first
end

#event_removed(event, last) ⇒ Object



212
213
214
215
216
# File 'lib/volt/reactive/reactive_value.rb', line 212

def event_removed(event, last)
  # If no one is listening on the reactive value, then we don't need to listen on our
  # current object for events, because no one cares.
  object_tracker.disable! if @listeners.size == 0
end

#inspectObject



197
198
199
# File 'lib/volt/reactive/reactive_value.rb', line 197

def inspect
  "@<#{self.class.to_s}:#{reactive_object_id} #{cur.inspect}>"
end

#object_trackerObject



218
219
220
# File 'lib/volt/reactive/reactive_value.rb', line 218

def object_tracker
  @object_tracker ||= ::ObjectTracker.new(self)
end

#reactive?Boolean

Returns:



193
194
195
# File 'lib/volt/reactive/reactive_value.rb', line 193

def reactive?
  true
end

#reactive_object_idObject



201
202
203
# File 'lib/volt/reactive/reactive_value.rb', line 201

def reactive_object_id
  @reactive_object_id ||= rand(100000)
end

#remove_parent!(parent) ⇒ Object



352
353
354
355
# File 'lib/volt/reactive/reactive_value.rb', line 352

def remove_parent!(parent)
  @parents.delete(parent)
  event_chain.remove_object(parent)
end

#set_scope(new_scope) ⇒ Object



364
365
366
# File 'lib/volt/reactive/reactive_value.rb', line 364

def set_scope(new_scope)
  dup.scope!(new_scope)
end

#set_scope!(new_scope) ⇒ Object



358
359
360
361
362
# File 'lib/volt/reactive/reactive_value.rb', line 358

def set_scope!(new_scope)
  @scope = new_scope
  
  self
end

#setter!(setter = nil, &block) ⇒ Object

Sets the setter



369
370
371
# File 'lib/volt/reactive/reactive_value.rb', line 369

def setter!(setter=nil, &block)
  @setter = setter || block
end

#unwrap_if_pass_reactive(args, method_name, current_obj) ⇒ Object



292
293
294
295
296
297
298
# File 'lib/volt/reactive/reactive_value.rb', line 292

def unwrap_if_pass_reactive(args, method_name, current_obj)
  # Check to see if the method we're calling wants to receive reactive values.
  pass_reactive = check_tag(method_name, :pass_reactive, current_obj)

  # Unwrap arguments if the method doesn't want reactive values
  return pass_reactive ? args : args.map{|v| v.cur }
end

#with(*args, &block) ⇒ Object

With returns a new reactive value dependent on any arguments passed in. If a block is passed in, the getter is the block its self, which will be passed the .cur and the .cur of any reactive arguments.



303
304
305
# File 'lib/volt/reactive/reactive_value.rb', line 303

def with(*args, &block)
  return with_and_options(args, &block)
end

#with_and_options(args, &block) ⇒ Object



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/volt/reactive/reactive_value.rb', line 307

def with_and_options(args, &block)
  getter = @getter
  setter = @setter
  scope = @scope
   
  if block
    # If a block was passed in, the getter now becomes a proc that calls
    # the passed in block with the right arguments.
    getter = ::Proc.new do        
      # TODO: Calling cur every time
      current_val = self.cur
      
      if current_val.is_a?(Exception)
        current_val
      else
        block.call(current_val, args)
      end
    end
    
    # TODO: Make this work with custom setters
    setter = nil

    # Scope also gets set to nil, because now we should always retrigger this
    # method because we don't know enough about what methods its calling.
    scope = nil
  end
  
  new_val = ReactiveValue.new(getter, setter, scope)
  
  # Add the ReactiveValue we're building from
  new_val.reactive_manager.add_parent!(self)

  # Add any reactive arguments as parents
  args.select(&:reactive?).each do |arg|
    new_val.reactive_manager.add_parent!(arg.reactive_manager)
  end
  
  return new_val
end