fresh_redis 0.0.8 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3a33a93d584d6db65a64b944214c598237f47170
4
+ data.tar.gz: 3f6fc12ed9e25d33fb67f889b4a8b8dc42fa4e7f
5
+ SHA512:
6
+ metadata.gz: 083f56e3c3c2e84877615e616501241130f27848094e34bcbe59ec03cd87e10a54f4e0f63572a44631a78e8351a4ff0cc383ca3edb45395460a7593c020126bc
7
+ data.tar.gz: cbeeace8ecf0d1944c9123181654aea4d114b7d6e9318b11dc8b13351e3eeade716c19ba60fa46e6fd45b03c0748b02c4737f9dd7f3c943933500ffa9969ade5
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fresh_redis (0.0.8)
4
+ fresh_redis (0.1.0)
5
5
  redis
6
6
 
7
7
  GEM
@@ -21,7 +21,7 @@ GEM
21
21
  rb-fsevent (0.9.2)
22
22
  rb-inotify (0.8.8)
23
23
  ffi (>= 0.5.0)
24
- redis (3.0.2)
24
+ redis (3.2.0)
25
25
  rspec (2.11.0)
26
26
  rspec-core (~> 2.11.0)
27
27
  rspec-expectations (~> 2.11.0)
data/lib/fresh_redis.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  require 'fresh_redis/hash'
2
2
  require 'fresh_redis/key'
3
+ require 'fresh_redis/set'
3
4
  require 'fresh_redis/string'
4
5
  require 'fresh_redis/version'
5
6
 
6
7
  class FreshRedis
7
8
  include Hash
9
+ include Set
8
10
  include String
9
11
 
10
12
  def initialize(redis, options={})
@@ -0,0 +1,48 @@
1
+ class FreshRedis
2
+ module Set
3
+
4
+ def fsadd(key, value, options={})
5
+ key = build_key(key, options)
6
+ @redis.multi do
7
+ @redis.sadd(key.redis_key, value)
8
+ @redis.expire(key.redis_key, key.freshness)
9
+ end
10
+ end
11
+
12
+ def fsmembers(key, options={})
13
+ key = build_key(key, options)
14
+
15
+ bucket_values = @redis.pipelined {
16
+ key.timestamp_buckets.reverse.each do |bucket_key|
17
+ @redis.smembers(bucket_key)
18
+ end
19
+ }
20
+
21
+ # find the first non-nil value
22
+ bucket_values.flatten.uniq
23
+ end
24
+
25
+ def fsismembers(key, value, options={})
26
+ key = build_key(key, options)
27
+
28
+ bucket_values = @redis.pipelined {
29
+ key.timestamp_buckets.reverse.each do |bucket_key|
30
+ return true if @redis.sismembers(bucket_key, value)
31
+ end
32
+ }
33
+
34
+ # find the first non-nil value
35
+ return false
36
+ end
37
+
38
+ def fsrem(key, value, options={})
39
+ key = build_key(key, options)
40
+
41
+ bucket_values = @redis.pipelined {
42
+ key.timestamp_buckets.reverse.each do |bucket_key|
43
+ @redis.srem(bucket_key, value)
44
+ end
45
+ }
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  class FreshRedis
2
- VERSION = "0.0.8"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,67 @@
1
+ require 'fresh_redis'
2
+ require 'mock_redis'
3
+ require 'timecop'
4
+
5
+ describe FreshRedis do
6
+ subject{ FreshRedis.new(mock_redis) }
7
+ let!(:mock_redis) { MockRedis.new }
8
+ let(:now) { Time.new(2012, 9, 27, 15, 40, 56, "+10:00") }
9
+ let(:normalized_now_minute) { Time.new(2012, 9, 27, 15, 40, 0, "+10:00") }
10
+ let(:normalized_one_minute_ago) { Time.new(2012, 9, 27, 15, 39, 0, "+10:00") }
11
+ let(:normalized_two_minutes_ago) { Time.new(2012, 9, 27, 15, 38, 0, "+10:00") }
12
+ let(:normalized_old) { Time.new(2012, 9, 27, 14, 38, 0, "+10:00") }
13
+
14
+ context "sets" do
15
+ before(:each) { Timecop.travel(now) }
16
+ after(:each) { Timecop.return }
17
+
18
+ describe "#fsadd" do
19
+ it "sets a value in a set for the normalized timestamp" do
20
+ Timecop.freeze(now - 3) { subject.fsadd "foo", "value" }
21
+ Timecop.freeze(now) { subject.fsadd "foo", "newer_value" }
22
+ Timecop.freeze(now - 60) { subject.fsadd "foo", "different_bucket" } # different normalized key
23
+
24
+ mock_redis.smembers("foo:#{normalized_now_minute.to_i}").should == ['newer_value', 'value']
25
+ end
26
+
27
+ it "sets a nil value ok" do
28
+ Timecop.freeze(now) { subject.fsadd "foo", nil }
29
+
30
+ mock_redis.smembers("foo:#{normalized_now_minute.to_i}").should == ['']
31
+ end
32
+
33
+ it "sets the freshness as the expiry" do
34
+ # relying on mock_redis's time handling here - which converts to/from using Time.now Possible flakey temporal breakage potential
35
+ subject.fsadd "foo", "baz", :freshness => 3600
36
+
37
+ mock_redis.ttl("foo:#{normalized_now_minute.to_i}").should == 3600
38
+ end
39
+ end
40
+
41
+ describe "#fsrem" do
42
+ it "removes the field from all timestamp buckets" do
43
+ Timecop.travel(now) { subject.fsadd "foo", "value" }
44
+ Timecop.travel(now) { subject.fsadd "foo", "don't touch" }
45
+ Timecop.travel(now - 60) { subject.fsadd "foo", "value" }
46
+ Timecop.travel(now - 60) { subject.fsadd "foo", "different_bucket" }
47
+ Timecop.travel(now - 60) { subject.fsadd "foo", "I shouldn't be returned" }
48
+
49
+ Timecop.travel(now) { subject.fsrem "foo", "value" } # Should only change the most recent bucket
50
+
51
+ mock_redis.smembers("foo:#{normalized_now_minute.to_i}").should == ["don't touch"]
52
+ mock_redis.smembers("foo:#{normalized_one_minute_ago.to_i}").should == ["I shouldn't be returned", "different_bucket"]
53
+ end
54
+ end
55
+
56
+ describe "#fsmembers" do
57
+ it "gets the union of all members for the fields across timestamped buckets" do
58
+ mock_redis.sadd "foo:#{normalized_now_minute.to_i}", "notbar"
59
+ mock_redis.sadd "foo:#{normalized_one_minute_ago.to_i}", "bar"
60
+ mock_redis.sadd "foo:#{normalized_two_minutes_ago.to_i}", "bar"
61
+
62
+ subject.fsmembers("foo").should == ['notbar', 'bar']
63
+ end
64
+ end
65
+ end
66
+
67
+ end
metadata CHANGED
@@ -1,52 +1,46 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fresh_redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
5
- prerelease:
4
+ version: 0.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Julian Doherty (madlep)
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-11-13 00:00:00.000000000 Z
11
+ date: 2015-01-25 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: redis
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rspec
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: mock_redis
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - '='
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - '='
60
53
  - !ruby/object:Gem::Version
