kredis 1.3.0.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6042f4320cf89f8b0eae1ce4c8daa61ee6821775b7fdeab02777673a25b2cba1
4
- data.tar.gz: 67121a89444ffd7f8e0a1636fc6651a2851bbc5b63514a23413136bca2abd22d
3
+ metadata.gz: c7b578a8b9d0b956e519c324d7ba9dd6036124637801366d9f1a2719a7d340d5
4
+ data.tar.gz: a4bc7d1a74540a7bd41691105833123bffd27ff32f07b01ce82986820d6068e3
5
5
  SHA512:
6
- metadata.gz: 81888671af0fb781788d890640142da0f36bf03589d628ec2aaeca1d86608d9602282a9b9955e0c496cd47be01d4f4e3e42d47ac9d9414949ca635c2768177b8
7
- data.tar.gz: eb7f0f1896bf2c27c4fa5630d43db65c8fcf183de9be5709146a3d06d183afdc33873f705a57dbbea5c58c2ca826758a82bd84ef81dfd320ca1d2a5c1c5eef1a
6
+ metadata.gz: 5ca284918aa9079b5265f1603a9ff33c7fe6f562b4cf76a97ce571542a7dccb9265d2d94441b578570729e415d0ea1adf29786612a31635660cebe82917172df
7
+ data.tar.gz: 569e06a45f6696800372a6f11a953e12267faf009596767366a860c0f6f691c40668d5a0e94ea7cd0c9bf09370870bca209a3e9081d8f0489be79fce64864ae1
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2020 Basecamp
1
+ Copyright (c) 2020-2025 37signals LLC
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
17
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -21,11 +21,11 @@ integer.value = 5 # => SET myinteger "5"
21
21
  5 == integer.value # => GET myinteger
22
22
 
23
23
  decimal = Kredis.decimal "mydecimal" # accuracy!
24
- decimal.value = "%.47f" % (1.0/10) # => SET mydecimal "0.10000000000000000555111512312578270211815834045"
24
+ decimal.value = "%.47f" % (1.0 / 10) # => SET mydecimal "0.10000000000000000555111512312578270211815834045"
25
25
  BigDecimal("0.10000000000000000555111512312578270211815834045e0") == decimal.value # => GET mydecimal
26
26
 
27
27
  float = Kredis.float "myfloat" # speed!
28
- float.value = 1.0/10 # => SET myfloat "0.1"
28
+ float.value = 1.0 / 10 # => SET myfloat "0.1"
29
29
  0.1 == float.value # => GET myfloat
30
30
 
31
31
  boolean = Kredis.boolean "myboolean"
@@ -48,11 +48,13 @@ There are data structures for counters, enums, flags, lists, unique lists, sets,
48
48
  list = Kredis.list "mylist"
49
49
  list << "hello world!" # => RPUSH mylist "hello world!"
50
50
  [ "hello world!" ] == list.elements # => LRANGE mylist 0, -1
51
+ list.clear # => DEL mylist
51
52
 
52
- integer_list = Kredis.list "myintegerlist", typed: :integer
53
- integer_list.append([ 1, 2, 3 ]) # => RPUSH myintegerlist "1" "2" "3"
54
- integer_list << 4 # => RPUSH myintegerlist "4"
55
- [ 1, 2, 3, 4 ] == integer_list.elements # => LRANGE myintegerlist 0 -1
53
+ integer_list = Kredis.list "myintegerlist", typed: :integer, default: [ 1, 2, 3 ] # => EXISTS? myintegerlist, RPUSH myintegerlist "1" "2" "3"
54
+ integer_list.append([ 4, 5, 6 ]) # => RPUSH myintegerlist "4" "5" "6"
55
+ integer_list << 7 # => RPUSH myintegerlist "7"
56
+ [ 1, 2, 3, 4, 5, 6, 7 ] == integer_list.elements # => LRANGE myintegerlist 0 -1
57
+ integer_list.clear # => DEL myintegerlist
56
58
 
57
59
  unique_list = Kredis.unique_list "myuniquelist"
58
60
  unique_list.append(%w[ 2 3 4 ]) # => LREM myuniquelist 0, "2" + LREM myuniquelist 0, "3" + LREM myuniquelist 0, "4" + RPUSH myuniquelist "2", "3", "4"
@@ -61,12 +63,22 @@ unique_list.append([])
61
63
  unique_list << "5" # => LREM myuniquelist 0, "5" + RPUSH myuniquelist "5"
62
64
  unique_list.remove(3) # => LREM myuniquelist 0, "3"
63
65
  [ "4", "2", "1", "5" ] == unique_list.elements # => LRANGE myuniquelist 0, -1
66
+ unique_list.clear # => DEL myuniquelist
67
+
68
+ ordered_set = Kredis.ordered_set "myorderedset"
69
+ ordered_set.append(%w[ 2 3 4 ]) # => ZADD myorderedset 1646131025.4953232 2 1646131025.495326 3 1646131025.4953272 4
70
+ ordered_set.prepend(%w[ 1 2 3 4 ]) # => ZADD myorderedset -1646131025.4957051 1 -1646131025.495707 2 -1646131025.4957082 3 -1646131025.4957092 4
71
+ ordered_set.append([])
72
+ ordered_set << "5" # => ZADD myorderedset 1646131025.4960442 5
73
+ ordered_set.remove(3) # => ZREM myorderedset 3
74
+ [ "4", "2", "1", "5" ] == ordered_set.elements # => ZRANGE myorderedset 0 -1
64
75
 
65
76
  set = Kredis.set "myset", typed: :datetime
66
77
  set.add(DateTime.tomorrow, DateTime.yesterday) # => SADD myset "2021-02-03 00:00:00 +0100" "2021-02-01 00:00:00 +0100"
