hyperactive 0.2.2 → 0.2.3
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.
- data/README +12 -5
- data/lib/hyperactive.rb +1 -1
- data/lib/hyperactive/hash.rb +172 -0
- data/lib/hyperactive/list.rb +128 -43
- data/lib/hyperactive/record.rb +159 -41
- data/tests/{tree_benchmark.rb → hash_benchmark.rb} +6 -6
- data/tests/{tree_test.rb → hash_test.rb} +17 -16
- data/tests/list_benchmark.rb +48 -0
- data/tests/list_test.rb +69 -11
- data/tests/record_test.rb +25 -31
- metadata +7 -6
- data/lib/hyperactive/tree.rb +0 -241
data/README
CHANGED
@@ -2,14 +2,21 @@
|
|
2
2
|
|
3
3
|
It uses archipelago for persistence, and is meaningful only in an environment where the server process doesnt restart at each request. This means that cgi environment is not really an option.
|
4
4
|
|
5
|
-
==
|
5
|
+
== Sub packages:
|
6
6
|
|
7
|
-
Hyperactive::
|
7
|
+
Hyperactive::Record:: The base class package itself, providing you with cached selectors and rejectors, along with cached finders for any number of attributes.
|
8
|
+
Hyperactive::Hash:: A collection class that contains any number of Hyperactive::Records in a hash like structure.
|
9
|
+
Hyperactive::List:: A collection class that contains any number of Hyperactive::Records in a list like structure.
|
8
10
|
|
9
|
-
==
|
11
|
+
== Usage:
|
12
|
+
|
13
|
+
To use Hyperactive in the simplest way, just run the script/services.rb script from the Archipelago
|
14
|
+
distribution to get a few services running, then subclass Hyperactive::Record::Bass and create
|
15
|
+
objects with <b>MyBassSubclass.get_instance</b> (not <b>new</b>!). They will be automagically
|
16
|
+
stored in the network, and fetchable via their <b>instance.record_id</b>.
|
10
17
|
|
11
|
-
Hyperactive::Record
|
12
|
-
|
18
|
+
By loading Hyperactive::Record you will automatically define Hyperactive::Record::CAPTAIN which will
|
19
|
+
be an Archipelago::Pirate::Captain that is your interface to the distributed database.
|
13
20
|
|
14
21
|
== Examples:
|
15
22
|
|
data/lib/hyperactive.rb
CHANGED
@@ -0,0 +1,172 @@
|
|
1
|
+
# Archipelago - a distributed computing toolkit for ruby
|
2
|
+
# Copyright (C) 2006 Martin Kihlgren <zond at troja dot ath dot cx>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or
|
5
|
+
# modify it under the terms of the GNU General Public License
|
6
|
+
# as published by the Free Software Foundation; either version 2
|
7
|
+
# of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'archipelago'
|
21
|
+
require 'digest/sha1'
|
22
|
+
|
23
|
+
module Hyperactive
|
24
|
+
|
25
|
+
#
|
26
|
+
# The package containing the Hash class that provides any
|
27
|
+
# kind of index for your Hyperactive classes.
|
28
|
+
#
|
29
|
+
# Is supposed to be constantly scaling, but preliminary benchmarks show some
|
30
|
+
# problems with that assumption?
|
31
|
+
#
|
32
|
+
module Hash
|
33
|
+
|
34
|
+
#
|
35
|
+
# A wrapper class that knows what key, value and list_element belong together.
|
36
|
+
#
|
37
|
+
class Element < Hyperactive::Record::Bass
|
38
|
+
attr_accessor :key, :value, :list_element
|
39
|
+
#
|
40
|
+
# Initialize a new Hash::Element with given +key+, +value+ and +list_element+.
|
41
|
+
#
|
42
|
+
def initialize(key, value, list_element)
|
43
|
+
self.key = key
|
44
|
+
self.value = value
|
45
|
+
self.list_element = list_element
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# A class suitable for storing large and often-changing datasets in
|
51
|
+
# an Archipelago environment.
|
52
|
+
#
|
53
|
+
class Head < Hyperactive::Record::Bass
|
54
|
+
|
55
|
+
attr_accessor :list
|
56
|
+
|
57
|
+
include Archipelago::Current::ThreadedCollection
|
58
|
+
|
59
|
+
#
|
60
|
+
# Initialize a Hash::Head.
|
61
|
+
#
|
62
|
+
# NB: Remember to call create on the new instance or use Head.get_instance to get that done automatically.
|
63
|
+
#
|
64
|
+
def initialize
|
65
|
+
self.list = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Return the size of this Hash.
|
70
|
+
#
|
71
|
+
def size
|
72
|
+
self.list.size
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Return the value for +key+.
|
77
|
+
#
|
78
|
+
def [](key)
|
79
|
+
element = Hyperactive::Record::CAPTAIN[my_key_for(key), @transaction]
|
80
|
+
if element
|
81
|
+
return element.value
|
82
|
+
else
|
83
|
+
return nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Returns whether +key+ is included in this Hash.
|
89
|
+
#
|
90
|
+
def include?(key)
|
91
|
+
Hyperactive::Record::CAPTAIN.include?(my_key_for(key), @transaction)
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# Insert +value+ under +key+ in this Hash.
|
96
|
+
#
|
97
|
+
def []=(key, value)
|
98
|
+
self.list = Hyperactive::List::Head.get_instance_with_transaction(@transaction) unless self.list
|
99
|
+
|
100
|
+
if (element = Hyperactive::Record::CAPTAIN[my_key_for(key), @transaction])
|
101
|
+
element.value = value
|
102
|
+
else
|
103
|
+
element = Element.get_instance_with_transaction(@transaction, key, value, nil)
|
104
|
+
self.list << element
|
105
|
+
element.list_element = self.list.last_element
|
106
|
+
Hyperactive::Record::CAPTAIN[my_key_for(key), @transaction] = element
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Delete +key+ from this Hash.
|
112
|
+
#
|
113
|
+
def delete(key)
|
114
|
+
self.list = Hyperactive::List::Head.get_instance_with_transaction(@transaction) unless self.list
|
115
|
+
|
116
|
+
return_value = nil
|
117
|
+
|
118
|
+
element = Hyperactive::Record::CAPTAIN[my_key_for(key), @transaction]
|
119
|
+
if element
|
120
|
+
Hyperactive::Record::CAPTAIN.delete(my_key_for(key), @transaction)
|
121
|
+
self.list.unlink!(element.list_element)
|
122
|
+
return_value = element.value
|
123
|
+
element.destroy!
|
124
|
+
end
|
125
|
+
return return_value
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Will yield to +block+ once for each key/value pair in this Hash.
|
130
|
+
#
|
131
|
+
def each(&block)
|
132
|
+
self.list = Hyperactive::List::Head.get_instance_with_transaction(@transaction) unless self.list
|
133
|
+
|
134
|
+
self.list.each do |element|
|
135
|
+
yield([element.key, element.value])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# Remove all key/value pairs from this Hash.
|
141
|
+
#
|
142
|
+
def clear!
|
143
|
+
self.list = Hyperactive::List::Head.get_instance_with_transaction(@transaction) unless self.list
|
144
|
+
|
145
|
+
self.list.t_each do |element|
|
146
|
+
element.destroy!
|
147
|
+
end
|
148
|
+
self.list.clear!
|
149
|
+
end
|
150
|
+
|
151
|
+
#
|
152
|
+
# Clear everything from this Tree and destroy it.
|
153
|
+
#
|
154
|
+
def destroy!
|
155
|
+
self.clear!
|
156
|
+
super
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
#
|
162
|
+
# Get my private key for a given +key+.
|
163
|
+
#
|
164
|
+
def my_key_for(key)
|
165
|
+
Digest::SHA1.hexdigest("#{Marshal.dump(key)}#{self.record_id}")
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
data/lib/hyperactive/list.rb
CHANGED
@@ -27,73 +27,148 @@ module Hyperactive
|
|
27
27
|
module List
|
28
28
|
|
29
29
|
#
|
30
|
-
# A List
|
30
|
+
# A wrapper class that knows its previous and next List::Elements as well as its value and the id of its list.
|
31
31
|
#
|
32
32
|
class Element < Hyperactive::Record::Bass
|
33
|
-
attr_accessor :previous, :next, :value
|
33
|
+
attr_accessor :previous, :next, :value, :list_id
|
34
|
+
|
35
|
+
include Archipelago::Current::ThreadedCollection
|
36
|
+
|
37
|
+
#
|
38
|
+
# Initialize this List::Element with given +previous_element+, +next_element+, +value+ and +list_id+.
|
39
|
+
#
|
40
|
+
def initialize(previous_element, next_element, value, list_id)
|
41
|
+
self.previous = previous_element
|
42
|
+
self.next = next_element
|
43
|
+
self.value = value
|
44
|
+
self.list_id = list_id
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Yield to +block+ once for this and each following element.
|
49
|
+
#
|
50
|
+
def each(&block)
|
51
|
+
element = self
|
52
|
+
while element
|
53
|
+
yield(element)
|
54
|
+
element = self.next
|
55
|
+
end
|
56
|
+
end
|
34
57
|
end
|
35
58
|
|
36
59
|
#
|
37
60
|
# A List head.
|
38
61
|
#
|
39
62
|
class Head < Hyperactive::Record::Bass
|
40
|
-
|
63
|
+
attr_accessor :first_element, :last_element, :size
|
64
|
+
|
65
|
+
include Archipelago::Current::ThreadedCollection
|
41
66
|
|
42
67
|
#
|
43
|
-
# Create a Head.
|
68
|
+
# Create a List::Head. This is in essence the linked list.
|
44
69
|
#
|
45
|
-
# NB:
|
70
|
+
# NB: Remember to call create on the new instance or use Head.get_instance to get that done automatically.
|
46
71
|
#
|
47
72
|
def initialize
|
48
|
-
|
49
|
-
|
73
|
+
self.size = 0
|
74
|
+
self.first_element = self.last_element = nil
|
50
75
|
end
|
51
76
|
|
77
|
+
#
|
78
|
+
# Unlinks the given +element+ and reconnects the List around it.
|
79
|
+
#
|
80
|
+
def unlink!(element)
|
81
|
+
raise "#{element} is not a part of #{self}" unless element.list_id == @record_id
|
82
|
+
|
83
|
+
if size > 1
|
84
|
+
if element == self.first_element
|
85
|
+
self.first_element = element.next
|
86
|
+
self.first_element.previous = nil
|
87
|
+
elsif element == self.last_element
|
88
|
+
self.last_element = element.previous
|
89
|
+
self.last_element.next = nil
|
90
|
+
else
|
91
|
+
element.previous.next = element.next
|
92
|
+
element.next.previous = element.previous
|
93
|
+
end
|
94
|
+
else
|
95
|
+
if element == self.first_element
|
96
|
+
self.first_element = self.last_element = nil
|
97
|
+
else
|
98
|
+
raise "#{element} is not a part of #{self} even though it claims to be"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
self.size -= 1
|
102
|
+
element.destroy!
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Remove all elements from this List::Head.
|
107
|
+
#
|
108
|
+
def clear!
|
109
|
+
self.first_element.t_each do |element|
|
110
|
+
element.destroy!
|
111
|
+
end
|
112
|
+
self.first_element = self.last_element = nil
|
113
|
+
self.size = 0
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Destroys this list and all its elements.
|
118
|
+
#
|
119
|
+
def destroy!
|
120
|
+
self.clear!
|
121
|
+
super
|
122
|
+
end
|
123
|
+
|
52
124
|
#
|
53
125
|
# Return the first value of the list.
|
54
126
|
#
|
55
127
|
def first
|
56
|
-
|
128
|
+
if self.first_element
|
129
|
+
self.first_element.value
|
130
|
+
else
|
131
|
+
nil
|
132
|
+
end
|
57
133
|
end
|
58
|
-
|
134
|
+
|
59
135
|
#
|
60
136
|
# Return the last value of the list.
|
61
137
|
#
|
62
138
|
def last
|
63
|
-
|
139
|
+
if self.last_element
|
140
|
+
self.last_element.value
|
141
|
+
else
|
142
|
+
end
|
64
143
|
end
|
65
144
|
|
66
145
|
#
|
67
146
|
# Push +v+ onto the end of this list.
|
68
147
|
#
|
69
148
|
def <<(v)
|
70
|
-
if
|
71
|
-
new_element = Element.
|
72
|
-
|
73
|
-
|
74
|
-
@last_element.next = new_element
|
75
|
-
@last_element = new_element
|
149
|
+
if self.first_element
|
150
|
+
new_element = Element.get_instance_with_transaction(@transaction, self.last_element, nil, v, @record_id)
|
151
|
+
self.last_element.next = new_element
|
152
|
+
self.last_element = new_element
|
76
153
|
else
|
77
154
|
start(v)
|
78
155
|
end
|
79
|
-
|
156
|
+
self.size += 1
|
80
157
|
return v
|
81
158
|
end
|
82
|
-
|
159
|
+
|
83
160
|
#
|
84
161
|
# Push +v+ onto the beginning of this list.
|
85
162
|
#
|
86
163
|
def unshift(v)
|
87
|
-
if
|
88
|
-
new_element = Element.
|
89
|
-
|
90
|
-
|
91
|
-
@first_element.previous = new_element
|
92
|
-
@first_element = new_element
|
164
|
+
if self.first_element
|
165
|
+
new_element = Element.get_instance_with_transaction(@transaction, nil, self.first_element, v, @record_id)
|
166
|
+
self.first_element.previous = new_element
|
167
|
+
self.first_element = new_element
|
93
168
|
else
|
94
169
|
start(v)
|
95
170
|
end
|
96
|
-
|
171
|
+
self.size += 1
|
97
172
|
return v
|
98
173
|
end
|
99
174
|
|
@@ -103,37 +178,48 @@ module Hyperactive
|
|
103
178
|
def pop
|
104
179
|
v = nil
|
105
180
|
if size > 1
|
106
|
-
element =
|
107
|
-
|
108
|
-
|
181
|
+
element = self.last_element
|
182
|
+
self.last_element = element.previous
|
183
|
+
self.last_element.next = nil
|
109
184
|
v = element.value
|
110
|
-
element.destroy
|
185
|
+
element.destroy!
|
111
186
|
else
|
112
|
-
v =
|
113
|
-
|
114
|
-
|
187
|
+
v = self.first_element.value
|
188
|
+
self.first_element.destroy!
|
189
|
+
self.first_element = self.last_element = nil
|
115
190
|
end
|
116
|
-
|
191
|
+
self.size -= 1
|
117
192
|
return v
|
118
193
|
end
|
119
194
|
|
195
|
+
#
|
196
|
+
# Yield to +block+ once for each value in this list.
|
197
|
+
#
|
198
|
+
def each(&block)
|
199
|
+
element = self.first_element
|
200
|
+
while element
|
201
|
+
yield(element.value)
|
202
|
+
element = element.next
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
120
206
|
#
|
121
207
|
# Remove the first value from this list and return it.
|
122
208
|
#
|
123
209
|
def shift
|
124
210
|
v = nil
|
125
211
|
if size > 1
|
126
|
-
element =
|
127
|
-
|
128
|
-
|
212
|
+
element = self.first_element
|
213
|
+
self.first_element = element.next
|
214
|
+
self.first_element.previous = nil
|
129
215
|
v = element.value
|
130
|
-
element.destroy
|
216
|
+
element.destroy!
|
131
217
|
else
|
132
|
-
v =
|
133
|
-
|
134
|
-
|
218
|
+
v = self.first_element.value
|
219
|
+
self.first_element.destroy!
|
220
|
+
self.first_element = self.last_element = nil
|
135
221
|
end
|
136
|
-
|
222
|
+
self.size -= 1
|
137
223
|
return v
|
138
224
|
end
|
139
225
|
|
@@ -143,8 +229,7 @@ module Hyperactive
|
|
143
229
|
# Start this list with +v+ when it has no other values.
|
144
230
|
#
|
145
231
|
def start(v)
|
146
|
-
|
147
|
-
@first_element.value = v
|
232
|
+
self.first_element = self.last_element = Element.get_instance_with_transaction(@transaction, nil, nil, v, @record_id)
|
148
233
|
end
|
149
234
|
|
150
235
|
end
|