redisbetween 0.2.2
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 +7 -0
- data/lib/redisbetween/version.rb +3 -0
- data/lib/redisbetween.rb +110 -0
- data/spec/redisbetween_spec.rb +205 -0
- data/spec/spec_helper.rb +15 -0
- metadata +60 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 749198c4742de0123a0226e37853bba82f50b7effb9ccb570b421ec1a78d68c3
         | 
| 4 | 
            +
              data.tar.gz: 1eb3ac3e7f9c40b76154bee60091b6a13d01a4a2627f157014c8614cf2764040
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 3e6cb4c970d63130e51191eb450de90078032d05e9086e888aed7da4f99597676eef5fa5a6c7bb8f7b5a0cfdf60b4d96ef06e4590d0ca572485252538408f96d
         | 
| 7 | 
            +
              data.tar.gz: 601805fa28010afd16c3cb49859f268fcd4ce74cfb49cbec013d09f0b5990cebfe98a4cb74052d0214e5fdba87f15ea7b03e76915949566fe34101bf22594691
         | 
    
        data/lib/redisbetween.rb
    ADDED
    
    | @@ -0,0 +1,110 @@ | |
| 1 | 
            +
            require 'redisbetween/version'
         | 
| 2 | 
            +
            require 'redis'
         | 
| 3 | 
            +
            require 'uri'
         | 
| 4 | 
            +
            require 'set'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Redisbetween
         | 
| 7 | 
            +
              class Error < StandardError; end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              PIPELINE_START_SIGNAL = '🔜'
         | 
| 10 | 
            +
              PIPELINE_END_SIGNAL = '🔚'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              module ClientPatch
         | 
| 13 | 
            +
                attr_reader :redisbetween_enabled
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def initialize(options = {})
         | 
| 16 | 
            +
                  @redisbetween_enabled = !!options[:convert_to_redisbetween_socket]
         | 
| 17 | 
            +
                  @handle_unsupported_redisbetween_command = options[:handle_unsupported_redisbetween_command]
         | 
| 18 | 
            +
                  if @redisbetween_enabled
         | 
| 19 | 
            +
                    @handle_unsupported_redisbetween_command ||= ->(cmd) { puts "redisbetween: unsupported #{cmd}" }
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  if redisbetween_enabled
         | 
| 23 | 
            +
                    if options[:url]
         | 
| 24 | 
            +
                      u = URI(options[:url])
         | 
| 25 | 
            +
                      if u.scheme != 'unix'
         | 
| 26 | 
            +
                        path = u.path.empty? ? nil : u.path.delete_prefix('/')
         | 
| 27 | 
            +
                        u.path = Redisbetween.socket_path(options[:convert_to_redisbetween_socket], u.host, u.port, path)
         | 
| 28 | 
            +
                        u.host = nil
         | 
| 29 | 
            +
                        u.port = nil
         | 
| 30 | 
            +
                        u.scheme = 'unix'
         | 
| 31 | 
            +
                        options[:url] = u.to_s
         | 
| 32 | 
            +
                      end
         | 
| 33 | 
            +
                    elsif options[:host] && options[:port] && options[:scheme] != 'unix'
         | 
| 34 | 
            +
                      path = Redisbetween.socket_path(options[:convert_to_redisbetween_socket], options[:host], options[:port])
         | 
| 35 | 
            +
                      [:port, :host, :scheme].each { |k| options[k] = nil }
         | 
| 36 | 
            +
                      options[:url] = "unix:#{path}"
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                  super(options)
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                UNSUPPORTED_COMMANDS = Set.new([
         | 
| 43 | 
            +
                  :auth,
         | 
| 44 | 
            +
                  :blpop,
         | 
| 45 | 
            +
                  :brpop,
         | 
| 46 | 
            +
                  :bzpopmax,
         | 
| 47 | 
            +
                  :bzpopmin,
         | 
| 48 | 
            +
                  :select,
         | 
| 49 | 
            +
                  :wait,
         | 
| 50 | 
            +
                  :xread,
         | 
| 51 | 
            +
                  :xreadgroup,
         | 
| 52 | 
            +
                ])
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def process(commands)
         | 
| 55 | 
            +
                  @handle_unsupported_redisbetween_command&.call("multi without a block") if commands == [[:multi]]
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  logging(commands) do
         | 
