hyperactive 0.2.4 → 0.2.5
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 +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
|