redis-objects 0.5.2 → 0.5.3

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.
@@ -26,7 +26,9 @@ you want to create.
26
26
 
27
27
  == Installation
28
28
 
29
- gem install redis-objects
29
+ Add it to your Gemfile as:
30
+
31
+ gem 'redis-objects', :require => 'redis/objects'
30
32
 
31
33
  == Example 1: Model Class Usage
32
34
 
@@ -45,7 +47,7 @@ config/initializers/redis.rb is a good place for this.)
45
47
 
46
48
  require 'redis'
47
49
  require 'redis/objects'
48
- Redis::Objects.redis = Redis.new(:host => '127.0.0.1', :port => 6379)
50
+ Redis.current = Redis.new(:host => '127.0.0.1', :port => 6379)
49
51
 
50
52
  Remember you can use Redis::Objects in any Ruby code. There are *no* dependencies
51
53
  on Rails. Standalone, Sinatra, Resque - no problem.
@@ -124,15 +126,15 @@ which may already exist on the redis-server.
124
126
  === Initialization
125
127
 
126
128
  Redis::Objects needs a handle to the +redis+ server. For standalone use, you
127
- can either set the $redis global variable:
129
+ can either set Redis.current:
128
130
 
129
- $redis = Redis.new(:host => 'localhost', :port => 6379)
130
- @list = Redis::List.new('mylist')
131
+ Redis.current = Redis.new(:host => 'localhost', :port => 6379)
132
+ @list = Redis::List.new('mylist')
131
133
 
132
134
  Or you can pass the Redis handle into the new method for each type:
133
135
 
134
- redis = Redis.new(:host => 'localhost', :port => 6379)
135
- @list = Redis::List.new('mylist', redis)
136
+ @redis = Redis.new(:host => 'localhost', :port => 6379)
137
+ @list = Redis::List.new('mylist', @redis)
136
138
 
137
139
  === Counters
138
140
 
@@ -351,8 +353,8 @@ Atomic counters are a good way to handle concurrency:
351
353
  @team.drafted_players.decrement
352
354
  end
353
355
 
354
- Atomic block - a cleaner way to do the above. Exceptions or return nil
355
- rewind counter back to previous state:
356
+ Atomic block - a cleaner way to do the above. <b><em>Exceptions or returning nil
357
+ rewind counter back to previous state</em></b>:
356
358
 
357
359
  @team.drafted_players.increment do |val|
358
360
  raise Team::TeamFullError if val > @team.max_players
@@ -411,6 +413,6 @@ lock time.
411
413
 
412
414
  == Author
413
415
 