| 58 | 
            +
                    ensure_connected do
         | 
| 59 | 
            +
                      wrap = commands.size > 1 && redisbetween_enabled
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                      _rb_wrapped_write(wrap) do
         | 
| 62 | 
            +
                        commands.each do |command|
         | 
| 63 | 
            +
                          if UNSUPPORTED_COMMANDS.member?(command.first)
         | 
| 64 | 
            +
                            @handle_unsupported_redisbetween_command&.call(command.first.to_s)
         | 
| 65 | 
            +
                          end
         | 
| 66 | 
            +
                          if command_map[command.first]
         | 
| 67 | 
            +
                            command = command.dup
         | 
| 68 | 
            +
                            command[0] = command_map[command.first]
         | 
| 69 | 
            +
                          end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                          write(command)
         | 
| 72 | 
            +
                        end
         | 
| 73 | 
            +
                      end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                      _rb_wrapped_read(wrap) do
         | 
| 76 | 
            +
                        yield if block_given?
         | 
| 77 | 
            +
                      end
         | 
| 78 | 
            +
                    end
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def _rb_wrapped_write(wrap)
         | 
| 83 | 
            +
                  write([:get, PIPELINE_START_SIGNAL]) if wrap
         | 
| 84 | 
            +
                  yield
         | 
| 85 | 
            +
                  write([:get, PIPELINE_END_SIGNAL]) if wrap
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                # the proxy sends back nil values as placeholders for the signals, so discard them
         | 
| 89 | 
            +
                def _rb_wrapped_read(wrap)
         | 
| 90 | 
            +
                  read if wrap
         | 
| 91 | 
            +
                  res = yield
         | 
| 92 | 
            +
                  read if wrap
         | 
| 93 | 
            +
                  res
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
              def self.socket_path(option, host, port, path = nil)
         | 
| 98 | 
            +
                if option.respond_to?(:call)
         | 
| 99 | 
            +
                  option.call(host, port, path)
         | 
| 100 | 
            +
                else
         | 
| 101 | 
            +
                  default_socket_path(host, port, path)
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
              end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              def self.default_socket_path(host, port, path = nil)
         | 
| 106 | 
            +
                ['/var/tmp/redisbetween', host, port, path].compact.join('-') + '.sock'
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
            end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            Redis::Client.prepend(Redisbetween::ClientPatch)
         | 
| @@ -0,0 +1,205 @@ | |
| 1 | 
            +
            RSpec.describe Redisbetween do
         | 
| 2 | 
            +
              def test_logger(stream, level = Logger::DEBUG)
         | 
| 3 | 
            +
                logger = Logger.new(stream)
         | 
| 4 | 
            +
                logger.level = level
         | 
| 5 | 
            +
                logger.formatter = proc { |_, _, _, msg| msg.sub("[Redis]", "").strip + "\n" }
         | 
| 6 | 
            +
                logger
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def redis_host
         | 
| 10 | 
            +
                ENV['REDIS_HOST'] || '127.0.0.1'
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def redis_url(port, db = nil)
         | 
| 14 | 
            +
                out = "redis://#{redis_host}:#{port}"
         | 
| 15 | 
            +
                out += "/#{db}" if db
         | 
| 16 | 
            +
                out
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              def redis_socket(port)
         | 
| 20 | 
            +
                "unix:/var/tmp/redisbetween-#{redis_host}-#{port}.sock"
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def redis_client(cluster:, port:, **opts)
         | 
| 24 | 
            +
                opts = cluster ? opts.merge(cluster: [redis_url(port)]) : opts.merge(url: redis_url(port))
         | 
| 25 | 
            +
                Redis.new(opts)
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              it "has a version number" do
         | 
| 29 | 
            +
                expect(Redisbetween::VERSION).not_to be nil
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
              describe '#convert_to_redisbetween_socket' do
         | 
| 33 | 
            +
                it 'should allow passing a proc' do
         | 
| 34 | 
            +
                  path = Redisbetween.socket_path(->(host, port, path) { [host, port, path].join('-') }, "h", "p", "p")
         | 
| 35 | 
            +
                  expect(path).to eq("h-p-p")
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                it 'should default to /var/tmp' do
         | 
| 39 | 
            +
                  path = Redisbetween.socket_path(true, "h", "p", "p")
         | 
