familia 1.0.0.pre.rc2 → 1.0.0.pre.rc4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +198 -48
- data/VERSION.yml +1 -1
- data/lib/familia/base.rb +29 -1
- data/lib/familia/features/expiration.rb +90 -0
- data/lib/familia/features/quantization.rb +56 -0
- data/lib/familia/features/safe_dump.rb +2 -33
- data/lib/familia/features.rb +5 -4
- data/lib/familia/horreum/class_methods.rb +172 -53
- data/lib/familia/horreum/commands.rb +43 -5
- data/lib/familia/horreum/relations_management.rb +2 -2
- data/lib/familia/horreum/serialization.rb +172 -47
- data/lib/familia/horreum/settings.rb +0 -8
- data/lib/familia/horreum/utils.rb +0 -1
- data/lib/familia/horreum.rb +1 -1
- data/lib/familia/logging.rb +26 -4
- data/lib/familia/redistype/serialization.rb +60 -38
- data/lib/familia/redistype.rb +45 -17
- data/lib/familia/settings.rb +11 -1
- data/lib/familia/tools.rb +68 -0
- data/lib/familia/types/hashkey.rb +9 -8
- data/lib/familia/types/list.rb +4 -2
- data/lib/familia/types/sorted_set.rb +12 -12
- data/lib/familia/types/string.rb +1 -1
- data/lib/familia/types/unsorted_set.rb +2 -2
- data/lib/familia/utils.rb +106 -51
- data/lib/familia/version.rb +2 -2
- data/try/10_familia_try.rb +4 -4
- data/try/20_redis_type_try.rb +9 -6
- data/try/26_redis_bool_try.rb +1 -1
- data/try/27_redis_horreum_try.rb +1 -1
- data/try/30_familia_object_try.rb +3 -2
- data/try/40_customer_try.rb +3 -3
- data/try/test_helpers.rb +9 -2
- metadata +5 -5
- data/lib/familia/features/api_version.rb +0 -19
- data/lib/familia/features/atomic_saves.rb +0 -8
- data/lib/familia/features/quantizer.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b514a58bc45692f39123cce853a679078eccd78362a78facc397a1df6d94629d
|
4
|
+
data.tar.gz: d29686d172bec525bee366ab54ad4e81a5903547a9a2d98c68df8ca81853c7dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd750e1ee120eb666563e9c8c552f721926ccceaa032cd0cefcf4fad7920225ab1edc4961cf3a5a7c38d81ecab3c21b446e91a75347d51a4bc196c14f5ed94fd
|
7
|
+
data.tar.gz: 6c52919952e7ce8232cf1023fafe567655580a73e4d36dd0a38b8842cb618387272db6950380f71efa01797439d9542303d3addd8c94e841255923998b93589f
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,84 +1,234 @@
|
|
1
|
-
# Familia - 1.0.0-
|
1
|
+
# Familia - 1.0.0-rc4 (August 2024)
|
2
2
|
|
3
|
-
**Organize and store
|
3
|
+
**Organize and store Ruby objects in Redis. A powerful Ruby ORM (of sorts) for Redis.**
|
4
4
|
|
5
|
-
Familia provides a
|
5
|
+
Familia provides a flexible and feature-rich way to interact with Redis using Ruby objects. It's designed to make working with Redis as natural as working with Ruby classes, while offering advanced features for complex data management.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
+
|
9
10
|
Get it in one of the following ways:
|
10
11
|
|
11
|
-
* In your Gemfile: `gem 'familia', '>= 1.0.0-
|
12
|
-
* Install it by hand: `gem install familia`
|
12
|
+
* In your Gemfile: `gem 'familia', '>= 1.0.0-rc4'`
|
13
|
+
* Install it by hand: `gem install familia --pre`
|
13
14
|
* Or for development: `git clone git@github.com:delano/familia.git`
|
14
15
|
|
15
|
-
|
16
|
+
|
17
|
+
## Core Concepts and Features
|
18
|
+
|
19
|
+
### 1. Defining Horreum Classes
|
20
|
+
|
21
|
+
Familia uses the concept of "Horreum" classes to represent Redis-backed objects:
|
16
22
|
|
17
23
|
```ruby
|
18
24
|
class Flower < Familia::Horreum
|
19
|
-
identifier :
|
20
|
-
field
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
zset :metrics
|
25
|
+
identifier :token
|
26
|
+
field :name
|
27
|
+
list :owners
|
28
|
+
set :tags
|
29
|
+
zset :metrics
|
25
30
|
hashkey :props
|
26
|
-
string
|
31
|
+
string :counter
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
### 2. Flexible Identifiers
|
36
|
+
|
37
|
+
You can define identifiers in various ways:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class User < Familia::Horreum
|
41
|
+
identifier :email
|
42
|
+
# or
|
43
|
+
identifier -> (user) { "user:#{user.email}" }
|
44
|
+
# or
|
45
|
+
identifier [:type, :email]
|
46
|
+
|
47
|
+
field :email
|
48
|
+
field :type
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
### 3. Redis Data Types
|
53
|
+
|
54
|
+
Familia supports various Redis data types:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
class Product < Familia::Horreum
|
58
|
+
string :name
|
59
|
+
list :categories
|
60
|
+
set :tags
|
61
|
+
zset :ratings
|
62
|
+
hashkey :attributes
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
### 4. Class-level Redis Types
|
67
|
+
|
68
|
+
You can also define Redis types at the class level:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
class Customer < Familia::Horreum
|
72
|
+
class_sorted_set :values, key: 'project:customers'
|
73
|
+
class_hashkey :projects
|
74
|
+
class_list :customers, suffix: []
|
75
|
+
class_string :message
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
### 5. Automatic Expiration
|
80
|
+
|
81
|
+
Use the expiration feature to set TTL for objects:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
class Session < Familia::Horreum
|
85
|
+
feature :expiration
|
86
|
+
ttl 180.minutes
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
90
|
+
### 6. Safe Dumping for APIs
|
91
|
+
|
92
|
+
Control which fields are exposed when serializing objects:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
class User < Familia::Horreum
|
96
|
+
feature :safe_dump
|
97
|
+
|
98
|
+
@safe_dump_fields = [
|
99
|
+
:id,
|
100
|
+
:username,
|
101
|
+
{full_name: ->(user) { "#{user.first_name} #{user.last_name}" }}
|
102
|
+
]
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
### 7. Quantization for Time-based Data
|
107
|
+
|
108
|
+
Use quantization for time-based metrics:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
class DailyMetric < Familia::Horreum
|
112
|
+
feature :quantization
|
113
|
+
string :counter, ttl: 1.day, quantize: [10.minutes, '%H:%M']
|
27
114
|
end
|
28
115
|
```
|
29
116
|
|
30
|
-
|
117
|
+
### 8. Custom Methods and Logic
|
31
118
|
|
32
|
-
|
119
|
+
Add custom methods to your Horreum classes:
|
33
120
|
|
34
|
-
|
121
|
+
```ruby
|
122
|
+
class User < Familia::Horreum
|
123
|
+
def full_name
|
124
|
+
"#{first_name} #{last_name}"
|
125
|
+
end
|
126
|
+
|
127
|
+
def active?
|
128
|
+
status == 'active'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
```
|
35
132
|
|
36
|
-
|
37
|
-
- `field`: For simple key-value pairs
|
38
|
-
- `list`: For Redis lists
|
39
|
-
- `set`: For Redis sets
|
40
|
-
- `zset`: For Redis sorted sets
|
41
|
-
- `hashkey`: For Redis hashes
|
42
|
-
- `string`: For Redis strings
|
133
|
+
### 9. Custom Methods and Logic
|
43
134
|
|
44
|
-
|
135
|
+
You can add custom methods to your Horreum classes:
|
45
136
|
|
46
|
-
|
137
|
+
```ruby
|
138
|
+
class Customer < Familia::Horreum
|
139
|
+
def active?
|
140
|
+
verified && !reset_requested
|
141
|
+
end
|
142
|
+
end
|
47
143
|
|
48
|
-
|
144
|
+
class Session < Familia::Horreum
|
145
|
+
def external_identifier
|
146
|
+
elements = [ipaddress || 'UNKNOWNIP', custid || 'anon']
|
147
|
+
@external_identifier ||= Familia.generate_sha_hash(elements)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
```
|
151
|
+
### 10. Open-ended Serialization
|
49
152
|
|
50
|
-
|
153
|
+
```ruby
|
154
|
+
class ComplexObject < Familia::Horreum
|
155
|
+
def to_redis
|
156
|
+
custom_serialization_method
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.from_redis(data)
|
160
|
+
custom_deserialization_method(data)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
```
|
51
164
|
|
52
|
-
|
165
|
+
### 11. Transactional Operations
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
user.transaction do |conn|
|
169
|
+
conn.set("user:#{user.id}:status", "active")
|
170
|
+
conn.zadd("active_users", Time.now.to_i, user.id)
|
171
|
+
end
|
172
|
+
```
|
53
173
|
|
54
|
-
## Advanced Features
|
55
174
|
|
56
|
-
|
57
|
-
- **Custom Serialization**: You can specify custom serialization methods for your objects.
|
58
|
-
- **Redis URI Support**: Easily connect to Redis using URI strings.
|
59
|
-
- **Debugging Tools**: Built-in debugging capabilities to help troubleshoot Redis interactions.
|
175
|
+
## Usage Examples
|
60
176
|
|
61
|
-
|
177
|
+
### Creating and Saving Objects
|
62
178
|
|
63
179
|
```ruby
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
180
|
+
flower = Flower.create(name: "Red Rose", token: "rrose")
|
181
|
+
flower.owners.push("Alice", "Bob")
|
182
|
+
flower.tags.add("romantic")
|
183
|
+
flower.metrics.increment("views", 1)
|
184
|
+
flower.props[:color] = "red"
|
185
|
+
flower.save
|
186
|
+
```
|
187
|
+
|
188
|
+
### Retrieving and Updating Objects
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
rose = Flower.from_identifier("rrose")
|
192
|
+
rose.name = "Pink Rose"
|
69
193
|
rose.save
|
194
|
+
```
|
195
|
+
|
196
|
+
### Using Safe Dump
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
user = User.create(username: "rosedog", first_name: "Rose", last_name: "Dog")
|
200
|
+
user.safe_dump
|
201
|
+
# => {id: "user:rosedog", username: "rosedog", full_name: "Rose Dog"}
|
202
|
+
```
|
203
|
+
|
204
|
+
### Working with Time-based Data
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
metric = DailyMetric.new
|
208
|
+
metric.counter.increment # Increments the counter for the current hour
|
209
|
+
```
|
210
|
+
|
211
|
+
### Bulk Operations
|
70
212
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
213
|
+
```ruby
|
214
|
+
Flower.multiget("rrose", "tulip", "daisy")
|
215
|
+
```
|
216
|
+
|
217
|
+
### Transactional Operations
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
user.transaction do |conn|
|
221
|
+
conn.set("user:#{user.id}:status", "active")
|
222
|
+
conn.zadd("active_users", Time.now.to_i, user.id)
|
223
|
+
end
|
75
224
|
```
|
76
225
|
|
77
|
-
##
|
226
|
+
## Conclusion
|
78
227
|
|
79
|
-
|
80
|
-
* [Rubygems](https://rubygems.org/gems/familia)
|
228
|
+
Familia provides a powerful and flexible way to work with Redis in Ruby applications. Its features like automatic expiration, safe dumping, and quantization make it suitable for a wide range of use cases, from simple key-value storage to complex time-series data management.
|
81
229
|
|
82
|
-
|
230
|
+
For more information, visit:
|
231
|
+
- [Github Repository](https://github.com/delano/familia)
|
232
|
+
- [RubyGems Page](https://rubygems.org/gems/familia)
|
83
233
|
|
84
|
-
Contributions are welcome!
|
234
|
+
Contributions are welcome! Feel free to submit a Pull Request.
|
data/VERSION.yml
CHANGED
data/lib/familia/base.rb
CHANGED
@@ -24,10 +24,38 @@ module Familia
|
|
24
24
|
|
25
25
|
def add_feature(klass, methname)
|
26
26
|
@features ||= {}
|
27
|
-
Familia.ld "[#{self}] Adding feature #{klass} as #{methname}"
|
27
|
+
Familia.ld "[#{self}] Adding feature #{klass} as #{methname.inspect}"
|
28
28
|
|
29
29
|
features[methname] = klass
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
# Yo, this class is like that one friend who never checks expiration dates.
|
34
|
+
# It's living life on the edge, data-style!
|
35
|
+
#
|
36
|
+
# @param ttl [Integer, nil] Time To Live? More like Time To Laugh! This param
|
37
|
+
# is here for compatibility, but it's as useful as a chocolate teapot.
|
38
|
+
#
|
39
|
+
# @return [nil] Always returns nil. It's consistent in its laziness!
|
40
|
+
#
|
41
|
+
# @example Trying to teach an old dog new tricks
|
42
|
+
# immortal_data.update_expiration(86400) # Nice try, but this data is here to stay!
|
43
|
+
#
|
44
|
+
# @note This method is a no-op. It's like shouting into the void, but less echo-y.
|
45
|
+
#
|
46
|
+
def update_expiration(_ = nil)
|
47
|
+
Familia.info "[update_expiration] Skipped for #{rediskey}. #{self.class} data is immortal!"
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def generate_id
|
52
|
+
@key ||= Familia.generate_id
|
53
|
+
@key
|
54
|
+
end
|
55
|
+
|
56
|
+
def uuid
|
57
|
+
@uuid ||= SecureRandom.uuid
|
58
|
+
@uuid
|
59
|
+
end
|
32
60
|
end
|
33
61
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# rubocop:disable all
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
|
5
|
+
module Familia::Features
|
6
|
+
#
|
7
|
+
module Expiration
|
8
|
+
@ttl = nil
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
attr_writer :ttl
|
13
|
+
|
14
|
+
def ttl(v = nil)
|
15
|
+
@ttl = v.to_f unless v.nil?
|
16
|
+
@ttl || parent&.ttl || Familia.ttl
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.included base
|
22
|
+
Familia.ld "[#{base}] Loaded #{self}"
|
23
|
+
base.extend ClassMethods
|
24
|
+
|
25
|
+
# Optionally define ttl in the class to make
|
26
|
+
# sure we always have an array to work with.
|
27
|
+
unless base.instance_variable_defined?(:@ttl)
|
28
|
+
base.instance_variable_set(:@ttl, @ttl) # set above
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def ttl=(v)
|
33
|
+
@ttl = v.to_f
|
34
|
+
end
|
35
|
+
|
36
|
+
def ttl
|
37
|
+
@ttl || self.class.ttl
|
38
|
+
end
|
39
|
+
|
40
|
+
# Yo, check it out! We're gonna give our Redis data an expiration date!
|
41
|
+
#
|
42
|
+
# It's like slapping a "Best Before" sticker on your favorite snack,
|
43
|
+
# but for data. How cool is that?
|
44
|
+
#
|
45
|
+
# @param ttl [Integer, nil] The Time To Live in seconds. Nil? No worries!
|
46
|
+
# We'll dig up the default from our secret stash.
|
47
|
+
#
|
48
|
+
# @return [Boolean] Did Redis pin that expiry note successfully?
|
49
|
+
# True for "Yep!", false for "Oops, butter fingers!"
|
50
|
+
#
|
51
|
+
# @example Teaching your pet rock the concept of mortality
|
52
|
+
# rocky.update_expiration(86400) # Dwayne gets to party in Redis for one whole day!
|
53
|
+
#
|
54
|
+
# @note If TTL is zero, your data gets a VIP pass to the Redis eternity club.
|
55
|
+
# Fancy, huh?
|
56
|
+
#
|
57
|
+
# @raise [Familia::Problem] If you try to feed it non-numbers or time-travel
|
58
|
+
# (negative numbers). It's strict, but fair!
|
59
|
+
#
|
60
|
+
def update_expiration(ttl = nil)
|
61
|
+
ttl ||= self.ttl
|
62
|
+
# It's important to raise exceptions here and not just log warnings. We
|
63
|
+
# don't want to silently fail at setting expirations and cause data
|
64
|
+
# retention issues (e.g. not removed in a timely fashion).
|
65
|
+
#
|
66
|
+
# For the same reason, we don't want to default to 0 bc there's not a
|
67
|
+
# good reason for the ttl to not be set in the first place. If the
|
68
|
+
# class doesn't have a ttl, the default comes from Familia.ttl (which
|
69
|
+
# is 0).
|
70
|
+
raise Familia::Problem, "TTL must be a number (#{ttl.class})" unless ttl.is_a?(Numeric)
|
71
|
+
raise Familia::Problem, "TTL must be positive (#{ttl})" unless ttl.is_a?(Numeric)
|
72
|
+
|
73
|
+
if ttl.zero?
|
74
|
+
return Familia.ld "[update_expiration] No expiration for #{self.class} (#{rediskey})"
|
75
|
+
end
|
76
|
+
|
77
|
+
Familia.info "[update_expiration] Expires #{rediskey} in #{ttl} seconds"
|
78
|
+
|
79
|
+
# Redis' EXPIRE command returns 1 if the timeout was set, 0 if key does
|
80
|
+
# not exist or the timeout could not be set. Via redis-rb here, it's
|
81
|
+
# a bool.
|
82
|
+
expire(ttl)
|
83
|
+
end
|
84
|
+
|
85
|
+
extend ClassMethods
|
86
|
+
|
87
|
+
Familia::Base.add_feature self, :expiration
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# rubocop:disable all
|
2
|
+
|
3
|
+
module Familia::Features
|
4
|
+
|
5
|
+
module Quantization
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Generates a quantized timestamp based on the given parameters.
|
9
|
+
#
|
10
|
+
# @param quantum [Integer, Array, nil] The time quantum in seconds or an array of [quantum, pattern].
|
11
|
+
# @param pattern [String, nil] The strftime pattern to format the timestamp.
|
12
|
+
# @param now [Time, nil] The current time (default: Familia.now).
|
13
|
+
# @return [Integer, String] A unix timestamp or formatted timestamp string.
|
14
|
+
#
|
15
|
+
# This method rounds the current time to the nearest quantum and optionally formats it
|
16
|
+
# according to the given pattern. It's useful for creating time-based buckets
|
17
|
+
# or keys with reduced granularity.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# User.qstamp(1.hour, '%Y%m%d%H') # Returns a string like "2023060114" for 2:30 PM
|
21
|
+
# User.qstamp(10.minutes) # Returns an integer timestamp rounded to the nearest 10 minutes
|
22
|
+
# User.qstamp([1.hour, '%Y%m%d%H']) # Same as the first example
|
23
|
+
#
|
24
|
+
# @raise [ArgumentError] If quantum is not positive
|
25
|
+
#
|
26
|
+
def qstamp(quantum = nil, pattern: nil, time: nil)
|
27
|
+
# Handle default values and array input
|
28
|
+
if quantum.is_a?(Array)
|
29
|
+
quantum, pattern = quantum
|
30
|
+
end
|
31
|
+
quantum ||= @opts[:quantize] || ttl || 10.minutes
|
32
|
+
|
33
|
+
# Validate quantum
|
34
|
+
unless quantum.is_a?(Numeric) && quantum.positive?
|
35
|
+
raise ArgumentError, "Quantum must be positive (#{quantum.inspect} given)"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Call Familia.qstamp with our processed parameters
|
39
|
+
Familia.qstamp(quantum, pattern: pattern, time: time)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.included base
|
44
|
+
Familia.ld "[#{base}] Loaded #{self}"
|
45
|
+
base.extend ClassMethods
|
46
|
+
end
|
47
|
+
|
48
|
+
def qstamp(quantum = nil, pattern: nil, time: nil)
|
49
|
+
self.class.qstamp(quantum || ttl, pattern: pattern, time: time)
|
50
|
+
end
|
51
|
+
|
52
|
+
extend ClassMethods
|
53
|
+
|
54
|
+
Familia::Base.add_feature self, :quantization
|
55
|
+
end
|
56
|
+
end
|
@@ -102,7 +102,7 @@ module Familia::Features
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def self.included base
|
105
|
-
Familia.ld "[
|
105
|
+
Familia.ld "[#{self}] Enabled in #{base}"
|
106
106
|
base.extend ClassMethods
|
107
107
|
|
108
108
|
# Optionally define safe_dump_fields in the class to make
|
@@ -159,36 +159,5 @@ module Familia::Features
|
|
159
159
|
|
160
160
|
Familia::Base.add_feature self, :safe_dump
|
161
161
|
end
|
162
|
-
|
163
|
-
end
|
164
|
-
|
165
|
-
|
166
|
-
__END__
|
167
|
-
|
168
|
-
# Some leftovers related to dump_method and load_method
|
169
|
-
|
170
|
-
if value_to_distunguish.is_a?(Familia::Horreum)
|
171
|
-
Familia.trace :DISTINGUISHER, redis, "horreum", caller(1..1) if Familia.debug?
|
172
|
-
value_to_distunguish.identifier
|
173
|
-
elsif dump_method && value_to_distunguish.respond_to?(dump_method)
|
174
|
-
Familia.trace :DISTINGUISHER, redis, "#{value_to_distunguish.class}##{dump_method}", caller(1..1) if Familia.debug?
|
175
|
-
value_to_distunguish.send(dump_method)
|
176
|
-
else
|
177
|
-
if dump_method
|
178
|
-
msg = if dump_method.to_s.empty?
|
179
|
-
"No dump_method available for #{value_to_distunguish.class}"
|
180
|
-
else
|
181
|
-
"No such method: #{value_to_distunguish.class}##{dump_method}"
|
182
|
-
end
|
183
|
-
raise Familia::Problem, msg
|
184
|
-
else
|
185
|
-
Familia.trace :DISTINGUISHER, redis, "else", caller(1..1) if Familia.debug?
|
186
|
-
nil
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
|
191
|
-
if ret.nil? && dump_method && val.respond_to?(dump_method)
|
192
|
-
Familia.trace :TOREDIS, redis, "#{val.class}##{dump_method}", caller(1..1) if Familia.debug?
|
193
|
-
val.send dump_method
|
162
|
+
# end SafeDump
|
194
163
|
end
|
data/lib/familia/features.rb
CHANGED
@@ -2,17 +2,14 @@
|
|
2
2
|
|
3
3
|
module Familia
|
4
4
|
|
5
|
-
@features_enabled = nil
|
6
|
-
|
7
5
|
module Features
|
8
6
|
|
7
|
+
@features_enabled = nil
|
9
8
|
attr_reader :features_enabled
|
10
9
|
|
11
10
|
def feature(val = nil)
|
12
11
|
@features_enabled ||= []
|
13
12
|
|
14
|
-
Familia.ld "[Familia::Settings] feature: #{val.inspect}"
|
15
|
-
|
16
13
|
# If there's a value provied check that it's a valid feature
|
17
14
|
if val
|
18
15
|
val = val.to_sym
|
@@ -24,6 +21,8 @@ module Familia
|
|
24
21
|
return
|
25
22
|
end
|
26
23
|
|
24
|
+
Familia.trace :FEATURE, nil, "#{self} includes #{val.inspect}", caller(1..1) if Familia.debug?
|
25
|
+
|
27
26
|
klass = Familia::Base.features[val]
|
28
27
|
|
29
28
|
# Extend the Familia::Base subclass (e.g. Customer) with the feature module
|
@@ -48,4 +47,6 @@ module Familia
|
|
48
47
|
|
49
48
|
end
|
50
49
|
|
50
|
+
require_relative 'features/expiration'
|
51
|
+
require_relative 'features/quantization'
|
51
52
|
require_relative 'features/safe_dump'
|