redis-objects 1.0.1 → 1.1.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
2
  SHA1:
3
- metadata.gz: 735c34367c9ed2f4bdd4d64e96c22068bb2956b4
4
- data.tar.gz: 4e0cac119a34d58e46a2d65c3dfab74bda1394fd
3
+ metadata.gz: dc70bd55cafac46d93b6dc5dcd24d2e116c00d1e
4
+ data.tar.gz: d98febd210c47c61f8511f023e09edf86d848f25
5
5
  SHA512:
6
- metadata.gz: c1f48c5fa92ea83c2dcf0df1368d69d60564c69fdffaa82855ef9b898cfa446afa377bdc7a1590bbc82f0ff4282cdce274a615d99810624b7bbb132ca3636326
7
- data.tar.gz: 84ffd1f1185315c8d128c23b598b88b8fca03ede54e794afd8fc42ad2642312d5a086af735f2282e30f734fc83f3c04f011b22be8df2597575ca91bf079ddd29
6
+ metadata.gz: d854a41164664e2e4dafdf3c25e05ad6281ba305cb4c28fcccbff6777b4f2bcc9f773b96e0c7423552957395ab21aa7c0bef5175d70fe4aae7677c04c457c7d4
7
+ data.tar.gz: 090c58f4cbe376b4a37b0bd9c1b70894f036c8bc5b94a62c58e1047c0a175f8418659b260ca26daa3a3c21f6e2c9642694f1176f8c8bc390a6914eccd05e90bb
data/CHANGELOG.rdoc CHANGED
@@ -1,5 +1,23 @@
1
1
  = Changelog for Redis::Objects
2
2
 
3
+ == 1.1.0 (21 Jan 2015)
4
+
5
+ * Support connection_pool useage via a proxy object [Jared Jenkins]
6
+
7
+ * Fix typo on :counter usage [Kevin Bongart]
8
+
9
+ * Use parent redis_id_field if present [Arnaud Lavrard]
10
+
11
+ * Fetch the objects options through a redis_options method [Arnaud Lavrard]
12
+
13
+ == 1.0.1 (14 Oct 2014)
14
+
15
+ * Array handling for unmarshal [dreyks]
16
+
17
+ * Test against Ruby 2.1 / 2.2 on Travis CI [tricknotes]
18
+
19
+ * Redis::Set#randmember method accept count as optional parameter [xeviknal]
20
+
3
21
  == 1.0.0 (25 Jul 2014)
4
22
 
5
23
  * Fix expiration filter to handle atomic blocks, remove method aliasing [nateware]
data/README.md CHANGED
@@ -36,10 +36,17 @@ Add it to your Gemfile as:
36
36
  gem 'redis-objects'
37
37
  ~~~
38
38
 
