redis-set 0.0.2 → 0.0.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.
- checksums.yaml +4 -4
- data/README.md +24 -10
- data/lib/redis_set.rb +150 -0
- data/redis-set.gemspec +2 -2
- metadata +4 -4
- data/lib/redis/set.rb +0 -139
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38c7747969cffe4f84c06b7c4c249e1db96b60b2
|
4
|
+
data.tar.gz: cc72aef22abc64c4a4ed886eef069865451131a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b38c5833ea9b105ae3a516154319389708db9b3f6e2103d7215736673f686bbba823ed25fd8064be7bf4062e295f158c07a34b436d5febf59469801c61d94e6
|
7
|
+
data.tar.gz: 53c98de243c00205a442a6e7ca987e15219260eda9bc9c8820e7ad22fedfc408a9159bee0f82a0c638b63a50b82be10722612a31e9c34c9ecc7ef25c4117ba18
|
data/README.md
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
A unique set of unordered items. Lightweight wrapper over redis sets with some additional enumeration and atomic operations.
|
4
4
|
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
6
|
-
|
7
5
|
## Installation
|
8
6
|
|
9
7
|
Add this line to your application's Gemfile:
|
@@ -23,19 +21,19 @@ Or install it yourself as:
|
|
23
21
|
## Getting started
|
24
22
|
|
25
23
|
```ruby
|
26
|
-
s =
|
24
|
+
s = RedisSet.new 'completed_customer_ids'
|
27
25
|
```
|
28
26
|
|
29
27
|
Or you can pass in your own instance of the Redis class.
|
30
28
|
|
31
29
|
```ruby
|
32
|
-
s =
|
30
|
+
s = RedisSet.new 'completed_customer_ids', Redis.new(:host => "10.0.1.1", :port => 6380, :db => 15)
|
33
31
|
```
|
34
32
|
|
35
33
|
A third option is to instead pass your Redis configurations.
|
36
34
|
|
37
35
|
```ruby
|
38
|
-
s =
|
36
|
+
s = RedisSet.new 'completed_customer_ids', :host => "10.0.1.1", :port => 6380, :db => 15
|
39
37
|
```
|
40
38
|
|
41
39
|
## Using the set
|
@@ -48,11 +46,11 @@ s.add "world"
|
|
48
46
|
s.add "hello" # the item 'hello' will only exist once in the set since it is unique
|
49
47
|
```
|
50
48
|
|
51
|
-
You can
|
49
|
+
You can add multiple items
|
52
50
|
|
53
51
|
```ruby
|
54
|
-
s.
|
55
|
-
s.
|
52
|
+
s.add ["one","two","three"]
|
53
|
+
s.add "four","five","six"
|
56
54
|
# set should have items "one","two","three","four","five","six" now
|
57
55
|
```
|
58
56
|
|
@@ -68,7 +66,7 @@ result = s.pop
|
|
68
66
|
|
69
67
|
You can pop multiple random items from the set
|
70
68
|
```ruby
|
71
|
-
result = s.
|
69
|
+
result = s.pop 5 # pop 5 random items from set and return them
|
72
70
|
```
|
73
71
|
|
74
72
|
You can remove a specific item from the set
|
@@ -79,7 +77,7 @@ s.remove 5 #remove the item 5 from the set if it exists
|
|
79
77
|
You can atomically remove multiple items from the set.
|
80
78
|
|
81
79
|
```ruby
|
82
|
-
s.
|
80
|
+
s.remove 3,4,5 #removes items 3,4, and 5 from the set if they exist
|
83
81
|
```
|
84
82
|
|
85
83
|
You can get the size of the set.
|
@@ -105,6 +103,22 @@ The set can be cleared of all items
|
|
105
103
|
s.clear
|
106
104
|
```
|
107
105
|
|
106
|
+
You can get the intersection between the set and another set
|
107
|
+
```ruby
|
108
|
+
a = RedisSet.new 'a'
|
109
|
+
a.push 'a', 'b', 'c', 'd'
|
110
|
+
|
111
|
+
b = RedisSet.new 'b'
|
112
|
+
b.push 'c', 'd', 'e', 'f'
|
113
|
+
|
114
|
+
c = RedisSet.new 'c'
|
115
|
+
c.push 'c', 'd', 'f'
|
116
|
+
|
117
|
+
# should return ['c', 'd']
|
118
|
+
a.intersection b, c
|
119
|
+
|
120
|
+
```
|
121
|
+
|
108
122
|
The set can also be set to expire (in seconds).
|
109
123
|
```ruby
|
110
124
|
# expire in five minutes
|
data/lib/redis_set.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require "redis"
|
2
|
+
|
3
|
+
class RedisSet
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
VERSION = "0.0.3"
|
7
|
+
|
8
|
+
class InvalidNameException < StandardError; end;
|
9
|
+
class InvalidRedisConfigException < StandardError; end;
|
10
|
+
|
11
|
+
def initialize(name, redis_or_options = {})
|
12
|
+
name = name.to_s if name.kind_of? Symbol
|
13
|
+
|
14
|
+
raise InvalidNameException.new unless name.kind_of?(String) && name.size > 0
|
15
|
+
@name = name
|
16
|
+
@redis = if redis_or_options.kind_of?(Redis)
|
17
|
+
redis_or_options
|
18
|
+
elsif redis_or_options.kind_of? Hash
|
19
|
+
::Redis.new redis_or_options
|
20
|
+
elsif defined?(ActiveSupport::Cache::RedisStore) && redis_or_options.kind_of?(ActiveSupport::Cache::RedisStore)
|
21
|
+
@pooled = redis_or_options.data.kind_of?(ConnectionPool)
|
22
|
+
redis_or_options.data
|
23
|
+
elsif defined?(ConnectionPool) && redis_or_options.kind_of?(ConnectionPool)
|
24
|
+
@pooled = true
|
25
|
+
redis_or_options
|
26
|
+
else
|
27
|
+
raise InvalidRedisConfigException.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def add *values
|
32
|
+
values = [values].flatten
|
33
|
+
with{|redis| redis.sadd name, values} if values.size > 0
|
34
|
+
end
|
35
|
+
|
36
|
+
alias push add
|
37
|
+
|
38
|
+
def add_with_count value
|
39
|
+
block_on_atomic_attempt { attempt_atomic_add_read_count value }
|
40
|
+
end
|
41
|
+
|
42
|
+
alias push_with_count add_with_count
|
43
|
+
|
44
|
+
def remove *values
|
45
|
+
values = [values].flatten
|
46
|
+
with{|redis|redis.srem name, values} if values.size > 0
|
47
|
+
end
|
48
|
+
|
49
|
+
def pop(amount = 1)
|
50
|
+
with{|redis| redis.spop name, amount}
|
51
|
+
end
|
52
|
+
|
53
|
+
def include? value
|
54
|
+
with{|redis| redis.sismember(name, value)}
|
55
|
+
end
|
56
|
+
|
57
|
+
def size
|
58
|
+
with{|redis| redis.scard name}
|
59
|
+
end
|
60
|
+
|
61
|
+
alias count size
|
62
|
+
|
63
|
+
def all
|
64
|
+
with{|redis| redis.smembers name}
|
65
|
+
end
|
66
|
+
|
67
|
+
def intersection *sets
|
68
|
+
sets = [sets].flatten
|
69
|
+
sets = sets.map do |s|
|
70
|
+
if s.kind_of?(self.class)
|
71
|
+
s.name
|
72
|
+
else
|
73
|
+
s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
with{|redis| redis.sinter *sets }
|
78
|
+
end
|
79
|
+
|
80
|
+
def scan cursor = 0, amount = 10, match = "*"
|
81
|
+
with{|redis| redis.sscan name, cursor, :count => amount, :match => match}
|
82
|
+
end
|
83
|
+
|
84
|
+
def enumerator(slice_size = 10)
|
85
|
+
cursor = 0
|
86
|
+
Enumerator.new do |yielder|
|
87
|
+
loop do
|
88
|
+
cursor, items = scan cursor, slice_size
|
89
|
+
items.each do |item|
|
90
|
+
yielder << item
|
91
|
+
end
|
92
|
+
raise StopIteration if cursor.to_i.zero?
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def clear
|
98
|
+
with{|redis| redis.del name}
|
99
|
+
[]
|
100
|
+
end
|
101
|
+
|
102
|
+
alias flush clear
|
103
|
+
|
104
|
+
def expire seconds
|
105
|
+
with{|redis| redis.expire name, seconds}
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def attempt_atomic_add_read_count value
|
111
|
+
attempt_atomic_write_read lambda { add value }, lambda { |multi, read_result| multi.scard name }
|
112
|
+
end
|
113
|
+
|
114
|
+
def block_on_atomic_attempt
|
115
|
+
begin
|
116
|
+
success, result = yield
|
117
|
+
#puts "success is #{success} and result is #{result}"
|
118
|
+
end while !success && result
|
119
|
+
result.value
|
120
|
+
end
|
121
|
+
|
122
|
+
def attempt_atomic_write_read write_op, read_op
|
123
|
+
success, write_result, read_result = false, nil, nil
|
124
|
+
|
125
|
+
with do |redis|
|
126
|
+
success = redis.watch(name) do
|
127
|
+
write_result = write_op.call
|
128
|
+
#if write_result
|
129
|
+
redis.multi do |multi|
|
130
|
+
read_result = read_op.call multi, write_result
|
131
|
+
end
|
132
|
+
#end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
[success, read_result]
|
137
|
+
end
|
138
|
+
|
139
|
+
def with(&block)
|
140
|
+
if pooled?
|
141
|
+
@redis.with(&block)
|
142
|
+
else
|
143
|
+
block.call(@redis)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def pooled?
|
148
|
+
!!@pooled
|
149
|
+
end
|
150
|
+
end
|
data/redis-set.gemspec
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require '
|
4
|
+
require 'redis_set'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "redis-set"
|
8
|
-
spec.version =
|
8
|
+
spec.version = RedisSet::VERSION
|
9
9
|
spec.authors = ["Misha Conway"]
|
10
10
|
spec.email = ["mishaAconway@gmail.com"]
|
11
11
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-set
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Misha Conway
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -65,7 +65,7 @@ files:
|
|
65
65
|
- Rakefile
|
66
66
|
- bin/console
|
67
67
|
- bin/setup
|
68
|
-
- lib/
|
68
|
+
- lib/redis_set.rb
|
69
69
|
- redis-set.gemspec
|
70
70
|
homepage: https://github.com/MishaConway/ruby-redis-set
|
71
71
|
licenses:
|
@@ -87,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
87
|
version: '0'
|
88
88
|
requirements: []
|
89
89
|
rubyforge_project:
|
90
|
-
rubygems_version: 2.6.
|
90
|
+
rubygems_version: 2.6.14
|
91
91
|
signing_key:
|
92
92
|
specification_version: 4
|
93
93
|
summary: Lightweight wrapper over redis sets.
|
data/lib/redis/set.rb
DELETED
@@ -1,139 +0,0 @@
|
|
1
|
-
require "redis"
|
2
|
-
|
3
|
-
class Redis
|
4
|
-
class Set
|
5
|
-
attr_reader :name
|
6
|
-
|
7
|
-
VERSION = "0.0.2"
|
8
|
-
|
9
|
-
class InvalidNameException < StandardError; end;
|
10
|
-
class InvalidRedisConfigException < StandardError; end;
|
11
|
-
|
12
|
-
def initialize(name, redis_or_options = {})
|
13
|
-
name = name.to_s if name.kind_of? Symbol
|
14
|
-
|
15
|
-
raise InvalidNameException.new unless name.kind_of?(String) && name.size > 0
|
16
|
-
@name = name
|
17
|
-
@redis = if redis_or_options.kind_of? Redis
|
18
|
-
redis_or_options
|
19
|
-
elsif redis_or_options.kind_of? Hash
|
20
|
-
Redis.new redis_or_options
|
21
|
-
else
|
22
|
-
raise InvalidRedisConfigException.new
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def add value
|
27
|
-
@redis.sadd name, value
|
28
|
-
end
|
29
|
-
|
30
|
-
alias push add
|
31
|
-
|
32
|
-
def add_multi *values
|
33
|
-
if values.size > 0
|
34
|
-
values = values.first if 1 == values.size && values.first.kind_of?(Array)
|
35
|
-
@redis.sadd name, values
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
alias push_multi add_multi
|
40
|
-
|
41
|
-
def add_with_count value
|
42
|
-
block_on_atomic_attempt{ attempt_atomic_add_read_count value }
|
43
|
-
end
|
44
|
-
|
45
|
-
alias push_with_count add_with_count
|
46
|
-
|
47
|
-
def remove value
|
48
|
-
@redis.srem name, value
|
49
|
-
end
|
50
|
-
|
51
|
-
def remove_multi *values
|
52
|
-
if values.size > 0
|
53
|
-
values = values.first if 1 == values.size && values.first.kind_of?(Array)
|
54
|
-
@redis.srem name, values
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def pop
|
59
|
-
@redis.pop name, 1
|
60
|
-
end
|
61
|
-
|
62
|
-
def pop_multi amount
|
63
|
-
@redis.pop name, amount
|
64
|
-
end
|
65
|
-
|
66
|
-
def include? value
|
67
|
-
@redis.sismember(name, value)
|
68
|
-
end
|
69
|
-
|
70
|
-
def size
|
71
|
-
@redis.scard name
|
72
|
-
end
|
73
|
-
|
74
|
-
alias count size
|
75
|
-
|
76
|
-
def all
|
77
|
-
@redis.smembers name
|
78
|
-
end
|
79
|
-
|
80
|
-
def scan cursor = 0, amount=10, match = "*"
|
81
|
-
@redis.sscan name, cursor, :count => amount, :match => match
|
82
|
-
end
|
83
|
-
|
84
|
-
def enumerator(slice_size = 10)
|
85
|
-
cursor = 0
|
86
|
-
Enumerator.new do |yielder|
|
87
|
-
loop do
|
88
|
-
cursor, items = scan cursor, slice_size
|
89
|
-
items.each do |item|
|
90
|
-
yielder << item
|
91
|
-
end
|
92
|
-
raise StopIteration if cursor.to_i.zero?
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def clear
|
98
|
-
@redis.del name
|
99
|
-
[]
|
100
|
-
end
|
101
|
-
|
102
|
-
alias flush clear
|
103
|
-
|
104
|
-
def expire seconds
|
105
|
-
@redis.expire name, seconds
|
106
|
-
end
|
107
|
-
|
108
|
-
private
|
109
|
-
|
110
|
-
def attempt_atomic_add_read_count value
|
111
|
-
attempt_atomic_write_read lambda{ add value }, lambda{ |multi, read_result| multi.scard name}
|
112
|
-
end
|
113
|
-
|
114
|
-
def block_on_atomic_attempt
|
115
|
-
begin
|
116
|
-
success, result = yield
|
117
|
-
#puts "success is #{success} and result is #{result}"
|
118
|
-
end while !success && result
|
119
|
-
result.value
|
120
|
-
end
|
121
|
-
|
122
|
-
def attempt_atomic_write_read write_op, read_op
|
123
|
-
|
124
|
-
write_result, read_result = nil, nil
|
125
|
-
success = @redis.watch(name) do
|
126
|
-
write_result = write_op.call
|
127
|
-
#if write_result
|
128
|
-
@redis.multi do |multi|
|
129
|
-
read_result = read_op.call multi, write_result
|
130
|
-
end
|
131
|
-
#end
|
132
|
-
end
|
133
|
-
|
134
|
-
[success, read_result]
|
135
|
-
end
|
136
|
-
|
137
|
-
|
138
|
-
end
|
139
|
-
end
|