kredis 1.6.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: f90d8ba8eadeb9cc6dbd2ca4bbb8532629281595e5a1feccd42487b98f248e67
4
- data.tar.gz: 3d5e2768e7647d27bb004bc7167f9b35b97702bdcc3e3f6f76032abd3b85bb5d
3
+ metadata.gz: c7b578a8b9d0b956e519c324d7ba9dd6036124637801366d9f1a2719a7d340d5
4
+ data.tar.gz: a4bc7d1a74540a7bd41691105833123bffd27ff32f07b01ce82986820d6068e3
5
5
  SHA512:
6
- metadata.gz: 590e5baac4b4a2c85c4867f6ee55d4598c3b21e9c9b22961556626f59e8b17524cc4e4e9040f9109d30671ba4b615b074edcad5723df459f75a10dd1da956a23
7
- data.tar.gz: 8ad76868f04ac0c0828485f2e03ce93fc8514eb32e2661028adcbc6ff9866f6016d26530b6af30f8df15009723e01797fc913084bb6bcb219f36558db7ed2768
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
@@ -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
53
  integer_list = Kredis.list "myintegerlist", typed: :integer, default: [ 1, 2, 3 ] # => EXISTS? myintegerlist, RPUSH myintegerlist "1" "2" "3"
53
54
  integer_list.append([ 4, 5, 6 ]) # => RPUSH myintegerlist "4" "5" "6"
54
55
  integer_list << 7 # => RPUSH myintegerlist "7"
55
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,6 +63,7 @@ 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
64
67
 
65
68
  ordered_set = Kredis.ordered_set "myorderedset"
66
69
  ordered_set.append(%w[ 2 3 4 ]) # => ZADD myorderedset 1646131025.4953232 2 1646131025.495326 3 1646131025.4953272 4
@@ -75,6 +78,7 @@ set.add(DateTime.tomorrow, DateTime.yesterday) # => SADD myset "2021-0
75
78
  set << DateTime.tomorrow # => SADD myset "2021-02-03 00:00:00 +0100"
76
79
  2 == set.size # => SCARD myset
77
80
  [ DateTime.tomorrow, DateTime.yesterday ] == set.members # => SMEMBERS myset
81
+ set.clear # => DEL myset
78
82
 
79
83
  hash = Kredis.hash "myhash"
80
84
  hash.update("key" => "value", "key2" => "value2") # => HSET myhash "key", "value", "key2", "value2"
@@ -102,6 +106,7 @@ counter.increment by: 2 # => SET mycounter 0 EX 5 NX + INCRBY "mycounter
102
106
  2 == counter.value # => GET "mycounter"
103
107
  sleep 6.seconds
104
108
  0 == counter.value # => GET "mycounter"
109
+ counter.reset # => DEL mycounter
105
110
 
106
111
  cycle = Kredis.cycle "mycycle", values: %i[ one two three ]
107
112
  :one == cycle.value # => GET mycycle
@@ -111,6 +116,7 @@ cycle.next # => GET mycycle + SET mycycle 2
111
116
  :three == cycle.value # => GET mycycle
112
117
  cycle.next # => GET mycycle + SET mycycle 0
113
118
  :one == cycle.value # => GET mycycle
119
+ cycle.reset # => DEL mycycle
114
120
 
115
121
  enum = Kredis.enum "myenum", values: %w[ one two three ], default: "one"
116
122
  "one" == enum.value # => GET myenum
@@ -161,6 +167,18 @@ sleep 0.5.seconds
161
167
  true == flag.marked? #=> EXISTS myflag
162
168
  sleep 0.6.seconds
163
169
  false == flag.marked? #=> EXISTS myflag