39
- Redis::Objects needs a handle created by `Redis.new`. The recommended approach
40
- is to set `Redis.current` to point to your server, which Redis::Objects will
41
- pick up automatically.
39
+ Redis::Objects needs a handle created by `Redis.new` or a [ConnectionPool](https://github.com/mperham/connection_pool):
42
40
 
41
+ The recommended approach is to use a `ConnectionPool` since this guarantees that most timeouts in the `redis` client
42
+ do not pollute your existing connection. However, you need to make sure that both `:timeout` and `:size` are set appropriately
43
+ in a multithreaded environment.
44
+ ~~~ruby
45
+ require 'connection_pool'
46
+ Redis::Objects.redis = ConnectionPool.new(size: 5, timeout: 5) { Redis.new(:host => '127.0.0.1', :port => 6379) }
47
+ ~~~
48
+
49
+ Redis::Objects can also default to `Redis.current` if `Redis::Objects.redis` is not set.
43
50
  ~~~ruby
44
51
  Redis.current = Redis.new(:host => '127.0.0.1', :port => 6379)
45
52
  ~~~
@@ -64,6 +71,7 @@ class Post
64
71
  include Redis::Objects
65
72
  end
66
73
 
74
+ # you can also use a ConnectionPool here as well
67
75
  User.redis = Redis.new(:host => '1.2.3.4')
68
76
  Post.redis = Redis.new(:host => '5.6.7.8')
69
77
  ~~~
@@ -97,7 +105,7 @@ user.id # 1
97
105
  user.my_posts.increment
98
106
  user.my_posts.increment
99
107
  user.my_posts.increment
100
- puts user.my_posts # 3
108
+ puts user.my_posts.value # 3
101
109
  user.my_posts.reset
102
110
  puts user.my_posts.value # 0
103
111
  user.my_posts.reset 5
data/Rakefile CHANGED
@@ -4,6 +4,10 @@ desc "run all the specs"
4
4
  task :test do
5
5
  sh "bacon spec/*_spec.rb"
6
6
  end
7
-
8
7
  task :default => :test
9
8
 
9
+ desc "show changelog"
10
+ task :changelog do
11
+ latest = `git tag |tail -1`.chomp
12
+ system "git log --pretty=format:'* %s %b [%an]' #{latest}..HEAD"
13
+ end
@@ -4,7 +4,7 @@ class Redis
4
4
  def initialize(key, *args)
5
5
  @key = key.is_a?(Array) ? key.flatten.join(':') : key
6
6
  @options = args.last.is_a?(Hash) ? args.pop : {}
7
- @myredis = args.first
7
+ @myredis = Objects::ConnectionPoolProxy.proxy_if_needed(args.first)
8
8
  end
9
9
 
10
10
  # Dynamically query the handle to enable resetting midstream
data/lib/redis/objects.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # Redis::Objects - Lightweight object layer around redis-rb
2
2
  # See README.rdoc for usage and approach.
3
3
  require 'redis'
4
+ require 'redis/objects/connection_pool_proxy'
4
5
 
5
6
  class Redis
6
7
  autoload :Counter, 'redis/counter'
@@ -60,7 +61,7 @@ class Redis
60
61
 
61
62
  class << self
62
63
  def redis=(conn)
63
- @redis = conn
64
+ @redis = Objects::ConnectionPoolProxy.proxy_if_needed(conn)
64
65
  end
65
66
  def redis
66
67
  @redis || $redis || Redis.current ||
@@ -88,7 +89,10 @@ class Redis
88
89
  # Class methods that appear in your class when you include Redis::Objects.
89
90
  module ClassMethods
90
91
  # Enable per-class connections (eg, User and Post can use diff redis-server)
91
- attr_writer :redis
92
+ def redis=(conn)
93
+ @redis = Objects::ConnectionPoolProxy.proxy_if_needed(conn)
94
+ end
95
+
92
96
  def redis
93
97
  @redis || Objects.redis
94
98
  end
@@ -109,9 +113,19 @@ class Redis
109
113
  downcase
110
114
  end
111
115
 
116
+ def redis_options(name)
117
+ klass = first_ancestor_with(name)
118
+ return klass.redis_objects[name.to_sym] || {}
119
+ end
120
+
112
121
  def redis_field_redis(name) #:nodoc:
113
122
  klass = first_ancestor_with(name)
114
- return klass.redis_objects[name.to_sym][:redis] || self.redis
123
+ override_redis = klass.redis_objects[name.to_sym][:redis]
124
+ if override_redis
125
+ Objects::ConnectionPoolProxy.proxy_if_needed(override_redis)
126
+ else
127
+ self.redis
128
+ end
115
129
  end
116
130
 
117
131
  def redis_field_key(name, id=nil, context=self) #:nodoc:
@@ -143,7 +157,13 @@ class Redis
143
157
  end
144
158
 
145
159
  def redis_id_field(id=nil)
146
- @redis_id_field = id || @redis_id_field || :id
160
+ @redis_id_field = id || @redis_id_field
161
+
162
+ if superclass && superclass.respond_to?(:redis_id_field)
163
+ @redis_id_field ||= superclass.redis_id_field
164
+ end
165
+
166
+ @redis_id_field ||= :id
147
167
  end
148
168
  end
149
169
 
@@ -153,6 +173,10 @@ class Redis
153
173
  def redis() self.class.redis end
154
174
  def redis_objects() self.class.redis_objects end
155
175
 
176
+ def redis_options(name) #:nodoc:
177
+ return self.class.redis_options(name)
178
+ end
179
+
156
180
  def redis_field_redis(name) #:nodoc:
157
181
  return self.class.redis_field_redis(name)
158
182
  end
@@ -0,0 +1,30 @@
1
+ class Redis
2
+ module Objects
3
+ class ConnectionPoolProxy
4
+ def initialize(pool)
5
+ raise ArgumentError "Should only proxy ConnectionPool!" unless self.class.should_proxy?(pool)
6
+ @pool = pool
7
+ end
8
+
9
+ def method_missing(name, *args, &block)
10
+ @pool.with { |x| x.send(name, *args, &block) }
11
+ end
12
+
13
+ def respond_to_missing?(name, include_all = false)
14
+ @pool.with { |x| x.respond_to?(name, include_all) }
15
+ end
16
+
17
+ def self.should_proxy?(conn)
18
+ defined?(::ConnectionPool) && conn.is_a?(::ConnectionPool)
19
+ end
20
+
21
+ def self.proxy_if_needed(conn)
22
+ if should_proxy?(conn)
23
+ ConnectionPoolProxy.new(conn)
24
+ else
25
+ conn
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -29,7 +29,7 @@ class Redis
29
29
  instance_variable_get("@#{name}") or
30
30
  instance_variable_set("@#{name}",
31
31
  Redis::Counter.new(
32
- redis_field_key(name), redis_field_redis(name), redis_objects[name.to_sym]
32
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
33
33
  )
34
34
  )
35
35
  end
@@ -21,7 +21,7 @@ class Redis
21
21
  instance_variable_get("@#{name}") or
22
22
  instance_variable_set("@#{name}",
23
23
  Redis::HashKey.new(
24
- redis_field_key(name), redis_field_redis(name), redis_objects[name.to_sym]
24
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
25
25
  )
26
26
  )
27
27
  end
@@ -21,7 +21,7 @@ class Redis
21
21
  instance_variable_get("@#{name}") or
22
22
  instance_variable_set("@#{name}",
23
23
  Redis::List.new(
24
- redis_field_key(name), redis_field_redis(name), redis_objects[name.to_sym]
24
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
25
25
  )
26
26
  )
27
27
  end
@@ -21,7 +21,7 @@ class Redis
21
21
  instance_variable_get("@#{name}") or
22
22
  instance_variable_set("@#{name}",
23
23
  Redis::Set.new(
24
- redis_field_key(name), redis_field_redis(name), redis_objects[name.to_sym]
24
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
25
25
  )
26
26
  )
27
27
  end
@@ -21,7 +21,7 @@ class Redis
21
21
  instance_variable_get("@#{name}") or
22
22
  instance_variable_set("@#{name}",
23
23
  Redis::SortedSet.new(
24
- redis_field_key(name), redis_field_redis(name), redis_objects[name.to_sym]
24
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
25
25
  )
26
26
  )
27
27
  end
@@ -21,7 +21,7 @@ class Redis
21
21
  instance_variable_get("@#{name}") or
22
22
  instance_variable_set("@#{name}",
23
23
  Redis::Value.new(
24
- redis_field_key(name), redis_field_redis(name), redis_objects[name.to_sym]
24
+ redis_field_key(name), redis_field_redis(name), redis_options(name)
25
25
  )
26
26
  )
27
27
  end
@@ -1,5 +1,5 @@
1
1
  class Redis
2
2
  module Objects
3
- VERSION = "1.0.1"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -4,13 +4,13 @@
4
4
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
5
5
 
6
6
  require 'redis/objects'
7
+ require 'connection_pool'
7
8
 
8
9
  BAD_REDIS = "totally bad bogus redis handle"
9
10
 
10
11
  # Grab a global handle
11
12
  describe 'Connection tests' do
12
- it "should support overriding object handles" do
13
-
13
+ it "should support overriding object handles with a vanilla redis connection" do
14
14
  class CustomConnectionObject
15
15
  include Redis::Objects
16
16
 
@@ -41,7 +41,38 @@ describe 'Connection tests' do
41
41
  obj.default_redis_value.clear
42
42
  end
43
43
 
44
- it "should support local handles" do
44
+ it "should support overriding object handles with a connection_pool" do
45
+ class CustomConnectionObject
46
+ include Redis::Objects
47
+
48
+ def id
49
+ return 1
50
+ end
51
+
52
+ redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT, :db => 31) }
53
+ value :redis_value, :redis => redis_handle, :key => 'rval'
54
+ value :default_redis_value, :key => 'rval'
55
+ end
56
+
57
+ obj = CustomConnectionObject.new
58
+
59
+ obj.default_redis_value.value.should == nil
60
+ obj.redis_value.value.should == nil
61
+
62
+ obj.default_redis_value.value = 'foo'
63
+ obj.default_redis_value.value.should == 'foo'
64
+ obj.redis_value.value.should == nil
65
+
66
+ obj.default_redis_value.clear
67
+ obj.redis_value.value = 'foo'
68
+ obj.redis_value.value.should == 'foo'
69
+ obj.default_redis_value.value.should == nil
70
+
71
+ obj.redis_value.clear
72
+ obj.default_redis_value.clear
73
+ end
74
+
75
+ it "should support local handles with a vanilla redis connection" do
45
76
  Redis.current = nil # reset from other tests
