diff --git a/.rubocop.yml b/.rubocop.yml index 740424b91..8663ff844 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -68,6 +68,9 @@ Style/NumericPredicate: Style/IfUnlessModifier: Enabled: false +Style/MutableConstant: + Enabled: false # false positives + Style/SignalException: Exclude: - 'lib/redis/connection/synchrony.rb' diff --git a/lib/redis/client.rb b/lib/redis/client.rb index 55d3b3f42..5ef083ef4 100644 --- a/lib/redis/client.rb +++ b/lib/redis/client.rb @@ -15,7 +15,7 @@ class Client < ::RedisClient RedisClient::WrongTypeError => Redis::WrongTypeError, RedisClient::ReadOnlyError => Redis::ReadOnlyError, RedisClient::ProtocolError => Redis::ProtocolError, - }.freeze + } class << self def config(**kwargs) @@ -78,7 +78,7 @@ def password def call_v(command, &block) super(command, &block) rescue ::RedisClient::Error => error - raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace + translate_error!(error) end def blocking_call_v(timeout, command, &block) @@ -91,19 +91,19 @@ def blocking_call_v(timeout, command, &block) super(timeout, command, &block) rescue ::RedisClient::Error => error - raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace + translate_error!(error) end def pipelined super rescue ::RedisClient::Error => error - raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace + translate_error!(error) end def multi super rescue ::RedisClient::Error => error - raise ERROR_MAPPING.fetch(error.class), error.message, error.backtrace + translate_error!(error) end def disable_reconnection(&block) @@ -121,6 +121,21 @@ def close private + def translate_error!(error) + redis_error = translate_error_class(error.class) + raise redis_error, error.message, error.backtrace + end + + def translate_error_class(error_class) + ERROR_MAPPING.fetch(error_class) + rescue IndexError + if (client_error = error_class.ancestors.find { |a| ERROR_MAPPING[a] }) + ERROR_MAPPING[error_class] = ERROR_MAPPING[client_error] + else + raise + end + end + def ensure_connected(retryable: true) unless @inherit_socket || (@pid ||= Process.pid) == Process.pid raise InheritedError, diff --git a/test/redis/client_test.rb b/test/redis/client_test.rb index 0e0628cdd..20aa15983 100644 --- a/test/redis/client_test.rb +++ b/test/redis/client_test.rb @@ -26,6 +26,15 @@ def test_call_raise end end + def test_error_translate_subclasses + error = Class.new(RedisClient::CommandError) + assert_equal Redis::CommandError, r._client.send(:translate_error_class, error) + + assert_raises KeyError do + r._client.send(:translate_error_class, StandardError) + end + end + def test_mixed_encoding r.call("MSET", "fée", "\x00\xFF".b, "じ案".encode(Encoding::SHIFT_JIS), "\t".encode(Encoding::ASCII)) assert_equal "\x00\xFF".b, r.call("GET", "fée")