class OFlow::Box

A Box encapsulates data in the system. It provides a wrapper around the data which becomes immutable as it is frozen in transit between Tasks. The Box allows the contents to be modified by replacing the contents with thawed copies of the original data.

Boxes are shipped between Tasks. A Tracker can also be attached to a Box to follow it and gather a history of it's movements.

Attributes

contents[R]

The contents of the Box.

tracker[R]

Tracker for the box if there is one.

Public Class Methods

new(value, tracker=nil) click to toggle source

Create a new Box withe the content provided. The value provided will be frozen to inhibit changes to the value after the Box is created. @param value contents of the Box @param tracker [Tracker] used to track the progress of the Box

# File lib/oflow/box.rb, line 23
def initialize(value, tracker=nil)
  @tracker = tracker
  @contents = value
end

Public Instance Methods

aget(path) click to toggle source

Returns the data element described by the path which is an array of element names or indices. Indices can be Fixnum or Strings. @param path [Array] location of element to return @return the data element.

# File lib/oflow/box.rb, line 71
def aget(path)
  _aget(path, @contents)
end
aset(path, value) click to toggle source

Sets or adds a value inside the Box where the path is an array of element names or indices. Indices can be Fixnum or Strings. @param path [Array] location of element to change or add. @param value value for the addition or change

# File lib/oflow/box.rb, line 53
def aset(path, value)
  Box.new(_aset(path, @contents, value), @tracker)
end
deep_freeze(value) click to toggle source

TBD make these module methods on a Freezer module

# File lib/oflow/box.rb, line 100
def deep_freeze(value)
  case value
  when Array
    value.each { |v| deep_freeze(v) }
  when Hash
    # hash keys are frozen already
    value.each { |k, v| deep_freeze(v) }
  end
  # Don't freeze other Objects. This leaves an out for special purpose
  # functionality.
  value.freeze
end
freeze() click to toggle source

Called when passing to another Task. It freezes the contents recursively.

Calls superclass method
# File lib/oflow/box.rb, line 86
def freeze()
  deep_freeze(@contents)
  super
end
get(path) click to toggle source

Returns the data element described by the path. A path is a set of element names in the case of a Hash or index numbers in the case of an Array joined with the ':' character as a separator. @param path [String] location of element to return @return the data element.

# File lib/oflow/box.rb, line 62
def get(path)
  return @contents if path.nil?
  aget(path.split(':'))
end
inspect()
Alias for: to_s
receive(location, op) click to toggle source

Receives a Box by creating a new Box whose contents is the same as the existing but with an updated tracker. @param location [String] where the Box was received, full name of Task @param op [Symbol] operation that the Box was received under @return [Box] new Box.

# File lib/oflow/box.rb, line 33
def receive(location, op)
  return self if @tracker.nil?
  Box.new(@contents, @tracker.receive(location, op))
end
set(path, value) click to toggle source

Sets or adds a value inside the Box. The Box is changed with the new contents being thawed where necessary. A path is a set of element names in the case of a Hash or index numbers in the case of an Array joined with the ':' character as a separator. @param path [String] location of element to change or add. @param value value for the addition or change

# File lib/oflow/box.rb, line 44
def set(path, value)
  return aset(nil, value) if path.nil?
  aset(path.split(':'), value)
end
thaw() click to toggle source

Makes a copy of the frozen contents and the Box to allow modifications. @return [Box] new Box.

# File lib/oflow/box.rb, line 93
def thaw()
  # Don't freeze the contents.
  Box.new(thaw_value(@contents, true), @tracker)
end
thaw_value(value, recurse) click to toggle source

Make a copy of the value, unfrozen.

# File lib/oflow/box.rb, line 114
def thaw_value(value, recurse)
  return value unless value.frozen? || recurse
  case value
  when Array
    # thaws the array itself but not the elements
    value = Array.new(value)
    value.map! { |v| thaw_value(v, true) } if recurse
  when Hash
    # thaws the hash itself but not the elements
    orig = value
    value = {}
    if recurse
      orig.each { |k, v| value[k] = thaw_value(v, true) }
    else
      orig.each { |k, v| value[k] = v }
    end
  when String
    value = String.new(value)
  end
  value
end
to_s() click to toggle source

Returns a string representation of the Box and contents.

# File lib/oflow/box.rb, line 76
def to_s()
  if @tracker.nil?
    "Box{#{@contents}}"
  else
    "Box{#{@contents}, tracker: #{@tracker}}"
  end
end
Also aliased as: inspect

Private Instance Methods

_aget(path, value) click to toggle source
# File lib/oflow/box.rb, line 174
def _aget(path, value)
  return value if path.nil? || path.empty? || value.nil?
  p = path[0]
  case value
  when Array
    begin
      _aget(path[1..-1], value[p.to_i])
    rescue
      nil
    end
  when Hash
    v = value[p] || value[p.to_sym]
    _aget(path[1..-1], v)
  else
    if value.respond_to?(p.to_sym)
      _aget(path[1..-1], value.send(p))
    else
      nil
    end
  end
end
_aset(path, value, rv) click to toggle source
# File lib/oflow/box.rb, line 138
def _aset(path, value, rv)
  return rv if path.nil? || path.empty?
  p = path[0]
  case value
  when Array
    value = Array.new(value) if value.frozen?
    i = p.to_i
    value[p.to_i] = _aset(path[1..-1], value[i], rv)
  when Hash
    if value.frozen?
      orig = value
      value = {}
      orig.each { |k, v| value[k] = v }
    end
    if value.has_key?(p)
      value[p] = _aset(path[1..-1], value[p], rv)
    else
      ps = p.to_sym
      value[ps] = _aset(path[1..-1], value[ps], rv)
    end
  when NilClass
    if /^\d+$/.match(p).nil?
      ps = p.to_sym
      value = {}
      value[ps] = _aset(path[1..-1], nil, rv)
    else
      i = p.to_i
      value = []
      value[i] = _aset(path[1..-1], nil, rv)
    end
  else
    raise FrozenError.new(p, value)
  end
  value
end