| 40 | 
            +
                  expect(path).to eq("/var/tmp/redisbetween-h-p-p.sock")
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                it 'should omit the path if not given' do
         | 
| 44 | 
            +
                  path = Redisbetween.socket_path(true, "h", "p")
         | 
| 45 | 
            +
                  expect(path).to eq("/var/tmp/redisbetween-h-p.sock")
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
              
         | 
| 49 | 
            +
              describe Redisbetween::ClientPatch do
         | 
| 50 | 
            +
                it 'should point the client to a socket when given a url' do
         | 
| 51 | 
            +
                  client = Redis.new(url: redis_url(7006), convert_to_redisbetween_socket: true)
         | 
| 52 | 
            +
                  client.get "hi"
         | 
| 53 | 
            +
                  expect(client._client.options[:url]).to eq(redis_socket(7006))
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                it 'should point the cluster to a socket when given a url' do
         | 
| 57 | 
            +
                  client = Redis.new(cluster: [redis_url(7000)], convert_to_redisbetween_socket: true)
         | 
| 58 | 
            +
                  client._client.connection_info.map { |l| l[:location] }.each do |loc|
         | 
| 59 | 
            +
                    expect(loc).to match(/\/var\/tmp\/redisbetween-\d+\.\d+\.\d+\.\d+-\d+.sock/)
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                it 'should point the client to a socket when given host and port' do
         | 
| 64 | 
            +
                  client = Redis.new(host: redis_host, port: 1234, convert_to_redisbetween_socket: true)
         | 
| 65 | 
            +
                  expect(client._client.options[:url]).to eq(redis_socket(1234))
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                it 'should not mess with the url when not enabled' do
         | 
| 69 | 
            +
                  client = Redis.new(url: redis_url(7006, 10))
         | 
| 70 | 
            +
                  expect(client._client.options[:url]).to eq(redis_url(7006, 10))
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                [
         | 
| 74 | 
            +
                  [false, 7006],
         | 
| 75 | 
            +
                  [true, 7000],
         | 
| 76 | 
            +
                ].each do |(cluster, port)|
         | 
| 77 | 
            +
                  context "with cluster #{cluster}, port #{port}" do
         | 
| 78 | 
            +
                    it 'should prepend and append the signal messages to all pipelines when enabled' do
         | 
| 79 | 
            +
                      stream = StringIO.new
         | 
| 80 | 
            +
                      client = redis_client(cluster: cluster, port: port, convert_to_redisbetween_socket: true, logger: test_logger(stream))
         | 
| 81 | 
            +
                      res = client.pipelined do
         | 
| 82 | 
            +
                        client.set("hi", 1)
         | 
| 83 | 
            +
                        client.get("hi")
         | 
| 84 | 
            +
                        client.set("yes", "maybe")
         | 
| 85 | 
            +
                        client.get("yes")
         | 
| 86 | 
            +
                      end
         | 
| 87 | 
            +
                      expect(res).to eq(%w[OK 1 OK maybe])
         | 
| 88 | 
            +
                      expect(stream.string).to include(<<~LOG
         | 
| 89 | 
            +
                        command=SET args="hi" "1"
         | 
| 90 | 
            +
                        command=GET args="hi"
         | 
| 91 | 
            +
                        command=SET args="yes" "maybe"
         | 
| 92 | 
            +
                        command=GET args="yes"
         | 
| 93 | 
            +
                      LOG
         | 
| 94 | 
            +
                      )
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    it 'should correctly process transactions with no cross slot keys' do
         | 
| 98 | 
            +
                      stream = StringIO.new
         | 
| 99 | 
            +
                      client = redis_client(cluster: cluster, port: port, convert_to_redisbetween_socket: true, logger: test_logger(stream))
         | 
| 100 | 
            +
                      res = client.multi do
         | 
| 101 | 
            +
                        client.set("{1}hi", 1)
         | 
| 102 | 
            +
                        client.get("{1}hi")
         | 
| 103 | 
            +
                        client.set("{1}yes", "maybe")
         | 
| 104 | 
            +
                        client.get("{1}yes")
         | 
| 105 | 
            +
                      end
         | 
| 106 | 
            +
                      expect(res).to eq(%w[OK 1 OK maybe])
         | 
