familia 0.5.3 → 0.6.0
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/CHANGES.txt +12 -0
- data/README.rdoc +1 -1
- data/VERSION.yml +2 -2
- data/familia.gemspec +18 -3
- data/lib/familia.rb +94 -869
- data/lib/familia/core_ext.rb +118 -0
- data/lib/familia/helpers.rb +70 -0
- data/lib/familia/object.rb +419 -0
- data/lib/familia/redisobject.rb +475 -0
- data/lib/familia/test_helpers.rb +38 -0
- data/lib/familia/tools.rb +67 -0
- data/try/00_familia.rb +8 -0
- data/try/10_familia_try.rb +36 -0
- data/try/20_redis_object_try.rb +18 -0
- data/try/21_redis_object_zset_try.rb +66 -0
- data/try/22_redis_object_set_try.rb +34 -0
- data/try/23_redis_object_list_try.rb +41 -0
- data/try/24_redis_object_string_try.rb +19 -0
- data/try/25_redis_object_hash_try.rb +53 -0
- data/try/30_familia_object_try.rb +75 -0
- metadata +20 -5
data/CHANGES.txt
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
FAMILIA, CHANGES
|
|
2
2
|
|
|
3
|
+
#### 0.6.0 (2010-12-10) ###############################
|
|
4
|
+
|
|
5
|
+
NOTE: Mucho refactoring. 0.6 syntax is not compatible with previous versions.
|
|
6
|
+
|
|
7
|
+
CHANGE: All methods name "key" are now "rediskey"
|
|
8
|
+
CHANGE: Familia#destroy! no longer takes a suffix argument. It now deletes
|
|
9
|
+
the object and all suffixes. See destroy.
|
|
10
|
+
CHANGE: Redis Object class methods now take the following args: name, options={}
|
|
11
|
+
CHANGE: Familia class suffixes are now derived from redis_objects
|
|
12
|
+
ADDED: Familia#destroy deletes just the object.
|
|
13
|
+
|
|
14
|
+
|
|
3
15
|
#### 0.5.3 (2010-12-10) ###############################
|
|
4
16
|
|
|
5
17
|
Initial public release
|
data/README.rdoc
CHANGED
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.
|
|
8
|
+
s.version = "0.6.0"
|
|
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-17}
|
|
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 = [
|
|
@@ -23,7 +23,22 @@ Gem::Specification.new do |s|
|
|
|
23
23
|
"Rakefile",
|
|
24
24
|
"VERSION.yml",
|
|
25
25
|
"familia.gemspec",
|
|
26
|
-
"lib/familia.rb"
|
|
26
|
+
"lib/familia.rb",
|
|
27
|
+
"lib/familia/core_ext.rb",
|
|
28
|
+
"lib/familia/helpers.rb",
|
|
29
|
+
"lib/familia/object.rb",
|
|
30
|
+
"lib/familia/redisobject.rb",
|
|
31
|
+
"lib/familia/test_helpers.rb",
|
|
32
|
+
"lib/familia/tools.rb",
|
|
33
|
+
"try/00_familia.rb",
|
|
34
|
+
"try/10_familia_try.rb",
|
|
35
|
+
"try/20_redis_object_try.rb",
|
|
36
|
+
"try/21_redis_object_zset_try.rb",
|
|
37
|
+
"try/22_redis_object_set_try.rb",
|
|
38
|
+
"try/23_redis_object_list_try.rb",
|
|
39
|
+
"try/24_redis_object_string_try.rb",
|
|
40
|
+
"try/25_redis_object_hash_try.rb",
|
|
41
|
+
"try/30_familia_object_try.rb"
|
|
27
42
|
]
|
|
28
43
|
s.homepage = %q{http://github.com/delano/familia}
|
|
29
44
|
s.rdoc_options = ["--charset=UTF-8"]
|
data/lib/familia.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
FAMILIA_LIB_HOME = File.expand_path File.dirname(__FILE__) unless defined?(FAMILIA_LIB_HOME)
|
|
3
3
|
require 'uri/redis'
|
|
4
|
+
require 'gibbler'
|
|
5
|
+
require 'familia/core_ext'
|
|
4
6
|
|
|
5
7
|
module Familia
|
|
6
8
|
module VERSION
|
|
@@ -16,24 +18,38 @@ module Familia
|
|
|
16
18
|
end
|
|
17
19
|
end
|
|
18
20
|
|
|
19
|
-
|
|
20
21
|
module Familia
|
|
21
22
|
include Gibbler::Complex
|
|
22
23
|
@secret = '1-800-AWESOME' # Should be modified via Familia.secret = ''
|
|
24
|
+
@apiversion = nil
|
|
25
|
+
@uri = URI.parse 'redis://localhost'
|
|
26
|
+
@delim = ':'
|
|
23
27
|
@clients = {}
|
|
28
|
+
@classes = []
|
|
24
29
|
@conf = {}
|
|
25
30
|
@suffix = :object.freeze
|
|
26
31
|
@index = :id.freeze
|
|
27
|
-
@apiversion = nil
|
|
28
|
-
@uri = URI.parse 'redis://localhost'
|
|
29
32
|
@debug = false.freeze
|
|
30
|
-
@
|
|
31
|
-
@
|
|
33
|
+
@dump_method = :to_json
|
|
34
|
+
@load_method = :from_json
|
|
32
35
|
class << self
|
|
33
36
|
attr_reader :conf, :classes, :clients
|
|
34
|
-
attr_accessor :debug, :secret, :delim
|
|
37
|
+
attr_accessor :debug, :secret, :delim, :dump_method, :load_method
|
|
38
|
+
attr_writer :apiversion, :uri
|
|
35
39
|
def debug?() @debug == true end
|
|
40
|
+
def info *msg
|
|
41
|
+
STDERR.puts *msg
|
|
42
|
+
end
|
|
43
|
+
def ld *msg
|
|
44
|
+
info *msg if debug?
|
|
45
|
+
end
|
|
46
|
+
def trace label, redis_client, ident, context=nil
|
|
47
|
+
return unless Familia.debug?
|
|
48
|
+
info "%s (%d:%s): %s" % [label, Thread.current.object_id, redis_client.object_id, ident]
|
|
49
|
+
info " +-> %s" % [context].flatten[0..3].join("\n ") if context
|
|
50
|
+
end
|
|
36
51
|
end
|
|
52
|
+
|
|
37
53
|
class Problem < RuntimeError; end
|
|
38
54
|
class EmptyIndex < Problem; end
|
|
39
55
|
class NonUniqueKey < Problem; end
|
|
@@ -46,870 +62,88 @@ module Familia
|
|
|
46
62
|
"No client for #{uri.serverid}"
|
|
47
63
|
end
|
|
48
64
|
end
|
|
49
|
-
def Familia.uri(db=nil)
|
|
50
|
-
if db.nil?
|
|
51
|
-
@uri
|
|
52
|
-
else
|
|
53
|
-
uri = URI.parse @uri.to_s
|
|
54
|
-
uri.db = db
|
|
55
|
-
uri
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
def Familia.apiversion(r=nil, &blk)
|
|
59
|
-
if blk.nil?
|
|
60
|
-
@apiversion = r if r;
|
|
61
|
-
else
|
|
62
|
-
tmp = @apiversion
|
|
63
|
-
@apiversion = r
|
|
64
|
-
blk.call
|
|
65
|
-
@apiversion = tmp
|
|
66
|
-
end
|
|
67
|
-
@apiversion
|
|
68
|
-
end
|
|
69
|
-
def Familia.apiversion=(r) @apiversion = r; r end
|
|
70
|
-
def Familia.conf=(conf={})
|
|
71
|
-
@conf = conf
|
|
72
|
-
@uri = Redis.uri(@conf).freeze
|
|
73
|
-
connect @uri
|
|
74
|
-
@conf
|
|
75
|
-
end
|
|
76
|
-
def Familia.redis(uri=nil)
|
|
77
|
-
uri &&= URI.parse uri if String === uri
|
|
78
|
-
uri ||= Familia.uri
|
|
79
|
-
connect(uri) unless @clients[uri.serverid]
|
|
80
|
-
#STDERR.puts "REDIS: #{uri} #{caller[0]}" if Familia.debug?
|
|
81
|
-
@clients[uri.serverid]
|
|
82
|
-
end
|
|
83
|
-
def Familia.connect(uri=nil, local_conf={})
|
|
84
|
-
uri &&= URI.parse uri if String === uri
|
|
85
|
-
uri ||= Familia.uri
|
|
86
|
-
local_conf[:thread_safe] = true
|
|
87
|
-
client = Redis.new local_conf.merge(uri.conf)
|
|
88
|
-
Familia.trace :CONNECT, client, uri.conf.inspect, caller.first
|
|
89
|
-
@clients[uri.serverid] = client
|
|
90
|
-
end
|
|
91
|
-
def Familia.reconnect_all!
|
|
92
|
-
Familia.classes.each do |klass|
|
|
93
|
-
klass.redis.client.reconnect
|
|
94
|
-
Familia.info "#{klass} ping: #{klass.redis.ping}" if debug?
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
def Familia.connected?(uri=nil)
|
|
98
|
-
uri &&= URI.parse uri if String === uri
|
|
99
|
-
@clients.has_key?(uri.serverid)
|
|
100
|
-
end
|
|
101
|
-
def Familia.default_suffix(a=nil) @suffix = a if a; @suffix end
|
|
102
|
-
def Familia.default_suffix=(a) @suffix = a end
|
|
103
|
-
def Familia.index(r=nil) @index = r if r; @index end
|
|
104
|
-
def Familia.index=(r) @index = r; r end
|
|
105
|
-
def Familia.split(r) r.split(Familia.delim) end
|
|
106
|
-
def Familia.key *args
|
|
107
|
-
el = args.flatten.compact
|
|
108
|
-
el.unshift @apiversion unless @apiversion.nil?
|
|
109
|
-
el.join(Familia.delim)
|
|
110
|
-
end
|
|
111
|
-
def Familia.info *msg
|
|
112
|
-
STDERR.puts *msg
|
|
113
|
-
end
|
|
114
|
-
def Familia.ld *msg
|
|
115
|
-
info *msg if debug?
|
|
116
|
-
end
|
|
117
|
-
def Familia.trace label, redis_client, ident, context=nil
|
|
118
|
-
return unless Familia.debug?
|
|
119
|
-
info "%s (%d:%s): %s" % [label, Thread.current.object_id, redis_client.object_id, ident]
|
|
120
|
-
info " +-> %s" % [context].flatten[0..3].join("\n ") if context
|
|
121
|
-
end
|
|
122
|
-
def Familia.destroy keyname, uri=nil
|
|
123
|
-
Familia.redis(uri).del keyname
|
|
124
|
-
end
|
|
125
|
-
def Familia.get_any keyname, uri=nil
|
|
126
|
-
type = Familia.redis(uri).type keyname
|
|
127
|
-
case type
|
|
128
|
-
when "string"
|
|
129
|
-
Familia.redis(uri).get keyname
|
|
130
|
-
when "list"
|
|
131
|
-
Familia.redis(uri).lrange(keyname, 0, -1) || []
|
|
132
|
-
when "set"
|
|
133
|
-
Familia.redis(uri).smembers( keyname) || []
|
|
134
|
-
when "zset"
|
|
135
|
-
Familia.redis(uri).zrange(keyname, 0, -1) || []
|
|
136
|
-
when "hash"
|
|
137
|
-
Familia.redis(uri).hgetall(keyname) || {}
|
|
138
|
-
else
|
|
139
|
-
nil
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
def Familia.exists?(keyname, uri=nil)
|
|
143
|
-
Familia.redis(uri).exists keyname
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def self.included(obj)
|
|
147
|
-
obj.send :include, Familia::InstanceMethods
|
|
148
|
-
obj.send :include, Gibbler::Complex
|
|
149
|
-
obj.extend Familia::ClassMethods
|
|
150
|
-
Familia.classes << obj
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
module InstanceMethods
|
|
154
|
-
def redisinfo
|
|
155
|
-
info = {
|
|
156
|
-
:db => self.class.db || 0,
|
|
157
|
-
#:uri => redisuri,
|
|
158
|
-
:key => key,
|
|
159
|
-
:type => redistype,
|
|
160
|
-
:ttl => realttl
|
|
161
|
-
}
|
|
162
|
-
end
|
|
163
|
-
def exists?
|
|
164
|
-
Familia.redis(self.class.uri).exists self.key
|
|
165
|
-
end
|
|
166
|
-
def destroy!(suffix=nil)
|
|
167
|
-
ret = Familia.redis(self.class.uri).del self.key(suffix)
|
|
168
|
-
Familia.trace :DELETED, Familia.redis(self.class.uri), "#{key(suffix)}: #{ret}", caller.first
|
|
169
|
-
ret
|
|
170
|
-
end
|
|
171
|
-
def allkeys
|
|
172
|
-
keynames = [key]
|
|
173
|
-
self.class.suffixes.each do |sfx|
|
|
174
|
-
keynames << key(sfx)
|
|
175
|
-
end
|
|
176
|
-
keynames
|
|
177
|
-
end
|
|
178
|
-
def key(suffix=nil)
|
|
179
|
-
raise EmptyIndex, self.class if index.nil? || index.empty?
|
|
180
|
-
if suffix.nil?
|
|
181
|
-
suffix = self.class.suffix.kind_of?(Proc) ?
|
|
182
|
-
self.class.suffix.call(self) :
|
|
183
|
-
self.class.suffix
|
|
184
|
-
end
|
|
185
|
-
self.class.key self.index, suffix
|
|
186
|
-
end
|
|
187
|
-
def save(force=false)
|
|
188
|
-
Familia.trace :SAVE, Familia.redis(self.class.uri), redisuri, caller.first
|
|
189
|
-
## Don't save if there are no changes
|
|
190
|
-
##return false unless force || self.gibbled? || self.gibbler_cache.nil?
|
|
191
|
-
preprocess if respond_to?(:preprocess)
|
|
192
|
-
self.update_time if self.respond_to?(:update_time)
|
|
193
|
-
ret = Familia.redis(self.class.uri).set self.key, self.to_json
|
|
194
|
-
unless self.ttl.nil? || self.ttl <= 0
|
|
195
|
-
Familia.trace :SET_EXPIRE, Familia.redis(self.class.uri), "#{self.key} to #{self.ttl}"
|
|
196
|
-
expire(self.ttl)
|
|
197
|
-
end
|
|
198
|
-
ret == "OK"
|
|
199
|
-
end
|
|
200
|
-
def index
|
|
201
|
-
if @index.nil?
|
|
202
|
-
self.class.index.kind_of?(Proc) ?
|
|
203
|
-
self.class.index.call(self) :
|
|
204
|
-
self.send(self.class.index)
|
|
205
|
-
else
|
|
206
|
-
@index
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
def index=(i)
|
|
210
|
-
@index = i
|
|
211
|
-
end
|
|
212
|
-
def expire(ttl=nil)
|
|
213
|
-
ttl ||= self.class.ttl
|
|
214
|
-
Familia.redis(self.class.uri).expire self.key, ttl.to_i
|
|
215
|
-
end
|
|
216
|
-
def realttl
|
|
217
|
-
Familia.redis(self.class.uri).ttl self.key
|
|
218
|
-
end
|
|
219
|
-
def ttl=(v)
|
|
220
|
-
@ttl = v.to_i
|
|
221
|
-
end
|
|
222
|
-
def ttl
|
|
223
|
-
@ttl || self.class.ttl
|
|
224
|
-
end
|
|
225
|
-
def raw(suffix=nil)
|
|
226
|
-
suffix ||= :object
|
|
227
|
-
Familia.redis(self.class.uri).get key(suffix)
|
|
228
|
-
end
|
|
229
|
-
def redisuri(suffix=nil)
|
|
230
|
-
u = URI.parse self.class.uri.to_s
|
|
231
|
-
u.db ||= self.class.db.to_s
|
|
232
|
-
u.key = key(suffix)
|
|
233
|
-
u
|
|
234
|
-
end
|
|
235
|
-
def redistype(suffix=nil)
|
|
236
|
-
Familia.redis(self.class.uri).type key(suffix)
|
|
237
|
-
end
|
|
238
|
-
# Finds the shortest available unique key (lower limit of 6)
|
|
239
|
-
def shortid
|
|
240
|
-
len = 6
|
|
241
|
-
loop do
|
|
242
|
-
begin
|
|
243
|
-
self.class.expand(@id.shorten(len))
|
|
244
|
-
break
|
|
245
|
-
rescue Familia::NonUniqueKey
|
|
246
|
-
len += 1
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
@id.shorten(len)
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
65
|
|
|
253
66
|
module ClassMethods
|
|
254
|
-
def
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
super(obj)
|
|
258
|
-
end
|
|
259
|
-
def from_redisdump dump
|
|
260
|
-
dump
|
|
261
|
-
end
|
|
262
|
-
def float
|
|
263
|
-
Proc.new do |v|
|
|
264
|
-
v.nil? ? 0 : v.to_f
|
|
265
|
-
end
|
|
266
|
-
end
|
|
267
|
-
def extended(obj)
|
|
268
|
-
obj.db = self.db
|
|
269
|
-
Familia.classes << obj
|
|
270
|
-
end
|
|
271
|
-
def db(db=nil)
|
|
272
|
-
@db = db if db;
|
|
273
|
-
@db
|
|
274
|
-
end
|
|
275
|
-
def db=(db) @db = db end
|
|
276
|
-
def host(host=nil) @host = host if host; @host end
|
|
277
|
-
def host=(host) @host = host end
|
|
278
|
-
def port(port=nil) @port = port if port; @port end
|
|
279
|
-
def port=(port) @port = port end
|
|
280
|
-
def uri=(uri)
|
|
281
|
-
uri = URI.parse uri if String === uri
|
|
282
|
-
@uri = uri
|
|
283
|
-
end
|
|
284
|
-
def uri(uri=nil)
|
|
285
|
-
self.uri = uri unless uri.to_s.empty?
|
|
286
|
-
return @uri if @uri
|
|
287
|
-
@uri = URI.parse Familia.uri.to_s
|
|
288
|
-
@uri.db = @db if @db
|
|
289
|
-
Familia.connect @uri #unless Familia.connected?(@uri)
|
|
290
|
-
@uri
|
|
291
|
-
end
|
|
292
|
-
def redis
|
|
293
|
-
Familia.redis(self.uri)
|
|
294
|
-
end
|
|
295
|
-
def flushdb
|
|
296
|
-
Familia.info "flushing #{uri}"
|
|
297
|
-
redis.flushdb
|
|
298
|
-
end
|
|
299
|
-
def keys(suffix=nil)
|
|
300
|
-
self.redis.keys(key('*',suffix)) || []
|
|
301
|
-
end
|
|
302
|
-
def all(suffix=nil)
|
|
303
|
-
# objects that could not be parsed will be nil
|
|
304
|
-
keys(suffix).collect { |k| from_key(k) }.compact
|
|
305
|
-
end
|
|
306
|
-
def any?(filter='*')
|
|
307
|
-
size(filter) > 0
|
|
308
|
-
end
|
|
309
|
-
def size(filter='*')
|
|
310
|
-
self.redis.keys(key(filter)).compact.size
|
|
311
|
-
end
|
|
312
|
-
def suffix=(val)
|
|
313
|
-
suffixes << (@suffix = val)
|
|
314
|
-
val
|
|
315
|
-
end
|
|
316
|
-
def suffix(a=nil, &blk)
|
|
317
|
-
@suffix = a || blk if a || !blk.nil?
|
|
318
|
-
val = @suffix || Familia.default_suffix
|
|
319
|
-
self.suffixes << val
|
|
320
|
-
val
|
|
321
|
-
end
|
|
322
|
-
def prefix=(a) @prefix = a end
|
|
323
|
-
def prefix(a=nil) @prefix = a if a; @prefix || self.name.downcase end
|
|
324
|
-
def index(i=nil, &blk)
|
|
325
|
-
@index = i || blk if i || !blk.nil?
|
|
326
|
-
@index ||= Familia.index
|
|
327
|
-
@index
|
|
328
|
-
end
|
|
329
|
-
def suffixes
|
|
330
|
-
@suffixes ||= []
|
|
331
|
-
@suffixes.uniq!
|
|
332
|
-
@suffixes
|
|
333
|
-
end
|
|
334
|
-
def child(opts={})
|
|
335
|
-
name, klass = opts.keys.first, opts.values.first
|
|
336
|
-
childs[name] = klass
|
|
337
|
-
self.suffixes << name
|
|
338
|
-
define_method :"#{name}_key" do
|
|
339
|
-
key(name)
|
|
340
|
-
end
|
|
341
|
-
define_method :"#{name}?" do
|
|
342
|
-
#Familia.ld "EXISTS? #{self.class.childs[name]} #{key(name)}"
|
|
343
|
-
self.class.childs[name].redis.exists key(name)
|
|
344
|
-
end
|
|
345
|
-
define_method :"clear_#{name}" do
|
|
346
|
-
self.class.redis.del key(name)
|
|
347
|
-
end
|
|
348
|
-
define_method :"#{name}" do
|
|
349
|
-
#Familia.ld "#{self.class} Return child #{key(name)}"
|
|
350
|
-
content = self.class.redis.get key(name)
|
|
351
|
-
#Familia.ld "TODO: don't reload #{self.class} every time"
|
|
352
|
-
if !content.nil?
|
|
353
|
-
begin
|
|
354
|
-
content = self.class.childs[name].from_json content if klass != String && content.is_a?(String)
|
|
355
|
-
rescue => ex
|
|
356
|
-
msg = "Error loading #{name} for #{key}: #{ex.message}"
|
|
357
|
-
Familia.info "#{msg}: #{$/}#{content}"
|
|
358
|
-
raise Familia::Problem, msg
|
|
359
|
-
end
|
|
360
|
-
else
|
|
361
|
-
content = self.class.childs[name].new
|
|
362
|
-
end
|
|
363
|
-
content
|
|
364
|
-
end
|
|
365
|
-
define_method :"#{name}=" do |content|
|
|
366
|
-
Familia.ld "#{self.class} Modify child #{key(name)} (#{content.class})"
|
|
367
|
-
self.class.redis.set key(name), (content.is_a?(String) ? content : content.to_json)
|
|
368
|
-
content
|
|
369
|
-
end
|
|
370
|
-
end
|
|
371
|
-
def child?(name)
|
|
372
|
-
childs.has_key? :"#{name}"
|
|
373
|
-
end
|
|
374
|
-
def childs
|
|
375
|
-
@childs ||= {}
|
|
376
|
-
@childs
|
|
377
|
-
end
|
|
378
|
-
def hashes
|
|
379
|
-
@hashes ||= {}
|
|
380
|
-
@hashes
|
|
381
|
-
end
|
|
382
|
-
def hash?(name)
|
|
383
|
-
@hashes.has_key? :"#{name}"
|
|
384
|
-
end
|
|
385
|
-
def hash(opts={}, &blk)
|
|
386
|
-
if Hash === opts
|
|
387
|
-
name, klass = opts.keys.first, opts.values.first
|
|
388
|
-
else
|
|
389
|
-
name, klass = opts, nil
|
|
390
|
-
end
|
|
391
|
-
hashes[name] = klass
|
|
392
|
-
self.suffixes << name
|
|
393
|
-
if name.to_s.match(/s$/i)
|
|
394
|
-
name_plural = name.to_s.clone
|
|
395
|
-
name_singular = name.to_s[0..-2]
|
|
67
|
+
def uri(db=nil)
|
|
68
|
+
if db.nil?
|
|
69
|
+
@uri
|
|
396
70
|
else
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
define_method :"#{name}_key" do
|
|
401
|
-
key(name)
|
|
402
|
-
end
|
|
403
|
-
define_method :"has_#{name}?" do |field|
|
|
404
|
-
self.class.redis.hexists key(name), field
|
|
405
|
-
end
|
|
406
|
-
define_method :"#{name}_size" do
|
|
407
|
-
self.class.redis.hlen key(name)
|
|
408
|
-
end
|
|
409
|
-
define_method :"clear_#{name}" do
|
|
410
|
-
self.class.redis.del key(name)
|
|
411
|
-
end
|
|
412
|
-
define_method :"#{name}_keys" do
|
|
413
|
-
self.class.redis.hkeys key(name)
|
|
414
|
-
end
|
|
415
|
-
define_method :"set_#{name}" do |hash|
|
|
416
|
-
self.class.redis.hmset key(name), *hash.to_a.flatten
|
|
417
|
-
end
|
|
418
|
-
define_method :"get_#{name}" do |*fields|
|
|
419
|
-
ret = self.class.redis.hmget key(name), *fields
|
|
420
|
-
ret.collect! { |obj| blk.call(obj) } if blk
|
|
421
|
-
fields.size == 1 ? ret.first : ret
|
|
422
|
-
end
|
|
423
|
-
define_method :"del_#{name}" do |field|
|
|
424
|
-
self.class.redis.hdel key(name), field
|
|
425
|
-
end
|
|
426
|
-
end
|
|
427
|
-
|
|
428
|
-
def sets
|
|
429
|
-
@sets ||= {}
|
|
430
|
-
@sets
|
|
431
|
-
end
|
|
432
|
-
def set?(name)
|
|
433
|
-
sets.has_key? :"#{name}"
|
|
434
|
-
end
|
|
435
|
-
def set(opts={})
|
|
436
|
-
if Hash === opts
|
|
437
|
-
name, klass = opts.keys.first, opts.values.first
|
|
438
|
-
else
|
|
439
|
-
name, klass = opts, nil
|
|
440
|
-
end
|
|
441
|
-
sets[name] = klass
|
|
442
|
-
self.suffixes << name
|
|
443
|
-
if name.to_s.match(/s$/i)
|
|
444
|
-
name_plural = name.to_s.clone
|
|
445
|
-
name_singular = name.to_s[0..-2]
|
|
446
|
-
else
|
|
447
|
-
name_plural = "#{name}s"
|
|
448
|
-
name_singular = name
|
|
449
|
-
end
|
|
450
|
-
define_method :"#{name}_key" do
|
|
451
|
-
key(name)
|
|
452
|
-
end
|
|
453
|
-
define_method :"#{name}_size" do
|
|
454
|
-
self.class.redis.scard key(name)
|
|
455
|
-
end
|
|
456
|
-
# Make the value stored at KEY identical to the given list
|
|
457
|
-
define_method :"#{name}_sync" do |*latest|
|
|
458
|
-
latest = latest.flatten.compact
|
|
459
|
-
# Do nothing if we're given an empty Array.
|
|
460
|
-
# Otherwise this would clear all current values
|
|
461
|
-
if latest.empty?
|
|
462
|
-
false
|
|
463
|
-
else
|
|
464
|
-
# Convert to a list of index values if we got the actual objects
|
|
465
|
-
latest = latest.collect { |obj| obj.index } if klass === latest.first
|
|
466
|
-
current = send("#{name_plural}raw")
|
|
467
|
-
added = latest-current
|
|
468
|
-
removed = current-latest
|
|
469
|
-
#Familia.info "#{self.index}: adding: #{added}"
|
|
470
|
-
added.each { |v| self.send("add_#{name_singular}", v) }
|
|
471
|
-
#Familia.info "#{self.index}: removing: #{removed}"
|
|
472
|
-
removed.each { |v| self.send("remove_#{name_singular}", v) }
|
|
473
|
-
true
|
|
474
|
-
end
|
|
475
|
-
end
|
|
476
|
-
define_method :"#{name}?" do
|
|
477
|
-
self.send(:"#{name}_size") > 0
|
|
478
|
-
end
|
|
479
|
-
define_method :"clear_#{name}" do
|
|
480
|
-
self.class.redis.del key(name)
|
|
481
|
-
end
|
|
482
|
-
define_method :"add_#{name_singular}" do |obj|
|
|
483
|
-
objid = klass === obj ? obj.index : obj
|
|
484
|
-
#Familia.ld "#{self.class} Add #{objid} to #{key(name)}"
|
|
485
|
-
self.class.redis.sadd key(name), objid
|
|
486
|
-
end
|
|
487
|
-
define_method :"remove_#{name_singular}" do |obj|
|
|
488
|
-
objid = klass === obj ? obj.index : obj
|
|
489
|
-
#Familia.ld "#{self.class} Remove #{objid} from #{key(name)}"
|
|
490
|
-
self.class.redis.srem key(name), objid
|
|
491
|
-
end
|
|
492
|
-
# Example:
|
|
493
|
-
#
|
|
494
|
-
# list = obj.response_time 10, :score => (now-12.hours)..now
|
|
495
|
-
#
|
|
496
|
-
define_method :"#{name_plural}raw" do
|
|
497
|
-
list = self.class.redis.smembers(key(name)) || []
|
|
498
|
-
end
|
|
499
|
-
define_method :"#{name_plural}" do
|
|
500
|
-
list = send("#{name_plural}raw")
|
|
501
|
-
if klass.nil?
|
|
502
|
-
list
|
|
503
|
-
elsif klass.include?(Familia)
|
|
504
|
-
klass.multiget(*list)
|
|
505
|
-
elsif klass.respond_to?(:from_json)
|
|
506
|
-
list.collect { |str| klass.from_json(str) }
|
|
507
|
-
else
|
|
508
|
-
list
|
|
509
|
-
end
|
|
510
|
-
end
|
|
511
|
-
end
|
|
512
|
-
def zsets
|
|
513
|
-
@zsets ||= {}
|
|
514
|
-
@zsets
|
|
515
|
-
end
|
|
516
|
-
def zset?(name)
|
|
517
|
-
zsets.has_key? :"#{name}"
|
|
518
|
-
end
|
|
519
|
-
def zset(opts={})
|
|
520
|
-
if Hash === opts
|
|
521
|
-
name, klass = opts.keys.first, opts.values.first
|
|
522
|
-
else
|
|
523
|
-
name, klass = opts, nil
|
|
524
|
-
end
|
|
525
|
-
zsets[name] = klass
|
|
526
|
-
self.suffixes << name
|
|
527
|
-
if name.to_s.match(/s$/i)
|
|
528
|
-
name_plural = name.to_s.clone
|
|
529
|
-
name_singular = name.to_s[0..-2]
|
|
530
|
-
else
|
|
531
|
-
name_plural = "#{name}s"
|
|
532
|
-
name_singular = name
|
|
533
|
-
end
|
|
534
|
-
define_method :"#{name}_key" do
|
|
535
|
-
key(name)
|
|
536
|
-
end
|
|
537
|
-
define_method :"#{name}_size" do
|
|
538
|
-
self.class.redis.zcard key(name)
|
|
539
|
-
end
|
|
540
|
-
define_method :"clear_#{name}" do
|
|
541
|
-
self.class.redis.del key(name)
|
|
542
|
-
end
|
|
543
|
-
define_method :"#{name}?" do
|
|
544
|
-
self.send(:"#{name}_size") > 0
|
|
545
|
-
end
|
|
546
|
-
define_method :"add_#{name_singular}" do |score,obj|
|
|
547
|
-
objid = klass === obj ? obj.index : obj
|
|
548
|
-
#Familia.ld "#{self.class} Add #{objid} (#{score}) to #{key(name)}"
|
|
549
|
-
self.class.redis.zadd key(name), score, objid
|
|
550
|
-
end
|
|
551
|
-
#p "Adding: #{self}#remove_#{name_singular}"
|
|
552
|
-
define_method :"remove_#{name_singular}" do |obj|
|
|
553
|
-
objid = klass === obj ? obj.index : obj
|
|
554
|
-
#Familia.ld "#{self.class} Remove #{objid} from #{key(name)}"
|
|
555
|
-
self.class.redis.zrem key(name), objid
|
|
556
|
-
end
|
|
557
|
-
# Example:
|
|
558
|
-
#
|
|
559
|
-
# list = obj.response_time 10, :score => (now-12.hours)..now
|
|
560
|
-
#
|
|
561
|
-
define_method :"#{name_plural}raw" do |*args|
|
|
562
|
-
|
|
563
|
-
count = args.first-1 unless args.empty?
|
|
564
|
-
count ||= -1
|
|
565
|
-
|
|
566
|
-
opts = args[1] || {}
|
|
567
|
-
if Range === opts[:score]
|
|
568
|
-
lo, hi = opts[:score].first, opts[:score].last
|
|
569
|
-
list = self.class.redis.zrangebyscore(key(name), lo, hi, :limit => [0, count]) || []
|
|
570
|
-
else
|
|
571
|
-
list = self.class.redis.zrange(key(name), 0, count) || []
|
|
572
|
-
end
|
|
573
|
-
end
|
|
574
|
-
define_method :"#{name_plural}" do |*args|
|
|
575
|
-
list = send("#{name_plural}raw", *args)
|
|
576
|
-
if klass.nil?
|
|
577
|
-
list
|
|
578
|
-
elsif klass.include?(Familia)
|
|
579
|
-
klass.multiget(*list)
|
|
580
|
-
elsif klass.respond_to?(:from_json)
|
|
581
|
-
list.collect { |str| klass.from_json(str) }
|
|
582
|
-
else
|
|
583
|
-
list
|
|
584
|
-
end
|
|
585
|
-
end
|
|
586
|
-
define_method :"#{name_plural}rev" do |*args|
|
|
587
|
-
|
|
588
|
-
count = args.first-1 unless args.empty?
|
|
589
|
-
count ||= -1
|
|
590
|
-
|
|
591
|
-
opts = args[1] || {}
|
|
592
|
-
if Range === opts[:score]
|
|
593
|
-
lo, hi = opts[:score].first, opts[:score].last
|
|
594
|
-
list = self.class.redis.zrangebyscore(key(name), lo, hi, :limit => [0, count]) || []
|
|
595
|
-
else
|
|
596
|
-
list = self.class.redis.zrevrange(key(name), 0, count) || []
|
|
597
|
-
end
|
|
598
|
-
if klass.nil?
|
|
599
|
-
list
|
|
600
|
-
elsif klass.include?(Familia)
|
|
601
|
-
klass.multiget(*list)
|
|
602
|
-
elsif klass.respond_to?(:from_json)
|
|
603
|
-
list.collect { |str| klass.from_json(str) }
|
|
604
|
-
else
|
|
605
|
-
list
|
|
606
|
-
end
|
|
607
|
-
end
|
|
608
|
-
end
|
|
609
|
-
|
|
610
|
-
def list(opts={})
|
|
611
|
-
if Hash === opts
|
|
612
|
-
name, klass = opts.keys.first, opts.values.first
|
|
613
|
-
else
|
|
614
|
-
name, klass = opts, nil
|
|
615
|
-
end
|
|
616
|
-
lists[name] = klass
|
|
617
|
-
self.suffixes << name
|
|
618
|
-
if name.to_s.match(/s$/i)
|
|
619
|
-
name_plural = name.to_s.clone
|
|
620
|
-
name_singular = name.to_s[0..-2]
|
|
621
|
-
else
|
|
622
|
-
name_plural = "#{name}s"
|
|
623
|
-
name_singular = name
|
|
624
|
-
end
|
|
625
|
-
define_method :"#{name}_key" do
|
|
626
|
-
key(name)
|
|
627
|
-
end
|
|
628
|
-
define_method :"#{name}_size" do
|
|
629
|
-
self.class.redis.llen key(name)
|
|
630
|
-
end
|
|
631
|
-
define_method :"clear_#{name}" do
|
|
632
|
-
self.class.redis.del key(name)
|
|
633
|
-
end
|
|
634
|
-
# Make the value stored at KEY identical to the given list
|
|
635
|
-
define_method :"#{name}_sync" do |*latest|
|
|
636
|
-
latest = latest.flatten.compact
|
|
637
|
-
# Do nothing if we're given an empty Array.
|
|
638
|
-
# Otherwise this would clear all current values
|
|
639
|
-
if latest.empty?
|
|
640
|
-
false
|
|
641
|
-
else
|
|
642
|
-
# Convert to a list of index values if we got the actual objects
|
|
643
|
-
latest = latest.collect { |obj| obj.index } if klass === latest.first
|
|
644
|
-
current = send("#{name_plural}raw")
|
|
645
|
-
added = latest-current
|
|
646
|
-
removed = current-latest
|
|
647
|
-
#Familia.info "#{self.index}: adding: #{added}"
|
|
648
|
-
added.each { |v| self.send("add_#{name_singular}", v) }
|
|
649
|
-
#Familia.info "#{self.index}: removing: #{removed}"
|
|
650
|
-
removed.each { |v| self.send("remove_#{name_singular}", v) }
|
|
651
|
-
true
|
|
652
|
-
end
|
|
653
|
-
end
|
|
654
|
-
define_method :"#{name}?" do
|
|
655
|
-
self.send(:"#{name}_size") > 0
|
|
656
|
-
end
|
|
657
|
-
define_method :"add_#{name_singular}" do |obj|
|
|
658
|
-
objid = klass === obj ? obj.index : obj
|
|
659
|
-
#Familia.ld "#{self.class} Add #{objid} to #{key(name)}"
|
|
660
|
-
ret = self.class.redis.rpush key(name), objid
|
|
661
|
-
# TODO : copy to zset and set
|
|
662
|
-
#unless self.ttl.nil? || self.ttl <= 0
|
|
663
|
-
# Familia.trace :SET_EXPIRE, Familia.redis(self.class.uri), "#{self.key} to #{self.ttl}"
|
|
664
|
-
# Familia.redis(self.class.uri).expire key(name), self.ttl
|
|
665
|
-
#end
|
|
666
|
-
ret
|
|
667
|
-
end
|
|
668
|
-
define_method :"remove_#{name_singular}" do |obj|
|
|
669
|
-
objid = klass === obj ? obj.index : obj
|
|
670
|
-
#Familia.ld "#{self.class} Remove #{objid} from #{key(name)}"
|
|
671
|
-
self.class.redis.lrem key(name), 0, objid
|
|
672
|
-
end
|
|
673
|
-
define_method :"#{name_plural}raw" do |*args|
|
|
674
|
-
count = args.first-1 unless args.empty?
|
|
675
|
-
count ||= -1
|
|
676
|
-
list = self.class.redis.lrange(key(name), 0, count) || []
|
|
677
|
-
end
|
|
678
|
-
define_method :"#{name_plural}" do |*args|
|
|
679
|
-
list = send("#{name_plural}raw", *args)
|
|
680
|
-
if klass.nil?
|
|
681
|
-
list
|
|
682
|
-
elsif klass.include?(Familia)
|
|
683
|
-
klass.multiget(*list)
|
|
684
|
-
elsif klass.respond_to?(:from_json)
|
|
685
|
-
list.collect { |str| klass.from_json(str) }
|
|
686
|
-
else
|
|
687
|
-
list
|
|
688
|
-
end
|
|
689
|
-
end
|
|
690
|
-
end
|
|
691
|
-
def lists
|
|
692
|
-
@lists ||= {}
|
|
693
|
-
@lists
|
|
694
|
-
end
|
|
695
|
-
def list?(name)
|
|
696
|
-
lists.has_key? :"#{name}"
|
|
697
|
-
end
|
|
698
|
-
def multiget(*ids)
|
|
699
|
-
ids = rawmultiget(*ids)
|
|
700
|
-
ids.compact.collect { |json| self.from_json(json) }.compact
|
|
701
|
-
end
|
|
702
|
-
def rawmultiget(*ids)
|
|
703
|
-
ids.collect! { |objid| self.key(objid) }
|
|
704
|
-
return [] if ids.compact.empty?
|
|
705
|
-
Familia.trace :MULTIGET, self.redis, "#{ids.size}: #{ids}", caller
|
|
706
|
-
ids = self.redis.mget *ids
|
|
707
|
-
end
|
|
708
|
-
def ttl(sec=nil)
|
|
709
|
-
@ttl = sec.to_i unless sec.nil?
|
|
710
|
-
@ttl
|
|
711
|
-
end
|
|
712
|
-
def create(*args)
|
|
713
|
-
me = new(*args)
|
|
714
|
-
raise "#{self} exists: #{me.to_json}" if me.exists?
|
|
715
|
-
me.save
|
|
716
|
-
me
|
|
717
|
-
end
|
|
718
|
-
def load_or_create(id)
|
|
719
|
-
if exists?(id)
|
|
720
|
-
from_redis(id)
|
|
721
|
-
else
|
|
722
|
-
me = new id
|
|
723
|
-
me.save
|
|
724
|
-
me
|
|
71
|
+
uri = URI.parse @uri.to_s
|
|
72
|
+
uri.db = db
|
|
73
|
+
uri
|
|
725
74
|
end
|
|
726
75
|
end
|
|
727
|
-
def
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
raise Familia::Problem, "Null key" if akey.nil? || akey.empty?
|
|
731
|
-
run_json = Familia.redis(self.uri).get akey
|
|
732
|
-
if run_json.nil? || run_json.empty?
|
|
733
|
-
Familia.info "No content @ #{akey}"
|
|
734
|
-
return
|
|
735
|
-
end
|
|
736
|
-
begin
|
|
737
|
-
#run_json.force_encoding("ASCII-8BIT") if RUBY_VERSION >= "1.9"
|
|
738
|
-
obj = self.from_json(run_json)
|
|
739
|
-
obj
|
|
740
|
-
rescue => ex
|
|
741
|
-
STDOUT.puts "Non-fatal error parsing JSON for #{akey}: #{ex.message}"
|
|
742
|
-
STDOUT.puts run_json
|
|
743
|
-
STDERR.puts ex.backtrace
|
|
744
|
-
nil
|
|
745
|
-
end
|
|
746
|
-
end
|
|
747
|
-
def from_redis(objid, suffix=nil)
|
|
748
|
-
objid &&= objid.to_s
|
|
749
|
-
return nil if objid.nil? || objid.empty?
|
|
750
|
-
this_key = key(objid, suffix)
|
|
751
|
-
#Familia.ld "Reading key: #{this_key}"
|
|
752
|
-
me = from_key(this_key)
|
|
753
|
-
me.gibbler # prime the gibbler cache (used to check for changes)
|
|
754
|
-
me
|
|
755
|
-
end
|
|
756
|
-
def exists?(objid, suffix=nil)
|
|
757
|
-
objid &&= objid.to_s
|
|
758
|
-
return false if objid.nil? || objid.empty?
|
|
759
|
-
ret = Familia.redis(self.uri).exists key(objid, suffix)
|
|
760
|
-
Familia.trace :EXISTS, Familia.redis(self.uri), "#{key(objid)} #{ret}", caller.first
|
|
761
|
-
ret
|
|
762
|
-
end
|
|
763
|
-
def destroy!(runid, suffix=nil)
|
|
764
|
-
ret = Familia.redis(self.uri).del key(runid, suffix)
|
|
765
|
-
Familia.trace :DELETED, Familia.redis(self.uri), "#{key(runid)}: #{ret}", caller.first
|
|
766
|
-
ret
|
|
767
|
-
end
|
|
768
|
-
def find(suffix='*')
|
|
769
|
-
list = Familia.redis(self.uri).keys(key('*', suffix)) || []
|
|
770
|
-
end
|
|
771
|
-
def key(runid, suffix=nil)
|
|
772
|
-
suffix ||= self.suffix
|
|
773
|
-
runid ||= ''
|
|
774
|
-
runid &&= runid.to_s
|
|
775
|
-
str = Familia.key(prefix, runid, suffix)
|
|
776
|
-
str
|
|
777
|
-
end
|
|
778
|
-
def expand(short_key, suffix=nil)
|
|
779
|
-
suffix ||= self.suffix
|
|
780
|
-
expand_key = Familia.key(self.prefix, "#{short_key}*", suffix)
|
|
781
|
-
Familia.trace :EXPAND, Familia.redis(self.uri), expand_key, caller.first
|
|
782
|
-
list = Familia.redis(self.uri).keys expand_key
|
|
783
|
-
case list.size
|
|
784
|
-
when 0
|
|
785
|
-
nil
|
|
786
|
-
when 1
|
|
787
|
-
matches = list.first.match(/\A#{Familia.key(prefix)}\:(.+?)\:#{suffix}/) || []
|
|
788
|
-
matches[1]
|
|
76
|
+
def apiversion(r=nil, &blk)
|
|
77
|
+
if blk.nil?
|
|
78
|
+
@apiversion = r if r;
|
|
789
79
|
else
|
|
790
|
-
|
|
791
|
-
|
|
80
|
+
tmp = @apiversion
|
|
81
|
+
@apiversion = r
|
|
82
|
+
blk.call
|
|
83
|
+
@apiversion = tmp
|
|
84
|
+
end
|
|
85
|
+
@apiversion
|
|
86
|
+
end
|
|
87
|
+
def conf=(conf={})
|
|
88
|
+
@conf = conf
|
|
89
|
+
@uri = Redis.uri(@conf).freeze
|
|
90
|
+
connect @uri
|
|
91
|
+
@conf
|
|
92
|
+
end
|
|
93
|
+
def redis(uri=nil)
|
|
94
|
+
uri &&= URI.parse uri if String === uri
|
|
95
|
+
uri ||= Familia.uri
|
|
96
|
+
connect(uri) unless @clients[uri.serverid]
|
|
97
|
+
#STDERR.puts "REDIS: #{uri} #{caller[0]}" if Familia.debug?
|
|
98
|
+
@clients[uri.serverid]
|
|
99
|
+
end
|
|
100
|
+
def connect(uri=nil, local_conf={})
|
|
101
|
+
uri &&= URI.parse uri if String === uri
|
|
102
|
+
uri ||= Familia.uri
|
|
103
|
+
local_conf[:thread_safe] = true
|
|
104
|
+
client = Redis.new local_conf.merge(uri.conf)
|
|
105
|
+
Familia.trace :CONNECT, client, uri.conf.inspect, caller.first
|
|
106
|
+
@clients[uri.serverid] = client
|
|
107
|
+
end
|
|
108
|
+
def reconnect_all!
|
|
109
|
+
Familia.classes.each do |klass|
|
|
110
|
+
klass.redis.client.reconnect
|
|
111
|
+
Familia.info "#{klass} ping: #{klass.redis.ping}" if debug?
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
def connected?(uri=nil)
|
|
115
|
+
uri &&= URI.parse uri if String === uri
|
|
116
|
+
@clients.has_key?(uri.serverid)
|
|
117
|
+
end
|
|
118
|
+
def default_suffix(a=nil) @suffix = a if a; @suffix end
|
|
119
|
+
def default_suffix=(a) @suffix = a end
|
|
120
|
+
def index(r=nil) @index = r if r; @index end
|
|
121
|
+
def index=(r) @index = r; r end
|
|
122
|
+
def split(r) r.split(Familia.delim) end
|
|
123
|
+
def rediskey *args
|
|
124
|
+
el = args.flatten.compact
|
|
125
|
+
el.unshift @apiversion unless @apiversion.nil?
|
|
126
|
+
el.join(Familia.delim)
|
|
127
|
+
end
|
|
128
|
+
def destroy keyname, uri=nil
|
|
129
|
+
Familia.redis(uri).del keyname
|
|
130
|
+
end
|
|
131
|
+
def exists? keyname, uri=nil
|
|
132
|
+
Familia.redis(uri).exists keyname
|
|
792
133
|
end
|
|
793
134
|
end
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
# field :name
|
|
801
|
-
# include Familia::Stamps
|
|
802
|
-
# end
|
|
803
|
-
#
|
|
804
|
-
module Stamps
|
|
805
|
-
def self.included(obj)
|
|
806
|
-
obj.module_eval do
|
|
807
|
-
field :created => Integer
|
|
808
|
-
field :updated => Integer
|
|
809
|
-
def init_stamps
|
|
810
|
-
now = Time.now.utc.to_i
|
|
811
|
-
@created ||= now
|
|
812
|
-
@updated ||= now
|
|
813
|
-
end
|
|
814
|
-
def created
|
|
815
|
-
@created ||= Time.now.utc.to_i
|
|
816
|
-
end
|
|
817
|
-
def updated
|
|
818
|
-
@updated ||= Time.now.utc.to_i
|
|
819
|
-
end
|
|
820
|
-
def created_age
|
|
821
|
-
Time.now.utc.to_i-created
|
|
822
|
-
end
|
|
823
|
-
def updated_age
|
|
824
|
-
Time.now.utc.to_i-updated
|
|
825
|
-
end
|
|
826
|
-
def update_time
|
|
827
|
-
@updated = Time.now.utc.to_i
|
|
828
|
-
end
|
|
829
|
-
def update_time!
|
|
830
|
-
update_time
|
|
831
|
-
save if respond_to? :save
|
|
832
|
-
@updated
|
|
833
|
-
end
|
|
834
|
-
end
|
|
835
|
-
end
|
|
836
|
-
end
|
|
837
|
-
module Status
|
|
838
|
-
def self.included(obj)
|
|
839
|
-
obj.module_eval do
|
|
840
|
-
field :status
|
|
841
|
-
field :message
|
|
842
|
-
def failure?() status? 'failure' end
|
|
843
|
-
def success?() status? 'success' end
|
|
844
|
-
def pending?() status? 'pending' end
|
|
845
|
-
def expired?() status? 'expired' end
|
|
846
|
-
def disabled?() status? 'disabled' end
|
|
847
|
-
def failure!(msg=nil) status! 'failure', msg end
|
|
848
|
-
def success!(msg=nil) status! 'success', msg end
|
|
849
|
-
def pending!(msg=nil) status! 'pending', msg end
|
|
850
|
-
def expired!(msg=nil) status! 'expired', msg end
|
|
851
|
-
def disabled!(msg=nil) status! 'disabled', msg end
|
|
852
|
-
private
|
|
853
|
-
def status?(s)
|
|
854
|
-
status.to_s == s.to_s
|
|
855
|
-
end
|
|
856
|
-
def status!(s, msg=nil)
|
|
857
|
-
@updated = Time.now.utc.to_f
|
|
858
|
-
@status, @message = s, msg
|
|
859
|
-
save if respond_to? :save
|
|
860
|
-
end
|
|
861
|
-
end
|
|
862
|
-
end
|
|
135
|
+
|
|
136
|
+
def self.included(obj)
|
|
137
|
+
obj.send :include, Familia::Object::InstanceMethods
|
|
138
|
+
obj.send :include, Gibbler::Complex
|
|
139
|
+
obj.extend Familia::Object::ClassMethods
|
|
140
|
+
Familia.classes << obj
|
|
863
141
|
end
|
|
864
|
-
|
|
142
|
+
|
|
143
|
+
require 'familia/object'
|
|
144
|
+
require 'familia/helpers'
|
|
865
145
|
|
|
866
|
-
|
|
867
|
-
module Tools
|
|
868
|
-
extend self
|
|
869
|
-
def move_keys(filter, source_uri, target_uri, &each_key)
|
|
870
|
-
if target_uri == source_uri
|
|
871
|
-
raise "Source and target are the same (#{target_uri})"
|
|
872
|
-
end
|
|
873
|
-
Familia.connect target_uri
|
|
874
|
-
source_keys = Familia.redis(source_uri).keys(filter)
|
|
875
|
-
puts "Moving #{source_keys.size} keys from #{source_uri} to #{target_uri} (filter: #{filter})"
|
|
876
|
-
source_keys.each_with_index do |key,idx|
|
|
877
|
-
type = Familia.redis(source_uri).type key
|
|
878
|
-
ttl = Familia.redis(source_uri).ttl key
|
|
879
|
-
if source_uri.host == target_uri.host && source_uri.port == target_uri.port
|
|
880
|
-
Familia.redis(source_uri).move key, target_uri.db
|
|
881
|
-
else
|
|
882
|
-
case type
|
|
883
|
-
when "string"
|
|
884
|
-
value = Familia.redis(source_uri).get key
|
|
885
|
-
when "list"
|
|
886
|
-
value = Familia.redis(source_uri).lrange key, 0, -1
|
|
887
|
-
when "set"
|
|
888
|
-
value = Familia.redis(source_uri).smembers key
|
|
889
|
-
else
|
|
890
|
-
raise Familia::Problem, "unknown key type: #{type}"
|
|
891
|
-
end
|
|
892
|
-
raise "Not implemented"
|
|
893
|
-
end
|
|
894
|
-
each_key.call(idx, type, key, ttl) unless each_key.nil?
|
|
895
|
-
end
|
|
896
|
-
end
|
|
897
|
-
# Use the return value from each_key as the new key name
|
|
898
|
-
def rename(filter, source_uri, target_uri=nil, &each_key)
|
|
899
|
-
target_uri ||= source_uri
|
|
900
|
-
move_keys filter, source_uri, target_uri if source_uri != target_uri
|
|
901
|
-
source_keys = Familia.redis(source_uri).keys(filter)
|
|
902
|
-
puts "Renaming #{source_keys.size} keys from #{source_uri} (filter: #{filter})"
|
|
903
|
-
source_keys.each_with_index do |key,idx|
|
|
904
|
-
Familia.trace :RENAME1, Familia.redis(source_uri), "#{key}", ''
|
|
905
|
-
type = Familia.redis(source_uri).type key
|
|
906
|
-
ttl = Familia.redis(source_uri).ttl key
|
|
907
|
-
newkey = each_key.call(idx, type, key, ttl) unless each_key.nil?
|
|
908
|
-
Familia.trace :RENAME2, Familia.redis(source_uri), "#{key} -> #{newkey}", caller[0]
|
|
909
|
-
ret = Familia.redis(source_uri).renamenx key, newkey
|
|
910
|
-
end
|
|
911
|
-
end
|
|
912
|
-
end
|
|
146
|
+
extend Familia::ClassMethods
|
|
913
147
|
end
|
|
914
148
|
|
|
915
149
|
|
|
@@ -924,12 +158,3 @@ module Familia
|
|
|
924
158
|
end
|
|
925
159
|
end
|
|
926
160
|
end
|
|
927
|
-
|
|
928
|
-
class Symbol
|
|
929
|
-
unless method_defined?(:to_proc)
|
|
930
|
-
def to_proc
|
|
931
|
-
proc { |obj, *args| obj.send(self, *args) }
|
|
932
|
-
end
|
|
933
|
-
end
|
|
934
|
-
end
|
|
935
|
-
|