class PEROBS::Hash
A Hash
that is transparently persisted in the back-end storage. It is very similar to the Ruby built-in Hash
class but has some additional limitations. The hash key must always be a String.
The implementation is largely a proxy around the standard Hash
class. But all mutating methods must be re-implemented to convert PEROBS::Objects to POXReference
objects and to register the object as modified with the cache. However, it is not designed for large data sets as it always reads and writes the full data set for every access (unless it is cached). For data sets that could have more than a few hundred entries BigHash
is the recommended alternative.
We explicitely don’t support Hash::store() as it conflicts with ObjectBase::store() method to access the store.
Public Class Methods
New PEROBS
objects must always be created by calling # Store.new()
. PEROBS
users should never call this method or equivalents of derived methods directly. @param p [PEROBS::Handle] PEROBS
handle @param default [Object] The default value that is returned when no value
is stored for a specific key. The default must be of the supported type.
# File lib/perobs/Hash.rb, line 112 def initialize(p, default = nil, &block) super(p) _check_assignment_value(default) if block_given? @data = ::Hash.new(&block) else @data = ::Hash.new(default) end # Ensure that the newly created object will be pushed into the database. @store.cache.cache_write(self) end
Public Instance Methods
Proxy for assignment method.
# File lib/perobs/Hash.rb, line 126 def []=(key, value) unless key.is_a?(String) || key.respond_to?(:is_poxreference?) raise ArgumentError, "PEROBS::Hash[] key must be a String or " + "a PEROBS object but is a #{key.class}" end _check_assignment_value(value) @store.cache.cache_write(self) @data[key] = value end
This method should only be used during store repair operations. It will delete all referenced to the given object ID. @param id [Integer] targeted object ID
# File lib/perobs/Hash.rb, line 162 def _delete_reference_to_id(id) original_length = @data.length @data.delete_if do |k, v| (k && k.respond_to?(:is_poxreference?) && k.id == id) || (v && v.respond_to?(:is_poxreference?) && v.id == id) end if @data.length != original_length @store.cache.cache_write(self) end end
Restore the persistent data from a single data structure. This is a library internal method. Do not use outside of this library. @param data [Hash] the actual Hash
object @private
# File lib/perobs/Hash.rb, line 179 def _deserialize(data) @data = {} data.each do |k, v| # References to other PEROBS Objects are marshalled with our own # format. If we detect such a marshalled String we convert it into a # POXReference object. if (match = /^#<PEROBS::POReference id=([0-9]+)>$/.match(k)) k = POXReference.new(@store, match[1].to_i) end dv = v.is_a?(POReference) ? POXReference.new(@store, v.id) : v @data[k] = dv end @data end
Return a list of all object IDs of all persistend objects that this Hash
is referencing. @return [Array of Integer] IDs of referenced objects
# File lib/perobs/Hash.rb, line 145 def _referenced_object_ids ids = [] @data.each do |k, v| if k && k.respond_to?(:is_poxreference?) ids << k.id end if v && v.respond_to?(:is_poxreference?) ids << v.id end end ids end
Proxy for default= method.
# File lib/perobs/Hash.rb, line 137 def default=(value) _check_assignment_value(value) @data.default=(value) end
Textual dump for debugging purposes @return [String]
# File lib/perobs/Hash.rb, line 198 def inspect "<#{self.class}:#{@_id}>\n{\n" + @data.map do |k, v| " #{k.inspect} => " + (v.respond_to?(:is_poxreference?) ? "<PEROBS::ObjectBase:#{v._id}>" : v.inspect) end.join(",\n") + "\n}\n" end
Private Instance Methods
# File lib/perobs/Hash.rb, line 209 def _serialize data = {} @data.each do |k, v| if k.respond_to?(:is_poxreference?) # JSON only supports Strings as hash keys. Since JSON is the default # internal storage format in the database, we have to marshall # PEROBS::Object references ourselves. k = "#<PEROBS::POReference id=#{k.id}>" elsif k[0..24] == '#<PEROBS::POReference id=' # This could obviously result in conflicts with 'normal' String hash # keys. This is extremely unlikely, but we better catch this case # before it causes hard to debug trouble. raise ArgumentError, "Hash key #{k} conflicts with PEROBS " + "internal representation of marshalled hash keys!" end data[k] = serialize_helper(v) end data end
# File lib/perobs/Hash.rb, line 231 def serialize_helper(v) if v.respond_to?(:is_poxreference?) # References to other PEROBS objects (POXReference) are stored as # POReference in the database. return POReference.new(v.id) else # Outside of the PEROBS library all PEROBS::ObjectBase derived # objects should not be used directly. The library only exposes them # via POXReference proxy objects. if v.is_a?(ObjectBase) PEROBS.log.fatal 'A PEROBS::ObjectBase object escaped! ' + "It is stored in a PEROBS::Hash. " + 'Have you used self() instead of myself() to ' + "get the reference of this PEROBS object?\n" + v.inspect end # All other objects are serialized by their native methods. return v end end