| 107 | 
            +
                      expect(stream.string).to include(<<~LOG
         | 
| 108 | 
            +
                        command=MULTI args=
         | 
| 109 | 
            +
                        command=SET args="{1}hi" "1"
         | 
| 110 | 
            +
                        command=GET args="{1}hi"
         | 
| 111 | 
            +
                        command=SET args="{1}yes" "maybe"
         | 
| 112 | 
            +
                        command=GET args="{1}yes"
         | 
| 113 | 
            +
                        command=EXEC args=
         | 
| 114 | 
            +
                      LOG
         | 
| 115 | 
            +
                      )
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                    it 'should not prepend or append the signal messages to any pipelines when not enabled' do
         | 
| 119 | 
            +
                      stream = StringIO.new
         | 
| 120 | 
            +
                      client = redis_client(cluster: cluster, port: port, logger: test_logger(stream))
         | 
| 121 | 
            +
                      res = client.pipelined do
         | 
| 122 | 
            +
                        client.set("hi", 1)
         | 
| 123 | 
            +
                        client.get("hi")
         | 
| 124 | 
            +
                        client.set("yes", "maybe")
         | 
| 125 | 
            +
                        client.get("yes")
         | 
| 126 | 
            +
                      end
         | 
| 127 | 
            +
                      expect(res).to eq(%w[OK 1 OK maybe])
         | 
| 128 | 
            +
                      expect(stream.string).to include(<<~LOG
         | 
| 129 | 
            +
                        command=SET args="hi" "1"
         | 
| 130 | 
            +
                        command=GET args="hi"
         | 
| 131 | 
            +
                        command=SET args="yes" "maybe"
         | 
| 132 | 
            +
                        command=GET args="yes"
         | 
| 133 | 
            +
                      LOG
         | 
| 134 | 
            +
                      )
         | 
| 135 | 
            +
                    end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                    it 'should not prepend or append the signal messages to multis when not enabled' do
         | 
| 138 | 
            +
                      stream = StringIO.new
         | 
| 139 | 
            +
                      client = redis_client(cluster: cluster, port: port, logger: test_logger(stream))
         | 
| 140 | 
            +
                      res = client.multi do
         | 
| 141 | 
            +
                        client.set("{1}hi", 1)
         | 
| 142 | 
            +
                        client.get("{1}hi")
         | 
| 143 | 
            +
                        client.set("{1}yes", "maybe")
         | 
| 144 | 
            +
                        client.get("{1}yes")
         | 
| 145 | 
            +
                      end
         | 
| 146 | 
            +
                      expect(res).to eq(%w[OK 1 OK maybe])
         | 
| 147 | 
            +
                      expect(stream.string).to include(<<~LOG
         | 
| 148 | 
            +
                        command=MULTI args=
         | 
| 149 | 
            +
                        command=SET args="{1}hi" "1"
         | 
| 150 | 
            +
                        command=GET args="{1}hi"
         | 
| 151 | 
            +
                        command=SET args="{1}yes" "maybe"
         | 
| 152 | 
            +
                        command=GET args="{1}yes"
         | 
| 153 | 
            +
                        command=EXEC args=
         | 
| 154 | 
            +
                      LOG
         | 
| 155 | 
            +
                      )
         | 
| 156 | 
            +
                    end
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                describe :handle_unsupported_redisbetween_command do
         | 
| 161 | 
            +
                  it 'should raise on unsupported commands when set to :raise' do
         | 
| 162 | 
            +
                    client = Redis.new(
         | 
| 163 | 
            +
                      url: redis_url(7006, 10),
         | 
| 164 | 
            +
                      handle_unsupported_redisbetween_command: ->(_cmd) { raise "hi" }
         | 
| 165 | 
            +
                    )
         | 
| 166 | 
            +
                    expect { client.select(2) }.to raise_error("hi")
         | 
| 167 | 
            +
                  end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  it 'standalone: should call the given proc' do
         | 
| 170 | 
            +
                    stream = StringIO.new
         | 
| 171 | 
            +
                    logger = test_logger(stream)
         | 
| 172 | 
            +
                    client = Redis.new(
         | 
| 173 | 
            +
                      url: redis_url(7006, 10),
         | 
| 174 | 
            +
                      handle_unsupported_redisbetween_command: ->(cmd) { logger.warn("hi #{cmd}") }
         | 
| 175 | 
            +
                    )
         | 
| 176 | 
            +
                    client.select(2)
         | 
