hyperactive 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README +5 -7
- data/lib/hyperactive/cleaner.rb +91 -0
- data/lib/hyperactive/hash.rb +13 -8
- data/lib/hyperactive/index.rb +25 -15
- data/lib/hyperactive/list.rb +4 -3
- data/lib/hyperactive/record.rb +92 -41
- data/lib/hyperactive/transactions.rb +7 -65
- data/lib/hyperactive.rb +1 -0
- data/tests/hash_benchmark.rb +5 -5
- data/tests/hash_test.rb +5 -5
- data/tests/list_benchmark.rb +3 -3
- data/tests/list_test.rb +6 -6
- data/tests/record_test.rb +7 -7
- metadata +3 -2
data/README
CHANGED
@@ -9,6 +9,7 @@ Hyperactive::Hash:: A collection class that contains any number of Hyperactive::
|
|
9
9
|
Hyperactive::List:: A collection class that contains any number of Hyperactive::Records in a list like structure.
|
10
10
|
Hyperactive::Index:: A module included into Hyperactive::Record that adds simple indexing capabilities of the <b>find_by_...</b> type.
|
11
11
|
Hyperactive::Transactions:: A module included into Hyperactive::Record that adds a few simplifications in handling transactions properly.
|
12
|
+
Hyperactive::Hooker:: A module that provides around-hook functinality to Hyperactive::Record, so that you can implement save, destroy, create and load hooks that wrap the actual event.
|
12
13
|
|
13
14
|
== Usage:
|
14
15
|
|
@@ -21,19 +22,16 @@ You can also use <b>new</b> of course, but beware that this will not store the o
|
|
21
22
|
<b>or</b> give you a proxy. Both of these things are good for you, so use get_instance unless you know
|
22
23
|
what you are doing.
|
23
24
|
|
24
|
-
By loading Hyperactive::Record you will automatically define Hyperactive::CAPTAIN which will
|
25
|
-
be an Archipelago::Pirate::Captain that is your interface to the distributed database.
|
26
|
-
|
27
25
|
== Examples:
|
28
26
|
|
29
27
|
To define a Record subclass that has the properties @active and @city that are indexed in two ways:
|
30
28
|
|
31
|
-
class MyClass < Hyperactive::Record
|
29
|
+
class MyClass < Hyperactive::Record:Bass
|
32
30
|
attr_accessor :active, :city
|
33
|
-
select
|
31
|
+
select :active_records do |record|
|
34
32
|
record.active == true
|
35
|
-
end
|
36
|
-
index_by
|
33
|
+
end
|
34
|
+
index_by :city
|
37
35
|
end
|
38
36
|
|
39
37
|
This will allow you to find all active MyClass instances by:
|
@@ -0,0 +1,91 @@
|
|
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
|
+
module Hyperactive
|
19
|
+
|
20
|
+
#
|
21
|
+
# A utility package for classes being aware of their dirtyness.
|
22
|
+
#
|
23
|
+
module Cleaner
|
24
|
+
|
25
|
+
#
|
26
|
+
# Include this to get the new accessor methods that automatically check if you are dirty.
|
27
|
+
#
|
28
|
+
module Accessors
|
29
|
+
|
30
|
+
#
|
31
|
+
# The +base+ class including this will get a our ClassMethods as well.
|
32
|
+
#
|
33
|
+
def self.append_features(base)
|
34
|
+
super
|
35
|
+
base.extend(ClassMethods)
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Replies whether we are dirty.
|
40
|
+
#
|
41
|
+
def dirty?
|
42
|
+
@dirty ||= false
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Mark us as dirty.
|
47
|
+
#
|
48
|
+
def is_dirty!
|
49
|
+
@dirty = true
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Mark us as clean.
|
54
|
+
#
|
55
|
+
def is_clean!
|
56
|
+
@dirty = false
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# The class methods that help us set/get instance variables in a dirt-aware way.
|
61
|
+
#
|
62
|
+
module ClassMethods
|
63
|
+
#
|
64
|
+
# Works like normal attr_writer but sets us to dirty.
|
65
|
+
#
|
66
|
+
def attr_writer(*attributes)
|
67
|
+
super
|
68
|
+
attributes.each do |attribute|
|
69
|
+
alias_method "hyperactive_cleaner_accessors_#{attribute}=", "#{attribute}="
|
70
|
+
define_method("#{attribute}=") do |new_value|
|
71
|
+
self.send("hyperactive_cleaner_accessors_#{attribute}=", new_value)
|
72
|
+
self.is_dirty!
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Works like normal attr_accessor but with with dirt-aware attr_writer.
|
79
|
+
#
|
80
|
+
def attr_accessor(*attributes)
|
81
|
+
attr_reader(*attributes)
|
82
|
+
attr_writer(*attributes)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
data/lib/hyperactive/hash.rb
CHANGED
@@ -35,7 +35,11 @@ module Hyperactive
|
|
35
35
|
# A wrapper class that knows what key, value and list_element belong together.
|
36
36
|
#
|
37
37
|
class Element < Hyperactive::Record::Bass
|
38
|
+
|
39
|
+
include Hyperactive::Cleaner::Accessors
|
40
|
+
|
38
41
|
attr_accessor :key, :value, :list_element
|
42
|
+
|
39
43
|
#
|
40
44
|
# Initialize a new Hash::Element with given +key+, +value+ and +list_element+.
|
41
45
|
#
|
@@ -52,9 +56,10 @@ module Hyperactive
|
|
52
56
|
#
|
53
57
|
class Head < Hyperactive::Record::Bass
|
54
58
|
|
55
|
-
attr_accessor :list
|
56
|
-
|
57
59
|
include Archipelago::Current::ThreadedCollection
|
60
|
+
include Hyperactive::Cleaner::Accessors
|
61
|
+
|
62
|
+
attr_accessor :list
|
58
63
|
|
59
64
|
#
|
60
65
|
# Initialize a Hash::Head.
|
@@ -84,7 +89,7 @@ module Hyperactive
|
|
84
89
|
# Return the value for +key+.
|
85
90
|
#
|
86
91
|
def [](key)
|
87
|
-
element =
|
92
|
+
element = Archipelago::Pirate::BLACKBEARD[my_key_for(key), @transaction]
|
88
93
|
if element
|
89
94
|
return element.value
|
90
95
|
else
|
@@ -96,7 +101,7 @@ module Hyperactive
|
|
96
101
|
# Returns whether +key+ is included in this Hash.
|
97
102
|
#
|
98
103
|
def include?(key)
|
99
|
-
|
104
|
+
Archipelago::Pirate::BLACKBEARD.include?(my_key_for(key), @transaction)
|
100
105
|
end
|
101
106
|
|
102
107
|
#
|
@@ -105,13 +110,13 @@ module Hyperactive
|
|
105
110
|
def []=(key, value)
|
106
111
|
self.list = Hyperactive::List::Head.get_instance_with_transaction(@transaction) unless self.list
|
107
112
|
|
108
|
-
if (element =
|
113
|
+
if (element = Archipelago::Pirate::BLACKBEARD[my_key_for(key), @transaction])
|
109
114
|
element.value = value
|
110
115
|
else
|
111
116
|
element = Element.get_instance_with_transaction(@transaction, key, value, nil)
|
112
117
|
self.list << element
|
113
118
|
element.list_element = self.list.last_element
|
114
|
-
|
119
|
+
Archipelago::Pirate::BLACKBEARD[my_key_for(key), @transaction] = element
|
115
120
|
end
|
116
121
|
end
|
117
122
|
|
@@ -123,9 +128,9 @@ module Hyperactive
|
|
123
128
|
|
124
129
|
return_value = nil
|
125
130
|
|
126
|
-
element =
|
131
|
+
element = Archipelago::Pirate::BLACKBEARD[my_key_for(key), @transaction]
|
127
132
|
if element
|
128
|
-
|
133
|
+
Archipelago::Pirate::BLACKBEARD.delete(my_key_for(key), @transaction)
|
129
134
|
self.list.unlink!(element.list_element)
|
130
135
|
return_value = element.value
|
131
136
|
element.destroy!
|
data/lib/hyperactive/index.rb
CHANGED
@@ -17,6 +17,10 @@
|
|
17
17
|
|
18
18
|
module Hyperactive
|
19
19
|
|
20
|
+
#
|
21
|
+
# A package containing methods that will help you create automatically
|
22
|
+
# updated indexes of your Records.
|
23
|
+
#
|
20
24
|
module Index
|
21
25
|
|
22
26
|
#
|
@@ -70,12 +74,12 @@ module Hyperactive
|
|
70
74
|
old_key = get_key_for(old_record)
|
71
75
|
new_key = get_key_for(record)
|
72
76
|
if old_key != new_key
|
73
|
-
(
|
74
|
-
(
|
77
|
+
(Archipelago::Pirate::BLACKBEARD[old_key] ||= Hyperactive::Hash::Head.get_instance_with_transaction(record.transaction)).delete(record.record_id)
|
78
|
+
(Archipelago::Pirate::BLACKBEARD[new_key] ||= Hyperactive::Hash::Head.get_instance_with_transaction(record.transaction))[record.record_id] = record
|
75
79
|
end
|
76
80
|
else
|
77
81
|
record = arguments.first
|
78
|
-
(
|
82
|
+
(Archipelago::Pirate::BLACKBEARD[get_key_for(record)] ||= Hyperactive::Hash::Head.get_instance_with_transaction(record.transaction)).delete(record.record_id)
|
79
83
|
end
|
80
84
|
end
|
81
85
|
end
|
@@ -107,32 +111,38 @@ module Hyperactive
|
|
107
111
|
case @mode
|
108
112
|
when :select
|
109
113
|
if @matcher.call(record)
|
110
|
-
|
114
|
+
Archipelago::Pirate::BLACKBEARD[@key, record.transaction][record.record_id] = record
|
111
115
|
else
|
112
|
-
|
116
|
+
Archipelago::Pirate::BLACKBEARD[@key, record.transaction].delete(record.record_id)
|
113
117
|
end
|
114
118
|
when :reject
|
115
119
|
if @matcher.call(record)
|
116
|
-
|
120
|
+
Archipelago::Pirate::BLACKBEARD[@key, record.transaction].delete(record.record_id)
|
117
121
|
else
|
118
|
-
|
122
|
+
Archipelago::Pirate::BLACKBEARD[@key, record.transaction][record.record_id] = record
|
119
123
|
end
|
120
124
|
when :delete_if_match
|
121
125
|
if @matcher.call(record)
|
122
|
-
|
126
|
+
Archipelago::Pirate::BLACKBEARD[@key, record.transaction].delete(record.record_id)
|
123
127
|
end
|
124
128
|
when :delete_unless_match
|
125
129
|
unless @matcher.call(record)
|
126
|
-
|
130
|
+
Archipelago::Pirate::BLACKBEARD[@key, record.transaction].delete(record.record_id)
|
127
131
|
end
|
128
132
|
end
|
129
133
|
end
|
130
134
|
end
|
131
135
|
|
132
136
|
module Indexable
|
133
|
-
|
137
|
+
|
134
138
|
def self.append_features(base)
|
135
139
|
super
|
140
|
+
base.class_eval do
|
141
|
+
#
|
142
|
+
# We depend on lots of hooks.
|
143
|
+
#
|
144
|
+
include(Hyperactive::Hooker::Pimp)
|
145
|
+
end
|
136
146
|
base.extend(ClassMethods)
|
137
147
|
end
|
138
148
|
|
@@ -147,7 +157,7 @@ module Hyperactive
|
|
147
157
|
klass = self
|
148
158
|
self.class.class_eval do
|
149
159
|
define_method("find_by_#{attributes.join("_and_")}") do |*args|
|
150
|
-
|
160
|
+
Archipelago::Pirate::BLACKBEARD[IndexBuilder.get_key(klass, attributes, args)]
|
151
161
|
end
|
152
162
|
end
|
153
163
|
index_builder = IndexBuilder.new(self, attributes)
|
@@ -163,10 +173,10 @@ module Hyperactive
|
|
163
173
|
#
|
164
174
|
def select(name, &block) #:yields: instance
|
165
175
|
key = collection_key(name)
|
166
|
-
|
176
|
+
Archipelago::Pirate::BLACKBEARD[key] ||= Hyperactive::Hash::Head.get_instance
|
167
177
|
self.class.class_eval do
|
168
178
|
define_method(name) do
|
169
|
-
|
179
|
+
Archipelago::Pirate::BLACKBEARD[key]
|
170
180
|
end
|
171
181
|
end
|
172
182
|
self.save_hooks << MatchSaver.new(key, block, :select)
|
@@ -181,10 +191,10 @@ module Hyperactive
|
|
181
191
|
#
|
182
192
|
def reject(name, &block) #:yields: instance
|
183
193
|
key = collection_key(name)
|
184
|
-
|
194
|
+
Archipelago::Pirate::BLACKBEARD[key] ||= Hyperactive::Hash::Head.get_instance
|
185
195
|
self.class.class_eval do
|
186
196
|
define_method(name) do
|
187
|
-
|
197
|
+
Archipelago::Pirate::BLACKBEARD[key]
|
188
198
|
end
|
189
199
|
end
|
190
200
|
self.save_hooks << MatchSaver.new(key, block, :reject)
|
data/lib/hyperactive/list.rb
CHANGED
@@ -30,10 +30,11 @@ module Hyperactive
|
|
30
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, :list_id
|
34
33
|
|
35
34
|
include Archipelago::Current::ThreadedCollection
|
36
35
|
|
36
|
+
attr_accessor :previous, :next, :value, :list_id
|
37
|
+
|
37
38
|
#
|
38
39
|
# Initialize this List::Element with given +previous_element+, +next_element+, +value+ and +list_id+.
|
39
40
|
#
|
@@ -43,7 +44,6 @@ module Hyperactive
|
|
43
44
|
self.value = value
|
44
45
|
self.list_id = list_id
|
45
46
|
end
|
46
|
-
|
47
47
|
#
|
48
48
|
# Yield to +block+ once for this and each following element.
|
49
49
|
#
|
@@ -60,10 +60,11 @@ module Hyperactive
|
|
60
60
|
# A List head.
|
61
61
|
#
|
62
62
|
class Head < Hyperactive::Record::Bass
|
63
|
-
attr_accessor :first_element, :last_element, :size
|
64
63
|
|
65
64
|
include Archipelago::Current::ThreadedCollection
|
66
65
|
|
66
|
+
attr_accessor :first_element, :last_element, :size
|
67
|
+
|
67
68
|
#
|
68
69
|
# Create a List::Head. This is in essence the linked list.
|
69
70
|
#
|
data/lib/hyperactive/record.rb
CHANGED
@@ -26,58 +26,65 @@ require 'archipelago'
|
|
26
26
|
module Hyperactive
|
27
27
|
|
28
28
|
#
|
29
|
-
# The
|
29
|
+
# The host we are running on.
|
30
30
|
#
|
31
|
-
|
31
|
+
HOST = "#{Socket::gethostbyname(Socket::gethostname)[0]}" rescue "localhost"
|
32
32
|
|
33
33
|
#
|
34
34
|
# The package containing the base class Bass that simplifies
|
35
35
|
# using archipelago for generic database stuff.
|
36
36
|
#
|
37
37
|
module Record
|
38
|
-
|
39
|
-
#
|
40
|
-
# A convenient base class to inherit when you want the basic utility methods
|
41
|
-
# provided by for example ActiveRecord::Base *hint hint*.
|
38
|
+
|
42
39
|
#
|
43
|
-
#
|
44
|
-
# which is not what you usually want. Every other time you fetch it using a select or other
|
45
|
-
# method you will instead receive a proxy object to the database. This means that nothing you
|
46
|
-
# do to it at that point will be persistent or even necessarily have a defined result.
|
47
|
-
# Therefore: do not use the instantiated object, instead call <b>my_instance.save</b>
|
48
|
-
# to get a proxy to the object stored into the database.
|
40
|
+
# The methods that make Hyperactive::Record::Bass persistent.
|
49
41
|
#
|
50
|
-
|
42
|
+
module Persistent
|
51
43
|
|
52
|
-
include Hyperactive::Index::Indexable
|
53
|
-
include Hyperactive::Transactions::Accessors
|
54
|
-
include Hyperactive::Transactions::Participant
|
55
|
-
include Hyperactive::Hooker::Pimp
|
56
|
-
|
57
44
|
#
|
58
|
-
#
|
45
|
+
# Give the class a @record_id getter/setter pair, @transaction getter/setter pair,
|
46
|
+
# our instance methods and the class methods of ClassMethods.
|
59
47
|
#
|
60
|
-
|
48
|
+
def self.append_features(base)
|
49
|
+
super
|
61
50
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
51
|
+
base.class_eval do
|
52
|
+
#
|
53
|
+
# Our semi-unique id.
|
54
|
+
#
|
55
|
+
attr_reader :record_id
|
56
|
+
#
|
57
|
+
# The transaction we are currently in.
|
58
|
+
#
|
59
|
+
attr_reader :transaction
|
60
|
+
end
|
61
|
+
|
62
|
+
base.extend(ClassMethods)
|
67
63
|
end
|
68
64
|
|
69
65
|
#
|
70
|
-
#
|
66
|
+
# Will execute +block+ within a transaction.
|
71
67
|
#
|
72
|
-
|
73
|
-
|
74
|
-
return instance.create
|
75
|
-
end
|
76
|
-
|
68
|
+
# What it does is just set the @transaction instance variable
|
69
|
+
# before calling the block, and unsetting it after.
|
77
70
|
#
|
78
|
-
#
|
71
|
+
# This means that any classes that want to be transaction sensitive
|
72
|
+
# need to take heed regarding the @transaction instance variable.
|
79
73
|
#
|
80
|
-
|
74
|
+
# For example, when creating new Record instances you may want to use
|
75
|
+
# get_instance_with_transaction(@transaction, *args) to ensure that the
|
76
|
+
# new instance exists within the same transaction as yourself.
|
77
|
+
#
|
78
|
+
# See Hyperactive::List::Head and Hyperactive::Hash::Head for examples of this behaviour.
|
79
|
+
#
|
80
|
+
def with_transaction(transaction, &block)
|
81
|
+
@transaction = transaction
|
82
|
+
begin
|
83
|
+
return yield
|
84
|
+
ensure
|
85
|
+
@transaction = nil
|
86
|
+
end
|
87
|
+
end
|
81
88
|
|
82
89
|
#
|
83
90
|
# Utility compare method. Override as you please.
|
@@ -90,11 +97,6 @@ module Hyperactive
|
|
90
97
|
end
|
91
98
|
end
|
92
99
|
|
93
|
-
def initialize
|
94
|
-
@record_id = nil
|
95
|
-
@transaction = nil
|
96
|
-
end
|
97
|
-
|
98
100
|
#
|
99
101
|
# Save this Record instance into the distributed database and return a proxy to the saved object.
|
100
102
|
#
|
@@ -105,10 +107,10 @@ module Hyperactive
|
|
105
107
|
@transaction ||= nil
|
106
108
|
|
107
109
|
self.class.with_hooks(:instance => self, :hooks => self.class.create_hooks) do
|
108
|
-
|
110
|
+
Archipelago::Pirate::BLACKBEARD[self.record_id, @transaction] = self
|
109
111
|
end
|
110
112
|
|
111
|
-
proxy =
|
113
|
+
proxy = Archipelago::Pirate::BLACKBEARD[@record_id, @transaction]
|
112
114
|
|
113
115
|
return proxy
|
114
116
|
end
|
@@ -120,11 +122,60 @@ module Hyperactive
|
|
120
122
|
#
|
121
123
|
def destroy!
|
122
124
|
self.class.with_hooks(:instance => self, :hooks => self.class.destroy_hooks) do
|
123
|
-
|
125
|
+
Archipelago::Pirate::BLACKBEARD.delete(@record_id, @transaction)
|
124
126
|
self.freeze
|
125
127
|
end
|
126
128
|
end
|
127
129
|
|
130
|
+
module ClassMethods
|
131
|
+
#
|
132
|
+
# Utility method to get a proxy to a within a transaction newly saved instance of this class in one call.
|
133
|
+
#
|
134
|
+
def get_instance_with_transaction(transaction, *args)
|
135
|
+
instance = self.new(*args)
|
136
|
+
return_value = nil
|
137
|
+
instance.with_transaction(transaction) do
|
138
|
+
return_value = instance.create
|
139
|
+
end
|
140
|
+
return return_value
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Return the record with +record_id+, optionally within a +transaction+.
|
145
|
+
#
|
146
|
+
def find(record_id, transaction = nil)
|
147
|
+
Archipelago::Pirate::BLACKBEARD[record_id, transaction]
|
148
|
+
end
|
149
|
+
|
150
|
+
#
|
151
|
+
# Utility method to get a proxy to a newly saved instance of this class in one call.
|
152
|
+
#
|
153
|
+
def get_instance(*args)
|
154
|
+
instance = self.new(*args)
|
155
|
+
return instance.create
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
#
|
163
|
+
# A convenient base class to inherit when you want the basic utility methods
|
164
|
+
# provided by for example ActiveRecord::Base *hint hint*.
|
165
|
+
#
|
166
|
+
# NB: When an instance is created you will actually have a copy <b>within your local machine</b>
|
167
|
+
# which is not what you usually want. Every other time you fetch it using a select or other
|
168
|
+
# method you will instead receive a proxy object to the database. This means that nothing you
|
169
|
+
# do to it at that point will be persistent or even necessarily have a defined result.
|
170
|
+
# Therefore: do not use the instantiated object, instead call <b>my_instance.save</b>
|
171
|
+
# to get a proxy to the object stored into the database.
|
172
|
+
#
|
173
|
+
class Bass
|
174
|
+
|
175
|
+
include Hyperactive::Record::Persistent
|
176
|
+
include Hyperactive::Index::Indexable
|
177
|
+
include Hyperactive::Transactions::Accessors
|
178
|
+
|
128
179
|
end
|
129
180
|
end
|
130
181
|
end
|
@@ -22,68 +22,6 @@ module Hyperactive
|
|
22
22
|
#
|
23
23
|
module Transactions
|
24
24
|
|
25
|
-
#
|
26
|
-
# Include this to get methods to do with participating in a transaction.
|
27
|
-
#
|
28
|
-
module Participant
|
29
|
-
|
30
|
-
#
|
31
|
-
# The transaction we are currently in.
|
32
|
-
#
|
33
|
-
attr_reader :transaction
|
34
|
-
|
35
|
-
#
|
36
|
-
# Will execute +block+ within a transaction.
|
37
|
-
#
|
38
|
-
# What it does is just set the @transaction instance variable
|
39
|
-
# before calling the block, and unsetting it after.
|
40
|
-
#
|
41
|
-
# This means that any classes that want to be transaction sensitive
|
42
|
-
# need to take heed regarding the @transaction instance variable.
|
43
|
-
#
|
44
|
-
# For example, when creating new Record instances you may want to use
|
45
|
-
# get_instance_with_transaction(@transaction, *args) to ensure that the
|
46
|
-
# new instance exists within the same transaction as yourself.
|
47
|
-
#
|
48
|
-
# See Hyperactive::List::Head and Hyperactive::Hash::Head for examples of this behaviour.
|
49
|
-
#
|
50
|
-
def with_transaction(transaction, &block)
|
51
|
-
@transaction = transaction
|
52
|
-
begin
|
53
|
-
yield
|
54
|
-
ensure
|
55
|
-
@transaction = nil
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
#
|
60
|
-
# Add our ClassMethods to anyone that includes us.
|
61
|
-
#
|
62
|
-
def self.append_features(base)
|
63
|
-
super
|
64
|
-
base.extend(ClassMethods)
|
65
|
-
end
|
66
|
-
|
67
|
-
#
|
68
|
-
# Class methods for transaction participants.
|
69
|
-
#
|
70
|
-
module ClassMethods
|
71
|
-
#
|
72
|
-
# Utility method to get a proxy to a within a transaction newly saved instance of this class in one call.
|
73
|
-
#
|
74
|
-
def get_instance_with_transaction(transaction, *args)
|
75
|
-
instance = self.new(*args)
|
76
|
-
return_value = nil
|
77
|
-
instance.with_transaction(transaction) do
|
78
|
-
return_value = instance.create
|
79
|
-
end
|
80
|
-
return return_value
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
25
|
#
|
88
26
|
# Include this to get the default attr_reader at al redefined to be transactionally aware.
|
89
27
|
#
|
@@ -105,9 +43,11 @@ module Hyperactive
|
|
105
43
|
# Works like normal attr_reader but with transactional awareness.
|
106
44
|
#
|
107
45
|
def attr_reader(*attributes)
|
46
|
+
super
|
108
47
|
attributes.each do |attribute|
|
48
|
+
alias_method "hyperactive_transactions_accessors_#{attribute}", attribute
|
109
49
|
define_method(attribute) do
|
110
|
-
value =
|
50
|
+
value = self.send("hyperactive_transactions_accessors_#{attribute}")
|
111
51
|
if Archipelago::Treasure::Dubloon === value
|
112
52
|
if @transaction ||= nil
|
113
53
|
return value.join(@transaction)
|
@@ -125,13 +65,15 @@ module Hyperactive
|
|
125
65
|
# Works like normal attr_writer but with transactional awareness.
|
126
66
|
#
|
127
67
|
def attr_writer(*attributes)
|
68
|
+
super
|
128
69
|
attributes.each do |attribute|
|
70
|
+
alias_method "hyperactive_transactions_accessors_#{attribute}=", "#{attribute}="
|
129
71
|
define_method("#{attribute}=") do |new_value|
|
130
72
|
if Archipelago::Treasure::Dubloon === new_value
|
131
73
|
new_value.assert_transaction(@transaction) if @transaction ||= nil
|
132
|
-
|
74
|
+
self.send("hyperactive_transactions_accessors_#{attribute}=", new_value)
|
133
75
|
else
|
134
|
-
|
76
|
+
self.send("hyperactive_transactions_accessors_#{attribute}=", new_value)
|
135
77
|
end
|
136
78
|
end
|
137
79
|
end
|
data/lib/hyperactive.rb
CHANGED
data/tests/hash_benchmark.rb
CHANGED
@@ -10,13 +10,13 @@ class HashBenchmark < Test::Unit::TestCase
|
|
10
10
|
@c2.publish!
|
11
11
|
@tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny1.db")))
|
12
12
|
@tm.publish!
|
13
|
-
|
13
|
+
Archipelago::Pirate::BLACKBEARD.setup(:chest_description => {:class => 'TestChest'},
|
14
14
|
:tranny_description => {:class => 'TestManager'})
|
15
15
|
assert_within(20) do
|
16
|
-
Set.new(
|
16
|
+
Set.new(Archipelago::Pirate::BLACKBEARD.chests.keys) == Set.new([@c.service_id, @c2.service_id])
|
17
17
|
end
|
18
18
|
assert_within(20) do
|
19
|
-
|
19
|
+
Archipelago::Pirate::BLACKBEARD.trannies.keys == [@tm.service_id]
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -36,8 +36,8 @@ class HashBenchmark < Test::Unit::TestCase
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def test_regular_hash_set_get
|
39
|
-
|
40
|
-
h =
|
39
|
+
Archipelago::Pirate::BLACKBEARD["h"] = {}
|
40
|
+
h = Archipelago::Pirate::BLACKBEARD["h"]
|
41
41
|
r = Hyperactive::Record::Bass.get_instance
|
42
42
|
hash_test("Hash", h, r, 100)
|
43
43
|
end
|
data/tests/hash_test.rb
CHANGED
@@ -19,14 +19,14 @@ class HashTest < Test::Unit::TestCase
|
|
19
19
|
@c2.publish!
|
20
20
|
@tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny1.db")))
|
21
21
|
@tm.publish!
|
22
|
-
|
22
|
+
Archipelago::Pirate::BLACKBEARD.setup(:chest_description => {:class => 'TestChest'},
|
23
23
|
:tranny_description => {:class => 'TestManager'})
|
24
|
-
|
24
|
+
Archipelago::Pirate::BLACKBEARD.update_services!
|
25
25
|
assert_within(10) do
|
26
|
-
|
26
|
+
Archipelago::Pirate::BLACKBEARD.chests.keys.sort == [@c.service_id, @c2.service_id].sort
|
27
27
|
end
|
28
28
|
assert_within(10) do
|
29
|
-
|
29
|
+
Archipelago::Pirate::BLACKBEARD.trannies.keys == [@tm.service_id]
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -69,7 +69,7 @@ class HashTest < Test::Unit::TestCase
|
|
69
69
|
|
70
70
|
h2.each do |k,v|
|
71
71
|
assert_equal(v, h[k])
|
72
|
-
assert_equal(v,
|
72
|
+
assert_equal(v, Archipelago::Pirate::BLACKBEARD[h.record_id][k])
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
data/tests/list_benchmark.rb
CHANGED
@@ -10,13 +10,13 @@ class ListBenchmark < Test::Unit::TestCase
|
|
10
10
|
@c2.publish!
|
11
11
|
@tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny1.db")))
|
12
12
|
@tm.publish!
|
13
|
-
|
13
|
+
Archipelago::Pirate::BLACKBEARD.setup(:chest_description => {:class => 'TestChest'},
|
14
14
|
:tranny_description => {:class => 'TestManager'})
|
15
15
|
assert_within(20) do
|
16
|
-
Set.new(
|
16
|
+
Set.new(Archipelago::Pirate::BLACKBEARD.chests.keys) == Set.new([@c.service_id, @c2.service_id])
|
17
17
|
end
|
18
18
|
assert_within(20) do
|
19
|
-
|
19
|
+
Archipelago::Pirate::BLACKBEARD.trannies.keys == [@tm.service_id]
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
data/tests/list_test.rb
CHANGED
@@ -18,14 +18,14 @@ class ListTest < Test::Unit::TestCase
|
|
18
18
|
@c2.publish!
|
19
19
|
@tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny1.db")))
|
20
20
|
@tm.publish!
|
21
|
-
|
21
|
+
Archipelago::Pirate::BLACKBEARD.setup(:chest_description => {:class => 'TestChest'},
|
22
22
|
:tranny_description => {:class => 'TestManager'})
|
23
|
-
|
23
|
+
Archipelago::Pirate::BLACKBEARD.update_services!
|
24
24
|
assert_within(10) do
|
25
|
-
|
25
|
+
Archipelago::Pirate::BLACKBEARD.chests.keys.sort == [@c.service_id, @c2.service_id].sort
|
26
26
|
end
|
27
27
|
assert_within(10) do
|
28
|
-
|
28
|
+
Archipelago::Pirate::BLACKBEARD.trannies.keys == [@tm.service_id]
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -56,8 +56,8 @@ class ListTest < Test::Unit::TestCase
|
|
56
56
|
r1 = l.first_element.record_id
|
57
57
|
r2 = l.record_id
|
58
58
|
l.destroy!
|
59
|
-
assert(!
|
60
|
-
assert(!
|
59
|
+
assert(!Archipelago::Pirate::BLACKBEARD.include?(r1))
|
60
|
+
assert(!Archipelago::Pirate::BLACKBEARD.include?(r2))
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_each
|
data/tests/record_test.rb
CHANGED
@@ -37,14 +37,14 @@ class RecordTest < Test::Unit::TestCase
|
|
37
37
|
@c2.publish!
|
38
38
|
@tm = TestManager.new(:persistence_provider => Archipelago::Hashish::BerkeleyHashishProvider.new(Pathname.new(__FILE__).parent.join("tranny1.db")))
|
39
39
|
@tm.publish!
|
40
|
-
|
40
|
+
Archipelago::Pirate::BLACKBEARD.setup(:chest_description => {:class => 'TestChest'},
|
41
41
|
:tranny_description => {:class => 'TestManager'})
|
42
|
-
|
42
|
+
Archipelago::Pirate::BLACKBEARD.update_services!
|
43
43
|
assert_within(10) do
|
44
|
-
|
44
|
+
Archipelago::Pirate::BLACKBEARD.chests.keys.sort == [@c.service_id, @c2.service_id].sort
|
45
45
|
end
|
46
46
|
assert_within(10) do
|
47
|
-
|
47
|
+
Archipelago::Pirate::BLACKBEARD.trannies.keys == [@tm.service_id]
|
48
48
|
end
|
49
49
|
$BEFORE_SAVE = 0
|
50
50
|
$AFTER_SAVE = 0
|
@@ -140,13 +140,13 @@ class RecordTest < Test::Unit::TestCase
|
|
140
140
|
assert_equal(2, $BEFORE_SAVE)
|
141
141
|
assert_equal(2, $AFTER_SAVE)
|
142
142
|
assert_equal("brunt", r.bajs)
|
143
|
-
assert_equal("brunt",
|
143
|
+
assert_equal("brunt", Archipelago::Pirate::BLACKBEARD[r.record_id].bajs)
|
144
144
|
i = r.record_id
|
145
|
-
assert_equal(r,
|
145
|
+
assert_equal(r, Archipelago::Pirate::BLACKBEARD[i])
|
146
146
|
r.destroy!
|
147
147
|
assert_equal(1, $BEFORE_DESTROY)
|
148
148
|
assert_equal(1, $AFTER_DESTROY)
|
149
|
-
assert_equal(nil,
|
149
|
+
assert_equal(nil, Archipelago::Pirate::BLACKBEARD[i])
|
150
150
|
end
|
151
151
|
|
152
152
|
end
|
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-12-
|
6
|
+
version: 0.2.5
|
7
|
+
date: 2006-12-20 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,6 +29,7 @@ authors:
|
|
29
29
|
- Martin Kihlgren
|
30
30
|
files:
|
31
31
|
- lib/hyperactive.rb
|
32
|
+
- lib/hyperactive/cleaner.rb
|
32
33
|
- lib/hyperactive/hash.rb
|
33
34
|
- lib/hyperactive/hooker.rb
|
34
35
|
- lib/hyperactive/index.rb
|