familia 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +11 -0
- data/VERSION.yml +1 -1
- data/familia.gemspec +2 -2
- data/lib/familia/object.rb +61 -30
- data/lib/familia/redisobject.rb +165 -33
- data/lib/familia/test_helpers.rb +1 -3
- data/lib/familia.rb +21 -20
- data/try/10_familia_try.rb +8 -8
- data/try/21_redis_object_zset_try.rb +15 -15
- data/try/22_redis_object_set_try.rb +9 -9
- data/try/23_redis_object_list_try.rb +11 -11
- data/try/24_redis_object_string_try.rb +52 -5
- data/try/25_redis_object_hash_try.rb +12 -12
- data/try/30_familia_object_try.rb +34 -22
- metadata +4 -4
data/CHANGES.txt
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
FAMILIA, CHANGES
|
2
2
|
|
3
|
+
#### 0.6.1 (2010-12-18) ###############################
|
4
|
+
|
5
|
+
* CHANGE: Default initialize method calls initialize_redis_objects before super
|
6
|
+
* CHANGE: Familia::String: lazy-set default value
|
7
|
+
* ADDED: Familia.index can accept an Array of field names
|
8
|
+
* ADDED: Support for using redis objects directly
|
9
|
+
* ADDED RedisObject.ttl, RedisObject.db
|
10
|
+
* ADDED: Familia classes maintain a set of instances (by index) which is updated
|
11
|
+
automatically anytime an instance is saved or destroyed.
|
12
|
+
|
13
|
+
|
3
14
|
#### 0.6.0 (2010-12-10) ###############################
|
4
15
|
|
5
16
|
NOTE: Mucho refactoring. 0.6 syntax is not compatible with previous versions.
|
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.1"
|
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-18}
|
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 = [
|
data/lib/familia/object.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
|
3
|
-
module Familia
|
3
|
+
module Familia
|
4
4
|
require 'familia/redisobject'
|
5
|
-
|
6
5
|
|
7
6
|
# Auto-extended into a class that includes Familia
|
8
7
|
module ClassMethods
|
9
8
|
|
10
|
-
RedisObject.
|
9
|
+
Familia::RedisObject.registration.each_pair do |kind, klass|
|
11
10
|
# e.g.
|
12
11
|
#
|
13
12
|
# list(name, klass, opts)
|
@@ -51,11 +50,19 @@ module Familia::Object
|
|
51
50
|
|
52
51
|
def inherited(obj)
|
53
52
|
obj.db = self.db
|
53
|
+
obj.ttl = self.ttl
|
54
|
+
obj.uri = self.uri
|
55
|
+
obj.parent = self
|
56
|
+
obj.class_set :instances
|
54
57
|
Familia.classes << obj
|
55
58
|
super(obj)
|
56
59
|
end
|
57
60
|
def extended(obj)
|
58
61
|
obj.db = self.db
|
62
|
+
obj.ttl = self.ttl
|
63
|
+
obj.uri = self.uri
|
64
|
+
obj.parent = self
|
65
|
+
obj.class_set :instances
|
59
66
|
Familia.classes << obj
|
60
67
|
end
|
61
68
|
|
@@ -81,6 +88,7 @@ module Familia::Object
|
|
81
88
|
name = name.to_s.to_sym
|
82
89
|
opts ||= {}
|
83
90
|
opts[:suffix] ||= nil
|
91
|
+
opts[:parent] ||= self
|
84
92
|
# TODO: investigate metaclass.redis_objects
|
85
93
|
class_redis_objects[name] = OpenStruct.new
|
86
94
|
class_redis_objects[name].name = name
|
@@ -92,7 +100,7 @@ module Familia::Object
|
|
92
100
|
metaclass.send :define_method, "#{name}=" do |v|
|
93
101
|
send(name).replace v
|
94
102
|
end
|
95
|
-
redis_object = klass.new name,
|
103
|
+
redis_object = klass.new name, opts
|
96
104
|
redis_object.freeze
|
97
105
|
self.instance_variable_set("@#{name}", redis_object)
|
98
106
|
class_redis_objects[name]
|
@@ -101,9 +109,14 @@ module Familia::Object
|
|
101
109
|
def from_redisdump dump
|
102
110
|
dump # todo
|
103
111
|
end
|
104
|
-
|
105
|
-
|
106
|
-
@
|
112
|
+
attr_accessor :parent
|
113
|
+
def ttl v=nil
|
114
|
+
@ttl = v unless v.nil?
|
115
|
+
@ttl || (parent ? parent.ttl : nil)
|
116
|
+
end
|
117
|
+
def db v=nil
|
118
|
+
@db = v unless v.nil?
|
119
|
+
@db || (parent ? parent.db : nil)
|
107
120
|
end
|
108
121
|
def db=(db) @db = db end
|
109
122
|
def host(host=nil) @host = host if host; @host end
|
@@ -120,7 +133,7 @@ module Familia::Object
|
|
120
133
|
@uri = URI.parse Familia.uri.to_s
|
121
134
|
@uri.db = @db if @db
|
122
135
|
Familia.connect @uri #unless Familia.connected?(@uri)
|
123
|
-
@uri
|
136
|
+
@uri || (parent ? parent.uri : Familia.uri)
|
124
137
|
end
|
125
138
|
def redis
|
126
139
|
Familia.redis(self.uri)
|
@@ -154,10 +167,6 @@ module Familia::Object
|
|
154
167
|
@index ||= Familia.index
|
155
168
|
@index
|
156
169
|
end
|
157
|
-
def ttl(sec=nil)
|
158
|
-
@ttl = sec.to_i unless sec.nil?
|
159
|
-
@ttl
|
160
|
-
end
|
161
170
|
def suffixes
|
162
171
|
redis_objects.keys.uniq
|
163
172
|
end
|
@@ -278,8 +287,8 @@ module Familia::Object
|
|
278
287
|
# including Familia. In that case, the replacement
|
279
288
|
# must call initialize_redis_objects.
|
280
289
|
def initialize *args
|
281
|
-
super # call Storable#initialize or equivalent
|
282
290
|
initialize_redis_objects
|
291
|
+
super # call Storable#initialize or equivalent
|
283
292
|
end
|
284
293
|
|
285
294
|
# This needs to be called in the initialize method of
|
@@ -303,7 +312,9 @@ module Familia::Object
|
|
303
312
|
# See RedisObject.install_redis_object
|
304
313
|
self.class.redis_objects.each_pair do |name, redis_object_definition|
|
305
314
|
klass, opts = redis_object_definition.klass, redis_object_definition.opts
|
306
|
-
|
315
|
+
opts ||= {}
|
316
|
+
opts[:parent] ||= self
|
317
|
+
redis_object = klass.new name, opts
|
307
318
|
redis_object.freeze
|
308
319
|
self.instance_variable_set "@#{name}", redis_object
|
309
320
|
end
|
@@ -324,13 +335,6 @@ module Familia::Object
|
|
324
335
|
def exists?
|
325
336
|
Familia.redis(self.class.uri).exists rediskey
|
326
337
|
end
|
327
|
-
def destroy!
|
328
|
-
ret = Familia.redis(self.class.uri).del rediskey
|
329
|
-
if Familia.debug?
|
330
|
-
Familia.trace :DELETED, Familia.redis(self.class.uri), "#{rediskey}: #{ret}", caller.first
|
331
|
-
end
|
332
|
-
ret
|
333
|
-
end
|
334
338
|
|
335
339
|
#def rediskeys
|
336
340
|
# self.class.redis_objects.each do |redis_object_definition|
|
@@ -347,7 +351,7 @@ module Familia::Object
|
|
347
351
|
keynames
|
348
352
|
end
|
349
353
|
def rediskey(suffix=nil)
|
350
|
-
raise Familia::
|
354
|
+
raise Familia::NoIndex, self.class if index.to_s.empty?
|
351
355
|
if suffix.nil?
|
352
356
|
suffix = self.class.suffix.kind_of?(Proc) ?
|
353
357
|
self.class.suffix.call(self) :
|
@@ -356,20 +360,47 @@ module Familia::Object
|
|
356
360
|
self.class.rediskey self.index, suffix
|
357
361
|
end
|
358
362
|
def save
|
359
|
-
Familia.trace :SAVE, Familia.redis(self.class.uri), redisuri, caller.first
|
363
|
+
#Familia.trace :SAVE, Familia.redis(self.class.uri), redisuri, caller.first
|
360
364
|
preprocess if respond_to?(:preprocess)
|
361
365
|
self.update_time if self.respond_to?(:update_time)
|
362
|
-
ret = self.object.
|
363
|
-
|
366
|
+
ret = self.object.set self # object is a name reserved by Familia
|
367
|
+
unless ret.nil?
|
368
|
+
self.class.instances.add index # use this set instead of Klass.keys
|
369
|
+
self.object.update_expiration self.ttl # does nothing unless if not specified
|
370
|
+
end
|
364
371
|
true
|
365
372
|
end
|
373
|
+
def destroy!
|
374
|
+
ret = self.object.delete
|
375
|
+
if Familia.debug?
|
376
|
+
Familia.trace :DELETED, Familia.redis(self.class.uri), "#{rediskey}: #{ret}", caller.first
|
377
|
+
end
|
378
|
+
self.class.instances.rem index if ret > 0
|
379
|
+
ret
|
380
|
+
end
|
366
381
|
def index
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
382
|
+
case self.class.index
|
383
|
+
when Proc
|
384
|
+
self.class.index.call(self)
|
385
|
+
when Array
|
386
|
+
parts = self.class.index.collect { |meth|
|
387
|
+
unless self.respond_to? meth
|
388
|
+
raise NoIndex, "No such method: `#{meth}' for #{self.class}"
|
389
|
+
end
|
390
|
+
self.send(meth)
|
391
|
+
}
|
392
|
+
parts.join Familia.delim
|
393
|
+
when Symbol, String
|
394
|
+
if self.class.redis_object?(self.class.index.to_sym)
|
395
|
+
raise Familia::NoIndex, "Cannot use a RedisObject as an index"
|
396
|
+
else
|
397
|
+
unless self.respond_to? self.class.index
|
398
|
+
raise NoIndex, "No such method: `#{self.class.index}' for #{self.class}"
|
399
|
+
end
|
400
|
+
self.send self.class.index
|
401
|
+
end
|
371
402
|
else
|
372
|
-
|
403
|
+
raise Familia::NoIndex, self
|
373
404
|
end
|
374
405
|
end
|
375
406
|
def index=(i)
|
data/lib/familia/redisobject.rb
CHANGED
@@ -1,32 +1,98 @@
|
|
1
1
|
|
2
|
-
module Familia
|
2
|
+
module Familia
|
3
3
|
|
4
4
|
class RedisObject
|
5
|
+
@registration = {}
|
6
|
+
@classes = []
|
5
7
|
|
6
|
-
|
8
|
+
# To be called inside every class that inherits RedisObject
|
9
|
+
# +meth+ becomes the base for the class and instances methods
|
10
|
+
# that are created for the given +klass+ (e.g. Obj.list)
|
11
|
+
def RedisObject.register klass, meth
|
12
|
+
registration[meth] = klass
|
13
|
+
end
|
14
|
+
|
15
|
+
def RedisObject.registration
|
16
|
+
@registration
|
17
|
+
end
|
18
|
+
|
19
|
+
def RedisObject.classes
|
20
|
+
@classes
|
21
|
+
end
|
22
|
+
|
23
|
+
@db, @ttl = nil, nil
|
7
24
|
class << self
|
8
|
-
|
9
|
-
|
10
|
-
def
|
11
|
-
|
25
|
+
attr_accessor :parent
|
26
|
+
attr_writer :ttl, :classes, :db, :uri
|
27
|
+
def ttl v=nil
|
28
|
+
@ttl = v unless v.nil?
|
29
|
+
@ttl || (parent ? parent.ttl : nil)
|
30
|
+
end
|
31
|
+
def db v=nil
|
32
|
+
@db = v unless v.nil?
|
33
|
+
@db || (parent ? parent.db : nil)
|
34
|
+
end
|
35
|
+
def uri v=nil
|
36
|
+
@uri = v unless v.nil?
|
37
|
+
@uri || (parent ? parent.uri : Familia.uri)
|
38
|
+
end
|
39
|
+
def inherited(obj)
|
40
|
+
obj.db = self.db
|
41
|
+
obj.ttl = self.ttl
|
42
|
+
obj.uri = self.uri
|
43
|
+
obj.parent = self
|
44
|
+
RedisObject.classes << obj
|
45
|
+
super(obj)
|
12
46
|
end
|
13
47
|
end
|
14
48
|
|
15
49
|
attr_reader :name, :parent
|
16
|
-
|
17
|
-
|
18
|
-
|
50
|
+
attr_accessor :redis
|
51
|
+
|
52
|
+
# +name+: If parent is set, this will be used as the suffix
|
53
|
+
# for rediskey. Otherwise this becomes the value of the key.
|
54
|
+
# If this is an Array, the elements will be joined.
|
55
|
+
#
|
56
|
+
# Options:
|
57
|
+
#
|
58
|
+
# :parent: The Familia object that this redis object belongs
|
59
|
+
# to. This can be a class that includes Familia or an instance.
|
60
|
+
#
|
61
|
+
# :ttl => the time to live in seconds. When not nil, this will
|
62
|
+
# set the redis expire for this key whenever #save is called.
|
63
|
+
# You can also call it explicitly via #update_expiration.
|
64
|
+
#
|
65
|
+
# :default => the default value (String-only)
|
66
|
+
#
|
67
|
+
# :class => A class that responds to Familia.load_method and
|
68
|
+
# Familia.dump_method. These will be used when loading and
|
69
|
+
# saving data from/to redis to unmarshal/marshal the class.
|
70
|
+
#
|
71
|
+
# :db => the redis database to use (ignored if :redis is used).
|
72
|
+
#
|
73
|
+
# :redis => an instance of Redis.
|
74
|
+
#
|
75
|
+
# Uses the redis connection of the parent or the value of
|
76
|
+
# opts[:redis] or Familia.redis (in that order).
|
77
|
+
def initialize name, opts={}
|
78
|
+
@name, @opts = name, opts
|
79
|
+
@name = @name.join(Familia.delim) if Array === @name
|
80
|
+
@opts[:ttl] ||= self.class.ttl
|
81
|
+
@opts[:db] ||= self.class.db
|
82
|
+
@parent = @opts.delete(:parent)
|
83
|
+
@redis = parent.redis if parent?
|
84
|
+
@redis ||= @opts.delete(:redis) || Familia.redis(@opts[:db])
|
19
85
|
init if respond_to? :init
|
20
86
|
end
|
21
87
|
|
22
88
|
# returns a redis key based on the parent
|
23
89
|
# object so it will include the proper index.
|
24
90
|
def rediskey
|
25
|
-
parent.rediskey(name)
|
91
|
+
parent? ? parent.rediskey(name) : Familia.rediskey(name)
|
26
92
|
end
|
27
93
|
|
28
|
-
def
|
29
|
-
parent.
|
94
|
+
def parent?
|
95
|
+
Class === parent || parent.kind_of?(Familia)
|
30
96
|
end
|
31
97
|
|
32
98
|
def update_expiration(ttl=nil)
|
@@ -39,27 +105,32 @@ module Familia::Object
|
|
39
105
|
def move db
|
40
106
|
redis.move rediskey, db
|
41
107
|
end
|
42
|
-
|
43
|
-
def destroy!
|
44
|
-
clear
|
45
|
-
# TODO: delete redis objects for this instance
|
46
|
-
end
|
47
|
-
|
108
|
+
|
48
109
|
# TODO: rename, renamenx
|
49
110
|
|
50
111
|
def type
|
51
112
|
redis.type rediskey
|
52
113
|
end
|
53
114
|
|
54
|
-
def
|
115
|
+
def delete
|
55
116
|
redis.del rediskey
|
56
117
|
end
|
57
|
-
alias_method :
|
118
|
+
alias_method :clear, :delete
|
119
|
+
alias_method :del, :delete
|
120
|
+
|
121
|
+
#def destroy!
|
122
|
+
# clear
|
123
|
+
# # TODO: delete redis objects for this instance
|
124
|
+
#end
|
58
125
|
|
59
126
|
def exists?
|
60
127
|
!size.zero?
|
61
128
|
end
|
62
129
|
|
130
|
+
def ttl
|
131
|
+
redis.ttl rediskey
|
132
|
+
end
|
133
|
+
|
63
134
|
def expire sec
|
64
135
|
redis.expire rediskey, sec.to_i
|
65
136
|
end
|
@@ -187,7 +258,7 @@ module Familia::Object
|
|
187
258
|
# end
|
188
259
|
#end
|
189
260
|
|
190
|
-
Familia::
|
261
|
+
Familia::RedisObject.register self, :list
|
191
262
|
end
|
192
263
|
|
193
264
|
class Set < RedisObject
|
@@ -197,6 +268,10 @@ module Familia::Object
|
|
197
268
|
end
|
198
269
|
alias_method :length, :size
|
199
270
|
|
271
|
+
def empty?
|
272
|
+
size == 0
|
273
|
+
end
|
274
|
+
|
200
275
|
def << v
|
201
276
|
redis.sadd rediskey, to_redis(v)
|
202
277
|
self
|
@@ -207,6 +282,7 @@ module Familia::Object
|
|
207
282
|
# TODO: handle @opts[:marshal]
|
208
283
|
redis.smembers rediskey
|
209
284
|
end
|
285
|
+
alias_method :all, :members
|
210
286
|
alias_method :to_a, :members
|
211
287
|
|
212
288
|
def member? v
|
@@ -217,11 +293,25 @@ module Familia::Object
|
|
217
293
|
def delete v
|
218
294
|
redis.srem rediskey, to_redis(v)
|
219
295
|
end
|
296
|
+
alias_method :rem, :delete
|
297
|
+
alias_method :del, :delete
|
220
298
|
|
221
299
|
def intersection *setkeys
|
222
300
|
# TODO
|
223
301
|
end
|
224
302
|
|
303
|
+
def pop
|
304
|
+
redis.spop rediskey
|
305
|
+
end
|
306
|
+
|
307
|
+
def move dstkey, v
|
308
|
+
redis.smove rediskey, dstkey, v
|
309
|
+
end
|
310
|
+
|
311
|
+
def random
|
312
|
+
redis.srandmember rediskey
|
313
|
+
end
|
314
|
+
|
225
315
|
## Make the value stored at KEY identical to the given list
|
226
316
|
#define_method :"#{name}_sync" do |*latest|
|
227
317
|
# latest = latest.flatten.compact
|
@@ -243,7 +333,7 @@ module Familia::Object
|
|
243
333
|
# end
|
244
334
|
#end
|
245
335
|
|
246
|
-
Familia::
|
336
|
+
Familia::RedisObject.register self, :set
|
247
337
|
end
|
248
338
|
|
249
339
|
class SortedSet < RedisObject
|
@@ -351,7 +441,7 @@ module Familia::Object
|
|
351
441
|
at(-1)
|
352
442
|
end
|
353
443
|
|
354
|
-
Familia::
|
444
|
+
Familia::RedisObject.register self, :zset
|
355
445
|
end
|
356
446
|
|
357
447
|
class HashKey < RedisObject
|
@@ -429,13 +519,12 @@ module Familia::Object
|
|
429
519
|
redis.hmget rediskey, *names.flatten.compact
|
430
520
|
end
|
431
521
|
|
432
|
-
Familia::
|
522
|
+
Familia::RedisObject.register self, :hash
|
433
523
|
end
|
434
524
|
|
435
525
|
class String < RedisObject
|
436
526
|
|
437
527
|
def init
|
438
|
-
redis.setnx rediskey, @opts[:default] if @opts[:default]
|
439
528
|
end
|
440
529
|
|
441
530
|
def size
|
@@ -444,6 +533,7 @@ module Familia::Object
|
|
444
533
|
alias_method :length, :size
|
445
534
|
|
446
535
|
def value
|
536
|
+
redis.setnx rediskey, @opts[:default] if @opts[:default]
|
447
537
|
redis.get rediskey
|
448
538
|
end
|
449
539
|
alias_method :get, :value
|
@@ -452,24 +542,66 @@ module Familia::Object
|
|
452
542
|
value.to_s # value can return nil which to_s should not
|
453
543
|
end
|
454
544
|
|
545
|
+
def to_i
|
546
|
+
value.to_i
|
547
|
+
end
|
548
|
+
|
455
549
|
def value= v
|
456
550
|
redis.set rediskey, to_redis(v)
|
457
|
-
to_redis(v)
|
458
551
|
end
|
459
552
|
alias_method :replace, :value=
|
460
553
|
alias_method :set, :value=
|
461
554
|
|
555
|
+
def increment
|
556
|
+
redis.incr rediskey
|
557
|
+
end
|
558
|
+
alias_method :incr, :increment
|
559
|
+
|
560
|
+
def incrementby int
|
561
|
+
redis.incrby rediskey, int.to_i
|
562
|
+
end
|
563
|
+
alias_method :incrby, :incrementby
|
564
|
+
|
565
|
+
def decrement
|
566
|
+
redis.decr rediskey
|
567
|
+
end
|
568
|
+
alias_method :decr, :decrement
|
569
|
+
|
570
|
+
def decrementby int
|
571
|
+
redis.decrby rediskey, int.to_i
|
572
|
+
end
|
573
|
+
alias_method :decrby, :decrementby
|
574
|
+
|
575
|
+
def append v
|
576
|
+
redis.append rediskey, v
|
577
|
+
end
|
578
|
+
alias_method :<<, :append
|
579
|
+
|
580
|
+
def getbit offset
|
581
|
+
redis.getbit rediskey, offset
|
582
|
+
end
|
583
|
+
|
584
|
+
def setbit offset, v
|
585
|
+
redis.setbit rediskey, offset, v
|
586
|
+
end
|
587
|
+
|
588
|
+
def getrange spoint, epoint
|
589
|
+
redis.getrange rediskey, spoint, epoint
|
590
|
+
end
|
591
|
+
|
592
|
+
def setrange offset, v
|
593
|
+
redis.setrange rediskey, offset, v
|
594
|
+
end
|
595
|
+
|
596
|
+
def getset v
|
597
|
+
redis.getset rediskey, v
|
598
|
+
end
|
599
|
+
|
462
600
|
def nil?
|
463
601
|
value.nil?
|
464
602
|
end
|
465
603
|
|
466
|
-
Familia::
|
467
|
-
end
|
468
|
-
|
469
|
-
|
470
|
-
class Counter < RedisObject
|
471
|
-
|
472
|
-
#Familia::Object::RedisObject.register :counter, self
|
604
|
+
Familia::RedisObject.register self, :string
|
473
605
|
end
|
474
606
|
|
475
607
|
end
|
data/lib/familia/test_helpers.rb
CHANGED
data/lib/familia.rb
CHANGED
@@ -48,22 +48,6 @@ module Familia
|
|
48
48
|
info "%s (%d:%s): %s" % [label, Thread.current.object_id, redis_client.object_id, ident]
|
49
49
|
info " +-> %s" % [context].flatten[0..3].join("\n ") if context
|
50
50
|
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class Problem < RuntimeError; end
|
54
|
-
class EmptyIndex < Problem; end
|
55
|
-
class NonUniqueKey < Problem; end
|
56
|
-
class NotConnected < Problem
|
57
|
-
attr_reader :uri
|
58
|
-
def initialize uri
|
59
|
-
@uri = uri
|
60
|
-
end
|
61
|
-
def message
|
62
|
-
"No client for #{uri.serverid}"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
module ClassMethods
|
67
51
|
def uri(db=nil)
|
68
52
|
if db.nil?
|
69
53
|
@uri
|
@@ -91,7 +75,11 @@ module Familia
|
|
91
75
|
@conf
|
92
76
|
end
|
93
77
|
def redis(uri=nil)
|
94
|
-
|
78
|
+
if Integer === uri
|
79
|
+
uri = Familia.uri(uri)
|
80
|
+
else
|
81
|
+
uri &&= URI.parse uri if String === uri
|
82
|
+
end
|
95
83
|
uri ||= Familia.uri
|
96
84
|
connect(uri) unless @clients[uri.serverid]
|
97
85
|
#STDERR.puts "REDIS: #{uri} #{caller[0]}" if Familia.debug?
|
@@ -133,17 +121,30 @@ module Familia
|
|
133
121
|
end
|
134
122
|
end
|
135
123
|
|
124
|
+
class Problem < RuntimeError; end
|
125
|
+
class NoIndex < Problem; end
|
126
|
+
class NonUniqueKey < Problem; end
|
127
|
+
class NotConnected < Problem
|
128
|
+
attr_reader :uri
|
129
|
+
def initialize uri
|
130
|
+
@uri = uri
|
131
|
+
end
|
132
|
+
def message
|
133
|
+
"No client for #{uri.serverid}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
136
137
|
def self.included(obj)
|
137
|
-
obj.send :include, Familia::
|
138
|
+
obj.send :include, Familia::InstanceMethods
|
138
139
|
obj.send :include, Gibbler::Complex
|
139
|
-
obj.extend Familia::
|
140
|
+
obj.extend Familia::ClassMethods
|
141
|
+
obj.class_set :instances
|
140
142
|
Familia.classes << obj
|
141
143
|
end
|
142
144
|
|
143
145
|
require 'familia/object'
|
144
146
|
require 'familia/helpers'
|
145
147
|
|
146
|
-
extend Familia::ClassMethods
|
147
148
|
end
|
148
149
|
|
149
150
|
|
data/try/10_familia_try.rb
CHANGED
@@ -2,20 +2,20 @@ require 'familia'
|
|
2
2
|
require 'familia/test_helpers'
|
3
3
|
|
4
4
|
## Has all redis objects
|
5
|
-
redis_objects = Familia::
|
5
|
+
redis_objects = Familia::RedisObject.registration.keys
|
6
6
|
redis_objects.collect(&:to_s).sort
|
7
7
|
#=> ["hash", "list", "set", "string", "zset"]
|
8
8
|
|
9
|
-
## Familia
|
10
|
-
Familia::
|
9
|
+
## Familia created class methods for redis object class
|
10
|
+
Familia::ClassMethods.public_method_defined? :list?
|
11
11
|
#=> true
|
12
12
|
|
13
|
-
## Familia
|
14
|
-
Familia::
|
13
|
+
## Familia created class methods for redis object class
|
14
|
+
Familia::ClassMethods.public_method_defined? :list
|
15
15
|
#=> true
|
16
16
|
|
17
|
-
## Familia
|
18
|
-
Familia::
|
17
|
+
## Familia created class methods for redis object class
|
18
|
+
Familia::ClassMethods.public_method_defined? :lists
|
19
19
|
#=> true
|
20
20
|
|
21
21
|
## A Familia object knows its redis objects
|
@@ -33,4 +33,4 @@ Bone.list? :owners
|
|
33
33
|
## A Familia object can get a specific redis object def
|
34
34
|
definition = Bone.list :owners
|
35
35
|
definition.klass
|
36
|
-
#=> Familia::
|
36
|
+
#=> Familia::List
|
@@ -3,7 +3,7 @@ require 'familia/test_helpers'
|
|
3
3
|
|
4
4
|
@a = Bone.new 'atoken', 'akey'
|
5
5
|
|
6
|
-
## Familia::
|
6
|
+
## Familia::SortedSet#add
|
7
7
|
@a.metrics.add 2, :metric2
|
8
8
|
@a.metrics.add 4, :metric4
|
9
9
|
@a.metrics.add 0, :metric0
|
@@ -11,56 +11,56 @@ require 'familia/test_helpers'
|
|
11
11
|
@a.metrics.add 3, :metric3
|
12
12
|
#=> true
|
13
13
|
|
14
|
-
## Familia::
|
14
|
+
## Familia::SortedSet#members
|
15
15
|
@a.metrics.members
|
16
16
|
#=> ['metric0', 'metric1', 'metric2', 'metric3', 'metric4']
|
17
17
|
|
18
|
-
## Familia::
|
18
|
+
## Familia::SortedSet#members
|
19
19
|
@a.metrics.membersrev
|
20
20
|
#=> ['metric4', 'metric3', 'metric2', 'metric1', 'metric0']
|
21
21
|
|
22
|
-
## Familia::
|
22
|
+
## Familia::SortedSet#rank
|
23
23
|
@a.metrics.rank 'metric1'
|
24
24
|
#=> 1
|
25
25
|
|
26
|
-
## Familia::
|
26
|
+
## Familia::SortedSet#revrank
|
27
27
|
@a.metrics.revrank 'metric1'
|
28
28
|
#=> 3
|
29
29
|
|
30
|
-
## Familia::
|
30
|
+
## Familia::SortedSet#rangebyscore
|
31
31
|
@a.metrics.rangebyscore 1, 3
|
32
32
|
#=> ['metric1', 'metric2', 'metric3']
|
33
33
|
|
34
|
-
## Familia::
|
34
|
+
## Familia::SortedSet#rangebyscore with a limit
|
35
35
|
@a.metrics.rangebyscore 1, 3, :limit => [0, 2]
|
36
36
|
#=> ['metric1', 'metric2']
|
37
37
|
|
38
|
-
## Familia::
|
38
|
+
## Familia::SortedSet#increment
|
39
39
|
@a.metrics.increment 'metric4', 100
|
40
40
|
#=> 104
|
41
41
|
|
42
|
-
## Familia::
|
42
|
+
## Familia::SortedSet#decrement
|
43
43
|
@a.metrics.decrement 'metric4', 50
|
44
44
|
#=> 54
|
45
45
|
|
46
|
-
## Familia::
|
46
|
+
## Familia::SortedSet#score
|
47
47
|
@a.metrics.score 'metric4'
|
48
48
|
#=> 54
|
49
49
|
|
50
|
-
## Familia::
|
50
|
+
## Familia::SortedSet#remrangebyscore
|
51
51
|
@a.metrics.remrangebyscore 3, 100
|
52
52
|
#=> 2
|
53
53
|
|
54
|
-
## Familia::
|
54
|
+
## Familia::SortedSet#members after remrangebyscore
|
55
55
|
@a.metrics.members
|
56
56
|
#=> ['metric0', 'metric1', 'metric2']
|
57
57
|
|
58
|
-
## Familia::
|
58
|
+
## Familia::SortedSet#remrangebyrank
|
59
59
|
@a.metrics.remrangebyrank 0, 1
|
60
60
|
#=> 2
|
61
61
|
|
62
|
-
## Familia::
|
62
|
+
## Familia::SortedSet#members after remrangebyrank
|
63
63
|
@a.metrics.members
|
64
64
|
#=> ['metric2']
|
65
65
|
|
66
|
-
@a.metrics.
|
66
|
+
@a.metrics.clear
|
@@ -4,31 +4,31 @@ require 'familia/test_helpers'
|
|
4
4
|
|
5
5
|
@a = Bone.new 'atoken', 'akey'
|
6
6
|
|
7
|
-
## Familia::
|
7
|
+
## Familia::Set#add
|
8
8
|
ret = @a.tags.add :a
|
9
9
|
ret.class
|
10
|
-
#=> Familia::
|
10
|
+
#=> Familia::Set
|
11
11
|
|
12
|
-
## Familia::
|
12
|
+
## Familia::Set#<<
|
13
13
|
ret = @a.tags << :a << :b << :c
|
14
14
|
ret.class
|
15
|
-
#=> Familia::
|
15
|
+
#=> Familia::Set
|
16
16
|
|
17
|
-
## Familia::
|
17
|
+
## Familia::Set#members
|
18
18
|
@a.tags.members.sort
|
19
19
|
#=> ['a', 'b', 'c']
|
20
20
|
|
21
|
-
## Familia::
|
21
|
+
## Familia::Set#member? knows when a value exists
|
22
22
|
@a.tags.member? :a
|
23
23
|
#=> true
|
24
24
|
|
25
|
-
## Familia::
|
25
|
+
## Familia::Set#member? knows when a value doesn't exist
|
26
26
|
@a.tags.member? :x
|
27
27
|
#=> false
|
28
28
|
|
29
|
-
## Familia::
|
29
|
+
## Familia::Set#member? knows when a value doesn't exist
|
30
30
|
@a.tags.size
|
31
31
|
#=> 3
|
32
32
|
|
33
33
|
|
34
|
-
@a.tags.
|
34
|
+
@a.tags.clear
|
@@ -4,38 +4,38 @@ require 'familia/test_helpers'
|
|
4
4
|
|
5
5
|
@a = Bone.new 'atoken', 'akey'
|
6
6
|
|
7
|
-
## Familia::
|
7
|
+
## Familia::List#push
|
8
8
|
ret = @a.owners.push :value1
|
9
9
|
ret.class
|
10
|
-
#=> Familia::
|
10
|
+
#=> Familia::List
|
11
11
|
|
12
|
-
## Familia::
|
12
|
+
## Familia::List#<<
|
13
13
|
ret = @a.owners << :value2 << :value3 << :value4
|
14
14
|
ret.class
|
15
|
-
#=> Familia::
|
15
|
+
#=> Familia::List
|
16
16
|
|
17
|
-
## Familia::
|
17
|
+
## Familia::List#pop
|
18
18
|
@a.owners.pop
|
19
19
|
#=> 'value4'
|
20
20
|
|
21
|
-
## Familia::
|
21
|
+
## Familia::List#first
|
22
22
|
@a.owners.first
|
23
23
|
#=> 'value1'
|
24
24
|
|
25
|
-
## Familia::
|
25
|
+
## Familia::List#last
|
26
26
|
@a.owners.last
|
27
27
|
#=> 'value3'
|
28
28
|
|
29
|
-
## Familia::
|
29
|
+
## Familia::List#to_a
|
30
30
|
@a.owners.to_a
|
31
31
|
#=> ['value1','value2','value3']
|
32
32
|
|
33
|
-
## Familia::
|
33
|
+
## Familia::List#delete
|
34
34
|
@a.owners.delete 'value3'
|
35
35
|
#=> 1
|
36
36
|
|
37
|
-
## Familia::
|
37
|
+
## Familia::List#size
|
38
38
|
@a.owners.size
|
39
39
|
#=> 2
|
40
40
|
|
41
|
-
@a.owners.
|
41
|
+
@a.owners.clear
|
@@ -1,19 +1,66 @@
|
|
1
1
|
require 'familia'
|
2
2
|
require 'familia/test_helpers'
|
3
3
|
|
4
|
+
Familia.apiversion = 'v1'
|
4
5
|
|
5
|
-
@a = Bone.new '
|
6
|
+
@a = Bone.new 'atoken2', 'akey'
|
6
7
|
|
7
|
-
##
|
8
|
+
## Bone#rediskey
|
9
|
+
@a.rediskey
|
10
|
+
#=> 'v1:bone:atoken2:akey:object'
|
11
|
+
|
12
|
+
## Familia::String#value should give default value
|
8
13
|
@a.value.value
|
9
14
|
#=> 'GREAT!'
|
10
15
|
|
11
|
-
## Familia::
|
16
|
+
## Familia::String#value=
|
12
17
|
@a.value.value = "DECENT!"
|
13
18
|
#=> 'DECENT!'
|
14
19
|
|
15
|
-
## Familia::
|
20
|
+
## Familia::String#to_s
|
16
21
|
@a.value.to_s
|
17
22
|
#=> 'DECENT!'
|
18
23
|
|
19
|
-
|
24
|
+
## Familia::String#destroy!
|
25
|
+
@a.value.clear
|
26
|
+
#=> 1
|
27
|
+
|
28
|
+
## Familia::String.new
|
29
|
+
@ret = Familia::String.new 'arbitrary:key'
|
30
|
+
@ret.rediskey
|
31
|
+
#=> 'v1:arbitrary:key'
|
32
|
+
|
33
|
+
## instance set
|
34
|
+
@ret.value = '1000'
|
35
|
+
#=> '1000'
|
36
|
+
|
37
|
+
## instance get
|
38
|
+
@ret.value
|
39
|
+
#=> '1000'
|
40
|
+
|
41
|
+
## Familia::String#increment
|
42
|
+
@ret.increment
|
43
|
+
#=> 1001
|
44
|
+
|
45
|
+
## Familia::String#incrementby
|
46
|
+
@ret.incrementby 99
|
47
|
+
#=> 1100
|
48
|
+
|
49
|
+
## Familia::String#decrement
|
50
|
+
@ret.decrement
|
51
|
+
#=> 1099
|
52
|
+
|
53
|
+
## Familia::String#decrementby
|
54
|
+
@ret.decrementby 49
|
55
|
+
#=> 1050
|
56
|
+
|
57
|
+
## Familia::String#append
|
58
|
+
@ret.append 'bytes'
|
59
|
+
#=> 9
|
60
|
+
|
61
|
+
## Familia::String#value after append
|
62
|
+
@ret.value
|
63
|
+
#=> '1050bytes'
|
64
|
+
|
65
|
+
|
66
|
+
@ret.clear
|
@@ -3,51 +3,51 @@ require 'familia/test_helpers'
|
|
3
3
|
|
4
4
|
@a = Bone.new 'atoken', 'akey'
|
5
5
|
|
6
|
-
## Familia::
|
6
|
+
## Familia::HashKey#has_key? knows when there's no key
|
7
7
|
@a.props.has_key? 'fieldA'
|
8
8
|
#=> false
|
9
9
|
|
10
|
-
## Familia::
|
10
|
+
## Familia::HashKey#[]=
|
11
11
|
@a.props['fieldA'] = '1'
|
12
12
|
@a.props['fieldB'] = '2'
|
13
13
|
@a.props['fieldC'] = '3'
|
14
14
|
#=> '3'
|
15
15
|
|
16
|
-
## Familia::
|
16
|
+
## Familia::HashKey#[]
|
17
17
|
@a.props['fieldA']
|
18
18
|
#=> '1'
|
19
19
|
|
20
|
-
## Familia::
|
20
|
+
## Familia::HashKey#has_key? knows when there's a key
|
21
21
|
@a.props.has_key? 'fieldA'
|
22
22
|
#=> true
|
23
23
|
|
24
|
-
## Familia::
|
24
|
+
## Familia::HashKey#all
|
25
25
|
@a.props.all.class
|
26
26
|
#=> Hash
|
27
27
|
|
28
|
-
## Familia::
|
28
|
+
## Familia::HashKey#size counts the number of keys
|
29
29
|
@a.props.size
|
30
30
|
#=> 3
|
31
31
|
|
32
|
-
## Familia::
|
32
|
+
## Familia::HashKey#remove
|
33
33
|
@a.props.remove 'fieldB'
|
34
34
|
#=> 1
|
35
35
|
|
36
|
-
## Familia::
|
36
|
+
## Familia::HashKey#values
|
37
37
|
@a.props.values.sort
|
38
38
|
#=> ['1', '3']
|
39
39
|
|
40
|
-
## Familia::
|
40
|
+
## Familia::HashKey#increment
|
41
41
|
@a.props.increment 'counter', 100
|
42
42
|
#=> 100
|
43
43
|
|
44
|
-
## Familia::
|
44
|
+
## Familia::HashKey#decrement
|
45
45
|
@a.props.decrement 'counter', 60
|
46
46
|
#=> 40
|
47
47
|
|
48
|
-
## Familia::
|
48
|
+
## Familia::HashKey#values_at
|
49
49
|
@a.props.values_at 'fieldA', 'counter', 'fieldC'
|
50
50
|
#=> ['1', '40', '3']
|
51
51
|
|
52
52
|
|
53
|
-
@a.props.
|
53
|
+
@a.props.clear
|
@@ -4,72 +4,84 @@ Familia.apiversion = 'v1'
|
|
4
4
|
|
5
5
|
@a = Bone.new 'atoken', 'akey'
|
6
6
|
|
7
|
-
## Familia
|
7
|
+
## Familia.prefix
|
8
8
|
Bone.prefix
|
9
9
|
#=> :bone
|
10
10
|
|
11
|
-
## Familia
|
11
|
+
## Familia#index
|
12
12
|
@a.index
|
13
13
|
#=> 'atoken:akey'
|
14
14
|
|
15
|
-
## Familia
|
15
|
+
## Familia.suffix
|
16
16
|
Bone.suffix
|
17
17
|
#=> :object
|
18
18
|
|
19
|
-
## Familia
|
19
|
+
## Familia#rediskey
|
20
20
|
@a.rediskey
|
21
21
|
#=> 'v1:bone:atoken:akey:object'
|
22
22
|
|
23
|
-
## Familia
|
23
|
+
## Familia#rediskey
|
24
24
|
@a.rediskey
|
25
25
|
#=> 'v1:bone:atoken:akey:object'
|
26
26
|
|
27
|
-
## Familia
|
28
|
-
|
29
|
-
|
27
|
+
## Familia#save
|
28
|
+
@cust = Customer.new :delano, "Delano Mandelbaum"
|
29
|
+
@cust.save
|
30
30
|
#=> true
|
31
31
|
|
32
|
-
##
|
33
|
-
|
34
|
-
|
35
|
-
#=> true
|
32
|
+
## Customer.instances
|
33
|
+
Customer.instances.all
|
34
|
+
#=> ['delano']
|
36
35
|
|
37
|
-
## Familia
|
36
|
+
## Familia.from_redis
|
38
37
|
obj = Customer.from_redis :delano
|
39
38
|
obj.custid
|
40
39
|
#=> :delano
|
41
40
|
|
42
|
-
##
|
41
|
+
## Customer.destroy
|
42
|
+
@cust.destroy!
|
43
|
+
#=> 1
|
44
|
+
|
45
|
+
## Customer.instances
|
46
|
+
Customer.instances.size
|
47
|
+
#=> 0
|
48
|
+
|
49
|
+
## Familia#save with an object that expires
|
50
|
+
obj = Session.new 'sessionid', :delano
|
51
|
+
obj.save
|
52
|
+
#=> true
|
53
|
+
|
54
|
+
## Familia.class_list
|
43
55
|
Customer.customers.class
|
44
|
-
#=> Familia::
|
56
|
+
#=> Familia::List
|
45
57
|
|
46
|
-
## Familia
|
58
|
+
## Familia class rediskey
|
47
59
|
Customer.customers.rediskey
|
48
60
|
#=> 'v1:customer:customers'
|
49
61
|
|
50
|
-
## Familia
|
62
|
+
## Familia.class_list
|
51
63
|
Customer.customers << :delano << :tucker << :morton
|
52
64
|
Customer.customers.size
|
53
65
|
#=> 3
|
54
66
|
|
55
|
-
## Familia
|
67
|
+
## Familia class clear
|
56
68
|
Customer.customers.clear
|
57
69
|
#=> 1
|
58
70
|
|
59
71
|
|
60
|
-
## Familia
|
72
|
+
## Familia class replace 1
|
61
73
|
Customer.message.value = "msg1"
|
62
74
|
#=> "msg1"
|
63
75
|
|
64
|
-
## Familia
|
76
|
+
## Familia class replace 2
|
65
77
|
Customer.message.value
|
66
78
|
#=> "msg1"
|
67
79
|
|
68
|
-
## Familia
|
80
|
+
## Familia class replace 3
|
69
81
|
Customer.message = "msg2"
|
70
82
|
#=> "msg2"
|
71
83
|
|
72
|
-
## Familia
|
84
|
+
## Familia class replace 4
|
73
85
|
Customer.message.value
|
74
86
|
#=> "msg2"
|
75
87
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: familia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 0.6.
|
9
|
+
- 1
|
10
|
+
version: 0.6.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Delano Mandelbaum
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-12-
|
18
|
+
date: 2010-12-18 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|