| 177 | 
            +
                    expect(stream.string).to include("hi select")
         | 
| 178 | 
            +
                  end
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                  it 'cluster: should call the given proc' do
         | 
| 181 | 
            +
                    stream = StringIO.new
         | 
| 182 | 
            +
                    logger = test_logger(stream)
         | 
| 183 | 
            +
                    client = Redis.new(
         | 
| 184 | 
            +
                      cluster: [redis_url(7000)],
         | 
| 185 | 
            +
                      handle_unsupported_redisbetween_command: ->(cmd) { logger.warn(cmd) }
         | 
| 186 | 
            +
                    )
         | 
| 187 | 
            +
                    client.wait(1, 1)
         | 
| 188 | 
            +
                    expect(stream.string).to include("wait")
         | 
| 189 | 
            +
                  end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                  it 'should not mess with unsupported commands when not enabled' do
         | 
| 192 | 
            +
                    client = Redis.new(url: redis_url(7006, 10))
         | 
| 193 | 
            +
                    expect(client.select(2)).to eq("OK")
         | 
| 194 | 
            +
                  end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
                  it 'should disallow multi without a block' do
         | 
| 197 | 
            +
                    client = Redis.new(
         | 
| 198 | 
            +
                      url: redis_url(7006, 10),
         | 
| 199 | 
            +
                      handle_unsupported_redisbetween_command: ->(cmd) { raise cmd }
         | 
| 200 | 
            +
                    )
         | 
| 201 | 
            +
                    expect { client.multi }.to raise_error("multi without a block")
         | 
| 202 | 
            +
                  end
         | 
| 203 | 
            +
                end
         | 
| 204 | 
            +
              end
         | 
| 205 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require "bundler/setup"
         | 
| 2 | 
            +
            require "redisbetween"
         | 
| 3 | 
            +
            require 'logger'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            RSpec.configure do |config|
         | 
| 6 | 
            +
              # Enable flags like --only-failures and --next-failure
         | 
| 7 | 
            +
              config.example_status_persistence_file_path = ".rspec_status"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              # Disable RSpec exposing methods globally on `Module` and `main`
         | 
| 10 | 
            +
              config.disable_monkey_patching!
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              config.expect_with :rspec do |c|
         | 
| 13 | 
            +
                c.syntax = :expect
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,60 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: redisbetween
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.2.2
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Jordan Sitkin
         | 
| 8 | 
            +
            autorequire:
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2022-06-07 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: redis
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 27 | 
            +
            description: Client patch for the ruby redis driver to support redisbetween
         | 
| 28 | 
            +
            email:
         | 
| 29 | 
            +
            - jordan.sitkin@coinbase.com
         | 
| 30 | 
            +
            executables: []
         | 
| 31 | 
            +
            extensions: []
         | 
| 32 | 
            +
            extra_rdoc_files: []
         | 
| 33 | 
            +
            files:
         | 
| 34 | 
            +
            - lib/redisbetween.rb
         | 
| 35 | 
            +
            - lib/redisbetween/version.rb
         | 
| 36 | 
            +
            - spec/redisbetween_spec.rb
         | 
| 37 | 
            +
            - spec/spec_helper.rb
         | 
| 38 | 
            +
            homepage:
         | 
| 39 | 
            +
            licenses: []
         | 
| 40 | 
            +
            metadata: {}
         | 
| 41 | 
            +
            post_install_message:
         | 
| 42 | 
            +
            rdoc_options: []
         | 
| 43 | 
            +
            require_paths:
         | 
| 44 | 
            +
            - lib
         | 
| 45 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 46 | 
            +
              requirements:
         | 
| 47 | 
            +
              - - ">="
         | 
| 48 | 
            +
                - !ruby/object:Gem::Version
         | 
| 49 | 
            +
                  version: 2.3.0
         | 
| 50 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
              requirements:
         | 
| 52 | 
            +
              - - ">="
         | 
| 53 | 
            +
                - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                  version: '0'
         | 
| 55 | 
            +
            requirements: []
         | 
| 56 | 
            +
            rubygems_version: 3.2.3
         | 
| 57 | 
            +
            signing_key:
         | 
| 58 | 
            +
            specification_version: 4
         | 
| 59 | 
            +
            summary: redisbetween client gem
         | 
| 60 | 
            +
            test_files: []
         |