414
- Copyright (c) 2009-2010 {Nate Wiger}[http://nate.wiger.org]. All Rights Reserved.
416
+ Copyright (c) 2009-2012 {Nate Wiger}[http://nateware.com]. All Rights Reserved.
415
417
  Released under the {Artistic License}[http://www.opensource.org/licenses/artistic-license-2.0.php].
416
418
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.2
1
+ 0.5.3
@@ -70,7 +70,7 @@ class Redis
70
70
 
71
71
  # Retrieve the entire hash. Redis: HGETALL
72
72
  def all
73
- h = redis.hgetall(key)
73
+ h = redis.hgetall(key) || {}
74
74
  h.each { |k,v| h[k] = from_redis(v, options[:marshal_keys][k]) }
75
75
  h
76
76
  end
@@ -115,6 +115,15 @@ class Redis
115
115
  arr + [kv[0], to_redis(kv[1], options[:marshal_keys][kv[0]])]
116
116
  })
117
117
  end
118
+ alias_method :update, :bulk_set
119
+
120
+ # Set keys in bulk if they do not exist. Takes a hash of field/values {'field1' => 'val1'}. Redis: HSETNX
121
+ def fill(pairs={})
122
+ raise ArgumentErorr, "Arugment to fill must be a hash of key/value pairs" unless pairs.is_a?(::Hash)
123
+ pairs.each do |field, value|
124
+ redis.hsetnx(key, field, to_redis(value, options[:marshal_keys][field]))
125
+ end
126
+ end
118
127
 
119
128
  # Get keys in bulk, takes an array of fields as arguments. Redis: HMGET
120
129
  def bulk_get(*fields)
@@ -38,8 +38,12 @@ class Redis
38
38
  redis.expire key, unixtime
39
39
  end
40
40
 
41
+ def persist
42
+ redis.persist key
43
+ end
44
+
41
45
  def ttl
42
- redis.ttl(@key).seconds
46
+ redis.ttl(@key)
43
47
  end
44
48
 
45
49
  def move(dbindex)
@@ -32,6 +32,18 @@ class Redis
32
32
  from_redis redis.rpop(key)
33
33
  end
34
34
 
35
+ # Atomically pops a value from one list, pushes to another and returns the
36
+ # value. Destination can be a String or a Redis::List
37
+ #
38
+ # list.rpoplpush(destination)
39
+ #
40
+ # Returns the popped/pushed value.
41
+ #
42
+ # Redis: RPOPLPUSH
43
+ def rpoplpush(destination)
44
+ from_redis redis.rpoplpush(key, destination.is_a?(Redis::List) ? destination.key : destination.to_s)
45
+ end
46
+
35
47
  # Add a member to the start of the list. Redis: LPUSH
36
48
  def unshift(value)
37
49
  redis.lpush(key, to_redis(value))
@@ -26,6 +26,11 @@ class Redis
26
26
  redis.sadd(key, to_redis(value))
27
27
  end
28
28
 
29
+ # Remove and return a random member. Redis:SPOP
30
+ def pop
31
+ from_redis redis.spop(key)
32
+ end
33
+
29
34
  # Return all members in the set. Redis: SMEMBERS
30
35
  def members
31
36
  v = from_redis redis.smembers(key)
@@ -133,6 +138,19 @@ class Redis
133
138
  redis.sdiffstore(name, key, *keys_from_objects(sets))
134
139
  end
135
140
 
141
+ # Moves value from one set to another. Destination can be a String
142
+ # or Redis::Set.
143
+ #
144
+ # set.move(value, "name_of_key_in_redis")
145
+ # set.move(value, set2)
146
+ #
147
+ # Returns true if moved successfully.
148
+ #
149
+ # Redis: SMOVE
150
+ def move(value, destination)
151
+ redis.smove(key, destination.is_a?(Redis::Set) ? destination.key : destination.to_s, value)
152
+ end
153
+
136
154
  # The number of members in the set. Aliased as size. Redis: SCARD
137
155
  def length
138
156
  redis.scard(key)
@@ -58,11 +58,19 @@ class Redis
58
58
  # When the given member does not exist in the sorted set, nil is returned.
59
59
  # The returned rank (or index) of the member is 0-based for both commands
60
60
  def rank(member)
61
- redis.zrank(key, to_redis(member)).to_i
61
+ if n = redis.zrank(key, to_redis(member))
62
+ n.to_i
63
+ else
64
+ nil
65
+ end
62
66
  end
63
67
 
64
68
  def revrank(member)
65
- redis.zrevrank(key, to_redis(member)).to_i
69
+ if n = redis.zrevrank(key, to_redis(member))
70
+ n.to_i
71
+ else
72
+ nil
73
+ end
66
74
  end
67
75
 
68
76
  # Return all members of the sorted set with their scores. Extremely CPU-intensive.
@@ -13,11 +13,15 @@ class Redis
13
13
  attr_reader :key, :options, :redis
14
14
  def initialize(key, *args)
15
15
  super(key, *args)
16
- @redis.setnx(key, @options[:default]) if @options[:default]
16
+ @redis.setnx(key, to_redis(@options[:default])) if @options[:default]
17
17
  end
18
18
 
19
19
  def value=(val)
20
- redis.set key, to_redis(val)
20
+ if val.nil?
21
+ delete
22
+ else
23
+ redis.set key, to_redis(val)
24
+ end
21
25
  end
22
26
  alias_method :set, :value=
23
27
 
@@ -26,8 +30,17 @@ class Redis
26
30
  end
27
31
  alias_method :get, :value
28
32
 
29
- def to_s; value.to_s; end
30
- def ==(x); value == x; end
31
- def nil?; value.nil?; end
33
+ def inspect
34
+ "#<Redis::Value #{value.inspect}>"
35
+ end
36
+
37
+ def ==(other); value == other end
38
+ def nil?; value.nil? end
39
+ def as_json(*args); value.as_json *args end
40
+ def to_json(*args); value.to_json *args end
41
+
42
+ def method_missing(*args)
43
+ self.value.send *args
44
+ end
32
45
  end
33
46
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "redis-objects"
8
- s.version = "0.5.2"
8
+ s.version = "0.5.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nate Wiger"]
12
- s.date = "2011-09-20"
12
+ s.date = "2012-06-13"
13
13
  s.description = "Map Redis types directly to Ruby objects. Works with any class or ORM."
