perobs 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/Rakefile +2 -4
- data/lib/perobs/Array.rb +58 -108
- data/lib/perobs/BTreeDB.rb +1 -1
- data/lib/perobs/Cache.rb +12 -0
- data/lib/perobs/Delegator.rb +78 -0
- data/lib/perobs/DynamoDB.rb +1 -1
- data/lib/perobs/Hash.rb +56 -110
- data/lib/perobs/Object.rb +35 -19
- data/lib/perobs/ObjectBase.rb +82 -28
- data/lib/perobs/Store.rb +75 -9
- data/lib/perobs/version.rb +1 -1
- data/tasks/test.rake +2 -1
- data/test/Array_spec.rb +208 -0
- data/{spec → test}/BTreeDB_spec.rb +23 -23
- data/{spec → test}/ClassMap_spec.rb +15 -15
- data/test/Hash_spec.rb +157 -0
- data/{spec → test}/Object_spec.rb +53 -28
- data/{spec → test}/Store_spec.rb +135 -129
- data/{spec → test}/perobs_spec.rb +44 -47
- data/{spec/Array_spec.rb → test/spec_helper.rb} +9 -61
- metadata +29 -26
- data/spec/Hash_spec.rb +0 -96
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cea78483599ce586c57310a9d4aa622b3bfc3ca2
|
4
|
+
data.tar.gz: febaf3328e7a157a38529507a4a5a91a0bc49d2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6be86d3f49ff2e7bb816d7a6a257f07642b01cd8bdb94636fc2ccbd571fd225e0cd281786372051fc940f84f5440001ab5519994980775bd710c73fef59cffeb
|
7
|
+
data.tar.gz: fc1632708462f8f81b15f28f8a0226d49521443bf6fc6a0b0f1470efcec0a9f81412a08093f956718d84ab9e02b3c5f6e31fa37fa9da3b949250f8c5904a8200
|
data/README.md
CHANGED
@@ -60,7 +60,7 @@ class Person < PEROBS::Object
|
|
60
60
|
def initialize(store, name)
|
61
61
|
super
|
62
62
|
attr_init(:name, name)
|
63
|
-
attr_init(:kids, PEROBS::Array
|
63
|
+
attr_init(:kids, store.new(PEROBS::Array))
|
64
64
|
end
|
65
65
|
|
66
66
|
def to_s
|
@@ -71,9 +71,9 @@ class Person < PEROBS::Object
|
|
71
71
|
end
|
72
72
|
|
73
73
|
store = PEROBS::Store.new('family')
|
74
|
-
store['grandpa'] = joe =
|
75
|
-
store['grandma'] = jane =
|
76
|
-
jim =
|
74
|
+
store['grandpa'] = joe = store.new(Person, 'Joe')
|
75
|
+
store['grandma'] = jane = store.new(Person, 'Jane')
|
76
|
+
jim = store.new(Person, 'Jim')
|
77
77
|
jim.father = joe
|
78
78
|
joe.kids << jim
|
79
79
|
jim.mother = jane
|
data/Rakefile
CHANGED
data/lib/perobs/Array.rb
CHANGED
@@ -30,11 +30,55 @@ require 'perobs/ObjectBase'
|
|
30
30
|
module PEROBS
|
31
31
|
|
32
32
|
# An Array that is transparently persisted onto the back-end storage. It is
|
33
|
-
# very similar to the Ruby built-in Array class but
|
34
|
-
#
|
33
|
+
# very similar to the Ruby built-in Array class but like other PEROBS
|
34
|
+
# object classes it converts direct references to other PEROBS objects into
|
35
|
+
# POXReference objects that only indirectly reference the other object. It
|
36
|
+
# also tracks all reads and write to any Array element and updates the cache
|
37
|
+
# accordingly.
|
38
|
+
#
|
39
|
+
# We don't support an Array.initialize_copy proxy as this would conflict
|
40
|
+
# with BasicObject.initialize_copy. You can use PEROBS::Array.replace()
|
41
|
+
# instead.
|
35
42
|
class Array < ObjectBase
|
36
43
|
|
37
|
-
|
44
|
+
attr_reader :data
|
45
|
+
|
46
|
+
# These methods do not mutate the Array. They only perform read
|
47
|
+
# operations.
|
48
|
+
([
|
49
|
+
:&, :*, :+, :-, :==, :[], :<=>, :at, :abbrev, :assoc, :bsearch, :collect,
|
50
|
+
:combination, :compact, :count, :cycle, :dclone, :drop, :drop_while,
|
51
|
+
:each, :each_index, :empty?, :eql?, :fetch, :find_index, :first,
|
52
|
+
:flatten, :frozen?, :hash, :include?, :index, :inspect, :join, :last,
|
53
|
+
:length, :map, :pack, :permutation, :pretty_print, :pretty_print_cycle,
|
54
|
+
:product, :rassoc, :reject, :repeated_combination,
|
55
|
+
:repeated_permutation, :reverse, :reverse_each, :rindex, :rotate,
|
56
|
+
:sample, :select, :shelljoin, :shuffle, :size, :slice, :sort, :take,
|
57
|
+
:take_while, :to_a, :to_ary, :to_s, :transpose, :uniq, :values_at, :zip,
|
58
|
+
:|
|
59
|
+
] + Enumerable.instance_methods).uniq.each do |method_sym|
|
60
|
+
define_method(method_sym) do |*args, &block|
|
61
|
+
@store.cache.cache_read(self)
|
62
|
+
@data.send(method_sym, *args, &block)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# These methods mutate the Array.
|
67
|
+
[
|
68
|
+
:<<, :[]=, :clear, :collect!, :compact!, :concat, :delete, :delete_at,
|
69
|
+
:delete_if, :fill, :flatten!, :insert, :keep_if, :map!, :pop, :push,
|
70
|
+
:reject!, :replace, :select!, :reverse!, :rotate!, :shift, :shuffle!,
|
71
|
+
:slice!, :sort!, :sort_by!, :uniq!, :unshift
|
72
|
+
].each do |method_sym|
|
73
|
+
define_method(method_sym) do |*args, &block|
|
74
|
+
@store.cache.cache_write(self)
|
75
|
+
@data.send(method_sym, *args, &block)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# New PEROBS objects must always be created by calling # Store.new().
|
80
|
+
# PEROBS users should never call this method or equivalents of derived
|
81
|
+
# methods directly.
|
38
82
|
# @param store [Store] The Store this hash is stored in
|
39
83
|
# @param size [Fixnum] The requested size of the Array
|
40
84
|
# @param default [Any] The default value that is returned when no value is
|
@@ -44,113 +88,22 @@ module PEROBS
|
|
44
88
|
@data = ::Array.new(size, default)
|
45
89
|
end
|
46
90
|
|
47
|
-
# Equivalent to Array::[]
|
48
|
-
def [](index)
|
49
|
-
_dereferenced(@data[index])
|
50
|
-
end
|
51
|
-
|
52
|
-
# Equivalent to Array::[]=
|
53
|
-
def []=(index, obj)
|
54
|
-
@data[index] = _referenced(obj)
|
55
|
-
@store.cache.cache_write(self)
|
56
|
-
|
57
|
-
obj
|
58
|
-
end
|
59
|
-
|
60
|
-
# Equivalent to Array::<<
|
61
|
-
def <<(obj)
|
62
|
-
@store.cache.cache_write(self)
|
63
|
-
@data << _referenced(obj)
|
64
|
-
end
|
65
|
-
|
66
|
-
# Equivalent to Array::+
|
67
|
-
def +(ary)
|
68
|
-
@store.cache.cache_write(self)
|
69
|
-
@data + ary
|
70
|
-
end
|
71
|
-
|
72
|
-
# Equivalent to Array::push
|
73
|
-
def push(obj)
|
74
|
-
@store.cache.cache_write(self)
|
75
|
-
@data.push(_referenced(obj))
|
76
|
-
end
|
77
|
-
|
78
|
-
# Equivalent to Array::pop
|
79
|
-
def pop
|
80
|
-
@store.cache.cache_write(self)
|
81
|
-
_dereferenced(@data.pop)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Equivalent to Array::clear
|
85
|
-
def clear
|
86
|
-
@store.cache.cache_write(self)
|
87
|
-
@data.clear
|
88
|
-
end
|
89
|
-
|
90
|
-
# Equivalent to Array::delete
|
91
|
-
def delete(obj)
|
92
|
-
@store.cache.cache_write(self)
|
93
|
-
@data.delete { |v| _dereferenced(v) == obj }
|
94
|
-
end
|
95
|
-
|
96
|
-
# Equivalent to Array::delete_at
|
97
|
-
def delete_at(index)
|
98
|
-
@store.cache.cache_write(self)
|
99
|
-
@data.delete_at(index)
|
100
|
-
end
|
101
|
-
|
102
|
-
# Equivalent to Array::delete_if
|
103
|
-
def delete_if
|
104
|
-
@data.delete_if do |item|
|
105
|
-
yield(_dereferenced(item))
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Equivalent to Array::each
|
110
|
-
def each
|
111
|
-
@data.each do |item|
|
112
|
-
yield(_dereferenced(item))
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Equivalent to Array::empty?
|
117
|
-
def empty?
|
118
|
-
@data.empty?
|
119
|
-
end
|
120
|
-
|
121
|
-
# Equivalent to Array::include?
|
122
|
-
def include?(obj)
|
123
|
-
@data.each { |v| return true if _dereferenced(v) == obj }
|
124
|
-
|
125
|
-
false
|
126
|
-
end
|
127
|
-
|
128
|
-
# Equivalent to Array::length
|
129
|
-
def length
|
130
|
-
@data.length
|
131
|
-
end
|
132
|
-
alias size length
|
133
|
-
|
134
|
-
# Equivalent to Array::map
|
135
|
-
def map
|
136
|
-
@data.map do |item|
|
137
|
-
yield(_dereferenced(item))
|
138
|
-
end
|
139
|
-
end
|
140
|
-
alias collect map
|
141
|
-
|
142
91
|
# Return a list of all object IDs of all persistend objects that this Array
|
143
92
|
# is referencing.
|
144
93
|
# @return [Array of Fixnum or Bignum] IDs of referenced objects
|
145
94
|
def _referenced_object_ids
|
146
|
-
@data.each.select
|
95
|
+
@data.each.select do |v|
|
96
|
+
v && v.respond_to?(:is_poxreference?)
|
97
|
+
end.map { |o| o.id }
|
147
98
|
end
|
148
99
|
|
149
100
|
# This method should only be used during store repair operations. It will
|
150
101
|
# delete all referenced to the given object ID.
|
151
102
|
# @param id [Fixnum/Bignum] targeted object ID
|
152
103
|
def _delete_reference_to_id(id)
|
153
|
-
@data.delete_if
|
104
|
+
@data.delete_if do |v|
|
105
|
+
v && v.respond_to?(:is_poxreference?) && v.id == id
|
106
|
+
end
|
154
107
|
end
|
155
108
|
|
156
109
|
# Restore the persistent data from a single data structure.
|
@@ -158,19 +111,16 @@ module PEROBS
|
|
158
111
|
# @param data [Array] the actual Array object
|
159
112
|
# @private
|
160
113
|
def _deserialize(data)
|
161
|
-
@data = data
|
162
|
-
|
163
|
-
|
164
|
-
# Textual dump for debugging purposes
|
165
|
-
# @return [String]
|
166
|
-
def inspect
|
167
|
-
"[\n" + @data.map { |v| " #{v.inspect}" }.join(",\n") + "\n]\n"
|
114
|
+
@data = data.map { |v| v.is_a?(POReference) ?
|
115
|
+
POXReference.new(@store, v.id) : v }
|
168
116
|
end
|
169
117
|
|
170
118
|
private
|
171
119
|
|
172
120
|
def _serialize
|
173
|
-
@data
|
121
|
+
@data.map do |v|
|
122
|
+
v.respond_to?(:is_poxreference?) ? POReference.new(v.id) : v
|
123
|
+
end
|
174
124
|
end
|
175
125
|
|
176
126
|
end
|
data/lib/perobs/BTreeDB.rb
CHANGED
@@ -103,7 +103,7 @@ module PEROBS
|
|
103
103
|
# Return true if the object with given ID exists
|
104
104
|
# @param id [Fixnum or Bignum]
|
105
105
|
def include?(id)
|
106
|
-
(blob = find_blob(id)) && blob.find(id)
|
106
|
+
!(blob = find_blob(id)).nil? && !blob.find(id).nil?
|
107
107
|
end
|
108
108
|
|
109
109
|
# Store a simple Hash as a JSON encoded file into the DB directory.
|
data/lib/perobs/Cache.rb
CHANGED
@@ -51,12 +51,24 @@ module PEROBS
|
|
51
51
|
# Add an PEROBS::Object to the read cache.
|
52
52
|
# @param obj [PEROBS::ObjectBase]
|
53
53
|
def cache_read(obj)
|
54
|
+
# This is just a safety check. It can probably be disabled in the future
|
55
|
+
# to increase performance.
|
56
|
+
if obj.respond_to?(:is_poxreference?)
|
57
|
+
# If this condition triggers, we have a bug in the library.
|
58
|
+
raise RuntimeError, "POXReference objects should never be cached"
|
59
|
+
end
|
54
60
|
@reads[index(obj)] = obj
|
55
61
|
end
|
56
62
|
|
57
63
|
# Add a PEROBS::Object to the write cache.
|
58
64
|
# @param obj [PEROBS::ObjectBase]
|
59
65
|
def cache_write(obj)
|
66
|
+
# This is just a safety check. It can probably be disabled in the future
|
67
|
+
# to increase performance.
|
68
|
+
if obj.respond_to?(:is_poxreference?)
|
69
|
+
# If this condition triggers, we have a bug in the library.
|
70
|
+
raise RuntimeError, "POXReference objects should never be cached"
|
71
|
+
end
|
60
72
|
if @transaction_stack.empty?
|
61
73
|
idx = index(obj)
|
62
74
|
if (old_obj = @writes[idx]) && old_obj._id != obj._id
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# = Delegator.rb -- Persistent Ruby Object Store
|
4
|
+
#
|
5
|
+
# Copyright (c) 2015 by Chris Schlaeger <chris@taskjuggler.org>
|
6
|
+
#
|
7
|
+
# MIT License
|
8
|
+
#
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
10
|
+
# a copy of this software and associated documentation files (the
|
11
|
+
# "Software"), to deal in the Software without restriction, including
|
12
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
13
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
14
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
15
|
+
# the following conditions:
|
16
|
+
#
|
17
|
+
# The above copyright notice and this permission notice shall be
|
18
|
+
# included in all copies or substantial portions of the Software.
|
19
|
+
#
|
20
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
21
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
23
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
24
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
25
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
26
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
|
+
|
28
|
+
require 'perobs/ClassMap'
|
29
|
+
|
30
|
+
module PEROBS
|
31
|
+
|
32
|
+
# This Delegator module provides the methods to turn the PEROBS::Array and
|
33
|
+
# PEROBS::Hash into proxies for Array and Hash.
|
34
|
+
module Delegator
|
35
|
+
|
36
|
+
# Proxy all calls to unknown methods to the data object.
|
37
|
+
def method_missing(method_sym, *args, &block)
|
38
|
+
if self.class::READERS.include?(method_sym) ||
|
39
|
+
Enumerable.instance_methods.include?(method_sym)
|
40
|
+
# If any element of this class is read, we register this object as
|
41
|
+
# being read with the cache.
|
42
|
+
@store.cache.cache_read(self)
|
43
|
+
@data.send(method_sym, *args, &block)
|
44
|
+
elsif self.class::REWRITERS.include?(method_sym)
|
45
|
+
# Re-writers don't introduce any new elements. We just mark the object
|
46
|
+
# as written in the cache and call the class' method.
|
47
|
+
@store.cache.cache_write(self)
|
48
|
+
@data.send(method_sym, *args, &block)
|
49
|
+
elsif (alias_sym = self.class::ALIASES[method_sym])
|
50
|
+
@store.cache.cache_write(self)
|
51
|
+
send(alias_sym, *args, &block)
|
52
|
+
else
|
53
|
+
# Any method we don't know about must cause an error. A new class
|
54
|
+
# method needs to be added to the right bucket first.
|
55
|
+
raise NoMethodError.new("undefined method '#{method_sym}' for " +
|
56
|
+
"#{self.class}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def respond_to?(method_sym, include_private = false)
|
61
|
+
self.class::READERS.include?(method_sym) ||
|
62
|
+
Enumerable.instance_methods.include?(method_sym) ||
|
63
|
+
self.class::REWRITERS.include?(method_sym) ||
|
64
|
+
super
|
65
|
+
end
|
66
|
+
|
67
|
+
# Equivalent to Class::==
|
68
|
+
# This method is just a reader but also part of BasicObject. Hence
|
69
|
+
# BasicObject::== would be called instead of method_missing.
|
70
|
+
def ==(obj)
|
71
|
+
@store.cache.cache_read(self)
|
72
|
+
@data == obj
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
data/lib/perobs/DynamoDB.rb
CHANGED
@@ -87,7 +87,7 @@ module PEROBS
|
|
87
87
|
# Return true if the object with given ID exists
|
88
88
|
# @param id [Fixnum or Bignum]
|
89
89
|
def include?(id)
|
90
|
-
dynamo_get_item(id.to_s)
|
90
|
+
!dynamo_get_item(id.to_s).nil?
|
91
91
|
end
|
92
92
|
|
93
93
|
# Store a simple Hash as a JSON encoded file into the DB directory.
|
data/lib/perobs/Hash.rb
CHANGED
@@ -32,9 +32,51 @@ module PEROBS
|
|
32
32
|
# A Hash that is transparently persisted in the back-end storage. It is very
|
33
33
|
# similar to the Ruby built-in Hash class but has some additional
|
34
34
|
# limitations. The hash key must always be a String.
|
35
|
+
#
|
36
|
+
# The implementation is largely a proxy around the standard Hash class. But
|
37
|
+
# all mutating methods must be re-implemented to convert PEROBS::Objects to
|
38
|
+
# POXReference objects and to register the object as modified with the
|
39
|
+
# cache.
|
40
|
+
#
|
41
|
+
# We explicitely don't support Hash::store() as it conflicts with
|
42
|
+
# ObjectBase::store() method to access the store.
|
35
43
|
class Hash < ObjectBase
|
36
44
|
|
37
|
-
#
|
45
|
+
# These methods do not mutate the Hash. They only perform read
|
46
|
+
# operations.
|
47
|
+
([
|
48
|
+
:==, :[], :assoc, :compare_by_identity, :compare_by_identity?, :default,
|
49
|
+
:default_proc, :each, :each_key, :each_pair, :each_value, :empty?,
|
50
|
+
:eql?, :fetch, :flatten, :has_key?, :has_value?, :hash, :include?,
|
51
|
+
:inspect, :invert, :key, :key?, :keys, :length, :member?, :merge,
|
52
|
+
:pretty_print, :pretty_print_cycle, :rassoc, :reject, :select, :size,
|
53
|
+
:to_a, :to_h, :to_hash, :to_s, :value?, :values, :values_at
|
54
|
+
] + Enumerable.instance_methods).uniq.each do |method_sym|
|
55
|
+
# Create a wrapper method that passes the call to @data.
|
56
|
+
define_method(method_sym) do |*args, &block|
|
57
|
+
# Register the read operation with the cache.
|
58
|
+
@store.cache.cache_read(self)
|
59
|
+
@data.send(method_sym, *args, &block)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# These methods mutate the Hash.
|
64
|
+
[
|
65
|
+
:[]=, :clear, :default=, :default_proc=, :delete, :delete_if,
|
66
|
+
:initialize_copy, :keep_if, :merge!, :rehash, :reject!, :replace,
|
67
|
+
:select!, :shift, :update
|
68
|
+
].each do |method_sym|
|
69
|
+
# Create a wrapper method that passes the call to @data.
|
70
|
+
define_method(method_sym) do |*args, &block|
|
71
|
+
# Register the write operation with the cache.
|
72
|
+
@store.cache.cache_write(self)
|
73
|
+
@data.send(method_sym, *args, &block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# New PEROBS objects must always be created by calling # Store.new().
|
78
|
+
# PEROBS users should never call this method or equivalents of derived
|
79
|
+
# methods directly.
|
38
80
|
# @param store [Store] The Store this hash is stored in
|
39
81
|
# @param default [Any] The default value that is returned when no value is
|
40
82
|
# stored for a specific key.
|
@@ -44,115 +86,21 @@ module PEROBS
|
|
44
86
|
@data = {}
|
45
87
|
end
|
46
88
|
|
47
|
-
# Retrieves the value object corresponding to the
|
48
|
-
# key object. If not found, returns the default value.
|
49
|
-
def [](key)
|
50
|
-
#unless key.is_a?(String)
|
51
|
-
# raise ArgumentError, 'The Hash key must be of type String'
|
52
|
-
#end
|
53
|
-
_dereferenced(@data.include?(key) ? @data[key] : @default)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Associates the value given by value with the key given by key.
|
57
|
-
# @param key [String] The key
|
58
|
-
# @param value [Any] The value to store
|
59
|
-
def []=(key, value)
|
60
|
-
#unless key.is_a?(String)
|
61
|
-
# raise ArgumentError, 'The Hash key must be of type String'
|
62
|
-
#end
|
63
|
-
@data[key] = _referenced(value)
|
64
|
-
@store.cache.cache_write(self)
|
65
|
-
|
66
|
-
value
|
67
|
-
end
|
68
|
-
|
69
|
-
# Equivalent to Hash::clear
|
70
|
-
def clear
|
71
|
-
@store.cache.cache_write(self)
|
72
|
-
@data.clear
|
73
|
-
end
|
74
|
-
|
75
|
-
# Equivalent to Hash::delete
|
76
|
-
def delete(key)
|
77
|
-
@store.cache.cache_write(self)
|
78
|
-
@data.delete(key)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Equivalent to Hash::delete_if
|
82
|
-
def delete_if
|
83
|
-
@store.cache.cache_write(self)
|
84
|
-
@data.delete_if do |k, v|
|
85
|
-
yield(k, _dereferenced(v))
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# Equivalent to Hash::each
|
90
|
-
def each
|
91
|
-
@data.each do |k, v|
|
92
|
-
yield(k, _dereferenced(v))
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Equivalent to Hash::each_key
|
97
|
-
def each_key
|
98
|
-
@data.each_key { |k| yield(k) }
|
99
|
-
end
|
100
|
-
|
101
|
-
# Equivalent to Hash::each_value
|
102
|
-
def each_value
|
103
|
-
@data.each_value do |v|
|
104
|
-
yield(_dereferenced(v))
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Equivalent to Hash::empty?
|
109
|
-
def emtpy?
|
110
|
-
@data.empty?
|
111
|
-
end
|
112
|
-
|
113
|
-
# Equivalent to Hash::has_key?
|
114
|
-
def has_key?(key)
|
115
|
-
@data.has_key?(key)
|
116
|
-
end
|
117
|
-
alias include? has_key?
|
118
|
-
alias key? has_key?
|
119
|
-
alias member? has_key?
|
120
|
-
|
121
|
-
# Equivalent to Hash::keys
|
122
|
-
def keys
|
123
|
-
@data.keys
|
124
|
-
end
|
125
|
-
|
126
|
-
# Equivalent to Hash::length
|
127
|
-
def length
|
128
|
-
@data.length
|
129
|
-
end
|
130
|
-
alias size length
|
131
|
-
|
132
|
-
# Equivalent to Hash::map
|
133
|
-
def map
|
134
|
-
@data.map do |k, v|
|
135
|
-
yield(k, _dereferenced(v))
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
# Equivalent to Hash::values
|
140
|
-
def values
|
141
|
-
@data.values.map { |v| _dereferenced(v) }
|
142
|
-
end
|
143
|
-
|
144
89
|
# Return a list of all object IDs of all persistend objects that this Hash
|
145
90
|
# is referencing.
|
146
91
|
# @return [Array of Fixnum or Bignum] IDs of referenced objects
|
147
92
|
def _referenced_object_ids
|
148
|
-
@data.each_value.select { |v| v && v.
|
93
|
+
@data.each_value.select { |v| v && v.respond_to?(:is_poxreference?) }.
|
94
|
+
map { |o| o.id }
|
149
95
|
end
|
150
96
|
|
151
97
|
# This method should only be used during store repair operations. It will
|
152
98
|
# delete all referenced to the given object ID.
|
153
99
|
# @param id [Fixnum/Bignum] targeted object ID
|
154
100
|
def _delete_reference_to_id(id)
|
155
|
-
@data.delete_if
|
101
|
+
@data.delete_if do |k, v|
|
102
|
+
v && v.respond_to?(:is_poxreference?) && v.id == id
|
103
|
+
end
|
156
104
|
end
|
157
105
|
|
158
106
|
# Restore the persistent data from a single data structure.
|
@@ -160,21 +108,19 @@ module PEROBS
|
|
160
108
|
# @param data [Hash] the actual Hash object
|
161
109
|
# @private
|
162
110
|
def _deserialize(data)
|
163
|
-
@data =
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
# @return [String]
|
168
|
-
def inspect
|
169
|
-
"{\n" +
|
170
|
-
@data.map { |k, v| " #{k.inspect}=>#{v.inspect}" }.join(",\n") +
|
171
|
-
"\n}\n"
|
111
|
+
@data = {}
|
112
|
+
data.each { |k, v| @data[k] = v.is_a?(POReference) ?
|
113
|
+
POXReference.new(@store, v.id) : v }
|
114
|
+
@data
|
172
115
|
end
|
173
116
|
|
174
117
|
private
|
175
118
|
|
176
119
|
def _serialize
|
177
|
-
|
120
|
+
data = {}
|
121
|
+
@data.each { |k, v| data[k] = v.respond_to?(:is_poxreference?) ?
|
122
|
+
POReference.new(v.id) : v }
|
123
|
+
data
|
178
124
|
end
|
179
125
|
|
180
126
|
end
|