redis-store 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 343594d8b51298be4a1d5c015a64d04fe1939c12
4
- data.tar.gz: 3ee360fae5b291f77f56175cc34e18e635af655d
2
+ SHA256:
3
+ metadata.gz: 10e6007fb1a0708fe88d7627a23a2b5e8e0303e9ee81ec886d27a5c6fdb7ed07
4
+ data.tar.gz: 9415f933dae0284fe8114cf6d350561bc23c58bcf9f1182d734f36fdf8436707
5
5
  SHA512:
6
- metadata.gz: '0906711b266addefc485ddad054c70eb1d25ccfdc8162c9c9225229d1e26be1c66361ef1704a86e8e7e17419ef961c6aec3c85156275794f956921964b599c2e'
7
- data.tar.gz: 4aa88e8de4f00b29e20dd4f93bbaf4f21a18850e6cedebfb93fcbb3b98190b2cc2fd327f4aceb8dc24c66896f66095a24706b94fec31eff078ecd6440e2a9a7c
6
+ metadata.gz: 69a4d72561bf0b9da2c88cc7a32d37a7ca06bb758a60d338bc4c12added10c1549f818f6e0e68af3854e0911a92f591c3c3094455d731f7a48d1cb1b47a9a700
7
+ data.tar.gz: da5fee4e7926a6032ca82fa7ee924c0a676124bffb55c84d5f553f066eb0ca47678cad583403ccc5979d04b7ddcdeb98652edf906472db364713baf483bc64e3
data/.gitignore CHANGED
@@ -2,3 +2,5 @@ Gemfile.lock
2
2
  *.gem
3
3
  tmp/
4
4
  stdout
