redis 4.1.0.beta1 → 4.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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -2
  3. data/README.md +45 -0
  4. data/lib/redis.rb +497 -20
  5. data/lib/redis/client.rb +14 -6
  6. data/lib/redis/cluster.rb +1 -0
  7. data/lib/redis/cluster/command_loader.rb +2 -0
  8. data/lib/redis/cluster/node_loader.rb +2 -0
  9. data/lib/redis/cluster/option.rb +1 -0
  10. data/lib/redis/cluster/slot_loader.rb +2 -0
  11. data/lib/redis/distributed.rb +3 -4
  12. data/lib/redis/version.rb +1 -1
  13. metadata +20 -243
  14. data/.gitignore +0 -19
  15. data/.travis.yml +0 -61
  16. data/.travis/Gemfile +0 -18
  17. data/.yardopts +0 -3
  18. data/Gemfile +0 -8
  19. data/benchmarking/logging.rb +0 -71
  20. data/benchmarking/pipeline.rb +0 -51
  21. data/benchmarking/speed.rb +0 -21
  22. data/benchmarking/suite.rb +0 -24
  23. data/benchmarking/worker.rb +0 -71
  24. data/bin/build +0 -71
  25. data/bors.toml +0 -14
  26. data/examples/basic.rb +0 -15
  27. data/examples/consistency.rb +0 -114
  28. data/examples/dist_redis.rb +0 -43
  29. data/examples/incr-decr.rb +0 -17
  30. data/examples/list.rb +0 -26
  31. data/examples/pubsub.rb +0 -37
  32. data/examples/sentinel.rb +0 -41
  33. data/examples/sentinel/start +0 -49
  34. data/examples/sets.rb +0 -36
  35. data/examples/unicorn/config.ru +0 -3
  36. data/examples/unicorn/unicorn.rb +0 -20
  37. data/makefile +0 -74
  38. data/redis.gemspec +0 -42
  39. data/test/bitpos_test.rb +0 -63
  40. data/test/blocking_commands_test.rb +0 -40
  41. data/test/client_test.rb +0 -76
  42. data/test/cluster_abnormal_state_test.rb +0 -38
  43. data/test/cluster_blocking_commands_test.rb +0 -15
  44. data/test/cluster_client_internals_test.rb +0 -77
  45. data/test/cluster_client_key_hash_tags_test.rb +0 -88
  46. data/test/cluster_client_options_test.rb +0 -147
  47. data/test/cluster_client_pipelining_test.rb +0 -59
  48. data/test/cluster_client_replicas_test.rb +0 -36
  49. data/test/cluster_client_slots_test.rb +0 -94
  50. data/test/cluster_client_transactions_test.rb +0 -71
  51. data/test/cluster_commands_on_cluster_test.rb +0 -165
  52. data/test/cluster_commands_on_connection_test.rb +0 -40
  53. data/test/cluster_commands_on_geo_test.rb +0 -74
  54. data/test/cluster_commands_on_hashes_test.rb +0 -11
  55. data/test/cluster_commands_on_hyper_log_log_test.rb +0 -17
  56. data/test/cluster_commands_on_keys_test.rb +0 -134
  57. data/test/cluster_commands_on_lists_test.rb +0 -15
  58. data/test/cluster_commands_on_pub_sub_test.rb +0 -101
  59. data/test/cluster_commands_on_scripting_test.rb +0 -56
  60. data/test/cluster_commands_on_server_test.rb +0 -221
  61. data/test/cluster_commands_on_sets_test.rb +0 -39
  62. data/test/cluster_commands_on_sorted_sets_test.rb +0 -35
  63. data/test/cluster_commands_on_streams_test.rb +0 -196
  64. data/test/cluster_commands_on_strings_test.rb +0 -15
  65. data/test/cluster_commands_on_transactions_test.rb +0 -41
  66. data/test/cluster_commands_on_value_types_test.rb +0 -14
  67. data/test/command_map_test.rb +0 -28
  68. data/test/commands_on_geo_test.rb +0 -116
  69. data/test/commands_on_hashes_test.rb +0 -7
  70. data/test/commands_on_hyper_log_log_test.rb +0 -7
  71. data/test/commands_on_lists_test.rb +0 -7
  72. data/test/commands_on_sets_test.rb +0 -7
  73. data/test/commands_on_sorted_sets_test.rb +0 -7
  74. data/test/commands_on_strings_test.rb +0 -7
  75. data/test/commands_on_value_types_test.rb +0 -207
  76. data/test/connection_handling_test.rb +0 -275
  77. data/test/connection_test.rb +0 -57
  78. data/test/distributed_blocking_commands_test.rb +0 -52
  79. data/test/distributed_commands_on_hashes_test.rb +0 -21
  80. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -26
  81. data/test/distributed_commands_on_lists_test.rb +0 -19
  82. data/test/distributed_commands_on_sets_test.rb +0 -105
  83. data/test/distributed_commands_on_sorted_sets_test.rb +0 -59
  84. data/test/distributed_commands_on_strings_test.rb +0 -79
  85. data/test/distributed_commands_on_value_types_test.rb +0 -129
  86. data/test/distributed_commands_requiring_clustering_test.rb +0 -162
  87. data/test/distributed_connection_handling_test.rb +0 -21
  88. data/test/distributed_internals_test.rb +0 -68
  89. data/test/distributed_key_tags_test.rb +0 -50
  90. data/test/distributed_persistence_control_commands_test.rb +0 -24
  91. data/test/distributed_publish_subscribe_test.rb +0 -90
  92. data/test/distributed_remote_server_control_commands_test.rb +0 -64
  93. data/test/distributed_scripting_test.rb +0 -100
  94. data/test/distributed_sorting_test.rb +0 -18
  95. data/test/distributed_test.rb +0 -56
  96. data/test/distributed_transactions_test.rb +0 -30
  97. data/test/encoding_test.rb +0 -14
  98. data/test/error_replies_test.rb +0 -57
  99. data/test/fork_safety_test.rb +0 -60
  100. data/test/helper.rb +0 -344
  101. data/test/helper_test.rb +0 -22
  102. data/test/internals_test.rb +0 -395
  103. data/test/lint/blocking_commands.rb +0 -174
  104. data/test/lint/hashes.rb +0 -203
  105. data/test/lint/hyper_log_log.rb +0 -74
  106. data/test/lint/lists.rb +0 -159
  107. data/test/lint/sets.rb +0 -282
  108. data/test/lint/sorted_sets.rb +0 -497
  109. data/test/lint/strings.rb +0 -348
  110. data/test/lint/value_types.rb +0 -130
  111. data/test/persistence_control_commands_test.rb +0 -24
  112. data/test/pipelining_commands_test.rb +0 -246
  113. data/test/publish_subscribe_test.rb +0 -280
  114. data/test/remote_server_control_commands_test.rb +0 -175
  115. data/test/scanning_test.rb +0 -407
  116. data/test/scripting_test.rb +0 -76
  117. data/test/sentinel_command_test.rb +0 -78
  118. data/test/sentinel_test.rb +0 -253
  119. data/test/sorting_test.rb +0 -57
  120. data/test/ssl_test.rb +0 -69
  121. data/test/support/cluster/orchestrator.rb +0 -199
  122. data/test/support/connection/hiredis.rb +0 -1
  123. data/test/support/connection/ruby.rb +0 -1
  124. data/test/support/connection/synchrony.rb +0 -17
  125. data/test/support/redis_mock.rb +0 -130
  126. data/test/support/ssl/gen_certs.sh +0 -31
  127. data/test/support/ssl/trusted-ca.crt +0 -25
  128. data/test/support/ssl/trusted-ca.key +0 -27
  129. data/test/support/ssl/trusted-cert.crt +0 -81
  130. data/test/support/ssl/trusted-cert.key +0 -28
  131. data/test/support/ssl/untrusted-ca.crt +0 -26
  132. data/test/support/ssl/untrusted-ca.key +0 -27
  133. data/test/support/ssl/untrusted-cert.crt +0 -82
  134. data/test/support/ssl/untrusted-cert.key +0 -28
  135. data/test/support/wire/synchrony.rb +0 -24
  136. data/test/support/wire/thread.rb +0 -5
  137. data/test/synchrony_driver.rb +0 -85
  138. data/test/test.conf.erb +0 -9
  139. data/test/thread_safety_test.rb +0 -60
  140. data/test/transactions_test.rb +0 -272
  141. data/test/unknown_commands_test.rb +0 -12
  142. data/test/url_param_test.rb +0 -136
