async-redis 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
+ SHA256:
3
+ metadata.gz: 3f51bfc647fd3f6a3f8a066cdfddd4147d072efb240fccce0e911ca6d0968831
4
+ data.tar.gz: e35d2061ecf625ad6dfd818e07718bc78af8b2c4095e2bf9b42b1ea02a385b0d
5
+ SHA512:
6
+ metadata.gz: 36d4b12adcaec403cf91f9ebfaa07d44f2e0381f72ca23c3420dd1359277d9ecc33de90c0413bb130ac8308aa88a6317bdcf0d722e7dcb34c1f8d5afbbee7cfe
7
+ data.tar.gz: b46435ea68404c5656631b362b130755a8b8a0837af03a29a950b988141ed61279eccc18d9711d3dd1fb03afc1b33fbe54d00d550158d719d6e1f38b24ee7132
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --warnings
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,23 @@
1
+ language: ruby
2
+ cache: bundler
3
+
4
+ services:
5
+ - redis-server
6
+
7
+ before_script:
8
+ - gem update --system
9
+ - gem install bundler
10
+
11
+ matrix:
12
+ include:
13
+ - rvm: 2.3
14
+ - rvm: 2.4
15
+ - rvm: 2.5
16
+ - rvm: jruby-head
17
+ env: JRUBY_OPTS="--debug -X+O"
18
+ - rvm: ruby-head
19
+ - rvm: rbx-3
20
+ allow_failures:
21
+ - rvm: ruby-head
22
+ - rvm: jruby-head
23
+ - rvm: rbx-3
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in async-io.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'pry'
8
+ end
9
+
10
+ group :test do
11
+ gem 'simplecov'
12
+ gem 'coveralls', require: false
13
+ end
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # Async::Redis
2
+
3
+ An asynchronous client for Redis including TLS. Support for streaming requests and responses. Built on top of [async] and [async-io].
4
+
5
+ [![Build Status](https://secure.travis-ci.org/socketry/async-redis.svg)](https://travis-ci.org/socketry/async-redis)
6
+ [![Code Climate](https://codeclimate.com/github/socketry/async-redis.svg)](https://codeclimate.com/github/socketry/async-redis)
7
+ [![Coverage Status](https://coveralls.io/repos/socketry/async-redis/badge.svg)](https://coveralls.io/r/socketry/async-redis)
8
+
9
+ [async]: https://github.com/socketry/async
10
+ [async-io]: https://github.com/socketry/async-io
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'async-redis'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install async-redis
27
+
28
+ ## Usage
29
+
30
+ ## Contributing
31
+
32
+ 1. Fork it
33
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
34
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
35
+ 4. Push to the branch (`git push origin my-new-feature`)
36
+ 5. Create new Pull Request
37
+
38
+ ## License
39
+
40
+ Released under the MIT license.
41
+
42
+ Copyright, 2018, by [Samuel G. D. Williams](https://www.codeotaku.com/samuel-williams) and
43
+ Huba Z. Nagy
44
+
45
+ Permission is hereby granted, free of charge, to any person obtaining a copy
46
+ of this software and associated documentation files (the "Software"), to deal
47
+ in the Software without restriction, including without limitation the rights
48
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
49
+ copies of the Software, and to permit persons to whom the Software is
50
+ furnished to do so, subject to the following conditions:
51
+
52
+ The above copyright notice and this permission notice shall be included in
53
+ all copies or substantial portions of the Software.
54
+
55
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
56
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
57
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
58
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
59
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
60
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
61
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:test)
5
+
6
+ task :default => :test
@@ -0,0 +1,27 @@
1
+
2
+ require_relative 'lib/async/redis/version'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "async-redis"
6
+ spec.version = Async::Redis::VERSION
7
+ spec.authors = ["Samuel Williams", "Huba Nagy"]
8
+ spec.email = ["samuel.williams@oriontransfer.co.nz", "12huba@gmail.com"]
9
+
10
+ spec.summary = "A Redis client library."
11
+ spec.homepage = "https://github.com/socketry/async-redis"
12
+
13
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
14
+ f.match(%r{^(test|spec|features)/})
15
+ end
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_dependency("async", "~> 1.6")
20
+ spec.add_dependency("async-io", "~> 1.7")
21
+
22
+ spec.add_development_dependency "async-rspec", "~> 1.1"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rspec", "~> 3.6"
26
+ spec.add_development_dependency "rake"
27
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require "async/redis/version"
@@ -0,0 +1,81 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'protocol/resp'
22
+ require_relative 'pool'
23
+
24
+ require 'async/io/endpoint'
25
+
26
+ module Async
27
+ module Redis
28
+ def self.local_endpoint
29
+ Async::IO::Endpoint.tcp('localhost', 6379)
30
+ end
31
+
32
+ class Client
33
+ def initialize(endpoint = Redis.local_endpoint, protocol = Protocol::RESP, **options)
34
+ @endpoint = endpoint
35
+ @protocol = protocol
36
+
37
+ @connections = connect(**options)
38
+ end
39
+
40
+ attr :endpoint
41
+ attr :protocol
42
+
43
+ def self.open(*args, &block)
44
+ client = self.new(*args)
45
+
46
+ return client unless block_given?
47
+
48
+ begin
49
+ yield client
50
+ ensure
51
+ client.close
52
+ end
53
+ end
54
+
55
+ def close
56
+ @connections.close
57
+ end
58
+
59
+ def call(*arguments)
60
+ @connections.acquire do |connection|
61
+ connection.write_request(arguments)
62
+ return connection.read_response
63
+ end
64
+ end
65
+
66
+ protected
67
+
68
+ def connect(connection_limit: nil)
69
+ Pool.new(connection_limit) do
70
+ peer = @endpoint.connect
71
+
72
+ peer.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
73
+
74
+ stream = IO::Stream.new(peer)
75
+
76
+ @protocol.client(stream)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,95 @@
1
+ # Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Async
22
+ module Redis
23
+ # It might make sense to add support for pipelining https://redis.io/topics/pipelining
24
+ # We should be able to wrap the protocol so that write_request and read_response happen in lockstep.
25
+ # The only problem would be blocking operations. It might also be confusing if order of operations affects commands.
26
+ class Pool
27
+ def initialize(limit = nil, &block)
28
+ @available = []
29
+ @waiting = []
30
+
31
+ @limit = limit
32
+
33
+ @constructor = block
34
+ end
35
+
36
+ def acquire
37
+ resource = wait_for_next_available
38
+
39
+ return resource unless block_given?
40
+
41
+ begin
42
+ yield resource
43
+ ensure
44
+ release(resource)
45
+ end
46
+ end
47
+
48
+ # Make the resource available and let waiting tasks know that there is something available.
49
+ def release(resource)
50
+ @available << resource
51
+
52
+ if task = @waiting.pop
53
+ task.resume
54
+ end
55
+ end
56
+
57
+ def close
58
+ @available.each(&:close)
59
+ @available.clear
60
+ end
61
+
62
+ protected
63
+
64
+ def wait_for_next_available
65
+ until resource = next_available
66
+ @waiting << Fiber.current
67
+ Task.yield
68
+ end
69
+
70
+ return resource
71
+ end
72
+
73
+ def create_resource
74
+ begin
75
+ # This might fail, which is okay :)
76
+ resource = @constructor.call
77
+ rescue StandardError
78
+ Async.logger.error "#{$!}: #{$!.backtrace}"
79
+ return nil
80
+ end
81
+
82
+ return resource
83
+ end
84
+
85
+ def next_available
86
+ if @available.any?
87
+ @available.pop
88
+ elsif !@limit or @available.count < @limit
89
+ Async.logger.debug(self) {"No available resources, allocating new one..."}
90
+ create_resource
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,117 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'async/io/protocol/line'
22
+
23
+ module Async
24
+ module Redis
25
+ class ServerError < StandardError
26
+ end
27
+
28
+ module Protocol
29
+ class RESP < Async::IO::Protocol::Line
30
+ CRLF = "\r\n".freeze
31
+
32
+ class << self
33
+ alias client new
34
+ end
35
+
36
+ def initialize(stream)
37
+ super(stream, CRLF)
38
+ end
39
+
40
+ # The redis server doesn't want actual objects (e.g. integers) but only bulk strings. So, we inline it for performance.
41
+ def write_request(arguments)
42
+ write_lines("*#{arguments.count}")
43
+
44
+ arguments.each do |argument|
45
+ string = argument.to_s
46
+
47
+ write_lines("$#{string.bytesize}", string)
48
+ end
49
+
50
+ @stream.flush
51
+ end
52
+
53
+ def write_object(object)
54
+ case object
55
+ when String
56
+ write_lines("$#{object.bytesize}", object)
57
+ when Array
58
+ write_array(object)
59
+ when Integer
60
+ write_lines(":#{object}")
61
+ else
62
+ write_object(object.to_redis)
63
+ end
64
+ end
65
+
66
+ # def write_lines(*args)
67
+ # puts "write_lines(#{args.inspect})"
68
+ # super
69
+ # end
70
+ #
71
+ # def read_line
72
+ # result = super
73
+ # puts "read_line #{result}"
74
+ #
75
+ # return result
76
+ # end
77
+
78
+ def read_object
79
+ token = @stream.read(1)
80
+ # puts "token: #{token}"
81
+
82
+ case token
83
+ when '$'
84
+ length = read_line.to_i
85
+
86
+ if length == -1
87
+ return nil
88
+ else
89
+ buffer = @stream.read(length)
90
+ read_line # Eat trailing whitespace?
91
+
92
+ return buffer
93
+ end
94
+ when '*'
95
+ count = read_line.to_i
96
+ array = Array.new(count) {read_object}
97
+
98
+ return array
99
+ when ':'
100
+ return read_line.to_i
101
+
102
+ when '-'
103
+ raise ServerError.new(read_line)
104
+
105
+ when '+'
106
+ return read_line
107
+
108
+ else
109
+ raise NotImplementedError, "Implementation for token #{token} missing"
110
+ end
111
+ end
112
+
113
+ alias read_response read_object
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Async
22
+ module Redis
23
+ VERSION = "0.1.0"
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: async-redis
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Samuel Williams
8
+ - Huba Nagy
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2018-04-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: async
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.6'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.6'
28
+ - !ruby/object:Gem::Dependency
29
+ name: async-io
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.7'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.7'
42
+ - !ruby/object:Gem::Dependency
43
+ name: async-rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.1'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.1'
56
+ - !ruby/object:Gem::Dependency
57
+ name: bundler
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '1.3'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '3.6'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '3.6'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rake
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description:
99
+ email:
100
+ - samuel.williams@oriontransfer.co.nz
101
+ - 12huba@gmail.com
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - ".rspec"
108
+ - ".travis.yml"
109
+ - Gemfile
110
+ - README.md
111
+ - Rakefile
112
+ - async-redis.gemspec
113
+ - lib/async/redis.rb
114
+ - lib/async/redis/client.rb
115
+ - lib/async/redis/pool.rb
116
+ - lib/async/redis/protocol/resp.rb
117
+ - lib/async/redis/version.rb
118
+ homepage: https://github.com/socketry/async-redis
119
+ licenses: []
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.7.6
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: A Redis client library.
141
+ test_files: []