46
77
  Redis::Objects.redis = nil
47
78
  @redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
@@ -86,6 +117,51 @@ describe 'Connection tests' do
86
117
  c.decr(1)
87
118
  end
88
119
 
120
+ it "should support local handles with a connection_pool" do
121
+ Redis.current = nil # reset from other tests
122
+ Redis::Objects.redis = nil
123
+ @redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT) }
124
+
125
+ # Redis.current is lazily auto-populated to touch 6379
126
+ # This why we choose the weird 9212 port to avoid
127
+ Redis.current.inspect.should == Redis.new.inspect
128
+ Redis::Objects.redis.inspect.should == Redis.new.inspect
129
+
130
+ v = Redis::Value.new('conn/value', @redis_handle)
131
+ v.clear
132
+ v.value = 'yay'
133
+ v.value.should == 'yay'
134
+
135
+ h = Redis::HashKey.new('conn/hash', @redis_handle)
136
+ h.clear
137
+ h['k'] = 'v'
138
+
139
+ l = Redis::List.new('conn/list', @redis_handle)
140
+ l.clear
141
+ l << 3
142
+ l << 4
143
+ l << 5
144
+
145
+ s = Redis::Set.new('conn/set', @redis_handle)
146
+ s.clear
147
+ s << 5
148
+ s << 5
149
+ s << 6
150
+ s << 7
151
+
152
+ z = Redis::SortedSet.new('conn/zset', @redis_handle)
153
+ z.clear
154
+ z['a'] = 8
155
+ z['b'] = 7
156
+ z['c'] = 9
157
+ z['d'] = 6
158
+
159
+ c = Redis::Counter.new('conn/counter', @redis_handle)
160
+ c.reset
161
+ c.incr(3)
162
+ c.decr(1)
163
+ end
164
+
89
165
  it "should support Redis.current" do