5
+ # Gemfile locks generated by Appraisals
6
+ gemfiles/*.gemfile.lock
@@ -1,19 +1,35 @@
1
1
  language: ruby
2
2
  sudo: false
3
3
  cache: bundler
4
+ notifications:
5
+ webhooks: https://www.travisbuddy.com
6
+ on_success: never
7
+
8
+ # 1.9.3 has Bundler 1.7.6 with the "undefined method `spec' for nil" bug
4
9
  before_install: gem install bundler
5
- script: 'bundle exec rake'
10
+
6
11
  rvm:
7
12
  - 1.9.3
8
- - 2.0.0
13
+ - 2.0
9
14
  - 2.1
10
15
  - 2.2
11
- - 2.3.0
16
+ - 2.3
17
+ - 2.4
12
18
  - ruby-head
13
19
  - jruby-head
14
- bundler_args: '--path vendor/bundle'
20
+
21
+ gemfile:
22
+ - gemfiles/redis_3_x.gemfile
23
+ - gemfiles/redis_4_x.gemfile
15
24
 
16
25
  matrix:
17
26
  allow_failures:
18
27
  - rvm: jruby-head
19
28
  - rvm: ruby-head
29
+ exclude:
30
+ - rvm: 1.9.3
31
+ gemfile: gemfiles/redis_4_x.gemfile
32
+ - rvm: 2.0
33
+ gemfile: gemfiles/redis_4_x.gemfile
34
+ - rvm: 2.1
35
+ gemfile: gemfiles/redis_4_x.gemfile
@@ -0,0 +1,8 @@
1
+
2
+ appraise "redis_3_x" do
3
+ gem "redis", "~> 3.0"
4
+ end
5
+
6
+ appraise "redis_4_x" do
7
+ gem "redis", "~> 4.0"
8
+ end
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.5.0
4
+
5
+ Breaking Changes
6
+
7
+ * None
8
+
9
+ Added
10
+
11
+ * [Support for Redis v4 and above](https://github.com/redis-store/redis-store/pull/292)
12
+ * [Support for distributed mget/read_multi in Redis v4](https://github.com/redis-store/redis-store/pull/282)
13
+ * [Tests for Namespace#flushdb](https://github.com/redis-store/redis-store/pull/299)
14
+ * [Support for UNIX Socket path connections](https://github.com/redis-store/redis-store/pull/298)
15
+ * [HashRing configuration for DistributedStore](https://github.com/redis-store/redis-store/pull/304)
16
+
17
+ Fixed
18
+
19
+ * [Inefficient use of KEYS when calling FLUSHDB without a namespace](https://github.com/redis-store/redis-store/pull/297)
20
+
3
21
  ## 1.4.1
4
22
 
5
23
  Breaking Changes
data/Gemfile CHANGED
@@ -1,2 +1,7 @@
1
1
  source 'https://rubygems.org'
2
+
3
+ if RUBY_VERSION < '2'
4
+ gem 'redis', '< 4'
5
+ end
6
+
2
7
  gemspec
data/Rakefile CHANGED
@@ -2,3 +2,11 @@ require 'bundler/setup'
2
2
  require 'rake'
3
3
  require 'bundler/gem_tasks'
4
4
  require 'redis-store/testing/tasks'
5
+ require 'appraisal'
6
+
7
+
8
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
9
+ task :default do
10
+ sh "appraisal install && rake appraisal default"
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "redis", "~> 3.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "redis", "~> 4.0"
6
+
7
+ gemspec path: "../"
@@ -6,12 +6,12 @@ class Redis
6
6
  attr_reader :ring
7
7
 
8
8
  def initialize(addresses, options = { })
9
- nodes = addresses.map do |address|
10
- ::Redis::Store.new _merge_options(address, options)
11
- end
12
-
13
9
  _extend_namespace options
14
- @ring = Redis::HashRing.new nodes
10
+ @ring = options[:ring] || Redis::HashRing.new([], options[:replicas] || Redis::HashRing::POINTS_PER_SERVER)
11
+
12
+ addresses.each do |address|
13
+ @ring.add_node(::Redis::Store.new _merge_options(address, options))
14
+ end
15
15
  end
16
16
 
17
17
  def nodes
@@ -42,8 +42,17 @@ class Redis
42
42
  end
43
43
 
44
44
  def to_s
45
- h = @client.host
46
- "Redis Client connected to #{/:/ =~ h ? '['+h+']' : h}:#{@client.port} against DB #{@client.db}"
45
+ "Redis Client connected to #{location} against DB #{@client.db}"
46
+ end
47
+
48
+ def location
49
+ if @client.path
50
+ @client.path
51
+ else
52
+ h = @client.host
53
+ h = "[#{h}]" if h.include?(":")
54
+ "#{h}:#{@client.port}"
55
+ end
47
56
  end
48
57
 
49
58
  private
@@ -62,27 +62,33 @@ class Redis
62
62
  end
63
63
 
64
64
  def self.host_options?(options)
65
- if options.keys.any? {|n| [:host, :db, :port].include?(n) }
66
- options
67
- else
68
- nil # just to be clear
69
- end
65
+ options.keys.any? {|n| [:host, :db, :port, :path].include?(n) }
70
66
  end
71
67
 
72
68
  def self.extract_host_options_from_uri(uri)
73
69
  uri = URI.parse(uri)
74
- _, db, namespace = if uri.path
75
- uri.path.split(/\//)
76
- end
77
-
78
- options = {
79
- :host => uri.hostname,
80
- :port => uri.port || DEFAULT_PORT,
81
- :password => uri.password.nil? ? nil : CGI::unescape(uri.password.to_s)
82
- }
83
-
84
- options[:db] = db.to_i if db
85
- options[:namespace] = namespace if namespace
70
+ if uri.scheme == "unix"
71
+ options = { :path => uri.path }
72
+ else
73
+ _, db, namespace = if uri.path
74
+ uri.path.split(/\//)
75
+ end
76
+
77
+ options = {
78
+ :host => uri.hostname,
79
+ :port => uri.port || DEFAULT_PORT,
80
+ :password => uri.password.nil? ? nil : CGI::unescape(uri.password.to_s)
81
+ }
82
+
83
+ options[:db] = db.to_i if db
84
+ options[:namespace] = namespace if namespace
85
+ end
86
+ if uri.query
87
+ query = Hash[URI.decode_www_form(uri.query)]
88
+ query.each do |(key, value)|
89
+ options[key.to_sym] = value
90
+ end
91
+ end
86
92
 
87
93
  options
88
94
  end
@@ -47,14 +47,14 @@ class Redis
47
47
  super(*keys.map {|key| interpolate(key) }) if keys.any?
48
48
  end
49
49
 
50
- def mget(*keys)
50
+ def mget(*keys, &blk)
51
51
  options = (keys.pop if keys.last.is_a? Hash) || {}
52
52
  if keys.any?
53
53
  # Serialization gets extended before Namespace does, so we need to pass options further
54
54
  if singleton_class.ancestors.include? Serialization
55
- super(*keys.map {|key| interpolate(key) }, options)
55
+ super(*keys.map {|key| interpolate(key) }, options, &blk)
56
56
  else
57
- super(*keys.map {|key| interpolate(key) })
57
+ super(*keys.map {|key| interpolate(key) }, &blk)
58
58
  end
59
59
  end
60
60
  end
@@ -72,6 +72,7 @@ class Redis
72
72
  end
73
73
 
74
74
  def flushdb
75
+ return super unless namespace_str
75
76
  keys.each_slice(FLUSHDB_BATCH_SIZE) { |key_slice| del(*key_slice) }
76
77
  end
77
78
 
@@ -17,10 +17,11 @@ class Redis
17
17
  _unmarshal super(key), options
18
18
  end
19
19
 
20
- def mget(*keys)
20
+ def mget(*keys, &blk)
21
21
  options = keys.pop if keys.last.is_a?(Hash)
22
- super(*keys).map do |result|
23
- _unmarshal result, options
22
+ super(*keys) do |reply|
23
+ reply.map! { |value| _unmarshal value, options }
24
+ blk ? blk.call(reply) : reply
24
25
  end
25
26
  end
26
27
 
@@ -1,5 +1,5 @@
1
1
  class Redis
2
2
  class Store < self
3
- VERSION = '1.4.1'
3
+ VERSION = '1.5.0'
4
4
  end
5
5
  end
@@ -29,4 +29,5 @@ Gem::Specification.new do |s|
29
29
  s.add_development_dependency 'pry-nav', '~> 0.2.4'
30
30
  s.add_development_dependency 'pry', '~> 0.10.4'
31
31
  s.add_development_dependency 'redis-store-testing'
32
+ s.add_development_dependency 'appraisal', '~> 2.0'
32
33
  end
@@ -39,6 +39,50 @@ describe "Redis::DistributedStore" do
39
39
  @dmr.get("rabbit").must_equal(@rabbit)
40
40
  end
41
41
 
42
+ it "mget" do
43
+ @dmr.set "rabbit2", @white_rabbit
44
+ begin
45
+ @dmr.mget "rabbit", "rabbit2" do |rabbits|
46
+ rabbit, rabbit2 = rabbits
47
+ rabbits.length.must_equal(2)
48
+ rabbit.must_equal(@rabbit)
49
+ rabbit2.must_equal(@white_rabbit)
50
+ end
51
+ rescue Redis::Distributed::CannotDistribute
52
+ # Not supported on redis-rb < 4, and hence Ruby < 2.2.
53
+ end
54
+ end
55
+
56
+ it "mapped_mget" do
57
+ @dmr.set "rabbit2", @white_rabbit
58
+ begin
59
+ result = @dmr.mapped_mget("rabbit", "rabbit2")
60
+ result.keys.must_equal %w[ rabbit rabbit2 ]
61
+ result["rabbit"].must_equal @rabbit
62
+ result["rabbit2"].must_equal @white_rabbit
63
+ rescue Redis::Distributed::CannotDistribute
64
+ # Not supported on redis-rb < 4, and hence Ruby < 2.2.
65
+ end
66
+ end
67
+
68
+ it "passes through ring replica options" do
69
+ dmr = Redis::DistributedStore.new [
70
+ {:host => "localhost", :port => "6380", :db => 0},
71
+ {:host => "localhost", :port => "6381", :db => 0}
72
+ ], replicas: 1024
73
+ dmr.ring.replicas.must_equal 1024
74
+ end
75
+
76
+ it "uses a custom ring object" do
77
+ my_ring = Redis::HashRing.new
78
+ dmr = Redis::DistributedStore.new [
79
+ {:host => "localhost", :port => "6380", :db => 0},
80
+ {:host => "localhost", :port => "6381", :db => 0}
81
+ ], ring: my_ring
82
+ dmr.ring.must_equal my_ring
83
+ dmr.ring.nodes.length.must_equal 2
84
+ end
85
+
42
86
  describe '#redis_version' do
43
87
  it 'returns redis version' do
44
88
  @dmr.nodes.first.expects(:redis_version)
@@ -22,6 +22,11 @@ describe "Redis::Store::Factory" do
22
22
  store.to_s.must_equal("Redis Client connected to localhost:6380 against DB 0")
23
23
  end
24
24
 
25
+ it "uses specified path" do
26
+ store = Redis::Store::Factory.create :path => "/var/run/redis.sock"
27
+ store.to_s.must_equal("Redis Client connected to /var/run/redis.sock against DB 0")
28
+ end
29
+
25
30
  it "uses specified db" do
26
31
  store = Redis::Store::Factory.create :host => "localhost", :port => 6380, :db => 13
27
32
  store.to_s.must_equal("Redis Client connected to localhost:6380 against DB 13")
@@ -115,6 +120,11 @@ describe "Redis::Store::Factory" do
115
120
  store.to_s.must_equal("Redis Client connected to 127.0.0.1:6380 against DB 0")
116
121
  end
117
122
 
123
+ it "uses specified path" do
124
+ store = Redis::Store::Factory.create "unix:///var/run/redis.sock"
125
+ store.to_s.must_equal("Redis Client connected to /var/run/redis.sock against DB 0")
126
+ end
127
+
118
128
  it "uses specified db" do
119
129
  store = Redis::Store::Factory.create "redis://127.0.0.1:6380/13"
120
130
  store.to_s.must_equal("Redis Client connected to 127.0.0.1:6380 against DB 13")
@@ -125,6 +135,16 @@ describe "Redis::Store::Factory" do
125
135
  store.to_s.must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist")
126
136
  end
127
137
 
138
+ it "uses specified via query namespace" do
139
+ store = Redis::Store::Factory.create "redis://127.0.0.1:6379/0?namespace=theplaylist"
140
+ store.to_s.must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist")
141
+ end
142
+
143
+ it "uses specified namespace with path" do
144
+ store = Redis::Store::Factory.create "unix:///var/run/redis.sock?db=2&namespace=theplaylist"
145
+ store.to_s.must_equal("Redis Client connected to /var/run/redis.sock against DB 2 with namespace theplaylist")
146
+ end
147
+
128
148
  it "uses specified password" do
129
149
  store = Redis::Store::Factory.create "redis://:secret@127.0.0.1:6379/0/theplaylist"
130
150
  store.instance_variable_get(:@client).password.must_equal("secret")
@@ -139,8 +139,18 @@ describe "Redis::Store::Namespace" do
139
139
  end
140
140
 
141
141
  it "should namespace mget" do
142
- client.expects(:call).with([:mget, "#{@namespace}:rabbit", "#{@namespace}:white_rabbit"])
143
- store.mget "rabbit", "white_rabbit"
142
+ client.expects(:call).with([:mget, "#{@namespace}:rabbit", "#{@namespace}:white_rabbit"]).returns(%w[ foo bar ])
143
+ store.mget "rabbit", "white_rabbit" do |result|
144
+ result.must_equal(%w[ foo bar ])
145
+ end
146
+ end
147
+
148
+ it "should namespace mapped_mget" do
149
+ client.expects(:process).with([[:mget, "#{@namespace}:rabbit", "#{@namespace}:white_rabbit"]]).returns(%w[ foo bar ])
150
+ result = store.mapped_mget "rabbit", "white_rabbit"
151
+ result.keys.must_equal %w[ rabbit white_rabbit ]
152
+ result["rabbit"].must_equal "foo"
153
+ result["white_rabbit"].must_equal "bar"
144
154
  end
145
155
 
146
156
  it "should namespace expire" do
@@ -157,5 +167,20 @@ describe "Redis::Store::Namespace" do
157
167
  client.expects(:call).with([:watch,"#{@namespace}:rabbit"]).once
158
168
  store.watch("rabbit")
159
169
  end
170
+
171
+ it "wraps flushdb with appropriate KEYS * calls" do
172
+ client.expects(:call).with([:flushdb]).never
173
+ client.expects(:call).with([:keys,"#{@namespace}:*"]).once.returns(["rabbit"])
174
+ client.expects(:call).with([:del,"#{@namespace}:rabbit"]).once
175
+ store.flushdb
176
+ end
177
+
178
+ it "skips flushdb wrapping if the namespace is nil" do
179
+ client.expects(:call).with([:flushdb])
180
+ client.expects(:call).with([:keys]).never
181
+ store.with_namespace(nil) do
182
+ store.flushdb
183
+ end
184
+ end
160
185
  end
161
186
  end
@@ -97,28 +97,39 @@ describe "Redis::Serialization" do
97
97
  @store.get("rabbit", :raw => true).must_equal(%(#<OpenStruct color="white">))
98
98
  end
99
99
 
100
- it "doesn't unmarshal on multi get" do
100
+ it "unmarshals on multi get" do
101
101
  @store.set "rabbit2", @white_rabbit
102
- rabbits = @store.mget "rabbit", "rabbit2"
103
- rabbit, rabbit2 = rabbits
104
- rabbits.length.must_equal(2)
105
- rabbit.must_equal(@rabbit)
106
- rabbit2.must_equal(@white_rabbit)
102
+ @store.mget "rabbit", "rabbit2" do |rabbits|
103
+ rabbit, rabbit2 = rabbits
104
+ rabbits.length.must_equal(2)
105
+ rabbit.must_equal(@rabbit)
106
+ rabbit2.must_equal(@white_rabbit)
107
+ end
108
+ end
109
+
110
+ it "unmarshals on mapped_mget" do
111
+ @store.set "rabbit2", @white_rabbit
112
+ result = @store.mapped_mget("rabbit", "rabbit2")
113
+ result.keys.must_equal %w[ rabbit rabbit2 ]
114
+ result["rabbit"].must_equal @rabbit
115
+ result["rabbit2"].must_equal @white_rabbit
107
116
  end
108
117
 
109
118
  if RUBY_VERSION.match /1\.9/
110
119
  it "doesn't unmarshal on multi get if raw option is true" do
111
120
  @store.set "rabbit2", @white_rabbit
112
- rabbit, rabbit2 = @store.mget "rabbit", "rabbit2", :raw => true
113
- rabbit.must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF")
114
- rabbit2.must_equal("\x04\bU:\x0FOpenStruct{\x06:\ncolorI\"\nwhite\x06:\x06EF")
121
+ @store.mget "rabbit", "rabbit2", :raw => true do |rabbit, rabbit2|
122
+ rabbit.must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF")
123
+ rabbit2.must_equal("\x04\bU:\x0FOpenStruct{\x06:\ncolorI\"\nwhite\x06:\x06EF")
124
+ end
115
125
  end
116
126
  else
117
127
  it "doesn't unmarshal on multi get if raw option is true" do
118
128
  @store.set "rabbit2", @white_rabbit
119
- rabbit, rabbit2 = @store.mget "rabbit", "rabbit2", :raw => true
120
- rabbit.must_include("\x04\bU:\x0FOpenStruct{\x06:\tname")
121
- rabbit2.must_include("\x04\bU:\x0FOpenStruct{\x06:\ncolor")
129
+ @store.mget "rabbit", "rabbit2", :raw => true do |rabbit, rabbit2|
130
+ rabbit.must_include("\x04\bU:\x0FOpenStruct{\x06:\tname")
131
+ rabbit2.must_include("\x04\bU:\x0FOpenStruct{\x06:\ncolor")
132
+ end
122
133
  end
123
134
  end
124
135
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-store
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-13 00:00:00.000000000 Z
11
+ date: 2018-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -142,6 +142,20 @@ dependencies:
142
142
  - - ">="
143
143
  - !ruby/object:Gem::Version
144
144
  version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: appraisal
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '2.0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: '2.0'
145
159
  description: Namespaced Rack::Session, Rack::Cache, I18n and cache Redis stores for
146
160
  Ruby web frameworks.
147
161
  email:
@@ -152,11 +166,14 @@ extra_rdoc_files: []
152
166
  files:
153
167
  - ".gitignore"
154
168
  - ".travis.yml"
169
+ - Appraisals
155
170
  - CHANGELOG.md
156
171
  - Gemfile
157
172
  - MIT-LICENSE
158
173
  - README.md
159
174
  - Rakefile
175
+ - gemfiles/redis_3_x.gemfile
176
+ - gemfiles/redis_4_x.gemfile
160
177
  - lib/redis-store.rb
161
178
  - lib/redis/distributed_store.rb
162
179
  - lib/redis/store.rb
@@ -198,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
215
  version: '0'
199
216
  requirements: []
200
217
  rubyforge_project: redis-store
201
- rubygems_version: 2.6.11
218
+ rubygems_version: 2.7.3
202
219
  signing_key:
203
220
  specification_version: 4
204
221
  summary: Redis stores for Ruby frameworks