67
78
  set << DateTime.tomorrow # => SADD myset "2021-02-03 00:00:00 +0100"
68
79
  2 == set.size # => SCARD myset
69
80
  [ DateTime.tomorrow, DateTime.yesterday ] == set.members # => SMEMBERS myset
81
+ set.clear # => DEL myset
70
82
 
71
83
  hash = Kredis.hash "myhash"
72
84
  hash.update("key" => "value", "key2" => "value2") # => HSET myhash "key", "value", "key2", "value2"
@@ -94,6 +106,7 @@ counter.increment by: 2 # => SET mycounter 0 EX 5 NX + INCRBY "mycounter
94
106
  2 == counter.value # => GET "mycounter"
95
107
  sleep 6.seconds
96
108
  0 == counter.value # => GET "mycounter"
109
+ counter.reset # => DEL mycounter
97
110
 
98
111
  cycle = Kredis.cycle "mycycle", values: %i[ one two three ]
99
112
  :one == cycle.value # => GET mycycle
@@ -103,6 +116,7 @@ cycle.next # => GET mycycle + SET mycycle 2
103
116
  :three == cycle.value # => GET mycycle
104
117
  cycle.next # => GET mycycle + SET mycycle 0
105
118
  :one == cycle.value # => GET mycycle
119
+ cycle.reset # => DEL mycycle
106
120
 
107
121
  enum = Kredis.enum "myenum", values: %w[ one two three ], default: "one"
108
122
  "one" == enum.value # => GET myenum
@@ -153,18 +167,22 @@ sleep 0.5.seconds
153
167
  true == flag.marked? #=> EXISTS myflag
154
168
  sleep 0.6.seconds
155
169
  false == flag.marked? #=> EXISTS myflag
156
- ```
157
-
158
- And using structures on a different than the default `shared` redis instance, relying on `config/redis/secondary.yml`:
159
170
 
160
- ```ruby
161
- one_string = Kredis.string "mystring"
162
- two_string = Kredis.string "mystring", config: :secondary
163
-
164
- one_string.value = "just on shared"
165
- two_string.value != one_string.value
171
+ limiter = Kredis.limiter "mylimit", limit: 3, expires_in: 5.seconds
172
+ 0 == limiter.value # => GET "limiter"
173
+ limiter.poke # => SET limiter 0 NX + INCRBY limiter 1
174
+ limiter.poke # => SET limiter 0 NX + INCRBY limiter 1
175
+ false == limiter.exceeded? # => GET "limiter"
176
+ limiter.poke # => SET limiter 0 NX + INCRBY limiter 1
177
+ true == limiter.exceeded? # => GET "limiter"
178
+ sleep 6
179
+ limiter.poke # => SET limiter 0 NX + INCRBY limiter 1
180
+ limiter.poke # => SET limiter 0 NX + INCRBY limiter 1
181
+ false == limiter.exceeded? # => GET "limiter"
166
182
  ```
167
183
 
184
+ ### Models
185
+
168
186
  You can use all these structures in models:
169
187
 
170
188
  ```ruby
@@ -189,6 +207,29 @@ person.morning.value = "blue" # => SET people:5:morning
189
207
  true == person.morning.blue? # => GET people:5:morning
190
208
  ```
191
209
 
210
+ ### Default values
211
+
212
+ You can set a default value for all types. For example:
213
+
214
+ ```ruby
215
+ list = Kredis.list "favorite_colors", default: [ "red", "green", "blue" ]
216
+
217
+ # or, in a model
218
+ class Person < ApplicationRecord
219
+ kredis_string :name, default: "Unknown"
220
+ kredis_list :favorite_colors, default: [ "red", "green", "blue" ]
221
+ end
222
+ ```
223
+
224
+ There's a performance overhead to consider though. When you first read or write an attribute in a model, Kredis will
225
+ check if the underlying Redis key exists, while watching for concurrent changes, and if it does not,
226
+ write the specified default value.
227
+
228
+ This means that using default values in a typical Rails app additional Redis calls (WATCH, EXISTS, UNWATCH) will be
229
+ executed for each Kredis attribute with a default value read or written during a request.
230
+
231
+ ### Callbacks
232
+
192
233
  You can also define `after_change` callbacks that trigger on mutations:
193
234
 
194
235
  ```ruby
@@ -201,6 +242,18 @@ class Person < ApplicationRecord
201
242
  end