90
166
  Redis.current = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
91
167
 
@@ -97,7 +173,41 @@ describe 'Connection tests' do
97
173
  Redis::Counter.new('conn/counter').should == 2
98
174
  end
99
175
 
100
- it "should support Redis::Objects.redis=" do
176
+ it "should support Redis::Objects.redis= with a connection_pool" do
177
+ @redis_handle = ConnectionPool.new { Redis.new(:host => REDIS_HOST, :port => REDIS_PORT) }
178
+
179
+ # Redis.current is lazily auto-populated to touch 6379
180
+ # This why we choose the weird 9212 port to avoid
181
+ Redis.current = BAD_REDIS
182
+ Redis::Objects.redis.should == BAD_REDIS
183
+
184
+ # This set of tests sucks, it fucks up the per-data-type handles
185
+ # because Redis.current is then set to a BS value, and the lazy
186
+ # init code in redis-rb will keep that value until we clear it.
187
+ # This ends up fucking any sequential tests.
188
+ raises_exception{ Redis::Value.new('conn/value').should.be.nil }
189
+ raises_exception{ Redis::HashKey.new('conn/hash').keys.should == [] }
190
+ raises_exception{ Redis::List.new('conn/list').sort.should == [] }
191
+ raises_exception{ Redis::Set.new('conn/set').sort.should == [] }
192
+ raises_exception{ Redis::SortedSet.new('conn/zset').should == [] }
193
+ raises_exception{ Redis::Counter.new('conn/counter').get.should == 0 }
194
+
195
+ Redis::Objects.redis = @redis_handle
196
+ Redis::Value.new('fart').redis.is_a?(Redis::Objects::ConnectionPoolProxy).should == true
197
+
198
+ # These should now get the correct handle
199
+ Redis::Value.new('conn/value').should == 'yay'
200
+ Redis::HashKey.new('conn/hash').keys.should == ['k']
201
+ Redis::List.new('conn/list').sort.should == ['3', '4', '5']
202
+ Redis::Set.new('conn/set').sort.should == ['5', '6', '7']
203
+ Redis::SortedSet.new('conn/zset').should == ['d', 'b', 'a', 'c']
204
+ Redis::Counter.new('conn/counter').should == 2
205
+
206
+ end
207
+
208
+ it "should support Redis::Objects.redis= with a vanilla redis connection" do
209
+ # reset redis
210
+ Redis::Objects.redis = nil
101
211
  @redis_handle = Redis.new(:host => REDIS_HOST, :port => REDIS_PORT)
102
212
 
103
213
  # Redis.current is lazily auto-populated to touch 6379
@@ -130,5 +240,4 @@ describe 'Connection tests' do
130
240
  # Fix for future tests
131
241
  Redis.current = @redis_handle
132
242
  end
133
-
134
243
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-objects
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Wiger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-14 00:00:00.000000000 Z
11
+ date: 2015-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: connection_pool
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: redis-namespace
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -117,6 +131,7 @@ files:
117
131
  - lib/redis/list.rb
118
132
  - lib/redis/lock.rb
119
133
  - lib/redis/objects.rb
134
+ - lib/redis/objects/connection_pool_proxy.rb
120
135
  - lib/redis/objects/counters.rb
121
136
  - lib/redis/objects/hashes.rb
122
137
  - lib/redis/objects/lists.rb