familia 0.7.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/CHANGES.txt +19 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +36 -0
- data/README.md +24 -0
- data/VERSION.yml +2 -2
- data/familia.gemspec +17 -65
- data/lib/familia/core_ext.rb +21 -0
- data/lib/familia/object.rb +106 -71
- data/lib/familia/redisobject.rb +254 -191
- data/lib/familia/test_helpers.rb +6 -0
- data/lib/familia.rb +14 -6
- data/try/10_familia_try.rb +17 -0
- data/try/20_redis_object_try.rb +29 -2
- data/try/21_redis_object_zset_try.rb +3 -3
- metadata +99 -72
- data/README.rdoc +0 -14
- data/Rakefile +0 -70
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e5c7b9afb9555b1223964ed3e93ac014df3c278e9c7467dfd26c5fced66e7298
|
4
|
+
data.tar.gz: 5ec4da06d0223bc8f27a2ba0689df6482dfbaf971028c3431bdc330cad332c13
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7341bb23aa95bba387ab28377563d63d80933e99f3e5034ba65643c4806d7e7d7fc98308e9fc7ec7358d7c9775129bf0f02b198abd57b2b99bb1b28df0530a46
|
7
|
+
data.tar.gz: d4bbd6719f096d7f58ea00b0ae7a7ba2f5da71365b21b818863fc122b8a3856607248a803367ca9c87adc25b8d85b935331ce1413da4f803254baacf68cbb464
|
data/.gitignore
ADDED
data/CHANGES.txt
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
FAMILIA, CHANGES
|
2
2
|
|
3
|
+
|
4
|
+
#### 0.7.1 (2011-04-09) ###############################
|
5
|
+
|
6
|
+
* FIXED: Explicitly convert boolean conf options to true or false. Redis client
|
7
|
+
treats "true" as false.
|
8
|
+
* FIXED: Clone options for each RedisObject instance to prevent cross contamination.
|
9
|
+
* CHANGE: Fix for Familia objects with custom suffixes
|
10
|
+
* CHANGE: Familia::String methods that modify the key now automatically update_expiration.
|
11
|
+
* CHANGE: Familia::Object.prefix replaces :: in class names with Familia.delim
|
12
|
+
* CHANGE: Use Familia::Object#object_proxy instead of Familia::Object.string :object
|
13
|
+
* ADDED: Familia.qnow, Familia::Object.qstamp, RedisObject#qstamp
|
14
|
+
* ADDED: RedisObject option: quantize
|
15
|
+
* ADDED: Familia::Object#savenx
|
16
|
+
* ADDED: Can now include a Familia object in Familia::Object.index (it uses its index)
|
17
|
+
* ADDED: Dependency multi_json
|
18
|
+
* ADDED: Hash#to_json, Hash.from_json, Array#to_json, Array.from_json
|
19
|
+
* ADDED: Familia::Object#update!
|
20
|
+
|
21
|
+
|
3
22
|
#### 0.7.0 (2011-03-04) ###############################
|
4
23
|
|
5
24
|
* CHANGE: Use RedisObject#multi_from_redis when possible (uses mget command)
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
attic (1.0.0)
|
5
|
+
rake (~> 13.0.6)
|
6
|
+
drydock (0.6.9)
|
7
|
+
gibbler (1.0.0)
|
8
|
+
attic (~> 1.0)
|
9
|
+
rake (~> 13.0)
|
10
|
+
multi_json (1.15.0)
|
11
|
+
rake (13.0.6)
|
12
|
+
redis (4.8.1)
|
13
|
+
storable (0.10.0)
|
14
|
+
sysinfo (0.10.0)
|
15
|
+
drydock (< 1.0)
|
16
|
+
storable (~> 0.10)
|
17
|
+
tryouts (2.2.0)
|
18
|
+
sysinfo (~> 0.10)
|
19
|
+
uri-redis (0.4.2)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
arm64-darwin-22
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
gibbler
|
26
|
+
multi_json
|
27
|
+
redis (~> 4.8)
|
28
|
+
storable
|
29
|
+
tryouts (~> 2.2)
|
30
|
+
uri-redis
|
31
|
+
|
32
|
+
RUBY VERSION
|
33
|
+
ruby 2.6.8p205
|
34
|
+
|
35
|
+
BUNDLED WITH
|
36
|
+
2.4.12
|
data/README.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Familia - 0.9 (2024-04-04)
|
2
|
+
|
3
|
+
**Organize and store ruby objects in Redis**
|
4
|
+
|
5
|
+
|
6
|
+
## Basic Example
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
class Flower < Storable
|
10
|
+
include Familia
|
11
|
+
index [:token, :name]
|
12
|
+
field :token
|
13
|
+
field :name
|
14
|
+
list :owners
|
15
|
+
set :tags
|
16
|
+
zset :metrics
|
17
|
+
hash :props
|
18
|
+
string :value, :default => "GREAT!"
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
## More Information
|
23
|
+
|
24
|
+
* [Codes](https://github.com/delano/familia)
|
data/VERSION.yml
CHANGED
data/familia.gemspec
CHANGED
@@ -1,71 +1,23 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
-
# -*- encoding: utf-8 -*-
|
5
|
-
|
6
1
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
2
|
+
s.name = "familia"
|
3
|
+
s.version = "0.9.0"
|
4
|
+
s.summary = "Organize and store ruby objects in Redis"
|
5
|
+
s.description = "Familia: #{s.summary}"
|
6
|
+
s.authors = ["Delano Mandelbaum"]
|
7
|
+
s.email = "delano@solutious.com"
|
8
|
+
s.homepage = "https://github.com/delano/familia"
|
9
|
+
s.license = "MIT"
|
9
10
|
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.
|
13
|
-
s.description = %q{Organize and store ruby objects in Redis}
|
14
|
-
s.email = %q{delano@solutious.com}
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"LICENSE.txt",
|
17
|
-
"README.rdoc"
|
18
|
-
]
|
19
|
-
s.files = [
|
20
|
-
"CHANGES.txt",
|
21
|
-
"LICENSE.txt",
|
22
|
-
"README.rdoc",
|
23
|
-
"Rakefile",
|
24
|
-
"VERSION.yml",
|
25
|
-
"familia.gemspec",
|
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"
|
42
|
-
]
|
43
|
-
s.homepage = %q{http://github.com/delano/familia}
|
44
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
11
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
12
|
+
s.bindir = "exe"
|
13
|
+
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
45
14
|
s.require_paths = ["lib"]
|
46
|
-
s.rubyforge_project = %q{familia}
|
47
|
-
s.rubygems_version = %q{1.5.2}
|
48
|
-
s.summary = %q{Organize and store ruby objects in Redis}
|
49
15
|
|
50
|
-
|
51
|
-
s.specification_version = 3
|
16
|
+
s.required_ruby_version = Gem::Requirement.new(">= 2.6.8")
|
52
17
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
else
|
59
|
-
s.add_dependency(%q<redis>, [">= 2.1.0"])
|
60
|
-
s.add_dependency(%q<uri-redis>, [">= 0.4.2"])
|
61
|
-
s.add_dependency(%q<gibbler>, [">= 0.8.6"])
|
62
|
-
s.add_dependency(%q<storable>, [">= 0.8.6"])
|
63
|
-
end
|
64
|
-
else
|
65
|
-
s.add_dependency(%q<redis>, [">= 2.1.0"])
|
66
|
-
s.add_dependency(%q<uri-redis>, [">= 0.4.2"])
|
67
|
-
s.add_dependency(%q<gibbler>, [">= 0.8.6"])
|
68
|
-
s.add_dependency(%q<storable>, [">= 0.8.6"])
|
69
|
-
end
|
18
|
+
s.add_dependency "redis", "~> 4.8.0"
|
19
|
+
s.add_dependency "uri-redis", "~> 0.4", ">= 0.4.2"
|
20
|
+
s.add_dependency "gibbler", "~> 1.0.0"
|
21
|
+
s.add_dependency "storable", "~> 0.10.0"
|
22
|
+
s.add_dependency "multi_json", "~> 0.0", ">= 0.0.5"
|
70
23
|
end
|
71
|
-
|
data/lib/familia/core_ext.rb
CHANGED
@@ -7,6 +7,27 @@ class Symbol
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
class Hash
|
11
|
+
unless method_defined?(:to_json)
|
12
|
+
def to_json
|
13
|
+
MultiJson.encode self
|
14
|
+
end
|
15
|
+
def self.from_json str
|
16
|
+
MultiJson.decode str
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
class Array
|
21
|
+
unless method_defined?(:to_json)
|
22
|
+
def to_json
|
23
|
+
MultiJson.encode self
|
24
|
+
end
|
25
|
+
def self.from_json str
|
26
|
+
MultiJson.decode str
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
10
31
|
# Assumes Time::Units and Numeric mixins are available.
|
11
32
|
class String
|
12
33
|
def in_seconds
|
data/lib/familia/object.rb
CHANGED
@@ -2,12 +2,12 @@ require 'ostruct'
|
|
2
2
|
|
3
3
|
module Familia
|
4
4
|
require 'familia/redisobject'
|
5
|
-
|
5
|
+
|
6
6
|
# Auto-extended into a class that includes Familia
|
7
7
|
module ClassMethods
|
8
|
-
|
8
|
+
|
9
9
|
Familia::RedisObject.registration.each_pair do |kind, klass|
|
10
|
-
# e.g.
|
10
|
+
# e.g.
|
11
11
|
#
|
12
12
|
# list(name, klass, opts)
|
13
13
|
# list?(name)
|
@@ -22,12 +22,12 @@ module Familia
|
|
22
22
|
obj = redis_objects[name.to_s.to_sym]
|
23
23
|
!obj.nil? && klass == obj.klass
|
24
24
|
end
|
25
|
-
define_method :"#{kind}s" do
|
25
|
+
define_method :"#{kind}s" do
|
26
26
|
names = redis_objects_order.select { |name| send(:"#{kind}?", name) }
|
27
27
|
names.collect! { |name| redis_objects[name] }
|
28
28
|
names
|
29
29
|
end
|
30
|
-
# e.g.
|
30
|
+
# e.g.
|
31
31
|
#
|
32
32
|
# class_list(name, klass, opts)
|
33
33
|
# class_list?(name)
|
@@ -41,29 +41,23 @@ module Familia
|
|
41
41
|
obj = class_redis_objects[name.to_s.to_sym]
|
42
42
|
!obj.nil? && klass == obj.klass
|
43
43
|
end
|
44
|
-
define_method :"class_#{kind}s" do
|
44
|
+
define_method :"class_#{kind}s" do
|
45
45
|
names = class_redis_objects_order.select { |name| ret = send(:"class_#{kind}?", name) }
|
46
46
|
# TODO: This returns instances of the RedisObject class which
|
47
47
|
# also contain the options. This is different from the instance
|
48
|
-
# RedisObjects defined above which returns the OpenStruct of name, klass, and opts.
|
48
|
+
# RedisObjects defined above which returns the OpenStruct of name, klass, and opts.
|
49
49
|
#names.collect! { |name| self.send name }
|
50
50
|
# OR NOT:
|
51
51
|
names.collect! { |name| class_redis_objects[name] }
|
52
52
|
names
|
53
53
|
end
|
54
54
|
end
|
55
|
-
|
56
55
|
def inherited(obj)
|
57
56
|
obj.db = self.db
|
58
57
|
obj.uri = self.uri
|
59
58
|
obj.ttl = self.ttl
|
60
59
|
obj.parent = self
|
61
60
|
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
|
67
61
|
Familia.classes << obj
|
68
62
|
super(obj)
|
69
63
|
end
|
@@ -75,9 +69,9 @@ module Familia
|
|
75
69
|
obj.class_zset :instances, :class => obj, :reference => true
|
76
70
|
Familia.classes << obj
|
77
71
|
end
|
78
|
-
|
72
|
+
|
79
73
|
# Creates an instance method called +name+ that
|
80
|
-
# returns an instance of the RedisObject +klass+
|
74
|
+
# returns an instance of the RedisObject +klass+
|
81
75
|
def install_redis_object name, klass, opts
|
82
76
|
raise ArgumentError, "Name is blank" if name.to_s.empty?
|
83
77
|
name = name.to_s.to_sym
|
@@ -96,27 +90,34 @@ module Familia
|
|
96
90
|
end
|
97
91
|
redis_objects[name]
|
98
92
|
end
|
99
|
-
|
93
|
+
|
94
|
+
def qstamp quantum=nil, pattern=nil, now=Familia.now
|
95
|
+
quantum ||= ttl || 10.minutes
|
96
|
+
pattern ||= '%H%M'
|
97
|
+
rounded = now - (now % quantum)
|
98
|
+
Time.at(rounded).utc.strftime(pattern)
|
99
|
+
end
|
100
|
+
|
100
101
|
# Creates a class method called +name+ that
|
101
|
-
# returns an instance of the RedisObject +klass+
|
102
|
+
# returns an instance of the RedisObject +klass+
|
102
103
|
def install_class_redis_object name, klass, opts
|
103
104
|
raise ArgumentError, "Name is blank" if name.to_s.empty?
|
104
105
|
name = name.to_s.to_sym
|
105
|
-
opts
|
106
|
-
opts[:parent]
|
107
|
-
# TODO: investigate using
|
106
|
+
opts = opts.nil? ? {} : opts.clone
|
107
|
+
opts[:parent] = self unless opts.has_key?(:parent)
|
108
|
+
# TODO: investigate using attic.redis_objects
|
108
109
|
class_redis_objects_order << name
|
109
110
|
class_redis_objects[name] = OpenStruct.new
|
110
111
|
class_redis_objects[name].name = name
|
111
112
|
class_redis_objects[name].klass = klass
|
112
|
-
class_redis_objects[name].opts = opts
|
113
|
+
class_redis_objects[name].opts = opts
|
113
114
|
# An accessor method created in the metclass will
|
114
|
-
# access the instance variables for this class.
|
115
|
-
|
116
|
-
|
115
|
+
# access the instance variables for this class.
|
116
|
+
attic.send :attr_reader, name
|
117
|
+
attic.send :define_method, "#{name}=" do |v|
|
117
118
|
send(name).replace v
|
118
119
|
end
|
119
|
-
|
120
|
+
attic.send :define_method, "#{name}?" do
|
120
121
|
!send(name).empty?
|
121
122
|
end
|
122
123
|
redis_object = klass.new name, opts
|
@@ -124,7 +125,7 @@ module Familia
|
|
124
125
|
self.instance_variable_set("@#{name}", redis_object)
|
125
126
|
class_redis_objects[name]
|
126
127
|
end
|
127
|
-
|
128
|
+
|
128
129
|
def from_redisdump dump
|
129
130
|
dump # todo
|
130
131
|
end
|
@@ -145,9 +146,9 @@ module Familia
|
|
145
146
|
def port=(port) @port = port end
|
146
147
|
def uri=(uri)
|
147
148
|
uri = URI.parse uri if String === uri
|
148
|
-
@uri = uri
|
149
|
+
@uri = uri
|
149
150
|
end
|
150
|
-
def uri(uri=nil)
|
151
|
+
def uri(uri=nil)
|
151
152
|
self.uri = uri if !uri.to_s.empty?
|
152
153
|
@uri ||= (parent ? parent.uri : Familia.uri)
|
153
154
|
@uri.db = @db if @db && @uri.db.to_s != @db.to_s
|
@@ -165,7 +166,7 @@ module Familia
|
|
165
166
|
end
|
166
167
|
def all(suffix=:object)
|
167
168
|
# objects that could not be parsed will be nil
|
168
|
-
keys(suffix).collect { |k| from_key(k) }.compact
|
169
|
+
keys(suffix).collect { |k| from_key(k) }.compact
|
169
170
|
end
|
170
171
|
def any?(filter='*')
|
171
172
|
size(filter) > 0
|
@@ -173,17 +174,17 @@ module Familia
|
|
173
174
|
def size(filter='*')
|
174
175
|
self.redis.keys(rediskey(filter)).compact.size
|
175
176
|
end
|
176
|
-
def suffix(a=nil, &blk)
|
177
|
+
def suffix(a=nil, &blk)
|
177
178
|
@suffix = a || blk if a || !blk.nil?
|
178
179
|
val = @suffix || Familia.default_suffix
|
179
180
|
val
|
180
181
|
end
|
181
182
|
def prefix=(a) @prefix = a end
|
182
|
-
def prefix(a=nil) @prefix = a if a; @prefix || self.name.downcase.to_sym end
|
183
|
+
def prefix(a=nil) @prefix = a if a; @prefix || self.name.downcase.gsub('::', Familia.delim).to_sym end
|
183
184
|
# TODO: grab db, ttl, uri from parent
|
184
185
|
#def parent=(a) @parent = a end
|
185
186
|
#def parent(a=nil) @parent = a if a; @parent end
|
186
|
-
def index(i=nil, &blk)
|
187
|
+
def index(i=nil, &blk)
|
187
188
|
@index = i || blk if i || !blk.nil?
|
188
189
|
@index ||= Familia.index
|
189
190
|
@index
|
@@ -229,9 +230,9 @@ module Familia
|
|
229
230
|
Familia.trace :MULTIGET, self.redis, "#{ids.size}: #{ids}", caller if Familia.debug?
|
230
231
|
ids = self.redis.mget *ids
|
231
232
|
end
|
232
|
-
|
233
|
+
|
233
234
|
# Returns an instance based on +idx+ otherwise it
|
234
|
-
# creates and saves a new instance base on +idx+.
|
235
|
+
# creates and saves a new instance base on +idx+.
|
235
236
|
# See from_index
|
236
237
|
def load_or_create idx
|
237
238
|
return from_redis(idx) if exists?(idx)
|
@@ -239,17 +240,17 @@ module Familia
|
|
239
240
|
obj.save
|
240
241
|
obj
|
241
242
|
end
|
242
|
-
# Note +idx+ needs to be an appropriate index for
|
243
|
+
# Note +idx+ needs to be an appropriate index for
|
243
244
|
# the given class. If the index is multi-value it
|
244
245
|
# must be passed as an Array in the proper order.
|
245
246
|
# Does not call save.
|
246
247
|
def from_index idx
|
247
|
-
obj = new
|
248
|
+
obj = new
|
248
249
|
obj.index = idx
|
249
250
|
obj
|
250
251
|
end
|
251
252
|
def from_key objkey
|
252
|
-
raise ArgumentError, "Empty key" if objkey.to_s.empty?
|
253
|
+
raise ArgumentError, "Empty key" if objkey.to_s.empty?
|
253
254
|
Familia.trace :LOAD, Familia.redis(self.uri), objkey, caller if Familia.debug?
|
254
255
|
obj = Familia::String.new objkey, :class => self
|
255
256
|
obj.value
|
@@ -292,18 +293,18 @@ module Familia
|
|
292
293
|
case list.size
|
293
294
|
when 0
|
294
295
|
nil
|
295
|
-
when 1
|
296
|
+
when 1
|
296
297
|
matches = list.first.match(/\A#{Familia.rediskey(prefix)}\:(.+?)\:#{suffix}/) || []
|
297
298
|
matches[1]
|
298
299
|
else
|
299
|
-
raise Familia::NonUniqueKey, "Short key returned more than 1 match"
|
300
|
+
raise Familia::NonUniqueKey, "Short key returned more than 1 match"
|
300
301
|
end
|
301
302
|
end
|
302
303
|
end
|
303
304
|
|
304
|
-
|
305
|
+
|
305
306
|
module InstanceMethods
|
306
|
-
|
307
|
+
|
307
308
|
# A default initialize method. This will be replaced
|
308
309
|
# if a class defines its own initialize method after
|
309
310
|
# including Familia. In that case, the replacement
|
@@ -312,33 +313,41 @@ module Familia
|
|
312
313
|
initialize_redis_objects
|
313
314
|
init *args if respond_to? :init
|
314
315
|
end
|
315
|
-
|
316
|
+
|
316
317
|
# This needs to be called in the initialize method of
|
317
|
-
# any class that includes Familia.
|
318
|
+
# any class that includes Familia.
|
318
319
|
def initialize_redis_objects
|
319
320
|
# Generate instances of each RedisObject. These need to be
|
320
321
|
# unique for each instance of this class so they can refer
|
321
322
|
# to the index of this specific instance.
|
322
323
|
#
|
323
|
-
# i.e.
|
324
|
+
# i.e.
|
324
325
|
# familia_object.rediskey == v1:bone:INDEXVALUE:object
|
325
326
|
# familia_object.redis_object.rediskey == v1:bone:INDEXVALUE:name
|
326
327
|
#
|
327
328
|
# See RedisObject.install_redis_object
|
328
329
|
self.class.redis_objects.each_pair do |name, redis_object_definition|
|
329
330
|
klass, opts = redis_object_definition.klass, redis_object_definition.opts
|
330
|
-
opts
|
331
|
-
opts[:parent]
|
331
|
+
opts = opts.nil? ? {} : opts.clone
|
332
|
+
opts[:parent] = self unless opts.has_key?(:parent)
|
332
333
|
redis_object = klass.new name, opts
|
333
334
|
redis_object.freeze
|
334
335
|
self.instance_variable_set "@#{name}", redis_object
|
335
336
|
end
|
336
337
|
end
|
337
|
-
|
338
|
+
|
339
|
+
def qstamp quantum=nil, pattern=nil, now=Familia.now
|
340
|
+
self.class.qstamp ttl, pattern, now
|
341
|
+
end
|
342
|
+
|
343
|
+
def from_redis
|
344
|
+
self.class.from_redis self.index
|
345
|
+
end
|
346
|
+
|
338
347
|
def redis
|
339
348
|
self.class.redis
|
340
349
|
end
|
341
|
-
|
350
|
+
|
342
351
|
def redisinfo
|
343
352
|
info = {
|
344
353
|
:uri => self.class.uri,
|
@@ -350,51 +359,73 @@ module Familia
|
|
350
359
|
end
|
351
360
|
def exists?
|
352
361
|
Familia.redis(self.class.uri).exists rediskey
|
353
|
-
end
|
354
|
-
|
362
|
+
end
|
363
|
+
|
355
364
|
#def rediskeys
|
356
365
|
# self.class.redis_objects.each do |redis_object_definition|
|
357
|
-
#
|
366
|
+
#
|
358
367
|
# end
|
359
368
|
#end
|
360
|
-
|
369
|
+
|
361
370
|
def allkeys
|
362
371
|
# TODO: Use redis_objects instead
|
363
372
|
keynames = []
|
364
|
-
self.class.suffixes.each do |sfx|
|
373
|
+
self.class.suffixes.each do |sfx|
|
365
374
|
keynames << rediskey(sfx)
|
366
375
|
end
|
367
376
|
keynames
|
368
377
|
end
|
369
378
|
# +suffix+ is the value to be used at the end of the redis key
|
370
379
|
# + ignored+ is literally ignored. It's around to maintain
|
371
|
-
# consistency with the class version of this method.
|
380
|
+
# consistency with the class version of this method.
|
372
381
|
# (RedisObject#rediskey may call against a class or instance).
|
373
382
|
def rediskey(suffix=nil, ignored=nil)
|
374
383
|
Familia.info "[#{self.class}] something was ignored" unless ignored.nil?
|
375
384
|
raise Familia::NoIndex, self.class if index.to_s.empty?
|
376
385
|
if suffix.nil?
|
377
|
-
suffix = self.class.suffix.kind_of?(Proc) ?
|
378
|
-
self.class.suffix.call(self) :
|
386
|
+
suffix = self.class.suffix.kind_of?(Proc) ?
|
387
|
+
self.class.suffix.call(self) :
|
379
388
|
self.class.suffix
|
380
389
|
end
|
381
390
|
self.class.rediskey self.index, suffix
|
382
391
|
end
|
383
|
-
def
|
392
|
+
def object_proxy
|
393
|
+
@object_proxy ||= Familia::String.new self.rediskey, :ttl => ttl, :class => self.class
|
394
|
+
@object_proxy
|
395
|
+
end
|
396
|
+
def save meth=:set
|
384
397
|
#Familia.trace :SAVE, Familia.redis(self.class.uri), redisuri, caller.first if Familia.debug?
|
385
398
|
preprocess if respond_to?(:preprocess)
|
386
399
|
self.update_time if self.respond_to?(:update_time)
|
387
|
-
#
|
388
|
-
ret = self.object.set self # object is a name reserved by Familia
|
400
|
+
ret = object_proxy.send(meth, self) # object is a name reserved by Familia
|
389
401
|
unless ret.nil?
|
390
402
|
now = Time.now.utc.to_i
|
391
403
|
self.class.instances.add now, self # use this set instead of Klass.keys
|
392
|
-
|
404
|
+
object_proxy.update_expiration # does nothing unless if not specified
|
405
|
+
end
|
406
|
+
ret == "OK" || ret == true || ret == 1
|
407
|
+
end
|
408
|
+
def savenx
|
409
|
+
save :setnx
|
410
|
+
end
|
411
|
+
def update! hsh=nil
|
412
|
+
updated = false
|
413
|
+
hsh ||= {}
|
414
|
+
if hsh.empty?
|
415
|
+
raise Familia::Problem, "No #{self.class}#{to_hash} method" unless respond_to?(:to_hash)
|
416
|
+
ret = from_redis
|
417
|
+
hsh = ret.to_hash if ret
|
393
418
|
end
|
394
|
-
|
419
|
+
hsh.keys.each { |field|
|
420
|
+
v = hsh[field.to_s] || hsh[field.to_s.to_sym]
|
421
|
+
next if v.nil?
|
422
|
+
self.send(:"#{field}=", v)
|
423
|
+
updated = true
|
424
|
+
}
|
425
|
+
updated
|
395
426
|
end
|
396
427
|
def destroy!
|
397
|
-
ret =
|
428
|
+
ret = object_proxy.delete
|
398
429
|
if Familia.debug?
|
399
430
|
Familia.trace :DELETED, Familia.redis(self.class.uri), "#{rediskey}: #{ret}", caller.first if Familia.debug?
|
400
431
|
end
|
@@ -406,11 +437,13 @@ module Familia
|
|
406
437
|
when Proc
|
407
438
|
self.class.index.call(self)
|
408
439
|
when Array
|
409
|
-
parts = self.class.index.collect { |meth|
|
440
|
+
parts = self.class.index.collect { |meth|
|
410
441
|
unless self.respond_to? meth
|
411
442
|
raise NoIndex, "No such method: `#{meth}' for #{self.class}"
|
412
443
|
end
|
413
|
-
self.send(meth)
|
444
|
+
ret = self.send(meth)
|
445
|
+
ret = ret.index if ret.kind_of?(Familia)
|
446
|
+
ret
|
414
447
|
}
|
415
448
|
parts.join Familia.delim
|
416
449
|
when Symbol, String
|
@@ -420,7 +453,9 @@ module Familia
|
|
420
453
|
unless self.respond_to? self.class.index
|
421
454
|
raise NoIndex, "No such method: `#{self.class.index}' for #{self.class}"
|
422
455
|
end
|
423
|
-
self.send(
|
456
|
+
ret = self.send(self.class.index)
|
457
|
+
ret = ret.index if ret.kind_of?(Familia)
|
458
|
+
ret
|
424
459
|
end
|
425
460
|
else
|
426
461
|
raise Familia::NoIndex, self
|
@@ -434,11 +469,11 @@ module Familia
|
|
434
469
|
unless Array === v && v.size == self.class.index.size
|
435
470
|
raise ArgumentError, "Index mismatch (#{v.size} for #{self.class.index.size})"
|
436
471
|
end
|
437
|
-
parts = self.class.index.each_with_index { |meth,idx|
|
472
|
+
parts = self.class.index.each_with_index { |meth,idx|
|
438
473
|
unless self.respond_to? "#{meth}="
|
439
474
|
raise NoIndex, "No such method: `#{meth}=' for #{self.class}"
|
440
475
|
end
|
441
|
-
self.send("#{meth}=", v[idx])
|
476
|
+
self.send("#{meth}=", v[idx])
|
442
477
|
}
|
443
478
|
when Symbol, String
|
444
479
|
if self.class.redis_object?(self.class.index.to_sym)
|
@@ -452,7 +487,7 @@ module Familia
|
|
452
487
|
else
|
453
488
|
raise Familia::NoIndex, self
|
454
489
|
end
|
455
|
-
|
490
|
+
|
456
491
|
end
|
457
492
|
def expire(ttl=nil)
|
458
493
|
ttl ||= self.class.ttl
|
@@ -491,8 +526,8 @@ module Familia
|
|
491
526
|
len += 1
|
492
527
|
end
|
493
528
|
end
|
494
|
-
@id.shorten(len)
|
529
|
+
@id.shorten(len)
|
495
530
|
end
|
496
531
|
end
|
497
|
-
|
498
|
-
end
|
532
|
+
|
533
|
+
end
|