redis-objects 0.2.1 → 0.3.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.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,37 @@
1
+ = Changelog for Redis::Objects
2
+
3
+ == 0.3.0 [Final] (14 April 2010)
4
+
5
+ * Due to Ruby 1.9 bugs and performance considerations, marshaling of
6
+ data types is now OFF by default. You must say :marshal => true for
7
+ any objects that you want serialization enabled on. [Nate Wiger]
8
+
9
+ * Sorted Set class changed slightly due to feedback. You can now get
10
+ an individual element back via @set['item'] since it acts like a Hash.
11
+
12
+ == 0.2.4 [Final] (9 April 2010)*
13
+
14
+ * Added sorted set support via Redis::SortedSet [Nate Wiger]
15
+
16
+ == 0.2.3 [Final] (18 February 2010)*
17
+
18
+ * Added lock expiration to Redis::Lock [Ben VandenBos]
19
+
20
+ * Fixed some bugs [Ben VandenBos]
21
+
22
+ * Added lock tests and test helpers [Ben VandenBos]
23
+
24
+ == 0.2.2 [Final] (14 December 2009)*
25
+
26
+ * Added @set.diff(@set2) with "^" and "-" synonyms (oversight). [Nate Wiger]
27
+
28
+ * Implemented Redis core commands in all data types, such as rename. [Nate Wiger]
29
+
30
+ * Renamed Redis::Serialize to Redis::Helpers::Serialize to keep Redis:: cleaner. [Nate Wiger]
31
+
32
+ * More spec coverage. [Nate Wiger]
33
+
34
+ == 0.2.1 [Final] (27 November 2009)*
35
+
36
+ * First worthwhile public release, with good spec coverage and functionality. [Nate Wiger]
37
+
data/README.rdoc CHANGED
@@ -1,48 +1,142 @@
1
1
  = Redis::Objects - Map Redis types directly to Ruby objects
2
2
 
3
- This is *not* an ORM. People that are wrapping ORM's around Redis are missing
4
- the point.
3
+ This is *not* an ORM. People that are wrapping ORMs around Redis are missing the point.
5
4
 
