retrying_proxy 0.1.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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +54 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/retrying_proxy.rb +42 -0
- data/lib/retrying_proxy/active_support.rb +34 -0
- data/lib/retrying_proxy/base.rb +55 -0
- data/lib/retrying_proxy/proxy.rb +98 -0
- data/retrying_proxy.gemspec +60 -0
- data/test/helper.rb +53 -0
- data/test/test_base.rb +25 -0
- data/test/test_coverage.rb +21 -0
- data/test/test_proxy.rb +90 -0
- data/test/test_retrying_proxy.rb +31 -0
- metadata +87 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Christopher J. Bottaro
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= retrying_proxy
|
2
|
+
|
3
|
+
A simple gem to help you retry methods and deal with transient failures.
|
4
|
+
|
5
|
+
== Quickstart
|
6
|
+
|
7
|
+
Given a class that has methods that intermittently fail...
|
8
|
+
|
9
|
+
class Failer
|
10
|
+
|
11
|
+
def initialize(failure_rate = 0.5)
|
12
|
+
@failure_rate = failure_rate
|
13
|
+
end
|
14
|
+
|
15
|
+
def foo
|
16
|
+
if rand > @failure_rate
|
17
|
+
raise RuntimeError, "failure"
|
18
|
+
else
|
19
|
+
"foo"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
You can use retrying_proxy in a few ways to deal with it...
|
26
|
+
|
27
|
+
Create a retrying_proxy instance.
|
28
|
+
|
29
|
+
failer = Failer.new
|
30
|
+
proxy = RetryingProxy::Proxy.new(failer)
|
31
|
+
proxy.retry_method :foo
|
32
|
+
proxy.foo # Will retry once with no delay if an Exception is raised.
|
33
|
+
|
34
|
+
Create a retrying_proxy class.
|
35
|
+
|
36
|
+
class FailerProxy < RetryingProxy::Base
|
37
|
+
proxy_target{ |failure_rate| Failer.new(failure_rate) }
|
38
|
+
retry_method :foo, :exceptions => RuntimeError # :exceptions can be an array.
|
39
|
+
end
|
40
|
+
proxy = FailerProxy.new(0.33)
|
41
|
+
proxy.foo # Will retry once with no delay if a RuntimeError is raised.
|
42
|
+
|
43
|
+
Modify the class directly.
|
44
|
+
|
45
|
+
class Failer
|
46
|
+
include RetryingProxy
|
47
|
+
retry_method :foo, :times => 2, :delay => 0.25
|
48
|
+
end
|
49
|
+
failer = Failer.new(0.75)
|
50
|
+
failer.foo # Will retry up to 2 times with a delay of 0.25 seconds between retries on any Exception.
|
51
|
+
|
52
|
+
== Author
|
53
|
+
|
54
|
+
Christopher J. Bottaro - {cjbottaro}[http://github.com/cjbottaro]
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "retrying_proxy"
|
8
|
+
gem.summary = %Q{A simple gem to help you retry methods and deal with transient failures.}
|
9
|
+
gem.description = %Q{A simple gem to help you retry methods and deal with transient failures.}
|
10
|
+
gem.email = "cjbottaro@alumni.cs.utexas.edu"
|
11
|
+
gem.homepage = "http://github.com/cjbottaro/retrying_proxy"
|
12
|
+
gem.authors = ["Christopher J. Bottaro"]
|
13
|
+
#gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
Rake::TestTask.new(:test) do |test|
|
23
|
+
test.libs << 'lib' << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
begin
|
29
|
+
require 'rcov/rcovtask'
|
30
|
+
Rcov::RcovTask.new do |test|
|
31
|
+
test.libs << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
task :rcov do
|
37
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
task :test => :check_dependencies
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "retrying_proxy #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.2
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "retrying_proxy/active_support"
|
2
|
+
require "retrying_proxy/base"
|
3
|
+
require "retrying_proxy/proxy"
|
4
|
+
|
5
|
+
module RetryingProxy
|
6
|
+
|
7
|
+
VERSION = File.read(File.dirname(__FILE__)+"/../VERSION").freeze
|
8
|
+
|
9
|
+
def self.included(mod)
|
10
|
+
mod.send(:extend, ClassMethods)
|
11
|
+
mod.send(:include, InstanceMethods)
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def retrying_proxy
|
17
|
+
@retrying_proxy ||= Proxy.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def retry_methods(*args)
|
21
|
+
retrying_proxy.retry_methods(*args).each do |method_name|
|
22
|
+
alias_method_chain(method_name, :retrying_proxy) do |base_method_name, punc|
|
23
|
+
define_method("#{base_method_name}_with_retrying_proxy#{punc}") do |*args, &block|
|
24
|
+
retrying_proxy.call("#{base_method_name}_without_retrying_proxy#{punc}", args, :method_name => method_name, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :retry_method, :retry_methods
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
module InstanceMethods
|
35
|
+
|
36
|
+
def retrying_proxy
|
37
|
+
self.class.retrying_proxy.tap{ |proxy| proxy.target = self }
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Object #:nodoc:
|
2
|
+
|
3
|
+
def singleton_class
|
4
|
+
class << self
|
5
|
+
self
|
6
|
+
end
|
7
|
+
end unless method_defined?(:singleton_class)
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
class Module #:nodoc:
|
12
|
+
|
13
|
+
def alias_method_chain(target, feature)
|
14
|
+
# Strip out punctuation on predicates or bang methods since
|
15
|
+
# e.g. target?_without_feature is not a valid method name.
|
16
|
+
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
|
17
|
+
yield(aliased_target, punctuation) if block_given?
|
18
|
+
|
19
|
+
with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
|
20
|
+
|
21
|
+
alias_method without_method, target
|
22
|
+
alias_method target, with_method
|
23
|
+
|
24
|
+
case
|
25
|
+
when public_method_defined?(without_method)
|
26
|
+
public target
|
27
|
+
when protected_method_defined?(without_method)
|
28
|
+
protected target
|
29
|
+
when private_method_defined?(without_method)
|
30
|
+
private target
|
31
|
+
end
|
32
|
+
end unless method_defined?(:alias_method_chain)
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "retrying_proxy/proxy"
|
2
|
+
|
3
|
+
module RetryingProxy
|
4
|
+
class Base
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def proxy
|
9
|
+
@proxy ||= Proxy.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def proxy_target(&block)
|
13
|
+
if block_given?
|
14
|
+
@target = block
|
15
|
+
else
|
16
|
+
@target
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def retry_methods(*args)
|
21
|
+
proxy.retry_methods(*args).each do |method_name|
|
22
|
+
define_method(method_name) do |*args, &block|
|
23
|
+
call(method_name, *args, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
alias_method :retry_method, :retry_methods
|
29
|
+
|
30
|
+
def proxy_methods(*args)
|
31
|
+
retry_methods(*(args + [:times => 0])) # It has to be this way for Ruby 1.8
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :proxy_method, :proxy_methods
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(*args, &block)
|
39
|
+
proxy.target = self.class.proxy_target.call(*args, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def target
|
43
|
+
proxy.target
|
44
|
+
end
|
45
|
+
|
46
|
+
def proxy
|
47
|
+
self.class.proxy
|
48
|
+
end
|
49
|
+
|
50
|
+
def call(method_name, *args, &block)
|
51
|
+
proxy.send(method_name, *args, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module RetryingProxy
|
2
|
+
class Proxy
|
3
|
+
attr_accessor :target
|
4
|
+
attr_reader :settings
|
5
|
+
|
6
|
+
DEFAULTS = { :times => 1,
|
7
|
+
:exceptions => StandardError,
|
8
|
+
:delay => nil,
|
9
|
+
:predicate => nil }
|
10
|
+
|
11
|
+
def initialize(target = nil)
|
12
|
+
@target = target
|
13
|
+
@settings = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def retry_methods(*args)
|
17
|
+
# Handle options.
|
18
|
+
options = args.last.kind_of?(Hash) ? args.pop : {}
|
19
|
+
options = DEFAULTS.merge(options)
|
20
|
+
|
21
|
+
# Normalize some options.
|
22
|
+
options[:exceptions] = [options[:exceptions]].flatten
|
23
|
+
|
24
|
+
# Normalize the method names.
|
25
|
+
method_names = args.collect{ |arg| arg.to_sym }
|
26
|
+
|
27
|
+
# Store the settings
|
28
|
+
method_names.each{ |method_name| settings[method_name] = options }
|
29
|
+
|
30
|
+
method_names.each do |method_name|
|
31
|
+
singleton_class.class_eval do
|
32
|
+
define_method(method_name) do |*args, &block|
|
33
|
+
call(method_name, args, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
method_names
|
39
|
+
end
|
40
|
+
|
41
|
+
alias_method :retry_method, :retry_methods
|
42
|
+
|
43
|
+
# List of methods to pass through unaltered.
|
44
|
+
# proxy_methods :foo, :bar, :baz
|
45
|
+
def proxy_methods(*args)
|
46
|
+
retry_methods(*(args + [:times => 0])) # It has to be this way for Ruby 1.8
|
47
|
+
end
|
48
|
+
|
49
|
+
alias_method :proxy_method, :proxy_methods
|
50
|
+
|
51
|
+
# Direcly call a method on the target without any wrapping or anything.
|
52
|
+
def raw_call(method_name, *args, &block)
|
53
|
+
if target.respond_to?(method_name) or \
|
54
|
+
target.class.private_method_defined?(method_name) or \
|
55
|
+
target.class.protected_method_defined?(method_name)
|
56
|
+
target.send(method_name, *args, &block)
|
57
|
+
else
|
58
|
+
target.send(:method_missing, method_name, *args, &block)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Call a method on the target wrapped with the retry logic.
|
63
|
+
def call(method_name, args, options = {}, &block)
|
64
|
+
|
65
|
+
# This is tricky. In the case of including RetryingProxy, we have to do all that alias
|
66
|
+
# method chain stuff, so the method_name argument will have _without_retrying_proxy
|
67
|
+
# appended to it. options[:method_name] will provide the unmangled name in that case
|
68
|
+
# so we can look up the settings properly.
|
69
|
+
settings = self.settings[options[:method_name] || method_name]
|
70
|
+
|
71
|
+
# Don't increment our retries counter if we're in recursion or we'll do infinite retries.
|
72
|
+
@retries = 0 unless options[:in_recursion]
|
73
|
+
|
74
|
+
begin
|
75
|
+
value = raw_call(method_name, *args, &block)
|
76
|
+
rescue *settings[:exceptions] => e
|
77
|
+
should_retry?(settings) ? retry : raise
|
78
|
+
end
|
79
|
+
|
80
|
+
if settings[:predicate] and should_retry?(settings){ settings[:predicate].call(value) }
|
81
|
+
value = call(method_name, args, options.merge(:in_recursion => true), &block)
|
82
|
+
end
|
83
|
+
|
84
|
+
value
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns true if we should retry calling the method. +settings+ should be for the method
|
88
|
+
# being called. If a block an optional predicate to determine if we should retry.
|
89
|
+
def should_retry?(settings, &block)
|
90
|
+
return false unless @retries < settings[:times]
|
91
|
+
return false if block_given? and not block.call
|
92
|
+
sleep(settings[:delay]) if settings[:delay]
|
93
|
+
@retries += 1
|
94
|
+
true
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{retrying_proxy}
|
8
|
+
s.version = "0.1.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Christopher J. Bottaro"]
|
12
|
+
s.date = %q{2011-01-07}
|
13
|
+
s.description = %q{A simple gem to help you retry methods and deal with transient failures.}
|
14
|
+
s.email = %q{cjbottaro@alumni.cs.utexas.edu}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/retrying_proxy.rb",
|
27
|
+
"lib/retrying_proxy/active_support.rb",
|
28
|
+
"lib/retrying_proxy/base.rb",
|
29
|
+
"lib/retrying_proxy/proxy.rb",
|
30
|
+
"retrying_proxy.gemspec",
|
31
|
+
"test/helper.rb",
|
32
|
+
"test/test_base.rb",
|
33
|
+
"test/test_coverage.rb",
|
34
|
+
"test/test_proxy.rb",
|
35
|
+
"test/test_retrying_proxy.rb"
|
36
|
+
]
|
37
|
+
s.homepage = %q{http://github.com/cjbottaro/retrying_proxy}
|
38
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubygems_version = %q{1.3.7}
|
41
|
+
s.summary = %q{A simple gem to help you retry methods and deal with transient failures.}
|
42
|
+
s.test_files = [
|
43
|
+
"test/helper.rb",
|
44
|
+
"test/test_base.rb",
|
45
|
+
"test/test_coverage.rb",
|
46
|
+
"test/test_proxy.rb",
|
47
|
+
"test/test_retrying_proxy.rb"
|
48
|
+
]
|
49
|
+
|
50
|
+
if s.respond_to? :specification_version then
|
51
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
52
|
+
s.specification_version = 3
|
53
|
+
|
54
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
55
|
+
else
|
56
|
+
end
|
57
|
+
else
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
require 'retrying_proxy'
|
7
|
+
require "rr"
|
8
|
+
|
9
|
+
class Test::Unit::TestCase
|
10
|
+
include RR::Adapters::TestUnit
|
11
|
+
end
|
12
|
+
|
13
|
+
class Foo
|
14
|
+
|
15
|
+
module InstanceMethods
|
16
|
+
|
17
|
+
# Foo must be called +times+ times before not raising an exception.
|
18
|
+
def initialize(times = nil, exception = RuntimeError)
|
19
|
+
@times = times
|
20
|
+
@exception = exception
|
21
|
+
@count = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def foo
|
25
|
+
if @times.nil? or @count < @times
|
26
|
+
@count += 1
|
27
|
+
raise @exception, "oops"
|
28
|
+
end
|
29
|
+
@count = 0
|
30
|
+
"foo"
|
31
|
+
end
|
32
|
+
|
33
|
+
def bar
|
34
|
+
"bar"
|
35
|
+
end
|
36
|
+
|
37
|
+
def baz
|
38
|
+
"baz"
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(method_name, *args, &block)
|
42
|
+
if method_name == :fu
|
43
|
+
foo
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
include InstanceMethods
|
52
|
+
|
53
|
+
end
|
data/test/test_base.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestBase < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_retry
|
6
|
+
klass = Class.new(RetryingProxy::Base) do
|
7
|
+
proxy_target{ |times| Foo.new(times) }
|
8
|
+
retry_methods :foo, :times => 2
|
9
|
+
end
|
10
|
+
proxy = klass.new(2)
|
11
|
+
proxy(proxy.target).foo.times(3)
|
12
|
+
assert_equal "foo", proxy.foo
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_proxy
|
16
|
+
klass = Class.new(RetryingProxy::Base) do
|
17
|
+
proxy_target{ |times| Foo.new(times) }
|
18
|
+
proxy_method :foo
|
19
|
+
end
|
20
|
+
proxy = klass.new(1)
|
21
|
+
proxy(proxy.target).foo.times(1)
|
22
|
+
assert_raise(RuntimeError){ proxy.foo }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
# This is just to reach 100% coverage.
|
4
|
+
class TestCoverage < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_alias_method_chain
|
7
|
+
klass = Class.new do
|
8
|
+
def foo; end
|
9
|
+
def bar; end
|
10
|
+
def foo_with_nothing; end
|
11
|
+
def bar_with_nothing; end
|
12
|
+
protected :foo
|
13
|
+
private :bar
|
14
|
+
alias_method_chain :foo, :nothing
|
15
|
+
alias_method_chain :bar, :nothing
|
16
|
+
end
|
17
|
+
assert klass.protected_method_defined?(:foo)
|
18
|
+
assert klass.private_method_defined?(:bar)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/test/test_proxy.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestProxy < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_proxy
|
6
|
+
proxy = RetryingProxy::Proxy.new(Foo.new(1))
|
7
|
+
proxy.proxy_method :foo
|
8
|
+
proxy(proxy.target).foo.times(1)
|
9
|
+
assert_raise(RuntimeError){ proxy.foo }
|
10
|
+
proxy(proxy.target).foo.times(1)
|
11
|
+
assert_equal "foo", proxy.foo
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_retry
|
15
|
+
proxy = RetryingProxy::Proxy.new(Foo.new(1))
|
16
|
+
proxy.retry_method :foo
|
17
|
+
proxy(proxy.target).foo.times(2)
|
18
|
+
assert_equal "foo", proxy.foo
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_retry_with_times
|
22
|
+
proxy = RetryingProxy::Proxy.new(Foo.new(2))
|
23
|
+
proxy.retry_method :foo, :times => 2
|
24
|
+
proxy(proxy.target).foo.times(3)
|
25
|
+
assert_equal "foo", proxy.foo
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_retry_with_exceptions
|
29
|
+
proxy = RetryingProxy::Proxy.new(Foo.new(1, ArgumentError))
|
30
|
+
proxy.retry_method :foo, :exceptions => RuntimeError
|
31
|
+
proxy(proxy.target).foo.times(1)
|
32
|
+
assert_raise(ArgumentError){ proxy.foo }
|
33
|
+
|
34
|
+
proxy = RetryingProxy::Proxy.new(Foo.new(1, ArgumentError))
|
35
|
+
proxy.retry_method :foo, :exceptions => ArgumentError
|
36
|
+
proxy(proxy.target).foo.times(2)
|
37
|
+
assert_equal "foo", proxy.foo
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_retry_with_delay
|
41
|
+
proxy = RetryingProxy::Proxy.new(Foo.new(1))
|
42
|
+
proxy.retry_method :foo, :delay => 0.23
|
43
|
+
proxy(proxy.target).foo.times(2)
|
44
|
+
mock(proxy).sleep(0.23)
|
45
|
+
assert_equal "foo", proxy.foo
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_retry_with_predicate
|
49
|
+
proxy = RetryingProxy::Proxy.new(Foo.new)
|
50
|
+
proxy.retry_method :bar, :baz, :predicate => Proc.new{ |value| value =~ /r$/ }
|
51
|
+
proxy(proxy.target).bar.times(2)
|
52
|
+
assert_equal "bar", proxy.bar
|
53
|
+
proxy(proxy.target).baz.times(1)
|
54
|
+
assert_equal "baz", proxy.baz
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_retries_resets_between_method_calls
|
58
|
+
proxy = RetryingProxy::Proxy.new(Foo.new(1))
|
59
|
+
proxy.retry_method :bar, :predicate => Proc.new{ |value| value =~ /^b/ }
|
60
|
+
proxy(proxy.target).bar.times(2)
|
61
|
+
assert_equal "bar", proxy.bar
|
62
|
+
proxy(proxy.target).bar.times(2)
|
63
|
+
assert_equal "bar", proxy.bar
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_method_missing
|
67
|
+
proxy = RetryingProxy::Proxy.new(Foo.new(2))
|
68
|
+
proxy.retry_method :fu, :times => 2
|
69
|
+
proxy(proxy.target).fu.times(3)
|
70
|
+
assert_equal "foo", proxy.fu
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_private_and_protected_methods
|
74
|
+
klass = Class.new do
|
75
|
+
private
|
76
|
+
def foo; "foo"; end
|
77
|
+
protected
|
78
|
+
def bar; "bar"; end
|
79
|
+
end
|
80
|
+
object = klass.new
|
81
|
+
proxy = RetryingProxy::Proxy.new(object)
|
82
|
+
proxy.retry_method :foo
|
83
|
+
proxy(proxy.target).foo.times(1)
|
84
|
+
assert_equal "foo", proxy.foo
|
85
|
+
proxy.proxy_method :bar
|
86
|
+
proxy(proxy.target).bar.times(1)
|
87
|
+
assert_equal "bar", proxy.bar
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestRetryingProxy < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_retry
|
6
|
+
klass = Class.new do
|
7
|
+
include Foo::InstanceMethods
|
8
|
+
include RetryingProxy
|
9
|
+
retry_method :foo, :times => 2
|
10
|
+
end
|
11
|
+
object = klass.new(2)
|
12
|
+
proxy(object).foo_without_retrying_proxy.times(3)
|
13
|
+
assert_equal "foo", object.foo
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_punctuation
|
17
|
+
klass = Class.new do
|
18
|
+
include Foo::InstanceMethods
|
19
|
+
include RetryingProxy
|
20
|
+
alias_method :foo!, :foo
|
21
|
+
retry_method :foo!, :times => 3
|
22
|
+
end
|
23
|
+
assert klass.method_defined?(:foo!)
|
24
|
+
assert klass.method_defined?(:foo_with_retrying_proxy!)
|
25
|
+
assert klass.method_defined?(:foo_without_retrying_proxy!)
|
26
|
+
object = klass.new(3)
|
27
|
+
proxy(object).foo_without_retrying_proxy!.times(4)
|
28
|
+
assert_equal "foo", object.foo!
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: retrying_proxy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Christopher J. Bottaro
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-07 00:00:00 -06:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: A simple gem to help you retry methods and deal with transient failures.
|
23
|
+
email: cjbottaro@alumni.cs.utexas.edu
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- LICENSE
|
30
|
+
- README.rdoc
|
31
|
+
files:
|
32
|
+
- .document
|
33
|
+
- .gitignore
|
34
|
+
- LICENSE
|
35
|
+
- README.rdoc
|
36
|
+
- Rakefile
|
37
|
+
- VERSION
|
38
|
+
- lib/retrying_proxy.rb
|
39
|
+
- lib/retrying_proxy/active_support.rb
|
40
|
+
- lib/retrying_proxy/base.rb
|
41
|
+
- lib/retrying_proxy/proxy.rb
|
42
|
+
- retrying_proxy.gemspec
|
43
|
+
- test/helper.rb
|
44
|
+
- test/test_base.rb
|
45
|
+
- test/test_coverage.rb
|
46
|
+
- test/test_proxy.rb
|
47
|
+
- test/test_retrying_proxy.rb
|
48
|
+
has_rdoc: true
|
49
|
+
homepage: http://github.com/cjbottaro/retrying_proxy
|
50
|
+
licenses: []
|
51
|
+
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options:
|
54
|
+
- --charset=UTF-8
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 3
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.3.7
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: A simple gem to help you retry methods and deal with transient failures.
|
82
|
+
test_files:
|
83
|
+
- test/helper.rb
|
84
|
+
- test/test_base.rb
|
85
|
+
- test/test_coverage.rb
|
86
|
+
- test/test_proxy.rb
|
87
|
+
- test/test_retrying_proxy.rb
|