hyperactive 0.2.3 → 0.2.4
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 +9 -3
- data/TODO +4 -0
- data/lib/hyperactive/hash.rb +14 -6
- data/lib/hyperactive/hooker.rb +157 -47
- data/lib/hyperactive/index.rb +210 -0
- data/lib/hyperactive/list.rb +8 -0
- data/lib/hyperactive/record.rb +20 -407
- data/lib/hyperactive/transactions.rb +154 -0
- data/lib/hyperactive.rb +2 -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 +8 -8
- metadata +5 -2
data/README
CHANGED
@@ -7,15 +7,21 @@ It uses archipelago for persistence, and is meaningful only in an environment wh
|
|
7
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
8
|
Hyperactive::Hash:: A collection class that contains any number of Hyperactive::Records in a hash like structure.
|
9
9
|
Hyperactive::List:: A collection class that contains any number of Hyperactive::Records in a list like structure.
|
10
|
+
Hyperactive::Index:: A module included into Hyperactive::Record that adds simple indexing capabilities of the <b>find_by_...</b> type.
|
11
|
+
Hyperactive::Transactions:: A module included into Hyperactive::Record that adds a few simplifications in handling transactions properly.
|
10
12
|
|
11
13
|
== Usage:
|
12
14
|
|
13
15
|
To use Hyperactive in the simplest way, just run the script/services.rb script from the Archipelago
|
14
16
|
distribution to get a few services running, then subclass Hyperactive::Record::Bass and create
|
15
|
-
objects with <b>MyBassSubclass.get_instance</b
|
16
|
-
|
17
|
+
objects with <b>MyBassSubclass.get_instance</b>. They will be automagically stored in the network,
|
18
|
+
and fetchable via their <b>instance.record_id</b>.
|
17
19
|
|
18
|
-
|
20
|
+
You can also use <b>new</b> of course, but beware that this will not store the object persistently
|
21
|
+
<b>or</b> give you a proxy. Both of these things are good for you, so use get_instance unless you know
|
22
|
+
what you are doing.
|
23
|
+
|
24
|
+
By loading Hyperactive::Record you will automatically define Hyperactive::CAPTAIN which will
|
19
25
|
be an Archipelago::Pirate::Captain that is your interface to the distributed database.
|
20
26
|
|
21
27
|
== Examples:
|
data/TODO
ADDED
data/lib/hyperactive/hash.rb
CHANGED
@@ -62,6 +62,7 @@ module Hyperactive
|
|
62
62
|
# NB: Remember to call create on the new instance or use Head.get_instance to get that done automatically.
|
63
63
|
#
|
64
64
|
def initialize
|
65
|
+
super
|
65
66
|
self.list = nil
|
66
67
|
end
|
67
68
|
|
@@ -72,11 +73,18 @@ module Hyperactive
|
|
72
73
|
self.list.size
|
73
74
|
end
|
74
75
|
|
76
|
+
#
|
77
|
+
# Return whether this Hash is empty.
|
78
|
+
#
|
79
|
+
def empty?
|
80
|
+
self.list.empty?
|
81
|
+
end
|
82
|
+
|
75
83
|
#
|
76
84
|
# Return the value for +key+.
|
77
85
|
#
|
78
86
|
def [](key)
|
79
|
-
element = Hyperactive::
|
87
|
+
element = Hyperactive::CAPTAIN[my_key_for(key), @transaction]
|
80
88
|
if element
|
81
89
|
return element.value
|
82
90
|
else
|
@@ -88,7 +96,7 @@ module Hyperactive
|
|
88
96
|
# Returns whether +key+ is included in this Hash.
|
89
97
|
#
|
90
98
|
def include?(key)
|
91
|
-
Hyperactive::
|
99
|
+
Hyperactive::CAPTAIN.include?(my_key_for(key), @transaction)
|
92
100
|
end
|
93
101
|
|
94
102
|
#
|
@@ -97,13 +105,13 @@ module Hyperactive
|
|
97
105
|
def []=(key, value)
|
98
106
|
self.list = Hyperactive::List::Head.get_instance_with_transaction(@transaction) unless self.list
|
99
107
|
|
100
|
-
if (element = Hyperactive::
|
108
|
+
if (element = Hyperactive::CAPTAIN[my_key_for(key), @transaction])
|
101
109
|
element.value = value
|
102
110
|
else
|
103
111
|
element = Element.get_instance_with_transaction(@transaction, key, value, nil)
|
104
112
|
self.list << element
|
105
113
|
element.list_element = self.list.last_element
|
106
|
-
Hyperactive::
|
114
|
+
Hyperactive::CAPTAIN[my_key_for(key), @transaction] = element
|
107
115
|
end
|
108
116
|
end
|
109
117
|
|
@@ -115,9 +123,9 @@ module Hyperactive
|
|
115
123
|
|
116
124
|
return_value = nil
|
117
125
|
|
118
|
-
element = Hyperactive::
|
126
|
+
element = Hyperactive::CAPTAIN[my_key_for(key), @transaction]
|
119
127
|
if element
|
120
|
-
Hyperactive::
|
128
|
+
Hyperactive::CAPTAIN.delete(my_key_for(key), @transaction)
|
121
129
|
self.list.unlink!(element.list_element)
|
122
130
|
return_value = element.value
|
123
131
|
element.destroy!
|
data/lib/hyperactive/hooker.rb
CHANGED
@@ -19,61 +19,171 @@
|
|
19
19
|
module Hyperactive
|
20
20
|
|
21
21
|
#
|
22
|
-
# A
|
22
|
+
# A container of utility hook methods.
|
23
23
|
#
|
24
24
|
module Hooker
|
25
25
|
|
26
26
|
#
|
27
|
-
#
|
28
|
-
# calls the rest of the +hooks+ with +argument+ as argument
|
29
|
-
# and after that yields to the given +block+.
|
27
|
+
# Something that uses hooks a lot, include if you want support for various types of hooks.
|
30
28
|
#
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
# def update_timestamp(important_stuff_instance)
|
56
|
-
# important_stuff_instance.timestamp = Time.now
|
57
|
-
# Hyperactive::Hooker.call_with_hooks("changed at #{Time.now}",
|
58
|
-
# important_stuff_instance.method(:validate_and_notify)) do
|
59
|
-
# important_stuff_instance.do_save
|
60
|
-
# end
|
61
|
-
# end
|
62
|
-
# end
|
63
|
-
#
|
64
|
-
def call_with_hooks(argument, *hooks, &block)
|
65
|
-
if hooks.empty?
|
66
|
-
yield
|
67
|
-
else
|
68
|
-
first = hooks.first
|
69
|
-
rest = hooks[1..-1]
|
70
|
-
first.call(argument) do
|
71
|
-
call_with_hooks(argument, *rest, &block)
|
29
|
+
module Pimp
|
30
|
+
|
31
|
+
#
|
32
|
+
# Upon inclusion, our +base+ class will be given a set of hook
|
33
|
+
# arrays, and then get extended by ClassMethods.
|
34
|
+
#
|
35
|
+
def self.append_features(base)
|
36
|
+
super
|
37
|
+
base.instance_variable_set(:@create_hooks, [])
|
38
|
+
base.instance_variable_set(:@destroy_hooks, [])
|
39
|
+
base.instance_variable_set(:@save_hooks, [])
|
40
|
+
base.instance_variable_set(:@load_hooks, [])
|
41
|
+
base.extend(ClassMethods)
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# This will allow us to wrap any write of us to persistent storage
|
46
|
+
# in the @save_hooks as long as the Archipelago::Hashish provider
|
47
|
+
# supports it. See Archipelago::Hashish::BerkeleyHashish for an example
|
48
|
+
# of Hashish providers that do this.
|
49
|
+
#
|
50
|
+
def save_hook(old_value, &block)
|
51
|
+
self.class.with_hooks(:instance => self, :arguments => [old_value], :hooks => self.class.save_hooks) do
|
52
|
+
yield
|
72
53
|
end
|
73
54
|
end
|
74
|
-
|
55
|
+
|
56
|
+
#
|
57
|
+
# This will allow us to wrap any load of us from persistent storage
|
58
|
+
# in the @@load_hooks as long as the Archipelago::Hashish provider
|
59
|
+
# supports it. See Archipelago::Hashish::BerkeleyHashish for an example
|
60
|
+
# of Hashish providers that do this.
|
61
|
+
#
|
62
|
+
def load_hook(&block)
|
63
|
+
self.class.with_hooks(:instance => self, :hooks => self.class.load_hooks) do
|
64
|
+
yield
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
75
68
|
|
76
|
-
|
69
|
+
#
|
70
|
+
# The class methods of a Pimp.
|
71
|
+
#
|
72
|
+
module ClassMethods
|
73
|
+
|
74
|
+
#
|
75
|
+
# Will wrap a block within nested calls to given hooks.
|
76
|
+
#
|
77
|
+
# Parameters:
|
78
|
+
# * <i>:instance</i>: An instance to send methods to, defaults to self
|
79
|
+
# * <i>:arguments</i>: Extra arguments to send to whatever we call, defaults to self
|
80
|
+
# * <i>:hooks</i>: An Array of hook objects. They can be either Strings or Symbols, or
|
81
|
+
# whatever else can be given to <b>respond_to?</b>, <b>or</b> they can be anything
|
82
|
+
# that <b>respond_to?(:call)</b>. If the hook is something that
|
83
|
+
# <i>respond_to?(:call)</i> it will be <i>call</i>ed and given
|
84
|
+
# the the <i>:instance</i> and *<i>:arguments</i> and the provided +block+.
|
85
|
+
# Else the <i>:instance</i>.respond_to?(<i>the given hook</i>)
|
86
|
+
# must be true, and that <i>:instance</i> will be sent the <i>given hook</i> along with the <i>:arguments</i> and
|
87
|
+
# a block that does the rest of the hooks.
|
88
|
+
#
|
89
|
+
def with_hooks(options = {}, &block)
|
90
|
+
instance = options[:instance] || self
|
91
|
+
arguments = options[:arguments] || []
|
92
|
+
hooks = options[:hooks] || []
|
93
|
+
|
94
|
+
if hooks.empty?
|
95
|
+
yield
|
96
|
+
else
|
97
|
+
first = hooks.first
|
98
|
+
rest = hooks[1..-1]
|
99
|
+
if first.respond_to?(:call)
|
100
|
+
first.call(instance, *arguments) do
|
101
|
+
with_hooks(:instance => instance, :hooks => rest, :arguments => arguments, &block)
|
102
|
+
end
|
103
|
+
elsif instance.respond_to?(first)
|
104
|
+
instance.send(first, *arguments) do
|
105
|
+
with_hooks(:instance => instance, :hooks => rest, :arguments => arguments, &block)
|
106
|
+
end
|
107
|
+
else
|
108
|
+
raise "You can only send in hooks that are Symbols in the given instance or call'able objects"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Upon inheritance, our +subclass+ will be given copies of our hooks.
|
115
|
+
#
|
116
|
+
def inherited(subclass)
|
117
|
+
subclass.instance_variable_set(:@create_hooks, @create_hooks.clone)
|
118
|
+
subclass.instance_variable_set(:@destroy_hooks, @destroy_hooks.clone)
|
119
|
+
subclass.instance_variable_set(:@save_hooks, @save_hooks.clone)
|
120
|
+
subclass.instance_variable_set(:@load_hooks, @load_hooks.clone)
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Return our create_hooks, which can then be treated as any old Array.
|
125
|
+
#
|
126
|
+
# These must be <b>call</b>able objects with an arity of 1
|
127
|
+
# that will be sent the instance about to be created (initial
|
128
|
+
# insertion into the database system) that take a block argument.
|
129
|
+
#
|
130
|
+
# The block argument will be a Proc that actually injects the
|
131
|
+
# instance into the database system.
|
132
|
+
#
|
133
|
+
# Use this to preprocess, validate and/or postprocess your
|
134
|
+
# instances upon creation.
|
135
|
+
#
|
136
|
+
attr_reader :create_hooks
|
137
|
+
|
138
|
+
#
|
139
|
+
# Return our destroy_hooks, which can then be treated as any old Array.
|
140
|
+
#
|
141
|
+
# These must be <b>call</b>able objects with an arity of 1
|
142
|
+
# that will be sent the instance about to be destroyed (removal
|
143
|
+
# from the database system) that take a block argument.
|
144
|
+
#
|
145
|
+
# The block argument will be a Proc that actually removes the
|
146
|
+
# instance from the database system.
|
147
|
+
#
|
148
|
+
# Use this to preprocess, validate and/or postprocess your
|
149
|
+
# instances upon destruction.
|
150
|
+
#
|
151
|
+
attr_reader :destroy_hooks
|
152
|
+
|
153
|
+
#
|
154
|
+
# Return our load_hooks, which can then be treated as any old Array.
|
155
|
+
#
|
156
|
+
# These must be <b>call</b>able objects with an arity of 1
|
157
|
+
# that will be sent the instance about to be loaded (insertion
|
158
|
+
# into the live hash of the database in question) that take a block argument.
|
159
|
+
#
|
160
|
+
# The block argument will be a Proc that actually puts the
|
161
|
+
# instance into the live hash.
|
162
|
+
#
|
163
|
+
# Use this to preprocess, validate and/or postprocess your
|
164
|
+
# instances upon loading.
|
165
|
+
#
|
166
|
+
attr_reader :load_hooks
|
167
|
+
|
168
|
+
#
|
169
|
+
# Return our save_hooks, which can then be treated as any old Array.
|
170
|
+
#
|
171
|
+
# These must be <b>call</b>able objects with an arity of 1
|
172
|
+
# that will be sent [the old version, the new version] of the
|
173
|
+
# instance about to be saved (storage into the database system)
|
174
|
+
# along with a block argument.
|
175
|
+
#
|
176
|
+
# The block argument will be a Proc that actually saves the
|
177
|
+
# instance into the database system.
|
178
|
+
#
|
179
|
+
# Use this to preprocess, validate and/or postprocess your
|
180
|
+
# instances upon saving.
|
181
|
+
#
|
182
|
+
attr_reader :save_hooks
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
77
187
|
|
78
188
|
end
|
79
189
|
|
@@ -0,0 +1,210 @@
|
|
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
|
+
module Index
|
21
|
+
|
22
|
+
#
|
23
|
+
# A tiny <b>call</b>able class that saves stuff in
|
24
|
+
# indexes depending on certain attributes.
|
25
|
+
#
|
26
|
+
class IndexBuilder
|
27
|
+
#
|
28
|
+
# Get the key for the given attributes and values.
|
29
|
+
#
|
30
|
+
def self.get_key(klass, attributes, values)
|
31
|
+
"Hyperactive::IndexBuilder::#{klass}::#{attributes.join(",")}::#{values.join(",")}"
|
32
|
+
end
|
33
|
+
#
|
34
|
+
# Initialize an IndexBuilder giving it an array of +attributes+
|
35
|
+
# that will be indexed.
|
36
|
+
#
|
37
|
+
def initialize(klass, attributes)
|
38
|
+
@klass = klass
|
39
|
+
@attributes = attributes
|
40
|
+
end
|
41
|
+
#
|
42
|
+
# Get the key for the given +record+.
|
43
|
+
#
|
44
|
+
def get_key_for(record)
|
45
|
+
values = @attributes.collect do |att|
|
46
|
+
if record.respond_to?(att)
|
47
|
+
record.send(att)
|
48
|
+
else
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
key = self.class.get_key(@klass, @attributes, values)
|
53
|
+
end
|
54
|
+
#
|
55
|
+
# Call this IndexBuilder and pass it a +block+.
|
56
|
+
#
|
57
|
+
# If the +argument+ is an Array then we know we are a save hook,
|
58
|
+
# otherwise we are a destroy hook.
|
59
|
+
#
|
60
|
+
def call(*arguments, &block)
|
61
|
+
yield
|
62
|
+
|
63
|
+
#
|
64
|
+
# If the argument is an Array (of old value, new value)
|
65
|
+
# then we are a save hook, otherwise a destroy hook.
|
66
|
+
#
|
67
|
+
if arguments.size > 1
|
68
|
+
record = arguments.first
|
69
|
+
old_record = arguments.last
|
70
|
+
old_key = get_key_for(old_record)
|
71
|
+
new_key = get_key_for(record)
|
72
|
+
if old_key != new_key
|
73
|
+
(CAPTAIN[old_key] ||= Hyperactive::Hash::Head.get_instance_with_transaction(record.transaction)).delete(record.record_id)
|
74
|
+
(CAPTAIN[new_key] ||= Hyperactive::Hash::Head.get_instance_with_transaction(record.transaction))[record.record_id] = record
|
75
|
+
end
|
76
|
+
else
|
77
|
+
record = arguments.first
|
78
|
+
(CAPTAIN[get_key_for(record)] ||= Hyperactive::Hash::Head.get_instance_with_transaction(record.transaction)).delete(record.record_id)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# A tiny <b>call</b>able class that saves stuff inside containers
|
85
|
+
# if they match certain criteria.
|
86
|
+
#
|
87
|
+
class MatchSaver
|
88
|
+
#
|
89
|
+
# Initialize this MatchSaver with a +key+, a <b>call</b>able +matcher+
|
90
|
+
# and a +mode+ (:select, :reject, :delete_if_match or :delete_unless_match).
|
91
|
+
#
|
92
|
+
def initialize(key, matcher, mode)
|
93
|
+
@key = key
|
94
|
+
@matcher = matcher
|
95
|
+
@mode = mode
|
96
|
+
end
|
97
|
+
#
|
98
|
+
# Depending on <i>@mode</i> and return value of <i>@matcher</i>.call
|
99
|
+
# may save record in the Hash-like container named <i>@key</i> in
|
100
|
+
# the main database after having yielded to +block+.
|
101
|
+
#
|
102
|
+
def call(*arguments, &block)
|
103
|
+
yield
|
104
|
+
|
105
|
+
record = arguments.first
|
106
|
+
|
107
|
+
case @mode
|
108
|
+
when :select
|
109
|
+
if @matcher.call(record)
|
110
|
+
CAPTAIN[@key, record.transaction][record.record_id] = record
|
111
|
+
else
|
112
|
+
CAPTAIN[@key, record.transaction].delete(record.record_id)
|
113
|
+
end
|
114
|
+
when :reject
|
115
|
+
if @matcher.call(record)
|
116
|
+
CAPTAIN[@key, record.transaction].delete(record.record_id)
|
117
|
+
else
|
118
|
+
CAPTAIN[@key, record.transaction][record.record_id] = record
|
119
|
+
end
|
120
|
+
when :delete_if_match
|
121
|
+
if @matcher.call(record)
|
122
|
+
CAPTAIN[@key, record.transaction].delete(record.record_id)
|
123
|
+
end
|
124
|
+
when :delete_unless_match
|
125
|
+
unless @matcher.call(record)
|
126
|
+
CAPTAIN[@key, record.transaction].delete(record.record_id)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
module Indexable
|
133
|
+
|
134
|
+
def self.append_features(base)
|
135
|
+
super
|
136
|
+
base.extend(ClassMethods)
|
137
|
+
end
|
138
|
+
|
139
|
+
module ClassMethods
|
140
|
+
#
|
141
|
+
# Create an index for this class.
|
142
|
+
#
|
143
|
+
# Will create a method find_by_#{attributes.join("_and_")} for this
|
144
|
+
# class that will return what you expect.
|
145
|
+
#
|
146
|
+
def index_by(*attributes)
|
147
|
+
klass = self
|
148
|
+
self.class.class_eval do
|
149
|
+
define_method("find_by_#{attributes.join("_and_")}") do |*args|
|
150
|
+
CAPTAIN[IndexBuilder.get_key(klass, attributes, args)]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
index_builder = IndexBuilder.new(self, attributes)
|
154
|
+
self.save_hooks << index_builder
|
155
|
+
self.destroy_hooks << index_builder
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# Will define a method called +name+ that will include all
|
160
|
+
# existing instances of this class that when yielded to the +block+
|
161
|
+
# returns true. Will only return instances saved after this selector
|
162
|
+
# is defined.
|
163
|
+
#
|
164
|
+
def select(name, &block) #:yields: instance
|
165
|
+
key = collection_key(name)
|
166
|
+
CAPTAIN[key] ||= Hyperactive::Hash::Head.get_instance
|
167
|
+
self.class.class_eval do
|
168
|
+
define_method(name) do
|
169
|
+
CAPTAIN[key]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
self.save_hooks << MatchSaver.new(key, block, :select)
|
173
|
+
self.destroy_hooks << MatchSaver.new(key, block, :delete_if_match)
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Will define a method called +name+ that will include all
|
178
|
+
# existing instances of this class that when yielded to +block+
|
179
|
+
# does not return true. Will only return instances saved after this
|
180
|
+
# rejector is defined.
|
181
|
+
#
|
182
|
+
def reject(name, &block) #:yields: instance
|
183
|
+
key = collection_key(name)
|
184
|
+
CAPTAIN[key] ||= Hyperactive::Hash::Head.get_instance
|
185
|
+
self.class.class_eval do
|
186
|
+
define_method(name) do
|
187
|
+
CAPTAIN[key]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
self.save_hooks << MatchSaver.new(key, block, :reject)
|
191
|
+
self.destroy_hooks << MatchSaver.new(key, block, :delete_unless_match)
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
#
|
197
|
+
# The key used to store the collection with the given +sym+ as name.
|
198
|
+
#
|
199
|
+
def collection_key(sym)
|
200
|
+
"Hyperactive::Index::Indexable::collection_key::#{sym}"
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
data/lib/hyperactive/list.rb
CHANGED
@@ -70,6 +70,7 @@ module Hyperactive
|
|
70
70
|
# NB: Remember to call create on the new instance or use Head.get_instance to get that done automatically.
|
71
71
|
#
|
72
72
|
def initialize
|
73
|
+
super
|
73
74
|
self.size = 0
|
74
75
|
self.first_element = self.last_element = nil
|
75
76
|
end
|
@@ -102,6 +103,13 @@ module Hyperactive
|
|
102
103
|
element.destroy!
|
103
104
|
end
|
104
105
|
|
106
|
+
#
|
107
|
+
# Return whether this List is empty.
|
108
|
+
#
|
109
|
+
def empty?
|
110
|
+
return self.size == 0
|
111
|
+
end
|
112
|
+
|
105
113
|
#
|
106
114
|
# Remove all elements from this List::Head.
|
107
115
|
#
|