@@ -62,7 +55,6 @@ dependencies:
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: guard-rspec
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - '='
68
60
  - !ruby/object:Gem::Version
@@ -70,7 +62,6 @@ dependencies:
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - '='
76
67
  - !ruby/object:Gem::Version
@@ -78,7 +69,6 @@ dependencies:
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rake
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - '='
84
74
  - !ruby/object:Gem::Version
@@ -86,7 +76,6 @@ dependencies:
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - '='
92
81
  - !ruby/object:Gem::Version
@@ -94,7 +83,6 @@ dependencies:
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: timecop
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - '='
100
88
  - !ruby/object:Gem::Version
@@ -102,7 +90,6 @@ dependencies:
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - '='
108
95
  - !ruby/object:Gem::Version
@@ -114,8 +101,8 @@ executables: []
114
101
  extensions: []
115
102
  extra_rdoc_files: []
116
103
  files:
117
- - .gitignore
118
- - .rspec
104
+ - ".gitignore"
105
+ - ".rspec"
119
106
  - Gemfile
120
107
  - Gemfile.lock
121
108
  - Guardfile
@@ -126,45 +113,41 @@ files:
126
113
  - lib/fresh_redis.rb
127
114
  - lib/fresh_redis/hash.rb
128
115
  - lib/fresh_redis/key.rb
116
+ - lib/fresh_redis/set.rb
129
117
  - lib/fresh_redis/string.rb
130
118
  - lib/fresh_redis/version.rb
131
119
  - spec/fresh_redis/hash_spec.rb
132
120
  - spec/fresh_redis/key_spec.rb
121
+ - spec/fresh_redis/set_spec.rb
133
122
  - spec/fresh_redis/string_spec.rb
134
123
  - spec/fresh_redis_spec.rb
135
124
  homepage: ''
136
125
  licenses: []
126
+ metadata: {}
137
127
  post_install_message:
138
128
  rdoc_options: []
139
129
  require_paths:
140
130
  - lib
141
131
  required_ruby_version: !ruby/object:Gem::Requirement
142
- none: false
143
132
  requirements:
144
- - - ! '>='
133
+ - - ">="
145
134
  - !ruby/object:Gem::Version
146
135
  version: '0'
147
- segments:
148
- - 0
149
- hash: -3222965477484950148
150
136
  required_rubygems_version: !ruby/object:Gem::Requirement
151
- none: false
152
137
  requirements:
153
- - - ! '>='
138
+ - - ">="
154
139
  - !ruby/object:Gem::Version
155
140
  version: '0'
156
- segments:
157
- - 0
158
- hash: -3222965477484950148
159
141
  requirements: []
160
142
  rubyforge_project:
161
- rubygems_version: 1.8.23
143
+ rubygems_version: 2.2.2
162
144
  signing_key:
163
- specification_version: 3
145
+ specification_version: 4
164
146
  summary: Use redis for working with recent temporal based data that can expiry gradually.
165
147
  Useful for things like "get a count all failed login attempts for the last hour"
166
148
  test_files:
167
149
  - spec/fresh_redis/hash_spec.rb
168
150
  - spec/fresh_redis/key_spec.rb
151
+ - spec/fresh_redis/set_spec.rb
169
152
  - spec/fresh_redis/string_spec.rb
170
153
  - spec/fresh_redis_spec.rb