202
243
  ```
203
244
 
245
+ ### Multiple Redis servers
246
+
247
+ And using structures on a different than the default `shared` redis instance, relying on `config/redis/secondary.yml`:
248
+
249
+ ```ruby
250
+ one_string = Kredis.string "mystring"
251
+ two_string = Kredis.string "mystring", config: :secondary
252
+
253
+ one_string.value = "just on shared"
254
+ two_string.value != one_string.value
255
+ ```
256
+
204
257
  ## Installation
205
258
 
206
259
  1. Run `./bin/bundle add kredis`
@@ -210,9 +263,11 @@ Additional configurations can be added under `config/redis/*.yml` and referenced
210
263
 
211
264
  Kredis passes the configuration to `Redis.new` to establish the connection. See the [Redis documentation](https://github.com/redis/redis-rb) for other configuration options.
212
265
 
266
+ If you don't have `config/redis/shared.yml` (or use another named configuration), Kredis will default to look in env for `REDIS_URL`, then fallback to a default URL of `redis://127.0.0.1:6379/0`.
267
+
213
268
  ### Redis support
214
269
 
215
- Kredis works with Redis server 4.0+, with the [Redis Ruby](https://github.com/redis/redis-rb) client version 4.2+.
270
+ Kredis works with Redis server 4.0+, with the [Redis Ruby](https://github.com/redis/redis-rb) client version 4.2+. Redis Cluster is not supported.
216
271
 
217
272
  ### Setting SSL options on Redis Connections
218
273
 
@@ -220,14 +275,14 @@ If you need to connect to Redis with SSL, the recommended approach is to set you
220
275
 
221
276
  ```ruby
222
277
  Kredis::Connections.connections[:shared] = Redis.new(
223
- url: ENV['REDIS_URL'],
278
+ url: ENV["REDIS_URL"],
224
279
  ssl_params: {
225
280
  cert_store: OpenSSL::X509::Store.new.tap { |store|
226
- store.add_file(Rails.root.join('config', 'ca_cert.pem').to_s)
281
+ store.add_file(Rails.root.join("config", "ca_cert.pem").to_s)
227
282
  },
228
283
 
229
284
  cert: OpenSSL::X509::Certificate.new(File.read(
230
- Rails.root.join('config', 'client.crt')
285
+ Rails.root.join("config", "client.crt")
231
286
  )),
232
287
 
233
288
  key: OpenSSL::PKey::RSA.new(
@@ -251,6 +306,29 @@ config.kredis.connector = ->(config) { SomeRedisProxy.new(config) }
251
306
 
252
307
  By default Kredis will use `Redis.new(config)`.
253
308
 
309
+ ## Development
310
+
311
+ A development console is available by running `bin/console`.
312
+
313
+ From there, you can experiment with Kredis. e.g.
314
+
315
+ ```erb
316
+ >> str = Kredis.string "mystring"
317
+ Kredis (0.1ms) Connected to shared
318
+ =>
319
+ #<Kredis::Types::Scalar:0x0000000134c7d938
320
+ ...
321
+ >> str.value = "hello, world"
322
+ Kredis Proxy (2.4ms) SET mystring ["hello, world"]
323
+ => "hello, world"
324
+ >> str.value
325
+ ```
326
+
327
+ Run tests with `bin/test`.
328
+
329
+ [`debug`](https://github.com/ruby/debug) can be used in the development console and in the test suite by inserting a
330
+ breakpoint, e.g. `debugger`.
331
+
254
332
  ## License
255
333
 
256
334
  Kredis is released under the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  yaml_path = Rails.root.join("config/redis/shared.yml")
2
4
  unless yaml_path.exist?
3
5
  say "Adding `config/redis/shared.yml`"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kredis::Attributes
2
4
  extend ActiveSupport::Concern
3
5
 
@@ -6,52 +8,56 @@ module Kredis::Attributes
6
8
  kredis_connection_with __method__, name, key, config: config, after_change: after_change
7
9
  end
8
10
 
9
- def kredis_string(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
10
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
11
+ def kredis_string(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
12
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
11
13
  end
12
14
 
13
- def kredis_integer(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
14
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
15
+ def kredis_integer(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
16
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
15
17
  end
16
18
 
17
- def kredis_decimal(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
18
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
19
+ def kredis_decimal(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
20
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
19
21
  end
20
22
 
21
- def kredis_datetime(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
22
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
23
+ def kredis_datetime(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
24
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
23
25
  end
24
26
 
25
- def kredis_flag(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
26
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
27
+ def kredis_flag(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
28
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
27
29
 
28
30
  define_method("#{name}?") do
29
31
  send(name).marked?
30
32
  end
31
33
  end
32
34
 
33
- def kredis_float(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
34
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
35
+ def kredis_float(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
36
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
35
37
  end
36
38
 
37
39
  def kredis_enum(name, key: nil, values:, default:, config: :shared, after_change: nil)
38
40
  kredis_connection_with __method__, name, key, values: values, default: default, config: config, after_change: after_change
39
41
  end
40
42
 
41
- def kredis_json(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
42
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
43
+ def kredis_json(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
44
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
45
+ end
46
+
47
+ def kredis_list(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
48
+ kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
43
49
  end
44
50
 
45
- def kredis_list(name, key: nil, typed: :string, config: :shared, after_change: nil)
46
- kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
51
+ def kredis_unique_list(name, limit: nil, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
52
+ kredis_connection_with __method__, name, key, default: default, limit: limit, typed: typed, config: config, after_change: after_change
47
53
  end
48
54
 
49
- def kredis_unique_list(name, limit: nil, key: nil, typed: :string, config: :shared, after_change: nil)
50
- kredis_connection_with __method__, name, key, limit: limit, typed: typed, config: config, after_change: after_change
55
+ def kredis_set(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
56
+ kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
51
57
  end
52
58
 
53
- def kredis_set(name, key: nil, typed: :string, config: :shared, after_change: nil)
54
- kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
59
+ def kredis_ordered_set(name, limit: nil, default: nil, key: nil, typed: :string, config: :shared, after_change: nil)
60
+ kredis_connection_with __method__, name, key, default: default, limit: limit, typed: typed, config: config, after_change: after_change
55
61
  end
56
62
 
57
63
  def kredis_slot(name, key: nil, config: :shared, after_change: nil)
@@ -62,16 +68,20 @@ module Kredis::Attributes
62
68
  kredis_connection_with __method__, name, key, available: available, config: config, after_change: after_change
63
69
  end
64
70
 
65
- def kredis_counter(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
66
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
71
+ def kredis_counter(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
72
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
73
+ end
74
+
75
+ def kredis_limiter(name, limit:, key: nil, config: :shared, after_change: nil, expires_in: nil)
76
+ kredis_connection_with __method__, name, key, limit: limit, config: config, after_change: after_change, expires_in: expires_in
67
77
  end
68
78
 
69
- def kredis_hash(name, key: nil, typed: :string, config: :shared, after_change: nil)
70
- kredis_connection_with __method__, name, key, typed: typed, config: config, after_change: after_change
79
+ def kredis_hash(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
80
+ kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
71
81
  end
72
82
 
73
- def kredis_boolean(name, key: nil, config: :shared, after_change: nil, expires_in: nil)
74
- kredis_connection_with __method__, name, key, config: config, after_change: after_change, expires_in: expires_in
83
+ def kredis_boolean(name, key: nil, default: nil, config: :shared, after_change: nil, expires_in: nil)
84
+ kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
75
85
  end
76
86
 
77
87
  private
@@ -84,6 +94,7 @@ module Kredis::Attributes
84
94
  if instance_variable_defined?(ivar_symbol)
85
95
  instance_variable_get(ivar_symbol)
86
96
  else
97
+ options[:default] = kredis_default_evaluated(options[:default]) if options[:default]
87
98
  new_type = Kredis.send(type, kredis_key_evaluated(key) || kredis_key_for_attribute(name), **options)
88
99
  instance_variable_set ivar_symbol,
89
100
  after_change ? enrich_after_change_with_record_access(new_type, after_change) : new_type
@@ -102,7 +113,7 @@ module Kredis::Attributes
102
113
  end
103
114
 
104
115
  def kredis_key_for_attribute(name)
105
- "#{self.class.name.tableize.gsub("/", ":")}:#{extract_kredis_id}:#{name}"
116
+ "#{self.class.name.tableize.tr("/", ":")}:#{extract_kredis_id}:#{name}"
106
117
  end
107
118
 
108
119
  def extract_kredis_id
@@ -115,4 +126,12 @@ module Kredis::Attributes
115
126
  when Symbol then Kredis::Types::CallbacksProxy.new(type, ->(_) { send(original_after_change) })
116
127
  end
117
128
  end
129
+
130
+ def kredis_default_evaluated(default)
131
+ case default
132
+ when Proc then Proc.new { default.call(self) }
133
+ when Symbol then send(default)
134
+ else default
135
+ end
136
+ end
118
137
  end
@@ -1,14 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "redis"
2
4
 
3
5
  module Kredis::Connections
6
+ DEFAULT_REDIS_URL = "redis://127.0.0.1:6379/0"
7
+ DEFAULT_REDIS_TIMEOUT = 1
8
+
4
9
  mattr_accessor :connections, default: Hash.new
5
10
  mattr_accessor :configurator
6
11
  mattr_accessor :connector, default: ->(config) { Redis.new(config) }
7
12
 
8
13
  def configured_for(name)
9
- connections[name] ||= begin
10
- Kredis.instrument :meta, message: "Connected to #{name}" do
14
+ connections[name] ||= Kredis.instrument :meta, message: "Connected to #{name}" do
15
+ if configurator.root.join("config/redis/#{name}.yml").exist?
11
16
  connector.call configurator.config_for("redis/#{name}")
17
+ elsif name == :shared
18
+ Redis.new url: ENV.fetch("REDIS_URL", DEFAULT_REDIS_URL), timeout: DEFAULT_REDIS_TIMEOUT
19
+ else
20
+ raise "No configuration found for #{name}"
12
21
  end
13
22
  end
14
23
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kredis::DefaultValues
4
+ extend ActiveSupport::Concern
5
+
6
+ prepended do
7
+ attr_writer :default
8
+
9
+ proxying :watch, :unwatch, :exists?
10
+
11
+ def default
12
+ case @default
13
+ when Proc then @default.call
14
+ when Symbol then send(@default)
15
+ else @default
16
+ end
17
+ end
18
+
19
+ private
20
+ def set_default
21
+ raise NotImplementedError, "Kredis type #{self.class} needs to define #set_default"
22
+ end
23
+ end
24
+
25
+ def initialize(...)
26
+ super
27
+
28
+ if default
29
+ watch do
30
+ set_default unless exists?
31
+
32
+ unwatch
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/log_subscriber"
2
4
 
3
5
  class Kredis::LogSubscriber < ActiveSupport::LogSubscriber
@@ -15,7 +17,7 @@ class Kredis::LogSubscriber < ActiveSupport::LogSubscriber
15
17
 
16
18
  private
17
19
  def formatted_in(color, event, type: nil)
18
- color " Kredis #{type} (#{event.duration.round(1)}ms) #{event.payload[:message]}", color, true
20
+ color " Kredis #{type} (#{event.duration.round(1)}ms) #{event.payload[:message]}", color, bold: true
19
21
  end
20
22
  end
21
23
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/module/delegation"
2
4
 
3
5
  class Kredis::Migration
@@ -33,10 +35,10 @@ class Kredis::Migration
33
35
  def delete_all(*key_patterns)
34
36
  log_migration "DELETE ALL #{key_patterns.inspect}" do
35
37
  if key_patterns.length > 1
36
- @redis.del *key_patterns
38
+ @redis.del(*key_patterns)
37
39
  else
38
40
  each_key_batch_matching(key_patterns.first) do |keys, pipeline|
39
- pipeline.del *keys
41
+ pipeline.del(*keys)
40
42
  end
41
43
  end
42
44
  end
@@ -1,12 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kredis::Namespace
2
- def namespace=(namespace)
3
- Thread.current[:kredis_namespace] = namespace
4
- end
4
+ attr_accessor :global_namespace
5
5
 
6
6
  def namespace
7
- Thread.current[:kredis_namespace]
7
+ if global_namespace
8
+ if value = thread_namespace
9
+ "#{global_namespace}:#{value}"
10
+ else
11
+ global_namespace
12
+ end
13
+ else
14
+ thread_namespace
15
+ end
16
+ end
17
+
18
+ def thread_namespace
19
+ Thread.current[:kredis_thread_namespace]
8
20
  end
9
21
 
22
+ def thread_namespace=(value)
23
+ Thread.current[:kredis_thread_namespace] = value
24
+ end
25
+
26
+ # Backward compatibility
27
+ alias_method :namespace=, :thread_namespace=
28
+
10
29
  def namespaced_key(key)
11
30
  namespace ? "#{namespace}:#{key}" : key
12
31
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Railtie < ::Rails::Railtie
2
4
  config.kredis = ActiveSupport::OrderedOptions.new
3
5
 
4
6
  initializer "kredis.testing" do
5
7
  ActiveSupport.on_load(:active_support_test_case) do
6
- parallelize_setup { |worker| Kredis.namespace = "test-#{worker}" }
8
+ parallelize_setup { |worker| Kredis.global_namespace = [ Kredis.global_namespace, :test, worker ].compact.join("-") }
7
9
  teardown { Kredis.clear_all }
8
10
  end
9
11
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kredis
4
+ module Type
5
+ class Boolean < ActiveModel::Type::Boolean
6
+ def serialize(value)
7
+ super ? 1 : 0
8
+ end
9
+ end
10
+ end
11
+ end
@@ -4,11 +4,11 @@ module Kredis
4
4
  module Type
5
5
  class DateTime < ActiveModel::Type::DateTime
6
6
  def serialize(value)
7
- super&.iso8601(9)
7
+ super&.utc&.iso8601(9)
8
8
  end
9
9
 
10
10
  def cast_value(value)
11
- super&.to_datetime
11
+ super&.to_time
12
12
  end
13
13
  end
14
14
  end
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "json"
2
4
  require "active_model/type"
3
- require "kredis/type/json"
5
+ require "kredis/type/boolean"
4
6
  require "kredis/type/datetime"
7
+ require "kredis/type/json"
5
8
 
6
9
  module Kredis::TypeCasting
7
10
  class InvalidType < StandardError; end
@@ -11,7 +14,7 @@ module Kredis::TypeCasting
11
14
  integer: ActiveModel::Type::Integer.new,
12
15
  decimal: ActiveModel::Type::Decimal.new,
13
16
  float: ActiveModel::Type::Float.new,
14
- boolean: ActiveModel::Type::Boolean.new,
17
+ boolean: Kredis::Type::Boolean.new,
15
18
  datetime: Kredis::Type::DateTime.new,
16
19
  json: Kredis::Type::Json.new
17
20
  }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::CallbacksProxy
2
4
  attr_reader :type
3
5
  delegate :to_s, to: :type
@@ -1,18 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Counter < Kredis::Types::Proxying
4
+ prepend Kredis::DefaultValues
5
+
2
6
  proxying :multi, :set, :incrby, :decrby, :get, :del, :exists?
3
7
 
4
8
  attr_accessor :expires_in
5
9
 
6
10
  def increment(by: 1)
7
11
  multi do
8
- set 0, ex: expires_in, nx: true
12
+ set 0, ex: expires_in, nx: true if expires_in
9
13
  incrby by
10
14
  end[-1]
11
15
  end
12
16
 
13
17
  def decrement(by: 1)
14
18
  multi do
15
- set 0, ex: expires_in, nx: true
19
+ set 0, ex: expires_in, nx: true if expires_in
16
20
  decrby by
17
21
  end[-1]
18
22
  end
@@ -24,4 +28,9 @@ class Kredis::Types::Counter < Kredis::Types::Proxying
24
28
  def reset
25
29
  del
26
30
  end
31
+
32
+ private
33
+ def set_default
34
+ increment by: default
35
+ end
27
36
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Cycle < Kredis::Types::Counter
2
4
  attr_accessor :values
3
5
 
@@ -1,9 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/object/inclusion"
2
4
 
3
5
  class Kredis::Types::Enum < Kredis::Types::Proxying
4
- proxying :set, :get, :del, :exists?
6
+ prepend Kredis::DefaultValues
7
+
8
+ InvalidDefault = Class.new(StandardError)
5
9
 
6
- attr_accessor :values, :default
10
+ proxying :set, :get, :del, :exists?, :multi
11
+
12
+ attr_accessor :values
7
13
 
8
14
  def initialize(...)
9
15
  super
@@ -17,11 +23,14 @@ class Kredis::Types::Enum < Kredis::Types::Proxying
17
23
  end
18
24
 
19
25
  def value
20
- get || default
26
+ get
21
27
  end
22
28
 
23
29
  def reset
24
- del
30
+ multi do
31
+ del
32
+ set_default
33
+ end
25
34
  end
26
35
 
27
36
  private
@@ -31,4 +40,12 @@ class Kredis::Types::Enum < Kredis::Types::Proxying
31
40
  define_singleton_method("#{defined_value}!") { self.value = defined_value }
32
41
  end
33
42
  end
43
+
44
+ def set_default
45
+ if default.in?(values) || default.nil?
46
+ set default
47
+ else
48
+ raise InvalidDefault, "Default value #{default.inspect} for #{key} is not a valid option (Valid values: #{values.join(", ")})"
49
+ end
50
+ end
34
51
  end
@@ -1,4 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Flag < Kredis::Types::Proxying
4
+ prepend Kredis::DefaultValues
5
+
2
6
  proxying :set, :exists?, :del
3
7
 
4
8
  attr_accessor :expires_in
@@ -14,4 +18,9 @@ class Kredis::Types::Flag < Kredis::Types::Proxying
14
18
  def remove
15
19
  del
16
20
  end
21
+
22
+ private
23
+ def set_default
24
+ mark if default
25
+ end
17
26
  end
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/hash"
2
4
 
3
5
  class Kredis::Types::Hash < Kredis::Types::Proxying
6
+ prepend Kredis::DefaultValues
7
+
4
8
  proxying :hget, :hset, :hmget, :hdel, :hgetall, :hkeys, :hvals, :del, :exists?
5
9
 
6
10
  attr_accessor :typed
@@ -14,7 +18,7 @@ class Kredis::Types::Hash < Kredis::Types::Proxying
14
18
  end
15
19
 
16
20
  def update(**entries)
17
- hset entries.transform_values{ |val| type_to_string(val, typed) } if entries.flatten.any?
21
+ hset entries.transform_values { |val| type_to_string(val, typed) }.compact if entries.flatten.any?
18
22
  end
19
23
 
20
24
  def values_at(*keys)
@@ -42,4 +46,9 @@ class Kredis::Types::Hash < Kredis::Types::Proxying
42
46
  def values
43
47
  strings_to_types(hvals || [], typed)
44
48
  end
49
+
50
+ private
51
+ def set_default
52
+ update(**default)
53
+ end
45
54
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # A limiter is a specialized form of a counter that can be checked whether it has been exceeded and is provided fail safe. This means it can be used to guard login screens from brute force attacks without denying access in case Redis is offline.
4
+ #
5
+ # It will usually be used as an expiring limiter. Note that the limiter expires in total after the `expires_in` time used upon the first poke.
6
+ #
7
+ # It offers no guarentee that you can't poke yourself above the limit. You're responsible for checking `#exceeded?` yourself first, and this may produce a race condition. So only use this when the exact number of pokes is not critical.
8
+ class Kredis::Types::Limiter < Kredis::Types::Counter
9
+ class LimitExceeded < StandardError; end
10
+
11
+ attr_accessor :limit
12
+
13
+ def poke
14
+ failsafe returning: true do
15
+ increment
16
+ end
17
+ end
18
+
19
+ def exceeded?
20
+ failsafe returning: false do
21
+ value >= limit
22
+ end
23
+ end
24
+ end
@@ -1,4 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::List < Kredis::Types::Proxying
4
+ prepend Kredis::DefaultValues
5
+
2
6
  proxying :lrange, :lrem, :lpush, :ltrim, :rpush, :exists?, :del
3
7
 
4
8
  attr_accessor :typed
@@ -24,4 +28,13 @@ class Kredis::Types::List < Kredis::Types::Proxying
24
28
  def clear
25
29
  del
26
30
  end
31
+
32
+ def last(n = nil)
33
+ n ? lrange(-n, -1) : lrange(-1, -1).first
34
+ end
35
+
36
+ private
37
+ def set_default
38
+ append default
39
+ end
27
40
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Kredis::Types::OrderedSet < Kredis::Types::Proxying
4
+ prepend Kredis::DefaultValues
5
+
6
+ proxying :multi, :zrange, :zrem, :zadd, :zremrangebyrank, :zcard, :exists?, :del, :zscore
7
+
8
+ attr_accessor :typed
9
+ attr_reader :limit
10
+
11
+ def elements
12
+ strings_to_types(zrange(0, -1) || [], typed)
13
+ end
14
+ alias to_a elements
15
+
16
+ def remove(*elements)
17
+ zrem(types_to_strings(elements, typed))
18
+ end
19
+
20
+ def include?(element)
21
+ !!zscore(type_to_string(element, typed))
22
+ end
23
+
24
+ def prepend(elements)
25
+ insert(elements, prepending: true)
26
+ end
27
+
28
+ def append(elements)
29
+ insert(elements)
30
+ end
31
+ alias << append
32
+
33
+ def limit=(limit)
34
+ raise "Limit must be greater than 0" if limit && limit <= 0
35
+
36
+ @limit = limit
37
+ end
38
+
39
+ private
40
+ def insert(elements, prepending: false)
41
+ elements = Array(elements)
42
+ return if elements.empty?
43
+
44
+ elements_with_scores = types_to_strings(elements, typed).map.with_index do |element, index|
45
+ incremental_score = index * 0.000001
46
+
47
+ score = if prepending
48
+ -base_score - incremental_score
49
+ else
50
+ base_score + incremental_score
51
+ end
52
+
53
+ [ score, element ]
54
+ end
55
+
56
+ multi do
57
+ zadd(elements_with_scores)
58
+ trim(from_beginning: prepending)
59
+ end
60
+ end
61
+
62
+ def base_score
63
+ process_start_time + process_uptime
64
+ end
65
+
66
+ def process_start_time
67
+ @process_start_time ||= unproxied_redis.time.join(".").to_f - process_uptime
68
+ end
69
+
70
+ def process_uptime
71
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
72
+ end
73
+
74
+ def trim(from_beginning:)
75
+ return unless limit
76
+
77
+ if from_beginning
78
+ zremrangebyrank(limit, -1)
79
+ else
80
+ zremrangebyrank(0, -(limit + 1))
81
+ end
82
+ end
83
+
84
+ def set_default
85
+ append default
86
+ end
87
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kredis::Types::Proxy::Failsafe
2
4
  def initialize(*)
3
5
  super
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Proxy
2
4
  require_relative "proxy/failsafe"
3
5
  include Failsafe
@@ -20,6 +22,16 @@ class Kredis::Types::Proxy
20
22
  end
21
23
  end
22
24
 
25
+ def watch(&block)
26
+ redis.watch(key) do
27
+ block.call
28
+ end
29
+ end
30
+
31
+ def unwatch
32
+ redis.unwatch
33
+ end
34
+
23
35
  def method_missing(method, *args, **kwargs)
24
36
  Kredis.instrument :proxy, **log_message(method, *args, **kwargs) do
25
37
  failsafe do
@@ -1,13 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/module/delegation"
2
4
 
3
5
  class Kredis::Types::Proxying
4
6
  attr_accessor :proxy, :key
5
7
 
6
8
  def self.proxying(*commands)
7
- delegate *commands, to: :proxy
9
+ delegate(*commands, to: :proxy)
8
10
  end
9
11
 
10
12
  def initialize(redis, key, **options)
13
+ @redis = redis
11
14
  @key = key
12
15
  @proxy = Kredis::Types::Proxy.new(redis, key)
13
16
  options.each { |key, value| send("#{key}=", value) }
@@ -17,6 +20,12 @@ class Kredis::Types::Proxying
17
20
  proxy.suppress_failsafe_with(returning: returning, &block)
18
21
  end
19
22
 
23
+ def unproxied_redis
24
+ # Generally, this should not be used. It's only here for the rare case where we need to
25
+ # call Redis commands that don't reference a key and don't want to be pipelined.
26
+ @redis
27
+ end
28
+
20
29
  private
21
30
  delegate :type_to_string, :string_to_type, :types_to_strings, :strings_to_types, to: :Kredis
22
31
  end
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Scalar < Kredis::Types::Proxying
4
+ prepend Kredis::DefaultValues
5
+
2
6
  proxying :set, :get, :exists?, :del, :expire, :expireat
3
7
 
4
- attr_accessor :typed, :default, :expires_in
8
+ attr_accessor :typed, :expires_in
5
9
 
6
10
  def value=(value)
7
11
  set type_to_string(value, typed), ex: expires_in
@@ -36,4 +40,9 @@ class Kredis::Types::Scalar < Kredis::Types::Proxying
36
40
  def expire_at(datetime)
37
41
  expireat datetime.to_i
38
42
  end
43
+
44
+ private
45
+ def set_default
46
+ self.value = default
47
+ end
39
48
  end
@@ -1,8 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Set < Kredis::Types::Proxying
2
- proxying :smembers, :sadd, :srem, :multi, :del, :sismember, :scard, :spop, :exists?
4
+ prepend Kredis::DefaultValues
3
5
 
4
- attr_accessor :typed
6
+ proxying :smembers, :sadd, :srem, :multi, :del, :sismember, :scard, :spop, :exists?, :srandmember, :smove
5
7
 
8
+ attr_accessor :typed
9
+ def move(set, member)
10
+ destination = set.respond_to?(:key) ? set.key : set
11
+ smove(destination, member)
12
+ end
6
13
  def members
7
14
  strings_to_types(smembers || [], typed).sort
8
15
  end
@@ -33,10 +40,23 @@ class Kredis::Types::Set < Kredis::Types::Proxying
33
40
  end
34
41
 
35
42
  def take
36
- spop
43
+ string_to_type(spop, typed)
37
44
  end
38
45
 
39
46
  def clear
40
47
  del
41
48
  end
49
+
50
+ def sample(count = nil)
51
+ if count.nil?
52
+ string_to_type(srandmember(count), typed)
53
+ else
54
+ strings_to_types(srandmember(count), typed)
55
+ end
56
+ end
57
+
58
+ private
59
+ def set_default
60
+ add default
61
+ end
42
62
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Kredis::Types::Slots < Kredis::Types::Proxying
2
4
  class NotAvailable < StandardError; end
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # You'd normally call this a set, but Redis already has another data type for that
2
4
  class Kredis::Types::UniqueList < Kredis::Types::List
3
5
  proxying :multi, :ltrim, :exists?
@@ -22,7 +24,7 @@ class Kredis::Types::UniqueList < Kredis::Types::List
22
24
  multi do
23
25
  remove elements
24
26
  super
25
- ltrim -limit, -1 if limit
27
+ ltrim(-limit, -1) if limit
26
28
  end
27
29
  end
28
30
  alias << append
data/lib/kredis/types.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kredis::Types
2
4
  autoload :CallbacksProxy, "kredis/types/callbacks_proxy"
3
5
 
@@ -39,36 +41,40 @@ module Kredis::Types
39
41
  end
40
42
 
41
43
 
42
- def counter(key, expires_in: nil, config: :shared, after_change: nil)
43
- type_from(Counter, config, key, after_change: after_change, expires_in: expires_in)
44
+ def counter(key, expires_in: nil, default: nil, config: :shared, after_change: nil)
45
+ type_from(Counter, config, key, after_change: after_change, default: default, expires_in: expires_in)
44
46
  end
45
47
 
46
48
  def cycle(key, values:, expires_in: nil, config: :shared, after_change: nil)
47
49
  type_from(Cycle, config, key, after_change: after_change, values: values, expires_in: expires_in)
48
50
  end
49
51
 
50
- def flag(key, config: :shared, after_change: nil, expires_in: nil)
51
- type_from(Flag, config, key, after_change: after_change, expires_in: expires_in)
52
+ def flag(key, default: nil, config: :shared, after_change: nil, expires_in: nil)
53
+ type_from(Flag, config, key, after_change: after_change, default: default, expires_in: expires_in)
52
54
  end
53
55
 
54
56
  def enum(key, values:, default:, config: :shared, after_change: nil)
55
57
  type_from(Enum, config, key, after_change: after_change, values: values, default: default)
56
58
  end
57
59
 
58
- def hash(key, typed: :string, config: :shared, after_change: nil)
59
- type_from(Hash, config, key, after_change: after_change, typed: typed)
60
+ def hash(key, typed: :string, default: nil, config: :shared, after_change: nil)
61
+ type_from(Hash, config, key, after_change: after_change, default: default, typed: typed)
62
+ end
63
+
64
+ def list(key, default: nil, typed: :string, config: :shared, after_change: nil)
65
+ type_from(List, config, key, after_change: after_change, default: default, typed: typed)
60
66
  end
61
67
 
62
- def list(key, typed: :string, config: :shared, after_change: nil)
63
- type_from(List, config, key, after_change: after_change, typed: typed)
68
+ def unique_list(key, default: nil, typed: :string, limit: nil, config: :shared, after_change: nil)
69
+ type_from(UniqueList, config, key, after_change: after_change, default: default, typed: typed, limit: limit)
64
70
  end
65
71
 
66
- def unique_list(key, typed: :string, limit: nil, config: :shared, after_change: nil)
67
- type_from(UniqueList, config, key, after_change: after_change, typed: typed, limit: limit)
72
+ def set(key, default: nil, typed: :string, config: :shared, after_change: nil)
73
+ type_from(Set, config, key, after_change: after_change, default: default, typed: typed)
68
74
  end
69
75
 
70
- def set(key, typed: :string, config: :shared, after_change: nil)
71
- type_from(Set, config, key, after_change: after_change, typed: typed)
76
+ def ordered_set(key, default: nil, typed: :string, limit: nil, config: :shared, after_change: nil)
77
+ type_from(OrderedSet, config, key, after_change: after_change, default: default, typed: typed, limit: limit)
72
78
  end
73
79
 
74
80
  def slot(key, config: :shared, after_change: nil)
@@ -79,6 +85,10 @@ module Kredis::Types
79
85
  type_from(Slots, config, key, after_change: after_change, available: available)
80
86
  end
81
87
 
88
+ def limiter(key, limit:, expires_in: nil, config: :shared, after_change: nil)
89
+ type_from(Limiter, config, key, after_change: after_change, expires_in: expires_in, limit: limit)
90
+ end
91
+
82
92
  private
83
93
  def type_from(type_klass, config, key, after_change: nil, **options)
84
94
  type_klass.new(configured_for(config), namespaced_key(key), **options).then do |type|
@@ -99,4 +109,6 @@ require "kredis/types/hash"
99
109
  require "kredis/types/list"
100
110
  require "kredis/types/unique_list"
101
111
  require "kredis/types/set"
112
+ require "kredis/types/ordered_set"
102
113
  require "kredis/types/slots"
114
+ require "kredis/types/limiter"
@@ -1,3 +1,3 @@
1
1
  module Kredis
2
- VERSION = "1.3.0.1"
2
+ VERSION = "1.8.0"
3
3
  end
data/lib/kredis.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support"
2
4
  require "active_support/core_ext/module/attribute_accessors"
3
5
  require "active_support/core_ext/module/attribute_accessors_per_thread"
@@ -8,6 +10,7 @@ require "kredis/connections"
8
10
  require "kredis/log_subscriber"
9
11
  require "kredis/namespace"
10
12
  require "kredis/type_casting"
13
+ require "kredis/default_values"
11
14
  require "kredis/types"
12
15
  require "kredis/attributes"
13
16
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :kredis do
2
4
  desc "Install kredis"
3
5
  task :install do
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kredis
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0.1
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kasper Timm Hansen
8
8
  - David Heinemeier Hansson
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2023-03-13 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activesupport
@@ -25,6 +24,20 @@ dependencies:
25
24
  - - ">="
26
25
  - !ruby/object:Gem::Version
27
26
  version: 6.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activemodel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 6.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 6.0.0
28
41
  - !ruby/object:Gem::Dependency
29
42
  name: redis
30
43
  requirement: !ruby/object:Gem::Requirement
@@ -59,7 +72,6 @@ dependencies:
59
72
  - - ">="
60
73
  - !ruby/object:Gem::Version
61
74
  version: 6.0.0
62
- description:
63
75
  email: david@hey.com
64
76
  executables: []
65
77
  extensions: []
@@ -72,10 +84,12 @@ files:
72
84
  - lib/kredis.rb
73
85
  - lib/kredis/attributes.rb
74
86
  - lib/kredis/connections.rb
87
+ - lib/kredis/default_values.rb
75
88
  - lib/kredis/log_subscriber.rb
76
89
  - lib/kredis/migration.rb
77
90
  - lib/kredis/namespace.rb
78
91
  - lib/kredis/railtie.rb
92
+ - lib/kredis/type/boolean.rb
79
93
  - lib/kredis/type/datetime.rb
80
94
  - lib/kredis/type/json.rb
81
95
  - lib/kredis/type_casting.rb
@@ -86,7 +100,9 @@ files:
86
100
  - lib/kredis/types/enum.rb
87
101
  - lib/kredis/types/flag.rb
88
102
  - lib/kredis/types/hash.rb
103
+ - lib/kredis/types/limiter.rb
89
104
  - lib/kredis/types/list.rb
105
+ - lib/kredis/types/ordered_set.rb
90
106
  - lib/kredis/types/proxy.rb
91
107
  - lib/kredis/types/proxy/failsafe.rb
92
108
  - lib/kredis/types/proxying.rb
@@ -100,7 +116,6 @@ homepage: https://github.com/rails/kredis
100
116
  licenses:
101
117
  - MIT
102
118
  metadata: {}
103
- post_install_message:
104
119
  rdoc_options: []
105
120
  require_paths:
106
121
  - lib
@@ -115,8 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
130
  - !ruby/object:Gem::Version
116
131
  version: '0'
117
132
  requirements: []
118
- rubygems_version: 3.4.2
119
- signing_key:
133
+ rubygems_version: 3.6.7
120
134
  specification_version: 4
121
135
  summary: Higher-level data structures built on Redis.
122
136
  test_files: []