170
+
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"
164
182
  ```
165
183
 
166
184
  ### Models
@@ -249,7 +267,7 @@ If you don't have `config/redis/shared.yml` (or use another named configuration)
249
267
 
250
268
  ### Redis support
251
269
 
252
- 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.
253
271
 
254
272
  ### Setting SSL options on Redis Connections
255
273
 
@@ -72,6 +72,10 @@ module Kredis::Attributes
72
72
  kredis_connection_with __method__, name, key, default: default, config: config, after_change: after_change, expires_in: expires_in
73
73
  end
74
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
77
+ end
78
+
75
79
  def kredis_hash(name, key: nil, default: nil, typed: :string, config: :shared, after_change: nil)
76
80
  kredis_connection_with __method__, name, key, default: default, typed: typed, config: config, after_change: after_change
77
81
  end
@@ -1,14 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kredis::Namespace
4
- def namespace=(namespace)
5
- Thread.current[:kredis_namespace] = namespace
6
- end
4
+ attr_accessor :global_namespace
7
5
 
8
6
  def namespace
9
- 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]
10
20
  end
11
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
+
12
29
  def namespaced_key(key)
13
30
  namespace ? "#{namespace}:#{key}" : key
14
31
  end
@@ -5,7 +5,7 @@ class Kredis::Railtie < ::Rails::Railtie
5
5
 
6
6
  initializer "kredis.testing" do
7
7
  ActiveSupport.on_load(:active_support_test_case) do
8
- parallelize_setup { |worker| Kredis.namespace = "test-#{worker}" }
8
+ parallelize_setup { |worker| Kredis.global_namespace = [ Kredis.global_namespace, :test, worker ].compact.join("-") }
9
9
  teardown { Kredis.clear_all }
10
10
  end
11
11
  end
@@ -18,7 +18,7 @@ class Kredis::Types::Hash < Kredis::Types::Proxying
18
18
  end
19
19
 
20
20
  def update(**entries)
21
- 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?
22
22
  end
23
23
 
24
24
  def values_at(*keys)
@@ -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
@@ -3,10 +3,13 @@
3
3
  class Kredis::Types::Set < Kredis::Types::Proxying
4
4
  prepend Kredis::DefaultValues
5
5
 
6
- proxying :smembers, :sadd, :srem, :multi, :del, :sismember, :scard, :spop, :exists?, :srandmember
6
+ proxying :smembers, :sadd, :srem, :multi, :del, :sismember, :scard, :spop, :exists?, :srandmember, :smove
7
7
 
8
8
  attr_accessor :typed
9
-
9
+ def move(set, member)
10
+ destination = set.respond_to?(:key) ? set.key : set
11
+ smove(destination, member)
12
+ end
10
13
  def members
11
14
  strings_to_types(smembers || [], typed).sort
12
15
  end
data/lib/kredis/types.rb CHANGED
@@ -85,6 +85,10 @@ module Kredis::Types
85
85
  type_from(Slots, config, key, after_change: after_change, available: available)
86
86
  end
87
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
+
88
92
  private
89
93
  def type_from(type_klass, config, key, after_change: nil, **options)
90
94
  type_klass.new(configured_for(config), namespaced_key(key), **options).then do |type|
@@ -107,3 +111,4 @@ require "kredis/types/unique_list"
107
111
  require "kredis/types/set"
108
112
  require "kredis/types/ordered_set"
109
113
  require "kredis/types/slots"
114
+ require "kredis/types/limiter"
@@ -1,3 +1,3 @@
1
1
  module Kredis
2
- VERSION = "1.6.1"
2
+ VERSION = "1.8.0"
3
3
  end
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.6.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-12-29 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
@@ -73,7 +72,6 @@ dependencies:
73
72
  - - ">="
74
73
  - !ruby/object:Gem::Version
75
74
  version: 6.0.0
76
- description:
77
75
  email: david@hey.com
78
76
  executables: []
79
77
  extensions: []
@@ -102,6 +100,7 @@ files:
102
100
  - lib/kredis/types/enum.rb
103
101
  - lib/kredis/types/flag.rb
104
102
  - lib/kredis/types/hash.rb
103
+ - lib/kredis/types/limiter.rb
105
104
  - lib/kredis/types/list.rb
106
105
  - lib/kredis/types/ordered_set.rb
107
106
  - lib/kredis/types/proxy.rb
@@ -117,7 +116,6 @@ homepage: https://github.com/rails/kredis
117
116
  licenses:
118
117
  - MIT
119
118
  metadata: {}
120
- post_install_message:
121
119
  rdoc_options: []
122
120
  require_paths:
123
121
  - lib
@@ -132,8 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
130
  - !ruby/object:Gem::Version
133
131
  version: '0'
134
132
  requirements: []
135
- rubygems_version: 3.4.14
136
- signing_key:
133
+ rubygems_version: 3.6.7
137
134
  specification_version: 4
138
135
  summary: Higher-level data structures built on Redis.
139
136
  test_files: []