familia 0.6.1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +15 -0
- data/Rakefile +3 -3
- data/VERSION.yml +1 -1
- data/familia.gemspec +11 -11
- data/lib/familia/core_ext.rb +85 -84
- data/lib/familia/object.rb +123 -83
- data/lib/familia/redisobject.rb +224 -53
- data/lib/familia/test_helpers.rb +0 -2
- data/lib/familia.rb +38 -43
- data/try/21_redis_object_zset_try.rb +1 -1
- data/try/24_redis_object_string_try.rb +1 -1
- data/try/30_familia_object_try.rb +2 -2
- metadata +13 -13
data/CHANGES.txt
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
FAMILIA, CHANGES
|
2
2
|
|
3
|
+
#### 0.6.2 (2010-12-29) ###############################
|
4
|
+
|
5
|
+
* FIXED: Familia::ClassMethods.ttl=
|
6
|
+
* FIXED: Familia.class_lists (etc) methods.
|
7
|
+
* FIXED: Redis objects check if parent is a Module
|
8
|
+
* CHANGE: redis_objects, class_redis_objects maintain order they're defined in. (See Bluth::Queue)
|
9
|
+
* CHANGE: Depends on Storable 0.8.4
|
10
|
+
* CHANGE: FamiliaObject.instances is now a sorted set
|
11
|
+
* ADDED: InstanceMethods#initialize calls init if available
|
12
|
+
* ADDED: Can set index values via InstanceMethods#index=
|
13
|
+
* ADDED: empty? method for List, Set, et al
|
14
|
+
* ADDED: :extend option for RedisObject instances
|
15
|
+
* ADDED: :reference option for storing the index value instead of the marshaled value
|
16
|
+
|
17
|
+
|
3
18
|
#### 0.6.1 (2010-12-18) ###############################
|
4
19
|
|
5
20
|
* CHANGE: Default initialize method calls initialize_redis_objects before super
|
data/Rakefile
CHANGED
@@ -26,9 +26,9 @@ begin
|
|
26
26
|
gem.homepage = "http://github.com/delano/familia"
|
27
27
|
gem.authors = ["Delano Mandelbaum"]
|
28
28
|
gem.add_dependency("redis", ">= 2.1.0")
|
29
|
-
gem.add_dependency("uri-redis", ">= 0.4.
|
30
|
-
gem.add_dependency("gibbler", ">= 0.8.
|
31
|
-
gem.add_dependency("storable", ">= 0.8.
|
29
|
+
gem.add_dependency("uri-redis", ">= 0.4.2")
|
30
|
+
gem.add_dependency("gibbler", ">= 0.8.6")
|
31
|
+
gem.add_dependency("storable", ">= 0.8.5")
|
32
32
|
|
33
33
|
#gem.add_development_dependency("rspec", ">= 1.2.9")
|
34
34
|
#gem.add_development_dependency("mocha", ">= 0.9.8")
|
data/VERSION.yml
CHANGED
data/familia.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{familia}
|
8
|
-
s.version = "0.6.
|
8
|
+
s.version = "0.6.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Delano Mandelbaum"]
|
12
|
-
s.date = %q{2010-12-
|
12
|
+
s.date = %q{2010-12-30}
|
13
13
|
s.description = %q{Organize and store ruby objects in Redis}
|
14
14
|
s.email = %q{delano@solutious.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -53,20 +53,20 @@ Gem::Specification.new do |s|
|
|
53
53
|
|
54
54
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
55
55
|
s.add_runtime_dependency(%q<redis>, [">= 2.1.0"])
|
56
|
-
s.add_runtime_dependency(%q<uri-redis>, [">= 0.4.
|
57
|
-
s.add_runtime_dependency(%q<gibbler>, [">= 0.8.
|
58
|
-
s.add_runtime_dependency(%q<storable>, [">= 0.8.
|
56
|
+
s.add_runtime_dependency(%q<uri-redis>, [">= 0.4.2"])
|
57
|
+
s.add_runtime_dependency(%q<gibbler>, [">= 0.8.6"])
|
58
|
+
s.add_runtime_dependency(%q<storable>, [">= 0.8.5"])
|
59
59
|
else
|
60
60
|
s.add_dependency(%q<redis>, [">= 2.1.0"])
|
61
|
-
s.add_dependency(%q<uri-redis>, [">= 0.4.
|
62
|
-
s.add_dependency(%q<gibbler>, [">= 0.8.
|
63
|
-
s.add_dependency(%q<storable>, [">= 0.8.
|
61
|
+
s.add_dependency(%q<uri-redis>, [">= 0.4.2"])
|
62
|
+
s.add_dependency(%q<gibbler>, [">= 0.8.6"])
|
63
|
+
s.add_dependency(%q<storable>, [">= 0.8.5"])
|
64
64
|
end
|
65
65
|
else
|
66
66
|
s.add_dependency(%q<redis>, [">= 2.1.0"])
|
67
|
-
s.add_dependency(%q<uri-redis>, [">= 0.4.
|
68
|
-
s.add_dependency(%q<gibbler>, [">= 0.8.
|
69
|
-
s.add_dependency(%q<storable>, [">= 0.8.
|
67
|
+
s.add_dependency(%q<uri-redis>, [">= 0.4.2"])
|
68
|
+
s.add_dependency(%q<gibbler>, [">= 0.8.6"])
|
69
|
+
s.add_dependency(%q<storable>, [">= 0.8.5"])
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
data/lib/familia/core_ext.rb
CHANGED
@@ -17,102 +17,103 @@ class String
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
unless defined?(Time::Units)
|
21
|
+
class Time
|
22
|
+
module Units
|
23
|
+
PER_MICROSECOND = 0.000001.freeze
|
24
|
+
PER_MILLISECOND = 0.001.freeze
|
25
|
+
PER_MINUTE = 60.0.freeze
|
26
|
+
PER_HOUR = 3600.0.freeze
|
27
|
+
PER_DAY = 86400.0.freeze
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
def microseconds() seconds * PER_MICROSECOND end
|
30
|
+
def milliseconds() seconds * PER_MILLISECOND end
|
31
|
+
def seconds() self end
|
32
|
+
def minutes() seconds * PER_MINUTE end
|
33
|
+
def hours() seconds * PER_HOUR end
|
34
|
+
def days() seconds * PER_DAY end
|
35
|
+
def weeks() seconds * PER_DAY * 7 end
|
36
|
+
def years() seconds * PER_DAY * 365 end
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
def in_years() seconds / PER_DAY / 365 end
|
39
|
+
def in_weeks() seconds / PER_DAY / 7 end
|
40
|
+
def in_days() seconds / PER_DAY end
|
41
|
+
def in_hours() seconds / PER_HOUR end
|
42
|
+
def in_minutes() seconds / PER_MINUTE end
|
43
|
+
def in_milliseconds() seconds / PER_MILLISECOND end
|
44
|
+
def in_microseconds() seconds / PER_MICROSECOND end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
46
|
+
def in_time
|
47
|
+
Time.at(self).utc
|
48
|
+
end
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
50
|
+
def in_seconds(u=nil)
|
51
|
+
case u.to_s
|
52
|
+
when /\A(y)|(years?)\z/
|
53
|
+
years
|
54
|
+
when /\A(w)|(weeks?)\z/
|
55
|
+
weeks
|
56
|
+
when /\A(d)|(days?)\z/
|
57
|
+
days
|
58
|
+
when /\A(h)|(hours?)\z/
|
59
|
+
hours
|
60
|
+
when /\A(m)|(minutes?)\z/
|
61
|
+
minutes
|
62
|
+
when /\A(ms)|(milliseconds?)\z/
|
63
|
+
milliseconds
|
64
|
+
when /\A(us)|(microseconds?)|(μs)\z/
|
65
|
+
microseconds
|
66
|
+
else
|
67
|
+
self
|
68
|
+
end
|
67
69
|
end
|
68
|
-
end
|
69
70
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
71
|
+
## JRuby doesn't like using instance_methods.select here.
|
72
|
+
## It could be a bug or something quirky with Attic
|
73
|
+
## (although it works in 1.8 and 1.9). The error:
|
74
|
+
##
|
75
|
+
## lib/attic.rb:32:in `select': yield called out of block (LocalJumpError)
|
76
|
+
## lib/stella/mixins/numeric.rb:24
|
77
|
+
##
|
78
|
+
## Create singular methods, like hour and day.
|
79
|
+
# instance_methods.select.each do |plural|
|
80
|
+
# singular = plural.to_s.chop
|
81
|
+
# alias_method singular, plural
|
82
|
+
# end
|
82
83
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
84
|
+
alias_method :ms, :milliseconds
|
85
|
+
alias_method :'μs', :microseconds
|
86
|
+
alias_method :second, :seconds
|
87
|
+
alias_method :minute, :minutes
|
88
|
+
alias_method :hour, :hours
|
89
|
+
alias_method :day, :days
|
90
|
+
alias_method :week, :weeks
|
91
|
+
alias_method :year, :years
|
91
92
|
|
93
|
+
end
|
92
94
|
end
|
93
|
-
end
|
94
95
|
|
95
|
-
class Numeric
|
96
|
-
|
96
|
+
class Numeric
|
97
|
+
include Time::Units
|
97
98
|
|
98
|
-
|
99
|
-
|
100
|
-
|
99
|
+
def to_ms
|
100
|
+
(self*1000.to_f)
|
101
|
+
end
|
101
102
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
103
|
+
# TODO: Use 1024?
|
104
|
+
def to_bytes
|
105
|
+
args = case self.abs.to_i
|
106
|
+
when (1000)..(1000**2)
|
107
|
+
'%3.2f%s' % [(self / 1000.to_f).to_s, 'KB']
|
108
|
+
when (1000**2)..(1000**3)
|
109
|
+
'%3.2f%s' % [(self / (1000**2).to_f).to_s, 'MB']
|
110
|
+
when (1000**3)..(1000**4)
|
111
|
+
'%3.2f%s' % [(self / (1000**3).to_f).to_s, 'GB']
|
112
|
+
when (1000**4)..(1000**6)
|
113
|
+
'%3.2f%s' % [(self / (1000**4).to_f).to_s, 'TB']
|
114
|
+
else
|
115
|
+
[self.to_i, 'B'].join
|
116
|
+
end
|
115
117
|
end
|
116
118
|
end
|
117
119
|
end
|
118
|
-
|
data/lib/familia/object.rb
CHANGED
@@ -23,7 +23,7 @@ module Familia
|
|
23
23
|
!obj.nil? && klass == obj.klass
|
24
24
|
end
|
25
25
|
define_method :"#{kind}s" do
|
26
|
-
names =
|
26
|
+
names = redis_objects_order.select { |name| send(:"#{kind}?", name) }
|
27
27
|
names.collect! { |name| redis_objects[name] }
|
28
28
|
names
|
29
29
|
end
|
@@ -42,7 +42,12 @@ module Familia
|
|
42
42
|
!obj.nil? && klass == obj.klass
|
43
43
|
end
|
44
44
|
define_method :"class_#{kind}s" do
|
45
|
-
names =
|
45
|
+
names = class_redis_objects_order.select { |name| ret = send(:"class_#{kind}?", name) }
|
46
|
+
# TODO: This returns instances of the RedisObject class which
|
47
|
+
# also contain the options. This is different from the instance
|
48
|
+
# RedisObjects defined above which returns the OpenStruct of name, klass, and opts.
|
49
|
+
#names.collect! { |name| self.send name }
|
50
|
+
# OR NOT:
|
46
51
|
names.collect! { |name| class_redis_objects[name] }
|
47
52
|
names
|
48
53
|
end
|
@@ -50,10 +55,15 @@ module Familia
|
|
50
55
|
|
51
56
|
def inherited(obj)
|
52
57
|
obj.db = self.db
|
53
|
-
obj.ttl = self.ttl
|
54
58
|
obj.uri = self.uri
|
59
|
+
obj.ttl = self.ttl
|
55
60
|
obj.parent = self
|
56
|
-
obj.
|
61
|
+
obj.class_zset :instances, :class => obj, :reference => true
|
62
|
+
# :object is a special redis object because its reserved
|
63
|
+
# for storing the marshaled instance data (e.g. to_json).
|
64
|
+
# When it isn't defined explicitly we define it here b/c
|
65
|
+
# it's assumed to exist in other places (see #save).
|
66
|
+
obj.string :object, :class => obj unless obj.redis_object? :object
|
57
67
|
Familia.classes << obj
|
58
68
|
super(obj)
|
59
69
|
end
|
@@ -62,15 +72,17 @@ module Familia
|
|
62
72
|
obj.ttl = self.ttl
|
63
73
|
obj.uri = self.uri
|
64
74
|
obj.parent = self
|
65
|
-
obj.
|
75
|
+
obj.class_zset :instances, :class => obj, :reference => true
|
66
76
|
Familia.classes << obj
|
67
77
|
end
|
68
78
|
|
69
79
|
# Creates an instance method called +name+ that
|
70
80
|
# returns an instance of the RedisObject +klass+
|
71
81
|
def install_redis_object name, klass, opts
|
82
|
+
raise ArgumentError, "Name is blank" if name.to_s.empty?
|
72
83
|
name = name.to_s.to_sym
|
73
84
|
opts ||= {}
|
85
|
+
redis_objects_order << name
|
74
86
|
redis_objects[name] = OpenStruct.new
|
75
87
|
redis_objects[name].name = name
|
76
88
|
redis_objects[name].klass = klass
|
@@ -79,17 +91,22 @@ module Familia
|
|
79
91
|
define_method "#{name}=" do |v|
|
80
92
|
self.send(name).replace v
|
81
93
|
end
|
94
|
+
define_method "#{name}?" do
|
95
|
+
!self.send(name).empty?
|
96
|
+
end
|
82
97
|
redis_objects[name]
|
83
98
|
end
|
84
99
|
|
85
100
|
# Creates a class method called +name+ that
|
86
101
|
# returns an instance of the RedisObject +klass+
|
87
102
|
def install_class_redis_object name, klass, opts
|
103
|
+
raise ArgumentError, "Name is blank" if name.to_s.empty?
|
88
104
|
name = name.to_s.to_sym
|
89
105
|
opts ||= {}
|
90
106
|
opts[:suffix] ||= nil
|
91
107
|
opts[:parent] ||= self
|
92
|
-
# TODO: investigate metaclass.redis_objects
|
108
|
+
# TODO: investigate using metaclass.redis_objects
|
109
|
+
class_redis_objects_order << name
|
93
110
|
class_redis_objects[name] = OpenStruct.new
|
94
111
|
class_redis_objects[name].name = name
|
95
112
|
class_redis_objects[name].klass = klass
|
@@ -100,6 +117,9 @@ module Familia
|
|
100
117
|
metaclass.send :define_method, "#{name}=" do |v|
|
101
118
|
send(name).replace v
|
102
119
|
end
|
120
|
+
metaclass.send :define_method, "#{name}?" do
|
121
|
+
!send(name).empty?
|
122
|
+
end
|
103
123
|
redis_object = klass.new name, opts
|
104
124
|
redis_object.freeze
|
105
125
|
self.instance_variable_set("@#{name}", redis_object)
|
@@ -114,6 +134,7 @@ module Familia
|
|
114
134
|
@ttl = v unless v.nil?
|
115
135
|
@ttl || (parent ? parent.ttl : nil)
|
116
136
|
end
|
137
|
+
def ttl=(v) @ttl = v end
|
117
138
|
def db v=nil
|
118
139
|
@db = v unless v.nil?
|
119
140
|
@db || (parent ? parent.db : nil)
|
@@ -128,15 +149,13 @@ module Familia
|
|
128
149
|
@uri = uri
|
129
150
|
end
|
130
151
|
def uri(uri=nil)
|
131
|
-
self.uri = uri
|
132
|
-
|
133
|
-
@uri =
|
134
|
-
@uri
|
135
|
-
Familia.connect @uri #unless Familia.connected?(@uri)
|
136
|
-
@uri || (parent ? parent.uri : Familia.uri)
|
152
|
+
self.uri = uri if !uri.to_s.empty?
|
153
|
+
@uri ||= (parent ? parent.uri : Familia.uri)
|
154
|
+
@uri.db = @db if @db && @uri.db.to_s != @db.to_s
|
155
|
+
@uri
|
137
156
|
end
|
138
157
|
def redis
|
139
|
-
Familia.redis
|
158
|
+
Familia.redis uri
|
140
159
|
end
|
141
160
|
def flushdb
|
142
161
|
Familia.info "flushing #{uri}"
|
@@ -145,7 +164,7 @@ module Familia
|
|
145
164
|
def keys(suffix=nil)
|
146
165
|
self.redis.keys(rediskey('*',suffix)) || []
|
147
166
|
end
|
148
|
-
def all(suffix
|
167
|
+
def all(suffix=:object)
|
149
168
|
# objects that could not be parsed will be nil
|
150
169
|
keys(suffix).collect { |k| from_key(k) }.compact
|
151
170
|
end
|
@@ -170,6 +189,10 @@ module Familia
|
|
170
189
|
def suffixes
|
171
190
|
redis_objects.keys.uniq
|
172
191
|
end
|
192
|
+
def class_redis_objects_order
|
193
|
+
@class_redis_objects_order ||= []
|
194
|
+
@class_redis_objects_order
|
195
|
+
end
|
173
196
|
def class_redis_objects
|
174
197
|
@class_redis_objects ||= {}
|
175
198
|
@class_redis_objects
|
@@ -180,26 +203,20 @@ module Familia
|
|
180
203
|
def redis_object? name
|
181
204
|
redis_objects.has_key? name.to_s.to_sym
|
182
205
|
end
|
206
|
+
def redis_objects_order
|
207
|
+
@redis_objects_order ||= []
|
208
|
+
@redis_objects_order
|
209
|
+
end
|
183
210
|
def redis_objects
|
184
211
|
@redis_objects ||= {}
|
185
212
|
@redis_objects
|
186
213
|
end
|
187
|
-
def create
|
188
|
-
me =
|
189
|
-
raise "#{self} exists: #{me.
|
214
|
+
def create *args
|
215
|
+
me = from_array *args
|
216
|
+
raise "#{self} exists: #{me.rediskey}" if me.exists?
|
190
217
|
me.save
|
191
218
|
me
|
192
219
|
end
|
193
|
-
def load_or_create(id)
|
194
|
-
if exists?(id)
|
195
|
-
from_redis(id)
|
196
|
-
else
|
197
|
-
me = new id
|
198
|
-
me.save
|
199
|
-
me
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
220
|
def multiget(*ids)
|
204
221
|
ids = rawmultiget(*ids)
|
205
222
|
ids.compact.collect { |json| self.from_json(json) }.compact
|
@@ -211,49 +228,56 @@ module Familia
|
|
211
228
|
ids = self.redis.mget *ids
|
212
229
|
end
|
213
230
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
231
|
+
# Returns an instance based on +idx+ otherwise it
|
232
|
+
# creates and saves a new instance base on +idx+.
|
233
|
+
# See from_index
|
234
|
+
def load_or_create idx
|
235
|
+
return from_redis(idx) if exists?(idx)
|
236
|
+
obj = from_index idx
|
237
|
+
obj.save
|
238
|
+
obj
|
239
|
+
end
|
240
|
+
# Note +idx+ needs to be an appropriate index for
|
241
|
+
# the given class. If the index is multi-value it
|
242
|
+
# must be passed as an Array in the proper order.
|
243
|
+
# Does not call save.
|
244
|
+
def from_index idx
|
245
|
+
obj = new
|
246
|
+
obj.index = idx
|
247
|
+
obj
|
248
|
+
end
|
249
|
+
def from_key objkey
|
250
|
+
raise ArgumentError, "Null key" if objkey.to_s.empty?
|
251
|
+
Familia.trace :LOAD, redis, "#{self.uri}/#{objkey}", caller if Familia.debug?
|
252
|
+
obj = Familia::String.new objkey, :class => self
|
253
|
+
obj.exists? ? obj.value : nil
|
254
|
+
end
|
255
|
+
def from_redis idx, suffix=:object
|
256
|
+
return nil if idx.to_s.empty?
|
257
|
+
objkey = rediskey idx, suffix
|
258
|
+
Familia.trace :FROMREDIS, Familia.redis(self.uri), objkey, caller.first
|
259
|
+
me = from_key objkey
|
238
260
|
me
|
239
261
|
end
|
240
|
-
def exists?
|
241
|
-
|
242
|
-
|
243
|
-
ret = Familia.redis(self.uri).exists
|
244
|
-
Familia.trace :EXISTS, Familia.redis(self.uri), "#{rediskey(
|
262
|
+
def exists? idx, suffix=:object
|
263
|
+
return false if idx.to_s.empty?
|
264
|
+
objkey = rediskey idx, suffix
|
265
|
+
ret = Familia.redis(self.uri).exists objkey
|
266
|
+
Familia.trace :EXISTS, Familia.redis(self.uri), "#{rediskey(obj.index, suffix)} #{ret}", caller.first
|
245
267
|
ret
|
246
268
|
end
|
247
|
-
def destroy!
|
248
|
-
ret = Familia.redis(self.uri).del rediskey(
|
249
|
-
Familia.trace :DELETED, Familia.redis(self.uri), "#{rediskey(
|
269
|
+
def destroy! idx, suffix=:object
|
270
|
+
ret = Familia.redis(self.uri).del rediskey(idx, suffix)
|
271
|
+
Familia.trace :DELETED, Familia.redis(self.uri), "#{rediskey(idx, suffix)}: #{ret}", caller.first
|
250
272
|
ret
|
251
273
|
end
|
252
|
-
def find
|
274
|
+
def find suffix='*'
|
253
275
|
list = Familia.redis(self.uri).keys(rediskey('*', suffix)) || []
|
254
276
|
end
|
255
|
-
|
277
|
+
# idx can be a value or an Array of values used to create the index.
|
278
|
+
def rediskey idx, suffix=nil
|
256
279
|
raise RuntimeError, "No index for #{self}" if idx.to_s.empty?
|
280
|
+
idx = Familia.join *idx if Array === idx
|
257
281
|
idx &&= idx.to_s
|
258
282
|
Familia.rediskey(prefix, idx, suffix)
|
259
283
|
end
|
@@ -271,12 +295,6 @@ module Familia
|
|
271
295
|
raise Familia::NonUniqueKey, "Short key returned more than 1 match"
|
272
296
|
end
|
273
297
|
end
|
274
|
-
## TODO: Investigate
|
275
|
-
##def float
|
276
|
-
## Proc.new do |v|
|
277
|
-
## v.nil? ? 0 : v.to_f
|
278
|
-
## end
|
279
|
-
##end
|
280
298
|
end
|
281
299
|
|
282
300
|
|
@@ -288,23 +306,17 @@ module Familia
|
|
288
306
|
# must call initialize_redis_objects.
|
289
307
|
def initialize *args
|
290
308
|
initialize_redis_objects
|
291
|
-
|
309
|
+
from_array *args if respond_to? :from_array
|
310
|
+
init *args if respond_to? :init
|
292
311
|
end
|
293
312
|
|
294
313
|
# This needs to be called in the initialize method of
|
295
314
|
# any class that includes Familia.
|
296
315
|
def initialize_redis_objects
|
297
|
-
# :object is a special redis object because its reserved
|
298
|
-
# for storing the marshaled instance data (e.g. to_json).
|
299
|
-
# When it isn't defined explicitly we define it here b/c
|
300
|
-
# it's assumed to exist in other places (see #save).
|
301
|
-
unless self.class.redis_object? :object
|
302
|
-
self.class.string :object, :class => self.class
|
303
|
-
end
|
304
|
-
|
305
316
|
# Generate instances of each RedisObject. These need to be
|
306
317
|
# unique for each instance of this class so they can refer
|
307
|
-
# to the index of this specific instance.
|
318
|
+
# to the index of this specific instance.
|
319
|
+
#
|
308
320
|
# i.e.
|
309
321
|
# familia_object.rediskey == v1:bone:INDEXVALUE:object
|
310
322
|
# familia_object.redis_object.rediskey == v1:bone:INDEXVALUE:name
|
@@ -326,7 +338,8 @@ module Familia
|
|
326
338
|
|
327
339
|
def redisinfo
|
328
340
|
info = {
|
329
|
-
:
|
341
|
+
:uri => self.class.uri,
|
342
|
+
:db => self.class.db,
|
330
343
|
:key => rediskey,
|
331
344
|
:type => redistype,
|
332
345
|
:ttl => realttl
|
@@ -363,9 +376,11 @@ module Familia
|
|
363
376
|
#Familia.trace :SAVE, Familia.redis(self.class.uri), redisuri, caller.first
|
364
377
|
preprocess if respond_to?(:preprocess)
|
365
378
|
self.update_time if self.respond_to?(:update_time)
|
379
|
+
# TODO: Check here (run checkup)
|
366
380
|
ret = self.object.set self # object is a name reserved by Familia
|
367
381
|
unless ret.nil?
|
368
|
-
|
382
|
+
now = Time.now.utc.to_i
|
383
|
+
self.class.instances.add now, self # use this set instead of Klass.keys
|
369
384
|
self.object.update_expiration self.ttl # does nothing unless if not specified
|
370
385
|
end
|
371
386
|
true
|
@@ -375,7 +390,7 @@ module Familia
|
|
375
390
|
if Familia.debug?
|
376
391
|
Familia.trace :DELETED, Familia.redis(self.class.uri), "#{rediskey}: #{ret}", caller.first
|
377
392
|
end
|
378
|
-
self.class.instances.rem
|
393
|
+
self.class.instances.rem self if ret > 0
|
379
394
|
ret
|
380
395
|
end
|
381
396
|
def index
|
@@ -397,14 +412,39 @@ module Familia
|
|
397
412
|
unless self.respond_to? self.class.index
|
398
413
|
raise NoIndex, "No such method: `#{self.class.index}' for #{self.class}"
|
399
414
|
end
|
400
|
-
self.send self.class.index
|
415
|
+
self.send( self.class.index)
|
401
416
|
end
|
402
417
|
else
|
403
418
|
raise Familia::NoIndex, self
|
404
419
|
end
|
405
420
|
end
|
406
|
-
def index=(
|
407
|
-
|
421
|
+
def index=(v)
|
422
|
+
case self.class.index
|
423
|
+
when Proc
|
424
|
+
raise ArgumentError, "Cannot set a Proc index"
|
425
|
+
when Array
|
426
|
+
unless Array === v && v.size == self.class.index.size
|
427
|
+
raise ArgumentError, "Index mismatch (#{v.size} for #{self.class.index.size})"
|
428
|
+
end
|
429
|
+
parts = self.class.index.each_with_index { |meth,idx|
|
430
|
+
unless self.respond_to? "#{meth}="
|
431
|
+
raise NoIndex, "No such method: `#{meth}=' for #{self.class}"
|
432
|
+
end
|
433
|
+
self.send("#{meth}=", v[idx])
|
434
|
+
}
|
435
|
+
when Symbol, String
|
436
|
+
if self.class.redis_object?(self.class.index.to_sym)
|
437
|
+
raise Familia::NoIndex, "Cannot use a RedisObject as an index"
|
438
|
+
else
|
439
|
+
unless self.respond_to? "#{self.class.index}="
|
440
|
+
raise NoIndex, "No such method: `#{self.class.index}=' for #{self.class}"
|
441
|
+
end
|
442
|
+
self.send("#{self.class.index}=", v)
|
443
|
+
end
|
444
|
+
else
|
445
|
+
raise Familia::NoIndex, self
|
446
|
+
end
|
447
|
+
|
408
448
|
end
|
409
449
|
def expire(ttl=nil)
|
410
450
|
ttl ||= self.class.ttl
|