14
14
  s.email = "nate@wiger.org"
15
15
  s.extra_rdoc_files = [
@@ -14,6 +14,11 @@ describe Redis::Value do
14
14
  @value = Redis::Value.new('spec/value')
15
15
  @value.delete
16
16
  end
17
+
18
+ it "should marshal default value" do
19
+ @value = Redis::Value.new('spec/value', :default => {:json => 'data'}, :marshal => true)
20
+ @value.value.should == {:json => 'data'}
21
+ end
17
22
 
18
23
  it "should handle simple values" do
19
24
  @value.should == nil
@@ -58,6 +63,33 @@ describe Redis::Value do
58
63
  @value.value.should == 'Peter Pan'
59
64
  end
60
65
 
66
+ it "should provide a readable inspect" do
67
+ @value.value = 'monkey'
68
+ @value.inspect.should == '#<Redis::Value "monkey">'
69
+ @value.value = 1234
70
+ @value.inspect.should == '#<Redis::Value "1234">'
71
+ end
72
+
73
+ it 'should delegate unrecognized methods to the value' do
74
+ @value.value = 'monkey'
75
+ @value.to_sym.should == :monkey
76
+ end
77
+
78
+ it 'should properly pass equality operations on to the value' do
79
+ @value.value = 'monkey'
80
+ @value.should == 'monkey'
81
+ end
82
+
83
+ it 'should properly pass nil? on to the value' do
84
+ @value.delete
85
+ @value.nil?.should == true
86
+ end
87
+
88
+ it 'should equate setting the value to nil to deletion' do
89
+ @value.value = nil
90
+ @value.nil?.should == true
91
+ end
92
+
61
93
  after do
62
94
  @value.delete
63
95
  end
@@ -187,6 +219,17 @@ describe Redis::List do
187
219
  @list.get.should == ['a','c','f','j','a']
188
220
  end
189
221
 
222
+ it "should handle rpoplpush" do
223
+ list2 = Redis::List.new("spec/list2")
224
+ list2.clear
225
+
226
+ @list << "a" << "b"
227
+ result = @list.rpoplpush(list2)
228
+ result.should == "b"
229
+ @list.should == ["a"]
230
+ list2.should == ["b"]
231
+ end
232
+
190
233
  it "should handle lists of complex data types" do
191
234
  @list.options[:marshal] = true
192
235
  v1 = {:json => 'data'}
@@ -520,6 +563,15 @@ describe Redis::HashKey do
520
563
  @hash.incr('counter')
521
564
  @hash['counter'].to_i.should == 2
522
565
  end
566
+
567
+ it "should respond to fill" do
568
+ @hash['foo'] = 'bar'
569
+
570
+ @hash.fill('abc' => '123', 'bang' => 'michael')
571
+ @hash['foo'].should == 'bar'
572
+ @hash['abc'].should == '123'
573
+ @hash['bang'].should == 'michael'
574
+ end
523
575
 
524
576
 
525
577
  after do
@@ -559,7 +611,12 @@ describe Redis::Set do
559
611
  @set.get.sort.should == ['a','b']
560
612
  @set.length.should == 2
561
613
  @set.size.should == 2
614
+ @set.delete('a')
615
+ @set.pop.should == 'b'
562
616
 
617
+ @set.add('a')
618
+ @set.add('b')
619
+
563
620
  i = 0
564
621
  @set.each do |st|
565
622
  i += 1
@@ -742,6 +799,14 @@ describe Redis::SortedSet do
742
799
  # @set.rank('b').should == 2
743
800
  # @set.revrank('b').should == 3
744
801
 
802
+ # shouldn't report a rank for a key that doesn't exist
803
+ @set.rank('foo').should.not == @set.rank(@set.first)
804
+ @set.rank('foo').should == nil
805
+
806
+ # shouldn't report a rank for a key that doesn't exist
807
+ @set.revrank('foo').should.not == @set.revrank(@set.first)
808
+ @set.revrank('foo').should == nil
809
+
745
810
  @set['f'] = 100
746
811
  @set['g'] = 110
747
812
  @set['h'] = 120
@@ -142,6 +142,26 @@ describe Redis::Objects do
142
142
  @roster.contact_information.size.should == 2
143
143
  end
144
144
 
145
+ it 'should be able to expire keys and then persist them' do
146
+ # on a hash_key
147
+ @roster.contact_information['Jenny_Phone'] = '8675309'
148
+ @roster.contact_information.expire 30
149
+ @roster.contact_information.ttl.should > -1
150
+ @roster.contact_information.ttl.should <= 30
151
+ @roster.contact_information.persist
152
+ @roster.contact_information.ttl.should == -1
153
+ @roster.contact_information['Jenny_Phone'].should == '8675309'
154
+
155
+ # on a value
156
+ @roster.my_rank = 42
157
+ @roster.my_rank.expire 30
158
+ @roster.my_rank.ttl.should > -1
159
+ @roster.my_rank.ttl.should <= 30
160
+ @roster.my_rank.persist
161
+ @roster.my_rank.ttl.should == -1
162
+ @roster.my_rank.to_i.should == 42
163
+ end
164
+
145
165
  it "should be marshalling hash keys" do
146
166
  @roster.contact_information['updated_at'] = Time.now
147
167
  @roster.contact_information['updated_at'].class.should == Time
@@ -5,6 +5,9 @@ require 'redis'
5
5
  $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
6
6
  require 'bacon'
7
7
  Bacon.summary_at_exit
8
+ if $0 =~ /\brspec$/
9
+ raise "\n===\nThese tests are in bacon, not rspec. Try: bacon #{ARGV * ' '}\n===\n"
10
+ end
8
11
 
9
12
  UNIONSTORE_KEY = 'test:unionstore'
10
13
  INTERSTORE_KEY = 'test:interstore'
metadata CHANGED
@@ -1,59 +1,56 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: redis-objects
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.3
4
5
  prerelease:
5
- version: 0.5.2
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Nate Wiger
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-09-20 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
12
+ date: 2012-06-13 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
16
15
  name: bacon
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &2165783560 !ruby/object:Gem::Requirement
19
17
  none: false
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
24
22
  type: :development
25
- version_requirements: *id001
26
- - !ruby/object:Gem::Dependency
27
- name: redis-namespace
28
23
  prerelease: false
29
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *2165783560
25
+ - !ruby/object:Gem::Dependency
26
+ name: redis-namespace
27
+ requirement: &2165782960 !ruby/object:Gem::Requirement
30
28
  none: false
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: "0"
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
35
33
  type: :development
36
- version_requirements: *id002
37
- - !ruby/object:Gem::Dependency
38
- name: redis
39
34
  prerelease: false
40
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *2165782960
36
+ - !ruby/object:Gem::Dependency
37
+ name: redis
38
+ requirement: &2165782480 !ruby/object:Gem::Requirement
41
39
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
45
43
  version: 2.1.1
46
44
  type: :runtime
47
- version_requirements: *id003
45
+ prerelease: false
46
+ version_requirements: *2165782480
48
47
  description: Map Redis types directly to Ruby objects. Works with any class or ORM.
49
48
  email: nate@wiger.org
50
49
  executables: []
51
-
52
50
  extensions: []
53
-
54
- extra_rdoc_files:
51
+ extra_rdoc_files:
55
52
  - README.rdoc
56
- files:
53
+ files:
57
54
  - ATOMICITY.rdoc
58
55
  - CHANGELOG.rdoc
59
56
  - README.rdoc
@@ -85,25 +82,23 @@ files:
85
82
  - spec/spec_helper.rb
86
83
  homepage: http://github.com/nateware/redis-objects
87
84
  licenses: []
88
-
89
85
  post_install_message:
90
86
  rdoc_options: []
91
-
92
- require_paths:
87
+ require_paths:
93
88
  - lib
94
- required_ruby_version: !ruby/object:Gem::Requirement
89
+ required_ruby_version: !ruby/object:Gem::Requirement
95
90
  none: false
96
- requirements:
97
- - - ">="
98
- - !ruby/object:Gem::Version
99
- version: "0"
100
- required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
96
  none: false
102
- requirements:
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- version: "0"
106
- requirements:
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements:
107
102
  - redis, v2.1.1 or greater
108
103
  rubyforge_project:
109
104
  rubygems_version: 1.8.10
@@ -111,4 +106,3 @@ signing_key:
111
106
  specification_version: 3
112
107
  summary: Map Redis types directly to Ruby objects
113
108
  test_files: []
114
-