6
- The killer feature of Redis that it allows you to perform atomic operations
7
- on _individual_ data structures, like counters, lists, and sets. You can then use
8
- these *with* your existing ActiveRecord/DataMapper/etc models, or in classes that have
9
- nothing to do with an ORM or even a database. This gem maps Ezra's +redis+ library
10
- to Ruby objects to make use seamless.
5
+ The killer feature of Redis is that it allows you to perform _atomic_ operations
6
+ on _individual_ data structures, like counters, lists, and sets. The *atomic* part is HUGE.
7
+ Using an ORM wrapper that retrieves a "record", updates values, then sends those values back,
8
+ _removes_ the atomicity, cutting the nuts off the major advantage of Redis. Just use MySQL, k?
9
+
10
+ This gem provides a Rubyish interface to Redis, by mapping {Redis types}[http://code.google.com/p/redis/wiki/CommandReference]
11
+ to Ruby objects, via a thin layer over Ezra's +redis+ gem. It offers several advantages
12
+ over the lower-level redis-rb API:
13
+
14
+ 1. Easy to integrate directly with existing ORMs - ActiveRecord, DataMapper, etc. Add counters to your model!
15
+ 2. Complex data structures are automatically Marshaled (if you set :marshal => true)
16
+ 3. Integers are returned as integers, rather than '17'
17
+ 4. Higher-level types are provided, such as Locks, that wrap multiple calls
11
18
 
12
19
  This gem originally arose out of a need for high-concurrency atomic operations;
13
- for a fun rant on the topic, see
14
- {ATOMICITY}[http://github.com/nateware/redis-objects/blob/master/ATOMICITY.rdoc],
20
+ for a fun rant on the topic, see {An Atomic Rant}[http://nateware.com/2010/02/18/an-atomic-rant],
15
21
  or scroll down to "Atomicity" in this README.
16
22
 
17
- There are two ways to use Redis::Objects, either as an +include+ in a model class,
18
- or by using +new+ with the type of data structure you want to create.
23
+ There are two ways to use Redis::Objects, either as an include in a model class (to
24
+ integrate with ORMs or other classes), or by using new with the type of data structure
25
+ you want to create.
19
26
 
20
27
  == Installation
21
28
 
22
- gem install gemcutter
23
- gem tumble
24
29
  gem install redis-objects
25
30
 
26
- == Example 1: Individual Usage
31
+ == Example 1: Model Class Usage
32
+
33
+ Using Redis::Objects this way makes it trivial to integrate Redis types with an
34
+ existing ActiveRecord model, DataMapper resource, or other class. Redis::Objects
35
+ will work with _any_ class that provides an +id+ method that returns a unique
36
+ value. Redis::Objects will automatically create keys that are unique to
37
+ each object, in the format:
38
+
39
+ model_name:id:field_name
40
+
41
+ === Initialization
42
+
43
+ Redis::Objects needs a handle created by Redis.new. (If you're on Rails,
44
+ config/initializers/redis.rb is a good place for this.)
45
+
46
+ require 'redis'
47
+ require 'redis/objects'
48
+ Redis::Objects.redis = Redis.new(:host => 127.0.0.1, :port => 6379)
49
+
50
+ Remember you can use Redis::Objects in any Ruby code. There are *no* dependencies
51
+ on Rails. Standalone, Sinatra, Resque - no problem.
52
+
53
+ === Model Class
54
+
55
+ You can include Redis::Objects in any type of class:
56
+
57
+ class Team < ActiveRecord::Base
58
+ include Redis::Objects
59
+
60
+ lock :trade_players, :expiration => 15 # sec
61
+ counter :hits
62
+ counter :runs
63
+ counter :outs
64
+ counter :inning, :start => 1
65
+ list :on_base
66
+ set :outfielders
67
+ value :at_bat
68
+ end
69
+
70
+ Familiar Ruby array operations Just Work (TM):
71
+
72
+ @team = Team.find_by_name('New York Yankees')
73
+ @team.on_base << 'player1'
74
+ @team.on_base << 'player2'
75
+ @team.on_base << 'player3'
76
+ @team.on_base # ['player1', 'player2', 'player3']
77
+ @team.on_base.pop
78
+ @team.on_base.shift
79
+ @team.on_base.length # 1
80
+ @team.on_base.delete('player2')
81
+
82
+ Sets work too:
83
+
84
+ @team.outfielders << 'outfielder1'
85
+ @team.outfielders << 'outfielder2'
86
+ @team.outfielders << 'outfielder1' # dup ignored
87
+ @team.outfielders # ['outfielder1', 'outfielder2']
88
+ @team.outfielders.each do |player|
89
+ puts player
90
+ end
91
+ player = @team.outfielders.detect{|of| of == 'outfielder2'}
92
+
93
+ And you can do intersections between objects (kinda cool):
94
+
95
+ @team1.outfielders | @team2.outfielders # outfielders on both teams
96
+ @team1.outfielders & @team2.outfielders # in baseball, should be empty :-)
97
+
98
+ Counters can be atomically incremented/decremented (but not assigned):
99
+
100
+ @team.hits.increment # or incr
101
+ @team.hits.decrement # or decr
102
+ @team.hits.incr(3) # add 3
103
+ @team.runs = 4 # exception
104
+
105
+ Finally, for free, you get a +redis+ method that points directly to a Redis connection:
106
+
107
+ Team.redis.get('somekey')
108
+ @team = Team.new
109
+ @team.redis.get('somekey')
110
+ @team.redis.smembers('someset')
111
+
112
+ You can use the +redis+ handle to directly call any {Redis API command}[http://code.google.com/p/redis/wiki/CommandReference].
113
+
114
+ == Example 2: Standalone Usage
27
115
 
28
- There is a Ruby object that maps to each Redis type.
116
+ There is a Ruby class that maps to each Redis type, with methods for each
117
+ {Redis API command}[http://code.google.com/p/redis/wiki/CommandReference].
118
+ Note that calling +new+ does not imply it's actually a "new" value - it just
119
+ creates a mapping between that object and the corresponding Redis data structure,
120
+ which may already exist on the redis-server.
29
121
 
30
122
  === Initialization
31
123
 
32
- You can either set the $redis global variable to your Redis handle:
124
+ Redis::Objects needs a handle to the +redis+ server. For standalone use, you
125
+ can either set the $redis global variable:
33
126
 
34
127
  $redis = Redis.new(:host => 'localhost', :port => 6379)
35
- @value = Redis::Value.new('myvalue')
128
+ @list = Redis::List.new('mylist')
36
129
 
37
- Or you can pass the Redis handle into the new method:
130
+ Or you can pass the Redis handle into the new method for each type:
38
131
 
39
132
  redis = Redis.new(:host => 'localhost', :port => 6379)
40
- @value = Redis::Value.new('myvalue', redis)
133
+ @list = Redis::List.new('mylist', redis)
41
134
 
42
135
  === Counters
43
136
 
44
137
  Create a new counter. The +counter_name+ is the key stored in Redis.
45
138
 
139
+ require 'redis/counter'
46
140
  @counter = Redis::Counter.new('counter_name')
47
141
  @counter.increment
48
142
  @counter.decrement
@@ -56,10 +150,39 @@ This gem provides a clean way to do atomic blocks as well:
56
150
 
57
151
  See the section on "Atomicity" for cool uses of atomic counter blocks.
58
152
 
153
+ === Locks
154
+
155
+ A convenience class that wraps the pattern of {using +setnx+ to perform locking}[http://code.google.com/p/redis/wiki/SetnxCommand].
156
+
157
+ require 'redis/lock'
158
+ @lock = Redis::Lock.new('image_resizing', :expiration => 15, :timeout => 0.1)
159
+ @lock.lock do
160
+ # do work
161
+ end
162
+
163
+ This can be especially useful if you're running batch jobs spread across multiple hosts.
164
+
165
+ === Values
166
+
167
+ Simple values are easy as well:
168
+
169
+ require 'redis/value'
170
+ @value = Redis::Value.new('value_name')
171
+ @value.value = 'a'
172
+ @value.delete
173
+
174
+ Complex data is no problem with :marshal => true:
175
+
176
+ @account = Account.create!(params[:account])
177
+ @newest = Redis::Value.new('newest_account', :marshal => true)
178
+ @newest.value = @account.attributes
179
+ puts @newest.value['username']
180
+
59
181
  === Lists
60
182
 
61
183
  Lists work just like Ruby arrays:
62
184
 
185
+ require 'redis/list'
63
186
  @list = Redis::List.new('list_name')
64
187
  @list << 'a'
65
188
  @list << 'b'
@@ -75,18 +198,20 @@ Lists work just like Ruby arrays:
75
198
  @list.clear
76
199
  # etc
77
200
 
78
- Complex data types are no problem:
201
+ Complex data types are no problem with :marshal => true:
79
202
 
203
+ @list = Redis::List.new('list_name', :marshal => true)
80
204
  @list << {:name => "Nate", :city => "San Diego"}
81
205
  @list << {:name => "Peter", :city => "Oceanside"}
82
206
  @list.each do |el|
83
207
  puts "#{el[:name]} lives in #{el[:city]}"
84
208
  end
85
-
209
+
86
210
  === Sets
87
211
 
88
212
  Sets work like the Ruby {Set}[http://ruby-doc.org/core/classes/Set.html] class:
89
213
 
214
+ require 'redis/set'
90
215
  @set = Redis::Set.new('set_name')
91
216
  @set << 'a'
92
217
  @set << 'b'
@@ -99,7 +224,7 @@ Sets work like the Ruby {Set}[http://ruby-doc.org/core/classes/Set.html] class:
99
224
  @set.clear
100
225
  # etc
101
226
 
102
- You can perform Redis intersections/unions easily:
227
+ You can perform Redis intersections/unions/diffs easily:
103
228
 
104
229
  @set1 = Redis::Set.new('set1')
105
230
  @set2 = Redis::Set.new('set2')
@@ -107,8 +232,11 @@ You can perform Redis intersections/unions easily:
107
232
  members = @set1 & @set2 # intersection
108
233
  members = @set1 | @set2 # union
109
234
  members = @set1 + @set2 # union
235
+ members = @set1 ^ @set2 # difference
236
+ members = @set1 - @set2 # difference
110
237
  members = @set1.intersection(@set2, @set3) # multiple
111
238
  members = @set1.union(@set2, @set3) # multiple
239
+ members = @set1.difference(@set2, @set3) # multiple
112
240
 
113
241
  Or store them in Redis:
114
242
 
@@ -116,104 +244,66 @@ Or store them in Redis:
116
244
  members = @set1.redis.get('intername')
117
245
  @set1.unionstore('unionname', @set2, @set3)
118
246
  members = @set1.redis.get('unionname')
247
+ @set1.diffstore('diffname', @set2, @set3)
248
+ members = @set1.redis.get('diffname')
119
249
 
120
- And use complex data types too:
250
+ And use complex data types too, with :marshal => true:
121
251
 
252
+ @set1 = Redis::Set.new('set1', :marshal => true)
253
+ @set2 = Redis::Set.new('set2', :marshal => true)
122
254
  @set1 << {:name => "Nate", :city => "San Diego"}
123
255
  @set1 << {:name => "Peter", :city => "Oceanside"}
124
256
  @set2 << {:name => "Nate", :city => "San Diego"}
125
257
  @set2 << {:name => "Jeff", :city => "Del Mar"}
126
258
 
127
259
  @set1 & @set2 # Nate
260
+ @set1 - @set2 # Peter
128
261
  @set1 | @set2 # all 3 people
129
262
 
130
- === Values
131
-
132
- Simple values are easy as well:
133
-
134
- @value = Redis::Value.new('value_name')
135
- @value.value = 'a'
136
- @value.delete
137
-
138
- Of course complex data is no problem:
139
-
140
- @account = Account.create!(params[:account])
141
- @newest = Redis::Value.new('newest_account')
142
- @newest.value = @account
143
-
144
- == Example 2: Class Usage
145
-
146
- Using Redis::Objects this way makes it trivial to integrate Redis types with an
147
- existing ActiveRecord model, DataMapper resource, or other class. Redis::Objects
148
- will work with any class that provides an +id+ method that returns a unique
149
- value. Redis::Objects will automatically create keys that are unique to
150
- each object.
151
-
152
- === Initialization
153
-
154
- If on Rails, config/initializers/redis.rb is a good place for this:
263
+ === Sorted Sets
155
264
 
156
- require 'redis'
157
- require 'redis/objects'
158
- Redis::Objects.redis = Redis.new(:host => 127.0.0.1, :port => 6379)
159
-
160
- === Model Class
265
+ Due to their unique properties, Sorted Sets work like a hybrid between
266
+ a Hash and an Array. You assign like a Hash, but retrieve like an Array:
161
267
 
162
- Include Redis::Objects in any type of class:
163
-
164
- class Team < ActiveRecord::Base
165
- include Redis::Objects
166
-
167
- counter :hits
168
- counter :runs
169
- counter :outs
170
- counter :inning, :start => 1
171
- list :on_base
172
- set :outfielders
173
- value :at_bat
174
- end
268
+ require 'redis/sorted_set'
269
+ @sorted_set = Redis::SortedSet.new('number_of_posts')
270
+ @sorted_set['Nate'] = 15
271
+ @sorted_set['Peter'] = 75
272
+ @sorted_set['Jeff'] = 24
175
273
 
176
- Familiar Ruby array operations Just Work (TM):
274
+ # Array access to get sorted order
275
+ @sorted_set[0..2] # => ["Nate", "Jeff", "Peter"]
276
+ @sorted_set[0,2] # => ["Nate", "Jeff"]
177
277
 
178
- @team = Team.find_by_name('New York Yankees')
179
- @team.on_base << 'player1'
180
- @team.on_base << 'player2'
181
- @team.on_base << 'player3'
182
- @team.on_base # ['player1', 'player2']
183
- @team.on_base.pop
184
- @team.on_base.shift
185
- @team.on_base.length # 1
186
- @team.on_base.delete('player3')
278
+ @sorted_set['Peter'] # => 75
279
+ @sorted_set['Jeff'] # => 24
280
+ @sorted_set.score('Jeff') # same thing (24)
187
281
 
188
- Sets operations work too:
189
-
190
- @team.outfielders << 'outfielder1' << 'outfielder1'
191
- @team.outfielders << 'outfielder2'
192
- @team.outfielders # ['outfielder1', 'outfielder2']
193
- @team.outfielders.each do |player|
194
- puts player
195
- end
196
- player = @team.outfielders.detect{|of| of == 'outfielder2'}
282
+ @sorted_set.rank('Peter') # => 2
283
+ @sorted_set.rank('Jeff') # => 1
197
284
 
198
- Counters can be atomically incremented/decremented (but not assigned):
285
+ @sorted_set.first # => "Nate"
286
+ @sorted_set.last # => "Peter"
287
+ @sorted_set.revrange(0,2) # => ["Peter", "Jeff", "Nate"]
199
288
 
200
- @team.hits.increment # or incr
201
- @team.hits.decrement # or decr
202
- @team.hits.incr(3) # add 3
203
- @team.runs = 4 # exception
289
+ @sorted_set['Newbie'] = 1
290
+ @sorted_set.members # => ["Newbie", "Nate", "Jeff", "Peter"]
204
291
 
205
- For free, you get a +redis+ handle usable in your class:
292
+ @sorted_set.rangebyscore(10, 100, :limit => 2) # => ["Nate", "Jeff"]
293
+ @sorted_set.members(:withscores => true) # => [["Newbie", 1], ["Nate", 16], ["Jeff", 28], ["Peter", 76]]
206
294
 
207
- @team.redis.get('somekey')
208
- @team.redis.smembers('someset')
295
+ # atomic increment
296
+ @sorted_set.increment('Nate')
297
+ @sorted_set.incr('Peter') # shorthand
298
+ @sorted_set.incr('Jeff', 4)
209
299
 
210
- You can call any operation supported by {Redis}[http://code.google.com/p/redis/wiki/CommandReference]
300
+ The other Redis Sorted Set commands are supported as well; see {Sorted Sets API}[http://code.google.com/p/redis/wiki/SortedSets].
211
301
 
212
- == Atomicity
302
+ == Atomic Counters and Locks
213
303
 
214
304
  You are probably not handling atomicity correctly in your app. For a fun rant
215
305
  on the topic, see
216
- {ATOMICITY}[http://github.com/nateware/redis-objects/blob/master/ATOMICITY.rdoc].
306
+ {An Atomic Rant}[http://nateware.com/2010/02/18/an-atomic-rant].
217
307
 
218
308
  Atomic counters are a good way to handle concurrency:
219
309
 
@@ -260,6 +350,10 @@ Class-level atomic block (may save a DB fetch depending on your app):
260
350
 
261
351
  Locks with Redis. On completion or exception the lock is released:
262
352
 
353
+ class Team < ActiveRecord::Base
354
+ lock :reorder # declare a lock
355
+ end
356
+
263
357
  @team.reorder_lock.lock do
264
358
  @team.reorder_all_players
265
359
  end
@@ -270,9 +364,19 @@ Class-level lock (same concept)
270
364
  Team.reorder_all_players(team_id)
271
365
  end
272
366
 
367
+ Lock expiration. Sometimes you want to make sure your locks are cleaned up should
368
+ the unthinkable happen (server failure). You can set lock expirations to handle
369
+ this. Expired locks are released by the next process to attempt lock. Just
370
+ make sure you expiration value is sufficiently large compared to your expected
371
+ lock time.
372
+
373
+ class Team < ActiveRecord::Base
374
+ lock :reorder, :expiration => 15.minutes
375
+ end
376
+
273
377
 
274
378
  == Author
275
379
 
276
- Copyright (c) 2009 {Nate Wiger}[http://nate.wiger.org]. All Rights Reserved.
380
+ Copyright (c) 2009-2010 {Nate Wiger}[http://nate.wiger.org]. All Rights Reserved.
277
381
  Released under the {Artistic License}[http://www.opensource.org/licenses/artistic-license-2.0.php].
278
382
 
data/lib/redis/counter.rb CHANGED
@@ -7,11 +7,14 @@ class Redis
7
7
  # class to define a counter.
8
8
  #
9
9
  class Counter
10
+ require 'redis/helpers/core_commands'
11
+ include Redis::Helpers::CoreCommands
12
+
10
13
  attr_reader :key, :options, :redis
11
- def initialize(key, redis=$redis, options={})
14
+ def initialize(key, *args)
12
15
  @key = key
13
- @redis = redis
14
- @options = options
16
+ @options = args.last.is_a?(Hash) ? args.pop : {}
17
+ @redis = args.first || $redis
15
18
  @options[:start] ||= 0
16
19
  @redis.setnx(key, @options[:start]) unless @options[:start] == 0 || @options[:init] === false
17
20
  end
@@ -21,7 +24,8 @@ class Redis
21
24
  # with a parent and starting over (for example, restarting a game and
22
25
  # disconnecting all players).
23
26
  def reset(to=options[:start])
24
- redis.set(key, to.to_i)
27
+ redis.set key, to.to_i
28
+ true # hack for redis-rb regression
25
29
  end
26
30
 
27
31
  # Returns the current value of the counter. Normally just calling the
@@ -33,19 +37,13 @@ class Redis
33
37
  end
34
38
  alias_method :get, :value
35
39
 
36
- # Delete a counter. Usage discouraged. Consider +reset+ instead.
37
- def delete
38
- redis.del(key)
39
- end
40
- alias_method :del, :delete
41
-
42
40
  # Increment the counter atomically and return the new value. If passed
43
41
  # a block, that block will be evaluated with the new value of the counter
44
42
  # as an argument. If the block returns nil or throws an exception, the
45
43
  # counter will automatically be decremented to its previous value. This
46
44
  # method is aliased as incr() for brevity.
47
45
  def increment(by=1, &block)
48
- val = redis.incr(key, by).to_i
46
+ val = redis.incrby(key, by).to_i
49
47
  block_given? ? rewindable_block(:decrement, val, &block) : val
50
48
  end
51
49
  alias_method :incr, :increment
@@ -56,7 +54,7 @@ class Redis
56
54
  # counter will automatically be incremented to its previous value. This
57
55
  # method is aliased as incr() for brevity.
58
56
  def decrement(by=1, &block)
59
- val = redis.decr(key, by).to_i
57
+ val = redis.decrby(key, by).to_i
60
58
  block_given? ? rewindable_block(:increment, val, &block) : val
61
59
  end
62
60
  alias_method :decr, :decrement
@@ -0,0 +1,54 @@
1
+ class Redis
2
+ module Helpers
3
+ # These are core commands that all types share (rename, etc)
4
+ module CoreCommands
5
+ def exists?
6
+ redis.exists key
7
+ end
8
+
9
+ def delete
10
+ redis.del key
11
+ end
12
+ alias_method :del, :delete
13
+ alias_method :clear, :delete
14
+
15
+ def type
16
+ redis.type key
17
+ end
18
+
19
+ def rename(name, setkey=true)
20
+ dest = name.is_a?(self.class) ? name.key : name
21
+ ret = redis.rename key, dest
22
+ @key = dest if ret && setkey
23
+ ret
24
+ end
25
+
26
+ def renamenx(name, setkey=true)
27
+ dest = name.is_a?(self.class) ? name.key : name
28
+ ret = redis.renamenx key, dest
29
+ @key = dest if ret && setkey
30
+ ret
31
+ end
32
+
33
+ def expire(seconds)
34
+ redis.expire key, seconds
35
+ end
36
+
37
+ def expireat(unixtime)
38
+ redis.expire key, unixtime
39
+ end
40
+
41
+ def move(dbindex)
42
+ redis.move key, dbindex
43
+ end
44
+
45
+ # See the documentation for SORT: http://code.google.com/p/redis/wiki/SortCommand
46
+ # TODO
47
+ # def sort(options)
48
+ # args = []
49
+ # args += ['sort']
50
+ # from_redis redis.sort key
51
+ # end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,27 @@
1
+ class Redis
2
+ module Helpers
3
+ module Serialize
4
+ include Marshal
5
+
6
+ def to_redis(value)
7
+ return value unless options[:marshal]
8
+ case value
9
+ when String, Fixnum, Bignum, Float
10
+ value
11
+ else
12
+ dump(value)
13
+ end
14
+ end
15
+
16
+ def from_redis(value)
17
+ return value unless options[:marshal]
18
+ case value
19
+ when Array
20
+ value.collect{|v| from_redis(v)}
21
+ else
22
+ restore(value) rescue value
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
data/lib/redis/list.rb CHANGED
@@ -6,14 +6,16 @@ class Redis
6
6
  class List
7
7
  require 'enumerator'
8
8
  include Enumerable
9
- require 'redis/serialize'
10
- include Redis::Serialize
9
+ require 'redis/helpers/core_commands'
10
+ include Redis::Helpers::CoreCommands
11
+ require 'redis/helpers/serialize'
12
+ include Redis::Helpers::Serialize
11
13
 
12
14
  attr_reader :key, :options, :redis
13
- def initialize(key, redis=$redis, options={})
15
+ def initialize(key, *args)
14
16
  @key = key
15
- @redis = redis
16
- @options = options
17
+ @options = args.last.is_a?(Hash) ? args.pop : {}
18
+ @redis = args.first || $redis
17
19
  end
18
20
 
19
21
  # Works like push. Can chain together: list << 'a' << 'b'
@@ -60,9 +62,10 @@ class Redis
60
62
  at(index)
61
63
  end
62
64
  end
63
-
65
+
64
66
  # Delete the element(s) from the list that match name. If count is specified,
65
67
  # only the first-N (if positive) or last-N (if negative) will be removed.
68
+ # Use .del to completely delete the entire key.
66
69
  # Redis: LREM
67
70
  def delete(name, count=0)
68
71
  redis.lrem(key, count, name) # weird api
@@ -96,11 +99,6 @@ class Redis
96
99
  at(-1)
97
100
  end
98
101
 
99
- # Clear the list entirely. Redis: DEL
100
- def clear
101
- redis.del(key)
102
- end
103
-
104
102
  # Return the length of the list. Aliased as size. Redis: LLEN
105
103
  def length
106
104
  redis.llen(key)