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/tests/list_test.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
|
2
2
|
require File.join(File.dirname(__FILE__), 'test_helper')
|
3
3
|
|
4
|
+
class Collector
|
5
|
+
attr_accessor :es
|
6
|
+
def call(e)
|
7
|
+
@es ||= []
|
8
|
+
@es << e
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
4
12
|
class ListTest < Test::Unit::TestCase
|
5
13
|
|
6
14
|
def setup
|
@@ -23,19 +31,69 @@ class ListTest < Test::Unit::TestCase
|
|
23
31
|
|
24
32
|
def teardown
|
25
33
|
@c.stop!
|
26
|
-
@c.persistence_provider.unlink
|
34
|
+
@c.persistence_provider.unlink!
|
27
35
|
@c2.stop!
|
28
|
-
@c2.persistence_provider.unlink
|
36
|
+
@c2.persistence_provider.unlink!
|
29
37
|
@tm.stop!
|
30
|
-
@tm.persistence_provider.unlink
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
@tm.persistence_provider.unlink!
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_clear
|
42
|
+
l = Hyperactive::List::Head.get_instance
|
43
|
+
l << (r = Hyperactive::Record::Bass.get_instance)
|
44
|
+
assert_equal(1, l.size)
|
45
|
+
assert_equal(r, l.first)
|
46
|
+
assert_equal(r, l.last)
|
47
|
+
l.clear!
|
48
|
+
assert_equal(0, l.size)
|
49
|
+
assert_equal(nil, l.first)
|
50
|
+
assert_equal(nil, l.last)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_destroy
|
54
|
+
l = Hyperactive::List::Head.get_instance
|
55
|
+
l << (r = Hyperactive::Record::Bass.get_instance)
|
56
|
+
r1 = l.first_element.record_id
|
57
|
+
r2 = l.record_id
|
58
|
+
l.destroy!
|
59
|
+
assert(!Hyperactive::Record::CAPTAIN.include?(r1))
|
60
|
+
assert(!Hyperactive::Record::CAPTAIN.include?(r2))
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_each
|
64
|
+
l = Hyperactive::List::Head.get_instance
|
65
|
+
l << (r = Hyperactive::Record::Bass.get_instance)
|
66
|
+
l << (r2 = Hyperactive::Record::Bass.get_instance)
|
67
|
+
l << (r3 = Hyperactive::Record::Bass.get_instance)
|
68
|
+
c = Collector.new
|
69
|
+
l.t_each(c)
|
70
|
+
assert_equal(3, c.es.size)
|
71
|
+
assert(c.es.include?(r))
|
72
|
+
assert(c.es.include?(r2))
|
73
|
+
assert(c.es.include?(r3))
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_unlink
|
77
|
+
l = Hyperactive::List::Head.get_instance
|
78
|
+
l << (r = Hyperactive::Record::Bass.get_instance)
|
79
|
+
l << (r2 = Hyperactive::Record::Bass.get_instance)
|
80
|
+
e = l.last_element
|
81
|
+
l << (r3 = Hyperactive::Record::Bass.get_instance)
|
82
|
+
assert_equal([r, r2, r3].sort, l.t_collect do |ec| ec end.sort)
|
83
|
+
l.unlink!(e)
|
84
|
+
assert_equal(2, l.size)
|
85
|
+
assert_equal(r, l.first)
|
86
|
+
assert_equal(r3, l.last)
|
87
|
+
assert_equal(r3, l.first_element.next.value)
|
88
|
+
l.unlink!(l.last_element)
|
89
|
+
assert_equal(1, l.size)
|
90
|
+
assert_equal(r, l.first)
|
91
|
+
assert_equal(r, l.last)
|
92
|
+
l.unlink!(l.first_element)
|
93
|
+
assert_equal(0, l.size)
|
94
|
+
assert_equal(nil, l.first)
|
95
|
+
assert_equal(nil, l.last)
|
96
|
+
assert_equal([], l.t_collect do |e| e end)
|
39
97
|
end
|
40
98
|
|
41
99
|
def test_push_unshift_pop_shift
|
data/tests/record_test.rb
CHANGED
@@ -3,7 +3,9 @@ require File.join(File.dirname(__FILE__), 'test_helper')
|
|
3
3
|
|
4
4
|
class MyRecord < Hyperactive::Record::Bass
|
5
5
|
attr_accessor :bajs
|
6
|
-
|
6
|
+
def initialize
|
7
|
+
@bajs = nil
|
8
|
+
end
|
7
9
|
def self.save_hook(instance, &block)
|
8
10
|
$BEFORE_SAVE += 1
|
9
11
|
yield
|
@@ -54,19 +56,11 @@ class RecordTest < Test::Unit::TestCase
|
|
54
56
|
|
55
57
|
def teardown
|
56
58
|
@c.stop!
|
57
|
-
@c.persistence_provider.unlink
|
59
|
+
@c.persistence_provider.unlink!
|
58
60
|
@c2.stop!
|
59
|
-
@c2.persistence_provider.unlink
|
61
|
+
@c2.persistence_provider.unlink!
|
60
62
|
@tm.stop!
|
61
|
-
@tm.persistence_provider.unlink
|
62
|
-
Archipelago::Disco::MC.clear!
|
63
|
-
Hyperactive::Record::CAPTAIN.update_services!
|
64
|
-
assert_within(10) do
|
65
|
-
Hyperactive::Record::CAPTAIN.chests.empty?
|
66
|
-
end
|
67
|
-
assert_within(10) do
|
68
|
-
Hyperactive::Record::CAPTAIN.trannies.empty?
|
69
|
-
end
|
63
|
+
@tm.persistence_provider.unlink!
|
70
64
|
end
|
71
65
|
|
72
66
|
def test_index_find
|
@@ -82,18 +76,18 @@ class RecordTest < Test::Unit::TestCase
|
|
82
76
|
r4 = MyRecord.get_instance
|
83
77
|
r4.bajs = "beige"
|
84
78
|
|
85
|
-
assert_equal(Set.new([r2.record_id,r1.record_id]), Set.new(MyRecord.find_by_bajs("brunt").
|
86
|
-
|
87
|
-
|
88
|
-
assert_equal([r3.record_id], MyRecord.find_by_bajs("gult").
|
89
|
-
|
90
|
-
|
79
|
+
assert_equal(Set.new([r2.record_id,r1.record_id]), Set.new(MyRecord.find_by_bajs("brunt").t_collect(Proc.new do |k,v|
|
80
|
+
v.record_id
|
81
|
+
end)))
|
82
|
+
assert_equal([r3.record_id], MyRecord.find_by_bajs("gult").t_collect(Proc.new do |k,v|
|
83
|
+
v.record_id
|
84
|
+
end))
|
91
85
|
|
92
|
-
r1.destroy
|
86
|
+
r1.destroy!
|
93
87
|
|
94
|
-
assert_equal([r2.record_id], MyRecord.find_by_bajs("brunt").
|
95
|
-
|
96
|
-
|
88
|
+
assert_equal([r2.record_id], MyRecord.find_by_bajs("brunt").t_collect(Proc.new do |k,v|
|
89
|
+
v.record_id
|
90
|
+
end))
|
97
91
|
|
98
92
|
end
|
99
93
|
|
@@ -115,22 +109,22 @@ class RecordTest < Test::Unit::TestCase
|
|
115
109
|
r4 = MyRecord.get_instance
|
116
110
|
r4.bajs = "beige"
|
117
111
|
|
118
|
-
assert_equal(Set.new([r2.record_id,r1.record_id]), Set.new(MyRecord.brunt.
|
112
|
+
assert_equal(Set.new([r2.record_id,r1.record_id]), Set.new(MyRecord.brunt.t_collect(Proc.new do |k,v|
|
119
113
|
v.record_id
|
120
114
|
end)))
|
121
|
-
assert_equal(Set.new([r3.record_id,r4.record_id]), Set.new(MyRecord.not_brunt.
|
115
|
+
assert_equal(Set.new([r3.record_id,r4.record_id]), Set.new(MyRecord.not_brunt.t_collect(Proc.new do |k,v|
|
122
116
|
v.record_id
|
123
117
|
end)))
|
124
118
|
|
125
|
-
r1.destroy
|
126
|
-
r2.destroy
|
127
|
-
r3.destroy
|
128
|
-
r4.destroy
|
119
|
+
r1.destroy!
|
120
|
+
r2.destroy!
|
121
|
+
r3.destroy!
|
122
|
+
r4.destroy!
|
129
123
|
|
130
|
-
assert_equal(Set.new, Set.new(MyRecord.brunt.
|
124
|
+
assert_equal(Set.new, Set.new(MyRecord.brunt.t_collect(Proc.new do |k,v|
|
131
125
|
v.record_id
|
132
126
|
end)))
|
133
|
-
assert_equal(Set.new, Set.new(MyRecord.not_brunt.
|
127
|
+
assert_equal(Set.new, Set.new(MyRecord.not_brunt.t_collect(Proc.new do |k,v|
|
134
128
|
v.record_id
|
135
129
|
end)))
|
136
130
|
end
|
@@ -149,7 +143,7 @@ class RecordTest < Test::Unit::TestCase
|
|
149
143
|
assert_equal("brunt", Hyperactive::Record::CAPTAIN[r.record_id].bajs)
|
150
144
|
i = r.record_id
|
151
145
|
assert_equal(r, Hyperactive::Record::CAPTAIN[i])
|
152
|
-
r.destroy
|
146
|
+
r.destroy!
|
153
147
|
assert_equal(1, $BEFORE_DESTROY)
|
154
148
|
assert_equal(1, $AFTER_DESTROY)
|
155
149
|
assert_equal(nil, Hyperactive::Record::CAPTAIN[i])
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: hyperactive
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date: 2006-11-
|
6
|
+
version: 0.2.3
|
7
|
+
date: 2006-11-29 00:00:00 +01:00
|
8
8
|
summary: A base class for persistent objects that uses archipelago for persistence. Useful for Ruby on Rails models for example.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -29,21 +29,22 @@ authors:
|
|
29
29
|
- Martin Kihlgren
|
30
30
|
files:
|
31
31
|
- lib/hyperactive.rb
|
32
|
+
- lib/hyperactive/hash.rb
|
32
33
|
- lib/hyperactive/hooker.rb
|
33
34
|
- lib/hyperactive/list.rb
|
34
35
|
- lib/hyperactive/record.rb
|
35
|
-
-
|
36
|
+
- tests/hash_benchmark.rb
|
37
|
+
- tests/hash_test.rb
|
38
|
+
- tests/list_benchmark.rb
|
36
39
|
- tests/list_test.rb
|
37
40
|
- tests/record_test.rb
|
38
41
|
- tests/test_helper.rb
|
39
|
-
- tests/tree_benchmark.rb
|
40
|
-
- tests/tree_test.rb
|
41
42
|
- GPL-2
|
42
43
|
- README
|
43
44
|
test_files:
|
45
|
+
- tests/hash_test.rb
|
44
46
|
- tests/list_test.rb
|
45
47
|
- tests/record_test.rb
|
46
|
-
- tests/tree_test.rb
|
47
48
|
- tests/test_helper.rb
|
48
49
|
rdoc_options:
|
49
50
|
- --line-numbers
|
data/lib/hyperactive/tree.rb
DELETED
@@ -1,241 +0,0 @@
|
|
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 'rbtree'
|
22
|
-
|
23
|
-
module Hyperactive
|
24
|
-
|
25
|
-
#
|
26
|
-
# The package containing the Hash-like Tree class that provides any
|
27
|
-
# kind of index for your Hyperactive classes.
|
28
|
-
#
|
29
|
-
module Tree
|
30
|
-
|
31
|
-
#
|
32
|
-
# A class suitable for storing large and often-changing datasets in
|
33
|
-
# an Archipelago environment.
|
34
|
-
#
|
35
|
-
# Is constructed like a set of nested Hashes that automatically create
|
36
|
-
# new children on demand, and will thusly only have to check the path from
|
37
|
-
# the root node to the leaf for changes when method calls return (see Archipelago::Treasure::Chest)
|
38
|
-
# and will only have to actually store into database the leaf itself if it
|
39
|
-
# has changed.
|
40
|
-
#
|
41
|
-
class Root < Hyperactive::Record::Bass
|
42
|
-
|
43
|
-
attr_accessor :elements, :subtrees
|
44
|
-
|
45
|
-
WIDTH = 1 << 3
|
46
|
-
|
47
|
-
#
|
48
|
-
# Dont call this! Call <i>Root.get_instance(options)</i> instead!
|
49
|
-
#
|
50
|
-
def initialize(options = {})
|
51
|
-
@width = options[:width] || WIDTH
|
52
|
-
@elements = {}
|
53
|
-
@subtrees = nil
|
54
|
-
end
|
55
|
-
|
56
|
-
#
|
57
|
-
# Deletes +key+ in this Root.
|
58
|
-
#
|
59
|
-
def delete(key)
|
60
|
-
if @elements
|
61
|
-
@elements.delete(key)
|
62
|
-
else
|
63
|
-
subtree_for(key).delete(key)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
#
|
68
|
-
# Returns the size of this Root.
|
69
|
-
#
|
70
|
-
def size
|
71
|
-
if @elements
|
72
|
-
@elements.size
|
73
|
-
else
|
74
|
-
@subtrees.t_collect do |tree_id, tree|
|
75
|
-
tree.size
|
76
|
-
end.inject(0) do |sum, size|
|
77
|
-
sum + size
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
#
|
83
|
-
# Returns all keys and values returning true for +callable+.call(key, value) in this Root.
|
84
|
-
#
|
85
|
-
def select(callable)
|
86
|
-
if @elements
|
87
|
-
@elements.select do |k,v|
|
88
|
-
callable.call(k,v)
|
89
|
-
end
|
90
|
-
else
|
91
|
-
@subtrees.t_collect do |tree_id, tree|
|
92
|
-
tree.select(callable)
|
93
|
-
end.inject([]) do |sum, match|
|
94
|
-
sum + match
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
#
|
100
|
-
# Returns all keys and values returning false for +callable+.call(key, value) in this Root.
|
101
|
-
#
|
102
|
-
def reject(callable)
|
103
|
-
if @elements
|
104
|
-
@elements.reject do |k,v|
|
105
|
-
callable.call(k,v)
|
106
|
-
end
|
107
|
-
else
|
108
|
-
@subtrees.t_collect do |tree_id, tree|
|
109
|
-
tree.reject(callable)
|
110
|
-
end.inject([]) do |sum, match|
|
111
|
-
sum + match
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
#
|
117
|
-
# Puts +value+ under +key+ in this Root.
|
118
|
-
#
|
119
|
-
def []=(key, value)
|
120
|
-
if @elements
|
121
|
-
if @elements.size < @width
|
122
|
-
@elements[key] = value
|
123
|
-
else
|
124
|
-
split!
|
125
|
-
subtree_for(key)[key] = value
|
126
|
-
end
|
127
|
-
else
|
128
|
-
subtree_for(key)[key] = value
|
129
|
-
end
|
130
|
-
return value
|
131
|
-
end
|
132
|
-
|
133
|
-
#
|
134
|
-
# Returns the value for +key+ in this Root.
|
135
|
-
#
|
136
|
-
def [](key)
|
137
|
-
if @elements
|
138
|
-
return @elements[key]
|
139
|
-
else
|
140
|
-
return subtree_for(key)[key]
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
#
|
145
|
-
# Returns an Array containing +callable+.call(key, value) from all values in this Root.
|
146
|
-
#
|
147
|
-
def collect(callable)
|
148
|
-
rval = []
|
149
|
-
self.each(Proc.new do |k,v|
|
150
|
-
rval << callable.call(k,v)
|
151
|
-
end)
|
152
|
-
return rval
|
153
|
-
end
|
154
|
-
|
155
|
-
#
|
156
|
-
# Does +callable+.call(key, value) on all values in this Root.
|
157
|
-
#
|
158
|
-
def each(callable)
|
159
|
-
if @elements
|
160
|
-
@elements.each do |key, value|
|
161
|
-
callable.call(key, value)
|
162
|
-
end
|
163
|
-
else
|
164
|
-
@subtrees.t_each do |tree_id, tree|
|
165
|
-
tree.each(callable)
|
166
|
-
end
|
167
|
-
nil
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
#
|
172
|
-
# Clear everything from this Tree and destroy it.
|
173
|
-
#
|
174
|
-
def destroy
|
175
|
-
if @elements
|
176
|
-
@elements.each do |key, value|
|
177
|
-
value.destroy if value.respond_to?(:destroy)
|
178
|
-
end
|
179
|
-
else
|
180
|
-
@subtrees.each do |tree_id, tree|
|
181
|
-
tree.destroy
|
182
|
-
end
|
183
|
-
end
|
184
|
-
freeze
|
185
|
-
super
|
186
|
-
end
|
187
|
-
|
188
|
-
#
|
189
|
-
# Clear everything from this Root.
|
190
|
-
#
|
191
|
-
def clear
|
192
|
-
unless @elements
|
193
|
-
@subtrees.each do |tree_id, tree|
|
194
|
-
tree.clear
|
195
|
-
end
|
196
|
-
@subtrees = nil
|
197
|
-
end
|
198
|
-
@elements = {}
|
199
|
-
end
|
200
|
-
|
201
|
-
private
|
202
|
-
|
203
|
-
#
|
204
|
-
# Finds the subtree responsible for +key+.
|
205
|
-
#
|
206
|
-
# Does it in this ugly way cause the nice way of just doing modulo gave
|
207
|
-
# really odd results since all hashes seem to give some modulo values
|
208
|
-
# a lot more often than expected.
|
209
|
-
#
|
210
|
-
def subtree_for(key)
|
211
|
-
key_id = Digest::SHA1.new("#{key.hash}#{self.record_id}").to_s
|
212
|
-
@subtrees.each do |tree_id, tree|
|
213
|
-
return tree if tree_id > key_id
|
214
|
-
end
|
215
|
-
return @subtrees.values.first
|
216
|
-
end
|
217
|
-
|
218
|
-
#
|
219
|
-
# Split this Tree by creating @subtrees,
|
220
|
-
# then putting all @elements in them and then emptying @elements.
|
221
|
-
#
|
222
|
-
def split!
|
223
|
-
raise "Cant split twice!" unless @elements
|
224
|
-
|
225
|
-
@subtrees = RBTree.new
|
226
|
-
@subtrees.extend(Archipelago::Current::ThreadedCollection)
|
227
|
-
step = (1 << 160) / @width
|
228
|
-
0.upto(@width - 1) do |n|
|
229
|
-
@subtrees["%x" % (n * step)] = Root.get_instance(:width => @width)
|
230
|
-
end
|
231
|
-
@elements.each do |key, value|
|
232
|
-
subtree_for(key)[key] = value
|
233
|
-
end
|
234
|
-
@elements = nil
|
235
|
-
end
|
236
|
-
|
237
|
-
end
|
238
|
-
|
239
|
-
end
|
240
|
-
|
241
|
-
end
|