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 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
- == Dependencies:
5
+ == Sub packages:
6
6
 
7
- Hyperactive::Tree:: RBTree: http://raa.ruby-lang.org/project/ruby-rbtree
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
- == Sub packages:
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:: The base class itself, providing you with cached selectors and rejectors, along with cached finders for any number of attributes.
12
- Hyperactive::Tree:: A collection class that contains any number of Hyperactive::Records in a tree structure. Scales logarithmically, so use with care.
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
@@ -19,5 +19,5 @@ $: << File.dirname(__FILE__)
19
19
 
20
20
  require 'hyperactive/hooker'
21
21
  require 'hyperactive/record'
22
- require 'hyperactive/tree'
22
+ require 'hyperactive/hash'
23
23
  require 'hyperactive/list'
@@ -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
@@ -27,73 +27,148 @@ module Hyperactive
27
27
  module List
28
28
 
29
29
  #
30
- # A List element.
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
- attr_reader :first_element, :last_element, :size
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: As usual, dont call this. Use Head.get_instance instead.
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
- @size = 0
49
- @first_element = @last_element = nil
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
- @first_element.value
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
- @last_element.value
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 @first_element
71
- new_element = Element.get_instance
72
- new_element.value = v
73
- new_element.previous = @last_element
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
- @size += 1
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 @first_element
88
- new_element = Element.get_instance
89
- new_element.value = v
90
- new_element.next = @first_element
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
- @size += 1
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 = @last_element
107
- @last_element = element.previous
108
- @last_element.next = nil
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 = @first_element.value
113
- @first_element.destroy
114
- @first_element = @last_element = nil
187
+ v = self.first_element.value
188
+ self.first_element.destroy!
189
+ self.first_element = self.last_element = nil
115
190
  end
116
- @size -= 1
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 = @first_element
127
- @first_element = element.next
128
- @first_element.previous = nil
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 = @first_element.value
133
- @first_element.destroy
134
- @first_element = @last_element = nil
218
+ v = self.first_element.value
219
+ self.first_element.destroy!
220
+ self.first_element = self.last_element = nil
135
221
  end
136
- @size -= 1
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
- @first_element = @last_element = Element.get_instance
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