@@ -1,43 +0,0 @@
1
- require "redis"
2
- require "redis/distributed"
3
-
4
- r = Redis::Distributed.new %w[redis://localhost:6379 redis://localhost:6380 redis://localhost:6381 redis://localhost:6382]
5
-
6
- r.flushdb
7
-
8
- r['urmom'] = 'urmom'
9
- r['urdad'] = 'urdad'
10
- r['urmom1'] = 'urmom1'
11
- r['urdad1'] = 'urdad1'
12
- r['urmom2'] = 'urmom2'
13
- r['urdad2'] = 'urdad2'
14
- r['urmom3'] = 'urmom3'
15
- r['urdad3'] = 'urdad3'
16
- p r['urmom']
17
- p r['urdad']
18
- p r['urmom1']
19
- p r['urdad1']
20
- p r['urmom2']
21
- p r['urdad2']
22
- p r['urmom3']
23
- p r['urdad3']
24
-
25
- r.rpush 'listor', 'foo1'
26
- r.rpush 'listor', 'foo2'
27
- r.rpush 'listor', 'foo3'
28
- r.rpush 'listor', 'foo4'
29
- r.rpush 'listor', 'foo5'
30
-
31
- p r.rpop('listor')
32
- p r.rpop('listor')
33
- p r.rpop('listor')
34
- p r.rpop('listor')
35
- p r.rpop('listor')
36
-
37
- puts "key distribution:"
38
-
39
- r.ring.nodes.each do |node|
40
- p [node.client, node.keys("*")]
41
- end
42
- r.flushdb
43
- p r.keys('*')
@@ -1,17 +0,0 @@
1
- require 'redis'
2
-
3
- r = Redis.new
4
-
5
- puts
6
- p 'incr'
7
- r.del 'counter'
8
-
9
- p r.incr('counter')
10
- p r.incr('counter')
11
- p r.incr('counter')
12
-
13
- puts
14
- p 'decr'
15
- p r.decr('counter')
16
- p r.decr('counter')
17
- p r.decr('counter')
@@ -1,26 +0,0 @@
1
- require 'rubygems'
2
- require 'redis'
3
-
4
- r = Redis.new
5
-
6
- r.del 'logs'
7
-
8
- puts
9
-
10
- p "pushing log messages into a LIST"
11
- r.rpush 'logs', 'some log message'
12
- r.rpush 'logs', 'another log message'
13
- r.rpush 'logs', 'yet another log message'
14
- r.rpush 'logs', 'also another log message'
15
-
16
- puts
17
- p 'contents of logs LIST'
18
-
19
- p r.lrange('logs', 0, -1)
20
-
21
- puts
22
- p 'Trim logs LIST to last 2 elements(easy circular buffer)'
23
-
24
- r.ltrim('logs', -2, -1)
25
-
26
- p r.lrange('logs', 0, -1)
@@ -1,37 +0,0 @@
1
- require "redis"
2
-
3
- puts <<-EOS
4
- To play with this example use redis-cli from another terminal, like this:
5
-
6
- $ redis-cli publish one hello
7
-
8
- Finally force the example to exit sending the 'exit' message with:
9
-
10
- $ redis-cli publish two exit
11
-
12
- EOS
13
-
14
- redis = Redis.new
15
-
16
- trap(:INT) { puts; exit }
17
-
18
- begin
19
- redis.subscribe(:one, :two) do |on|
20
- on.subscribe do |channel, subscriptions|
21
- puts "Subscribed to ##{channel} (#{subscriptions} subscriptions)"
22
- end
23
-
24
- on.message do |channel, message|
25
- puts "##{channel}: #{message}"
26
- redis.unsubscribe if message == "exit"
27
- end
28
-
29
- on.unsubscribe do |channel, subscriptions|
30
- puts "Unsubscribed from ##{channel} (#{subscriptions} subscriptions)"
31
- end
32
- end
33
- rescue Redis::BaseConnectionError => error
34
- puts "#{error}, retrying in 1s"
35
- sleep 1
36
- retry
37
- end
@@ -1,41 +0,0 @@
1
- require 'redis'
2
-
3
- # This example creates a master-slave setup with a sentinel, then connects to
4
- # it and sends write commands in a loop.
5
- #
6
- # After 30 seconds, the master dies. You will be able to see how a new master
7
- # is elected and things continue to work as if nothing happened.
8
- #
9
- # To run this example:
10
- #
11
- # $ ruby -I./lib examples/sentinel.rb
12
- #
13
-
14
- at_exit do
15
- begin
16
- Process.kill(:INT, $redises)
17
- rescue Errno::ESRCH
18
- end
19
-
20
- Process.waitall
21
- end
22
-
23
- $redises = spawn("examples/sentinel/start")
24
-
25
- Sentinels = [{:host => "127.0.0.1", :port => 26379},
26
- {:host => "127.0.0.1", :port => 26380}]
27
- r = Redis.new(:url => "redis://master1", :sentinels => Sentinels, :role => :master)
28
-
29
- # Set keys into a loop.
30
- #
31
- # The example traps errors so that you can actually try to failover while
32
- # running the script to see redis-rb reconfiguring.
33
- (0..1000000).each{|i|
34
- begin
35
- r.set(i,i)
36
- $stdout.write("SET (#{i} times)\n") if i % 100 == 0
37
- rescue => e
38
- $stdout.write("E")
39
- end
40
- sleep(0.01)
41
- }
@@ -1,49 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- # This is a helper script used together with examples/sentinel.rb
4
- # It runs two Redis masters, two slaves for each of them, and two sentinels.
5
- # After 30 seconds, the first master dies.
6
- #
7
- # You don't need to run this script yourself. Rather, use examples/sentinel.rb.
8
-
9
- require "fileutils"
10
-
11
- $pids = []
12
-
13
- at_exit do
14
- $pids.each do |pid|
15
- begin
16
- Process.kill(:INT, pid)
17
- rescue Errno::ESRCH
18
- end
19
- end
20
-
21
- Process.waitall
22
- end
23
-
24
- base = File.expand_path(File.dirname(__FILE__))
25
-
26
- # Masters
27
- $pids << spawn("redis-server --port 6380 --loglevel warning")
28
- $pids << spawn("redis-server --port 6381 --loglevel warning")
29
-
30
- # Slaves of Master 1
31
- $pids << spawn("redis-server --port 63800 --slaveof 127.0.0.1 6380 --loglevel warning")
32
- $pids << spawn("redis-server --port 63801 --slaveof 127.0.0.1 6380 --loglevel warning")
33
-
34
- # Slaves of Master 2
35
- $pids << spawn("redis-server --port 63810 --slaveof 127.0.0.1 6381 --loglevel warning")
36
- $pids << spawn("redis-server --port 63811 --slaveof 127.0.0.1 6381 --loglevel warning")
37
-
38
- FileUtils.cp(File.join(base, "sentinel.conf"), "tmp/sentinel1.conf")
39
- FileUtils.cp(File.join(base, "sentinel.conf"), "tmp/sentinel2.conf")
40
-
41
- # Sentinels
42
- $pids << spawn("redis-server tmp/sentinel1.conf --sentinel --port 26379")
43
- $pids << spawn("redis-server tmp/sentinel2.conf --sentinel --port 26380")
44
-
45
- sleep 30
46
-
47
- Process.kill(:KILL, $pids[0])
48
-
49
- Process.waitall
@@ -1,36 +0,0 @@
1
- require 'rubygems'
2
- require 'redis'
3
-
4
- r = Redis.new
5
-
6
- r.del 'foo-tags'
7
- r.del 'bar-tags'
8
-
9
- puts
10
- p "create a set of tags on foo-tags"
11
-
12
- r.sadd 'foo-tags', 'one'
13
- r.sadd 'foo-tags', 'two'
14
- r.sadd 'foo-tags', 'three'
15
-
16
- puts
17
- p "create a set of tags on bar-tags"
18
-
19
- r.sadd 'bar-tags', 'three'
20
- r.sadd 'bar-tags', 'four'
21
- r.sadd 'bar-tags', 'five'
22
-
23
- puts
24
- p 'foo-tags'
25
-
26
- p r.smembers('foo-tags')
27
-
28
- puts
29
- p 'bar-tags'
30
-
31
- p r.smembers('bar-tags')
32
-
33
- puts
34
- p 'intersection of foo-tags and bar-tags'
35
-
36
- p r.sinter('foo-tags', 'bar-tags')
@@ -1,3 +0,0 @@
1
- run lambda { |env|
2
- [200, {"Content-Type" => "text/plain"}, [Redis.current.randomkey]]
3
- }
@@ -1,20 +0,0 @@
1
- require "redis"
2
-
3
- worker_processes 3
4
-
5
- # If you set the connection to Redis *before* forking,
6
- # you will cause forks to share a file descriptor.
7
- #
8
- # This causes a concurrency problem by which one fork
9
- # can read or write to the socket while others are
10
- # performing other operations.
11
- #
12
- # Most likely you'll be getting ProtocolError exceptions
13
- # mentioning a wrong initial byte in the reply.
14
- #
15
- # Thus we need to connect to Redis after forking the
16
- # worker processes.
17
-
18
- after_fork do |server, worker|
19
- Redis.current.disconnect!
20
- end
data/makefile DELETED
@@ -1,74 +0,0 @@
1
- TEST_FILES := $(shell find ./test -name *_test.rb -type f)
2
- REDIS_BRANCH ?= unstable
3
- TMP := tmp
4
- BUILD_DIR := ${TMP}/cache/redis-${REDIS_BRANCH}
5
- TARBALL := ${TMP}/redis-${REDIS_BRANCH}.tar.gz
6
- BINARY := ${BUILD_DIR}/src/redis-server
7
- REDIS_CLIENT := ${BUILD_DIR}/src/redis-cli
8
- REDIS_TRIB := ${BUILD_DIR}/src/redis-trib.rb
9
- PID_PATH := ${BUILD_DIR}/redis.pid
10
- SOCKET_PATH := ${BUILD_DIR}/redis.sock
11
- PORT := 6381
12
- CLUSTER_PORTS := 7000 7001 7002 7003 7004 7005
13
- CLUSTER_PID_PATHS := $(addprefix ${TMP}/redis,$(addsuffix .pid,${CLUSTER_PORTS}))
14
- CLUSTER_CONF_PATHS := $(addprefix ${TMP}/nodes,$(addsuffix .conf,${CLUSTER_PORTS}))
15
- CLUSTER_ADDRS := $(addprefix 127.0.0.1:,${CLUSTER_PORTS})
16
-
17
- define kill-redis
18
- (ls $1 2> /dev/null && kill $$(cat $1) && rm -f $1) || true
19
- endef
20
-
21
- all:
22
- make start
23
- make start_cluster
24
- make create_cluster
25
- make test
26
- make stop
27
- make stop_cluster
28
-
29
- ${TMP}:
30
- mkdir -p $@
31
-
32
- ${BINARY}: ${TMP}
33
- bin/build ${REDIS_BRANCH} $<
34
-
35
- test: ${TEST_FILES}
36
- env SOCKET_PATH=${SOCKET_PATH} \
37
- bundle exec ruby -v -e 'ARGV.each { |test_file| require test_file }' ${TEST_FILES}
38
-
39
- stop:
40
- $(call kill-redis,${PID_PATH})
41
-
42
- start: ${BINARY}
43
- ${BINARY} \
44
- --daemonize yes \
45
- --pidfile ${PID_PATH} \
46
- --port ${PORT} \
47
- --unixsocket ${SOCKET_PATH}
48
-
49
- stop_cluster:
50
- $(call kill-redis,${CLUSTER_PID_PATHS})
51
- rm -f appendonly.aof || true
52
- rm -f ${CLUSTER_CONF_PATHS} || true
53
-
54
- start_cluster: ${BINARY}
55
- for port in ${CLUSTER_PORTS}; do \
56
- ${BINARY} \
57
- --daemonize yes \
58
- --appendonly yes \
59
- --cluster-enabled yes \
60
- --cluster-config-file ${TMP}/nodes$$port.conf \
61
- --cluster-node-timeout 5000 \
62
- --pidfile ${TMP}/redis$$port.pid \
63
- --port $$port \
64
- --unixsocket ${TMP}/redis$$port.sock; \
65
- done
66
-
67
- create_cluster:
68
- yes yes | ((bundle exec ruby ${REDIS_TRIB} create --replicas 1 ${CLUSTER_ADDRS}) || \
69
- (${REDIS_CLIENT} --cluster create ${CLUSTER_ADDRS} --cluster-replicas 1))
70
-
71
- clean:
72
- (test -d ${BUILD_DIR} && cd ${BUILD_DIR}/src && make clean distclean) || true
73
-
74
- .PHONY: all test stop start stop_cluster start_cluster create_cluster clean
@@ -1,42 +0,0 @@
1
- require "./lib/redis/version"
2
-
3
- Gem::Specification.new do |s|
4
- s.name = "redis"
5
-
6
- s.version = Redis::VERSION
7
-
8
- s.homepage = "https://github.com/redis/redis-rb"
9
-
10
- s.summary = "A Ruby client library for Redis"
11
-
12
- s.description = <<-EOS
13
- A Ruby client that tries to match Redis' API one-to-one, while still
14
- providing an idiomatic interface.
15
- EOS
16
-
17
- s.license = "MIT"
18
-
19
- s.authors = [
20
- "Ezra Zygmuntowicz",
21
- "Taylor Weibley",
22
- "Matthew Clark",
23
- "Brian McKinney",
24
- "Salvatore Sanfilippo",
25
- "Luca Guidi",
26
- "Michel Martens",
27
- "Damian Janowski",
28
- "Pieter Noordhuis"
29
- ]
30
-
31
- s.email = ["redis-db@googlegroups.com"]
32
-
33
- s.files = `git ls-files`.split("\n")
34
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
35
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
36
-
37
- s.required_ruby_version = '>= 2.2.2'
38
-
39
- s.add_development_dependency("test-unit", ">= 3.1.5")
40
- s.add_development_dependency("hiredis")
41
- s.add_development_dependency("em-synchrony")
42
- end
@@ -1,63 +0,0 @@
1
- require_relative "helper"
2
-
3
- class TestBitpos < Test::Unit::TestCase
4
-
5
- include Helper::Client
6
-
7
- def test_bitpos_empty_zero
8
- target_version "2.9.11" do
9
- r.del "foo"
10
- assert_equal(0, r.bitpos("foo", 0))
11
- end
12
- end
13
-
14
- def test_bitpos_empty_one
15
- target_version "2.9.11" do
16
- r.del "foo"
17
- assert_equal(-1, r.bitpos("foo", 1))
18
- end
19
- end
20
-
21
- def test_bitpos_zero
22
- target_version "2.9.11" do
23
- r.set "foo", "\xff\xf0\x00"
24
- assert_equal(12, r.bitpos("foo", 0))
25
- end
26
- end
27
-
28
- def test_bitpos_one
29
- target_version "2.9.11" do
30
- r.set "foo", "\x00\x0f\x00"
31
- assert_equal(12, r.bitpos("foo", 1))
32
- end
33
- end
34
-
35
- def test_bitpos_zero_end_is_given
36
- target_version "2.9.11" do
37
- r.set "foo", "\xff\xff\xff"
38
- assert_equal(24, r.bitpos("foo", 0))
39
- assert_equal(24, r.bitpos("foo", 0, 0))
40
- assert_equal(-1, r.bitpos("foo", 0, 0, -1))
41
- end
42
- end
43
-
44
- def test_bitpos_one_intervals
45
- target_version "2.9.11" do
46
- r.set "foo", "\x00\xff\x00"
47
- assert_equal(8, r.bitpos("foo", 1, 0, -1))
48
- assert_equal(8, r.bitpos("foo", 1, 1, -1))
49
- assert_equal(-1, r.bitpos("foo", 1, 2, -1))
50
- assert_equal(-1, r.bitpos("foo", 1, 2, 200))
51
- assert_equal(8, r.bitpos("foo", 1, 1, 1))
52
- end
53
- end
54
-
55
- def test_bitpos_raise_exception_if_stop_not_start
56
- target_version "2.9.11" do
57
- assert_raises(ArgumentError) do
58
- r.bitpos("foo", 0, nil, 2)
59
- end
60
- end
61
- end
62
-
63
- end