familia 1.0.0.pre.rc2 → 1.0.0.pre.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION.yml +1 -1
- data/lib/familia/horreum/class_methods.rb +64 -11
- data/lib/familia/horreum/commands.rb +35 -3
- data/lib/familia/horreum/serialization.rb +187 -43
- data/lib/familia/types/hashkey.rb +4 -3
- data/lib/familia/types/list.rb +2 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c5cdd5bc9ccadb7e69c324e7a2716b378fa5e5fe9938c4ed44a61b23eef99c6a
|
4
|
+
data.tar.gz: de5bb8d9e3b6b09906e777f9a5586eff32a5b1d3ec7c5e51a3a26dac2bd85415
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76ffa691585dde5c45aaa17e1d02171bacb3fad0267f638b02d7c2cf0a65eaed4d0062656be2496c27ff9bd9788839a71d8475f3e14577ef607684cd179209c1
|
7
|
+
data.tar.gz: 96d52e17f1c3f3092d4ec39ad0fbd1455ef54a902a2f2aaa65c5531d11cdd8b53ee50ef1fa0bd967bd4fa49fd4b0693d89031bcb6decb6cc2def5cb4e1d85c9a
|
data/VERSION.yml
CHANGED
@@ -36,20 +36,40 @@ module Familia
|
|
36
36
|
attr_accessor :parent
|
37
37
|
attr_writer :redis, :dump_method, :load_method
|
38
38
|
|
39
|
+
# Returns the Redis connection for the class.
|
40
|
+
#
|
41
|
+
# This method retrieves the Redis connection instance for the class. If no
|
42
|
+
# connection is set, it initializes a new connection using the provided URI
|
43
|
+
# or database configuration.
|
44
|
+
#
|
45
|
+
# @return [Redis] the Redis connection instance.
|
46
|
+
#
|
39
47
|
def redis
|
40
48
|
@redis || Familia.redis(uri || db)
|
41
49
|
end
|
42
50
|
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
51
|
+
# Sets or retrieves the unique identifier for the class.
|
52
|
+
#
|
53
|
+
# This method defines or returns the unique identifier used to generate the
|
54
|
+
# Redis key for the object. If a value is provided, it sets the identifier;
|
55
|
+
# otherwise, it returns the current identifier.
|
56
|
+
#
|
57
|
+
# @param [Object] val the value to set as the identifier (optional).
|
58
|
+
# @return [Object] the current identifier.
|
59
|
+
#
|
46
60
|
def identifier(val = nil)
|
47
61
|
@identifier = val if val
|
48
62
|
@identifier
|
49
63
|
end
|
50
64
|
|
51
|
-
#
|
52
|
-
#
|
65
|
+
# Defines a field for the class and creates accessor methods.
|
66
|
+
#
|
67
|
+
# This method defines a new field for the class, creating getter and setter
|
68
|
+
# instance methods similar to `attr_accessor`. It also generates a fast
|
69
|
+
# writer method for immediate persistence to Redis.
|
70
|
+
#
|
71
|
+
# @param [Symbol, String] name the name of the field to define.
|
72
|
+
#
|
53
73
|
def field(name)
|
54
74
|
fields << name
|
55
75
|
attr_accessor name
|
@@ -58,13 +78,46 @@ module Familia
|
|
58
78
|
fast_writer! name
|
59
79
|
end
|
60
80
|
|
61
|
-
#
|
81
|
+
# Defines a writer method with a bang (!) suffix for a given attribute name.
|
82
|
+
#
|
83
|
+
# The dynamically defined method performs the following:
|
84
|
+
# - Checks if the correct number of arguments is provided (exactly one).
|
85
|
+
# - Converts the provided value to a format suitable for Redis storage.
|
86
|
+
# - Uses the existing accessor method to set the attribute value.
|
87
|
+
# - Persists the value to Redis immediately using the hset command.
|
88
|
+
# - Includes custom error handling to raise an ArgumentError if the wrong number of arguments is given.
|
89
|
+
# - Raises a custom error message if an exception occurs during the execution of the method.
|
90
|
+
#
|
91
|
+
# @param [Symbol, String] name the name of the attribute for which the writer method is defined.
|
92
|
+
# @raise [ArgumentError] if the wrong number of arguments is provided.
|
93
|
+
# @raise [RuntimeError] if an exception occurs during the execution of the method.
|
94
|
+
#
|
62
95
|
def fast_writer!(name)
|
63
|
-
define_method :"#{name}!" do |
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
96
|
+
define_method :"#{name}!" do |*args|
|
97
|
+
# Check if the correct number of arguments is provided (exactly one).
|
98
|
+
if args.size != 1
|
99
|
+
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 1)"
|
100
|
+
end
|
101
|
+
|
102
|
+
value = args.first
|
103
|
+
|
104
|
+
begin
|
105
|
+
# Trace the operation if debugging is enabled.
|
106
|
+
Familia.trace :FAST_WRITER, redis, "#{name}: #{value.inspect}", caller if Familia.debug?
|
107
|
+
|
108
|
+
# Convert the provided value to a format suitable for Redis storage.
|
109
|
+
prepared = to_redis(value)
|
110
|
+
Familia.ld "[.fast_writer!] #{name} val: #{value.class} prepared: #{prepared.class}"
|
111
|
+
|
112
|
+
# Use the existing accessor method to set the attribute value.
|
113
|
+
send :"#{name}=", value
|
114
|
+
|
115
|
+
# Persist the value to Redis immediately using the hset command.
|
116
|
+
hset name, prepared
|
117
|
+
rescue Familia::Problem => e
|
118
|
+
# Raise a custom error message if an exception occurs during the execution of the method.
|
119
|
+
raise "#{name}! method failed: #{e.message}", e.backtrace
|
120
|
+
end
|
68
121
|
end
|
69
122
|
end
|
70
123
|
|
@@ -20,9 +20,12 @@ module Familia
|
|
20
20
|
|
21
21
|
def exists?
|
22
22
|
ret = redis.exists rediskey
|
23
|
-
ret.positive?
|
23
|
+
ret.positive? # differs from redis API but I think it's okay bc `exists?` is a predicate method.
|
24
24
|
end
|
25
25
|
|
26
|
+
# Sets a timeout on key. After the timeout has expired, the key will automatically be deleted.
|
27
|
+
# Returns 1 if the timeout was set, 0 if key does not exist or the timeout could not be set.
|
28
|
+
#
|
26
29
|
def expire(ttl = nil)
|
27
30
|
ttl ||= self.class.ttl
|
28
31
|
redis.expire rediskey, ttl.to_i
|
@@ -32,6 +35,11 @@ module Familia
|
|
32
35
|
redis.ttl rediskey
|
33
36
|
end
|
34
37
|
|
38
|
+
# Deletes a field from the hash stored at the Redis key.
|
39
|
+
#
|
40
|
+
# @param field [String] The field to delete from the hash.
|
41
|
+
# @return [Integer] The number of fields that were removed from the hash (0 or 1).
|
42
|
+
# @note This method is destructive, as indicated by the bang (!).
|
35
43
|
def hdel!(field)
|
36
44
|
redis.hdel rediskey, field
|
37
45
|
end
|
@@ -76,21 +84,45 @@ module Familia
|
|
76
84
|
redis.hvals rediskey(suffix)
|
77
85
|
end
|
78
86
|
|
79
|
-
def
|
87
|
+
def incr(field)
|
88
|
+
redis.hincrby rediskey(suffix), field, 1
|
89
|
+
end
|
90
|
+
alias increment incr
|
91
|
+
|
92
|
+
def incrby(field, increment)
|
80
93
|
redis.hincrby rediskey(suffix), field, increment
|
81
94
|
end
|
95
|
+
alias incrementby incrby
|
82
96
|
|
83
|
-
def
|
97
|
+
def incrbyfloat(field, increment)
|
84
98
|
redis.hincrbyfloat rediskey(suffix), field, increment
|
85
99
|
end
|
100
|
+
alias incrementbyfloat incrbyfloat
|
101
|
+
|
102
|
+
def decrby(field, decrement)
|
103
|
+
redis.decrby rediskey(suffix), field, decrement
|
104
|
+
end
|
105
|
+
alias decrementby decrby
|
106
|
+
|
107
|
+
def decr(field)
|
108
|
+
redis.hdecr field
|
109
|
+
end
|
110
|
+
alias decrement decr
|
86
111
|
|
87
112
|
def hlen
|
88
113
|
redis.hlen rediskey(suffix)
|
89
114
|
end
|
115
|
+
alias hlength hlen
|
90
116
|
|
91
117
|
def hstrlen(field)
|
92
118
|
redis.hstrlen rediskey(suffix), field
|
93
119
|
end
|
120
|
+
alias hstrlength hstrlen
|
121
|
+
|
122
|
+
def key?(field)
|
123
|
+
redis.hexists rediskey(suffix), field
|
124
|
+
end
|
125
|
+
alias has_key? key?
|
94
126
|
|
95
127
|
def delete!
|
96
128
|
Familia.trace :DELETE!, redis, redisuri, caller(1..1) if Familia.debug?
|
@@ -1,30 +1,75 @@
|
|
1
1
|
# rubocop:disable all
|
2
2
|
#
|
3
3
|
module Familia
|
4
|
-
|
5
|
-
|
6
|
-
#
|
7
|
-
# instance-level functionality for Redis operations and object management.
|
4
|
+
|
5
|
+
|
6
|
+
# Familia::Horreum
|
8
7
|
#
|
9
8
|
class Horreum
|
10
|
-
|
11
|
-
#
|
9
|
+
# Serialization: Where Objects Go to Become Strings (and Vice Versa)!
|
10
|
+
#
|
11
|
+
# This module is chock-full of methods that'll make your head spin (in a
|
12
|
+
# good way)! We've got loaders, dumpers, and refreshers galore. It's like
|
13
|
+
# a laundromat for your data, but instead of quarters, it runs on Redis commands.
|
14
|
+
#
|
15
|
+
# A Note on Our Refreshing Refreshers:
|
16
|
+
# In the wild world of Ruby, '!' usually means "Watch out! I'm dangerous!"
|
17
|
+
# But here in Familia-land, we march to the beat of a different drummer.
|
18
|
+
# Our refresh! method is the real deal, doing all the heavy lifting.
|
19
|
+
# The non-bang refresh? Oh, it's just as rowdy, but it plays nice with
|
20
|
+
# method chaining. It's like the polite twin who still knows how to party.
|
21
|
+
#
|
22
|
+
# Remember: In Familia, refreshing isn't just a chore, it's a chance to
|
23
|
+
# dance with data! Whether you bang(!) or not, you're still invited to
|
24
|
+
# the Redis disco.
|
25
|
+
#
|
26
|
+
# (P.S. If you're reading these docs, lol sorry. I asked Claude 3.5 to
|
27
|
+
# write in the style of _why the lucky stiff today and got this uncanny
|
28
|
+
# valley response. I hope you enjoy reading it as much as I did writing
|
29
|
+
# the prompt for it. - @delano).
|
30
|
+
#
|
31
|
+
# (Ahem! What I meant to say was that if you're reading this, congratulations!
|
32
|
+
# You've stumbled upon the secret garden of documentation. Feel free to smell
|
33
|
+
# the Ruby roses, but watch out for the Redis thorns!)
|
12
34
|
#
|
13
|
-
# Note on refresh methods:
|
14
|
-
# In this class, refresh! is the primary method that performs the Redis
|
15
|
-
# query and state update. The non-bang refresh method is provided as a
|
16
|
-
# convenience for method chaining, but still performs the same destructive
|
17
|
-
# update as refresh!. This deviates from common Ruby conventions to better
|
18
|
-
# fit the specific needs of this system.
|
19
35
|
module Serialization
|
20
|
-
#include Familia::RedisType::Serialization
|
21
36
|
|
22
37
|
attr_writer :redis
|
23
38
|
|
39
|
+
# Summon the mystical Redis connection from the depths of instance or class.
|
40
|
+
#
|
41
|
+
# This method is like a magical divining rod, always pointing to the nearest
|
42
|
+
# source of Redis goodness. It first checks if we have a personal Redis
|
43
|
+
# connection (@redis), and if not, it borrows the class's connection.
|
44
|
+
#
|
45
|
+
# @return [Redis] A shimmering Redis connection, ready for your bidding.
|
46
|
+
#
|
47
|
+
# @example Finding your Redis way
|
48
|
+
# puts object.redis
|
49
|
+
# # => #<Redis client v4.5.1 for redis://localhost:6379/0>
|
50
|
+
#
|
24
51
|
def redis
|
25
52
|
@redis || self.class.redis
|
26
53
|
end
|
27
54
|
|
55
|
+
# Perform a sacred Redis transaction ritual.
|
56
|
+
#
|
57
|
+
# This method creates a protective circle around your Redis operations,
|
58
|
+
# ensuring they all succeed or fail together. It's like a group hug for your
|
59
|
+
# data operations, but with more ACID properties.
|
60
|
+
#
|
61
|
+
# @yield [conn] A block where you can perform your Redis incantations.
|
62
|
+
# @yieldparam conn [Redis] A Redis connection in multi mode.
|
63
|
+
#
|
64
|
+
# @example Performing a Redis rain dance
|
65
|
+
# transaction do |conn|
|
66
|
+
# conn.set("weather", "rainy")
|
67
|
+
# conn.set("mood", "melancholic")
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# @note This method temporarily replaces your Redis connection with a multi
|
71
|
+
# connection. Don't worry, it puts everything back where it found it when it's done.
|
72
|
+
#
|
28
73
|
def transaction
|
29
74
|
original_redis = self.redis
|
30
75
|
|
@@ -38,26 +83,74 @@ module Familia
|
|
38
83
|
end
|
39
84
|
end
|
40
85
|
|
41
|
-
#
|
42
|
-
#
|
86
|
+
# Save our precious data to Redis, with a sprinkle of timestamp magic!
|
87
|
+
#
|
88
|
+
# This method is like a conscientious historian, not only recording your
|
89
|
+
# object's current state but also meticulously timestamping when it was
|
90
|
+
# created and last updated. It's the record keeper of your data's life story!
|
91
|
+
#
|
92
|
+
# @return [Boolean] true if the save was successful, false if Redis was grumpy.
|
93
|
+
#
|
94
|
+
# @example Preserving your pet rock for posterity
|
95
|
+
# rocky = PetRock.new(name: "Dwayne")
|
96
|
+
# rocky.save
|
97
|
+
# # => true (Dwayne is now immortalized in Redis)
|
98
|
+
#
|
99
|
+
# @note This method will leave breadcrumbs (traces) if you're in debug mode.
|
100
|
+
# It's like Hansel and Gretel, but for data operations!
|
101
|
+
#
|
43
102
|
def save
|
44
103
|
Familia.trace :SAVE, redis, redisuri, caller(1..1) if Familia.debug?
|
45
104
|
|
46
|
-
# Update
|
105
|
+
# Update our object's life story
|
47
106
|
self.key ||= self.identifier
|
48
107
|
self.updated = Familia.now.to_i
|
49
108
|
self.created ||= Familia.now.to_i
|
50
109
|
|
51
|
-
#
|
110
|
+
# Commit our tale to the Redis chronicles
|
52
111
|
ret = commit_fields # e.g. ["OK"]
|
53
112
|
|
54
113
|
Familia.ld "[save] #{self.class} #{rediskey} #{ret}"
|
55
114
|
|
56
|
-
#
|
57
|
-
ret.all? { |value| value == "OK" }
|
115
|
+
# Did Redis accept our offering?
|
116
|
+
ret.uniq.all? { |value| value == "OK" }
|
58
117
|
end
|
59
118
|
|
60
|
-
#
|
119
|
+
# Apply a smattering of fields to this object like fairy dust.
|
120
|
+
#
|
121
|
+
# @param fields [Hash] A magical bag of named attributes to sprinkle onto this instance.
|
122
|
+
# Each key-value pair is like a tiny spell, ready to enchant our object's properties.
|
123
|
+
#
|
124
|
+
# @return [self] Returns the newly bejeweled instance, now sparkling with fresh attributes.
|
125
|
+
#
|
126
|
+
# @example Giving your object a makeover
|
127
|
+
# dragon.apply_fields(name: "Puff", breathes: "fire", loves: "little boys named Jackie")
|
128
|
+
# # => #<Dragon:0x007f8a1c8b0a28 @name="Puff", @breathes="fire", @loves="little boys named Jackie">
|
129
|
+
#
|
130
|
+
def apply_fields(**fields)
|
131
|
+
fields.each do |field, value|
|
132
|
+
# Whisper the new value into the object's ear (if it's listening)
|
133
|
+
send("#{field}=", value) if respond_to?("#{field}=")
|
134
|
+
end
|
135
|
+
self
|
136
|
+
end
|
137
|
+
|
138
|
+
# Commit our precious fields to Redis.
|
139
|
+
#
|
140
|
+
# This method performs a sacred ritual, sending our cherished attributes
|
141
|
+
# on a journey through the ethernet to find their resting place in Redis.
|
142
|
+
#
|
143
|
+
# @return [Array<String>] A mystical array of strings, cryptic messages from the Redis gods.
|
144
|
+
#
|
145
|
+
# @note Be warned, young programmer! This method dabbles in the arcane art of transactions.
|
146
|
+
# Side effects may include data persistence and a slight tingling sensation.
|
147
|
+
#
|
148
|
+
# @example Offering your changes to the Redis deities
|
149
|
+
# unicorn.name = "Charlie"
|
150
|
+
# unicorn.horn_length = "magnificent"
|
151
|
+
# unicorn.commit_fields
|
152
|
+
# # => ["OK", "OK"] (The Redis gods are pleased with your offering)
|
153
|
+
#
|
61
154
|
def commit_fields
|
62
155
|
Familia.ld "[commit_fields] #{self.class} #{rediskey} #{to_h}"
|
63
156
|
transaction do |conn|
|
@@ -66,11 +159,31 @@ module Familia
|
|
66
159
|
end
|
67
160
|
end
|
68
161
|
|
162
|
+
# Dramatically vanquish this object from the face of Redis! (ed: delete it)
|
163
|
+
#
|
164
|
+
# This method is the doomsday device of our little data world. It will
|
165
|
+
# mercilessly eradicate all traces of our object from Redis, leaving naught
|
166
|
+
# but digital dust in its wake. Use with caution, lest you accidentally
|
167
|
+
# destroy the wrong data-verse!
|
168
|
+
#
|
169
|
+
# @return [void] Returns nothing, for nothing remains after destruction.
|
170
|
+
#
|
171
|
+
# @example Bidding a fond farewell to your pet rock
|
172
|
+
# rocky = PetRock.new(name: "Dwayne")
|
173
|
+
# rocky.destroy!
|
174
|
+
# # => *poof* Rocky is no more. A moment of silence, please.
|
175
|
+
#
|
176
|
+
# @note If debugging is enabled, this method will leave a trace of its
|
177
|
+
# destructive path, like breadcrumbs for future data archaeologists.
|
178
|
+
#
|
179
|
+
# @see #delete! The actual hitman carrying out the deed.
|
180
|
+
#
|
69
181
|
def destroy!
|
70
182
|
Familia.trace :DESTROY, redis, redisuri, caller(1..1) if Familia.debug?
|
71
183
|
delete!
|
72
184
|
end
|
73
185
|
|
186
|
+
|
74
187
|
# Refreshes the object's state by querying Redis and overwriting the
|
75
188
|
# current field values. This method performs a destructive update on the
|
76
189
|
# object, regardless of unsaved changes.
|
@@ -98,9 +211,21 @@ module Familia
|
|
98
211
|
self
|
99
212
|
end
|
100
213
|
|
214
|
+
# Transform this object into a magical hash of wonders!
|
215
|
+
#
|
216
|
+
# This method performs an alchemical transmutation, turning our noble object
|
217
|
+
# into a more plebeian hash. But fear not, for in this form, it can slip through
|
218
|
+
# the cracks of the universe (or at least, into Redis) with ease.
|
219
|
+
#
|
220
|
+
# @return [Hash] A glittering hash, each key a field name, each value a Redis-ready treasure.
|
221
|
+
#
|
222
|
+
# @example Turning your dragon into a hash
|
223
|
+
# dragon.to_h
|
224
|
+
# # => {"name"=>"Puff", "breathes"=>"fire", "age"=>1000}
|
225
|
+
#
|
226
|
+
# @note Watch in awe as each field is lovingly prepared for its Redis adventure!
|
227
|
+
#
|
101
228
|
def to_h
|
102
|
-
# Use self.class.fields to efficiently generate a hash
|
103
|
-
# of all the fields for this object
|
104
229
|
self.class.fields.inject({}) do |hsh, field|
|
105
230
|
val = send(field)
|
106
231
|
prepared = to_redis(val)
|
@@ -110,6 +235,20 @@ module Familia
|
|
110
235
|
end
|
111
236
|
end
|
112
237
|
|
238
|
+
# Line up all our attributes in a neat little array parade!
|
239
|
+
#
|
240
|
+
# This method marshals all our object's attributes into an orderly procession,
|
241
|
+
# ready to march into Redis in perfect formation. It's like a little data army,
|
242
|
+
# but friendlier and less prone to conquering neighboring databases.
|
243
|
+
#
|
244
|
+
# @return [Array] A splendid array of Redis-ready values, in the order of our fields.
|
245
|
+
#
|
246
|
+
# @example Arranging your unicorn's attributes in a line
|
247
|
+
# unicorn.to_a
|
248
|
+
# # => ["Charlie", "magnificent", 5]
|
249
|
+
#
|
250
|
+
# @note Each value is carefully disguised in its Redis costume before joining the parade.
|
251
|
+
#
|
113
252
|
def to_a
|
114
253
|
self.class.fields.map do |field|
|
115
254
|
val = send(field)
|
@@ -160,34 +299,39 @@ module Familia
|
|
160
299
|
prepared
|
161
300
|
end
|
162
301
|
|
302
|
+
# Set an expiration date for our data, like a "best before" sticker for Redis!
|
303
|
+
#
|
304
|
+
# This method gives our data a lifespan in Redis. It's like telling Redis,
|
305
|
+
# "Hey, this data is fresh now, but it might get stale after a while!"
|
306
|
+
#
|
307
|
+
# @param ttl [Integer, nil] The Time To Live in seconds. If nil, we'll check
|
308
|
+
# our options for a default expiration time.
|
309
|
+
#
|
310
|
+
# @return [Boolean] true if the expiration was set successfully, false otherwise.
|
311
|
+
# It's like asking Redis, "Did you stick that expiration label on properly?"
|
312
|
+
#
|
313
|
+
# @example Making your pet rock data mortal
|
314
|
+
# rocky.update_expiration(86400) # Dwayne will live in Redis for one day
|
315
|
+
#
|
316
|
+
# @note If the TTL is zero, we assume our data wants to live forever.
|
317
|
+
# Immortality in Redis! Who wouldn't want that?
|
318
|
+
#
|
163
319
|
def update_expiration(ttl = nil)
|
164
320
|
ttl ||= opts[:ttl]
|
165
|
-
|
321
|
+
ttl = ttl.to_i
|
166
322
|
|
167
|
-
|
168
|
-
|
323
|
+
return if ttl.zero?
|
324
|
+
|
325
|
+
Familia.ld "Setting expiration for #{rediskey} to #{ttl} seconds"
|
326
|
+
|
327
|
+
# EXPIRE command returns 1 if the timeout was set, 0 if key does not
|
328
|
+
# exist or the timeout could not be set.
|
329
|
+
expire(ttl).positive?
|
169
330
|
end
|
331
|
+
|
170
332
|
end
|
171
333
|
# End of Serialization module
|
172
334
|
|
173
335
|
include Serialization # these become Horreum instance methods
|
174
336
|
end
|
175
337
|
end
|
176
|
-
|
177
|
-
__END__
|
178
|
-
|
179
|
-
# Consider adding a retry mechanism for the refresh operation
|
180
|
-
# if it fails to fetch the expected data:
|
181
|
-
def refresh_with_retry(max_attempts = 3)
|
182
|
-
attempts = 0
|
183
|
-
base = 2
|
184
|
-
while attempts < max_attempts
|
185
|
-
refresh!
|
186
|
-
return if name == "Jane Doe" # Or whatever condition indicates a successful refresh
|
187
|
-
attempts += 1
|
188
|
-
|
189
|
-
sleep_time = 0.1 * (base ** attempts)
|
190
|
-
sleep(sleep_time) # Exponential backoff
|
191
|
-
end
|
192
|
-
raise "Failed to refresh after #{max_attempts} attempts"
|
193
|
-
end
|
@@ -60,11 +60,12 @@ module Familia
|
|
60
60
|
end
|
61
61
|
alias all hgetall
|
62
62
|
|
63
|
-
def
|
63
|
+
def key?(field)
|
64
64
|
redis.hexists rediskey, field
|
65
65
|
end
|
66
|
-
alias
|
67
|
-
alias
|
66
|
+
alias has_key? key?
|
67
|
+
alias include? key?
|
68
|
+
alias member? key?
|
68
69
|
|
69
70
|
def delete(field)
|
70
71
|
redis.hdel rediskey, field
|
data/lib/familia/types/list.rb
CHANGED
@@ -18,6 +18,7 @@ module Familia
|
|
18
18
|
update_expiration
|
19
19
|
self
|
20
20
|
end
|
21
|
+
alias append push
|
21
22
|
|
22
23
|
def <<(val)
|
23
24
|
push val
|
@@ -31,6 +32,7 @@ module Familia
|
|
31
32
|
update_expiration
|
32
33
|
self
|
33
34
|
end
|
35
|
+
alias prepend unshift
|
34
36
|
|
35
37
|
def pop
|
36
38
|
from_redis redis.rpop(rediskey)
|