fresh_redis 0.0.8 → 0.1.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.
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