Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added better API Compatibility with the memcache-client gem for excep…

…tion handling.
  • Loading branch information...
commit c468f6548186a5d29371e14726dda9aae84cb28e 1 parent d4aa695
@chriseppstein authored Derek Perez committed
View
2  lib/memcached.rb
@@ -28,4 +28,4 @@ class Memcached
require 'memcached/exceptions'
require 'memcached/behaviors'
require 'memcached/memcached'
-require 'memcached/rails'
+require 'memcached/rails' if defined?(RAILS_ENV)
View
66 lib/memcached/rails.rb
@@ -1,3 +1,15 @@
+unless defined?(Timeout::Error)
+ module Timeout
+ class Error < Interrupt; end
+ end
+end
+
+unless defined?(MemCache::MemCacheError)
+ class MemCache
+ class MemCacheError < RuntimeError; end
+ end
+end
+
class Memcached
(instance_methods - NilClass.instance_methods).each do |method_name|
@@ -6,6 +18,30 @@ class Memcached
# A legacy compatibility wrapper for the Memcached class. It has basic compatibility with the <b>memcache-client</b> API.
class Rails < ::Memcached
+
+ DEFAULTS = {}
+
+ def self.translate_exception(method, mapping)
+ from_exception = mapping.keys.first
+ to_exception = mapping.values.first
+ exception_supported = (to_exception || from_exception).name.underscore.gsub(%r{/},'_')
+ old_method_name = "#{method}_without_#{exception_supported}_support".to_sym
+ eval %Q{alias #{old_method_name} #{method}}
+ action_to_perform = if to_exception
+ %Q{
+ raise #{to_exception.name}, "\#{e.class.name.split('::').last.underscore.humanize}: \#{e.message}", e.backtrace
+ }
+ else
+ %Q{nil}
+ end
+ eval %Q{
+ def #{method}(*args, &block)
+ #{old_method_name}(*args, &block)
+ rescue #{from_exception.name} => e
+ #{action_to_perform}
+ end
+ }
+ end
alias :servers= :set_servers
@@ -17,15 +53,17 @@ def initialize(*args)
).flatten.compact
opts[:prefix_key] ||= opts[:namespace]
- super(servers, opts)
+ super(servers, DEFAULTS.merge(opts))
end
# Wraps Memcached#get so that it doesn't raise. This has the side-effect of preventing you from
# storing <tt>nil</tt> values.
def get(key, raw=false)
super(key, !raw)
- rescue NotFound
end
+ translate_exception :get, NotFound => nil
+ translate_exception :get, ATimeoutOccurred => Timeout::Error
+ translate_exception :get, Memcached::Error => MemCache::MemCacheError
# Wraps Memcached#cas so that it doesn't raise. Doesn't set anything if no value is present.
def cas(key, ttl=@default_ttl, raw=false, &block)
@@ -34,16 +72,24 @@ def cas(key, ttl=@default_ttl, raw=false, &block)
end
alias :compare_and_swap :cas
+ translate_exception :cas, NotFound => nil
+ translate_exception :cas, ATimeoutOccurred => Timeout::Error
+ translate_exception :cas, Memcached::Error => MemCache::MemCacheError
# Wraps Memcached#get.
def get_multi(keys, raw=false)
get_orig(keys, !raw)
end
+ translate_exception :get_multi, ATimeoutOccurred => Timeout::Error
+ translate_exception :get_multi, Memcached::Error => MemCache::MemCacheError
+
# Wraps Memcached#set.
def set(key, value, ttl=@default_ttl, raw=false)
super(key, value, ttl, !raw)
end
+ translate_exception :set, ATimeoutOccurred => Timeout::Error
+ translate_exception :set, Memcached::Error => MemCache::MemCacheError
# Wraps Memcached#add so that it doesn't raise.
def add(key, value, ttl=@default_ttl, raw=false)
@@ -53,6 +99,12 @@ def add(key, value, ttl=@default_ttl, raw=false)
false
end
+ translate_exception :add, ATimeoutOccurred => Timeout::Error
+ translate_exception :add, Memcached::Error => MemCache::MemCacheError
+
+ # Wraps Memcached#delete so that it doesn't raise.
+ translate_exception :delete, NotFound => nil
+
# Wraps Memcached#delete so that it doesn't raise.
def delete(key)
super
@@ -62,15 +114,21 @@ def delete(key)
# Wraps Memcached#incr so that it doesn't raise.
def incr(*args)
super
- rescue NotFound
end
+
+ translate_exception :incr, NotFound => nil
+ translate_exception :incr, ATimeoutOccurred => Timeout::Error
+ translate_exception :incr, Memcached::Error => MemCache::MemCacheError
# Wraps Memcached#decr so that it doesn't raise.
def decr(*args)
super
- rescue NotFound
end
+ translate_exception :decr, NotFound => nil
+ translate_exception :decr, ATimeoutOccurred => Timeout::Error
+ translate_exception :decr, Memcached::Error => MemCache::MemCacheError
+
# Wraps Memcached#append so that it doesn't raise.
def append(*args)
super
View
88 test/unit/rails_test.rb
@@ -1,6 +1,39 @@
+class String
+ def underscore
+ self.gsub(/::/, '/').
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ tr("-", "_").
+ downcase
+ end
+ def humanize
+ self.gsub(/_id$/, "").gsub(/_/, " ").capitalize
+ end
+end
+require "#{File.dirname(__FILE__)}/../../lib/memcached/rails"
require "#{File.dirname(__FILE__)}/../test_helper"
+module TimeOuts
+ def get_without_timeout_error_support(*args, &block); raise Memcached::ATimeoutOccurred.new("timeout occured"); end
+ def cas_without_timeout_error_support(*args, &block); raise Memcached::ATimeoutOccurred.new("timeout occured"); end
+ def get_multi_without_timeout_error_support(*args, &block); raise Memcached::ATimeoutOccurred.new("timeout occured"); end
+ def set_without_timeout_error_support(*args, &block); raise Memcached::ATimeoutOccurred.new("timeout occured"); end
+ def add_without_timeout_error_support(*args, &block); raise Memcached::ATimeoutOccurred.new("timeout occured"); end
+ def incr_without_timeout_error_support(*args, &block); raise Memcached::ATimeoutOccurred.new("timeout occured"); end
+ def decr_without_timeout_error_support(*args, &block); raise Memcached::ATimeoutOccurred.new("timeout occured"); end
+end
+
+module OtherErrors
+ def get_without_mem_cache_mem_cache_error_support(*args, &block); raise Memcached::Failure.new("WTF?!"); end
+ def cas_without_mem_cache_mem_cache_error_support(*args, &block); raise Memcached::Failure.new("WTF?!"); end
+ def get_multi_without_mem_cache_mem_cache_error_support(*args, &block); raise Memcached::Failure.new("WTF?!"); end
+ def set_without_mem_cache_mem_cache_error_support(*args, &block); raise Memcached::Failure.new("WTF?!"); end
+ def add_without_mem_cache_mem_cache_error_support(*args, &block); raise Memcached::Failure.new("WTF?!"); end
+ def incr_without_mem_cache_mem_cache_error_support(*args, &block); raise Memcached::Failure.new("WTF?!"); end
+ def decr_without_mem_cache_mem_cache_error_support(*args, &block); raise Memcached::Failure.new("WTF?!"); end
+end
+
class RailsTest < Test::Unit::TestCase
def setup
@@ -69,13 +102,66 @@ def test_cas
# Conflicting set
cache.set key, @value
- assert_raises(Memcached::ConnectionDataExists) do
+ begin
cache.cas(key) do |current|
cache.set key, value2
current
end
+ assert false, "An error was not raised"
+ rescue MemCache::MemCacheError => e
+ assert_equal "Connection data exists: Key {\"test_cas\"=>\"127.0.0.1:43043:8\"}", e.message
end
end
+
+ def test_timeout_errors
+ @cache.extend TimeOuts
+ assert_raises Timeout::Error do
+ @cache.cas(key){"asdf"}
+ end
+ assert_raises Timeout::Error do
+ @cache.set(key, "asdf")
+ end
+ assert_raises Timeout::Error do
+ @cache.add(key, "asdf")
+ end
+ assert_raises Timeout::Error do
+ @cache.get(key)
+ end
+ assert_raises Timeout::Error do
+ @cache.get_multi(key, "asdf", "bacon")
+ end
+ assert_raises Timeout::Error do
+ @cache.incr(key)
+ end
+ assert_raises Timeout::Error do
+ @cache.decr(key)
+ end
+ end
+
+ def test_other_errors
+ @cache.extend OtherErrors
+ assert_raises MemCache::MemCacheError do
+ @cache.cas(key){"asdf"}
+ end
+ assert_raises MemCache::MemCacheError do
+ @cache.set(key, "asdf")
+ end
+ assert_raises MemCache::MemCacheError do
+ @cache.add(key, "asdf")
+ end
+ assert_raises MemCache::MemCacheError do
+ @cache.get(key)
+ end
+ assert_raises MemCache::MemCacheError do
+ @cache.get_multi(key, "asdf", "bacon")
+ end
+ assert_raises MemCache::MemCacheError do
+ @cache.incr(key)
+ end
+ assert_raises MemCache::MemCacheError do
+ @cache.decr(key)
+ end
+ end
def test_get_missing
@cache.delete key rescue nil
Please sign in to comment.
Something went wrong with that request. Please try again.