rescue_each 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.gemspec
2
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jason Weathered
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.markdown ADDED
@@ -0,0 +1,44 @@
1
+ # `rescue_each`
2
+ ## Rescue multiple exceptions when working with Enumerable objects.
3
+
4
+ Say you have a batch rake task which runs from cron which consists of many independent tasks ran in a loop.
5
+ These tasks could be anything from updating cached database entries to file conversions.
6
+
7
+ Once of these tasks fails, perhaps there's a corrupt image. Normally this would mean the entire batch task fails. But with rescue_each the other items can be processed and any errors will be re-raised at the end to be caught by your cron script.
8
+
9
+ ### Usage
10
+
11
+ #### Basics
12
+
13
+ Simply replace your `each` and `each_with_index` calls with `rescue_each` and `rescue_each_with_index` respectively:
14
+
15
+ BatchTasks.all.each &:process!
16
+
17
+ transforms into:
18
+
19
+ BatchTasks.all.rescue_each &:process!
20
+
21
+ #### Verbosity
22
+
23
+ `rescue_each` also supports a option to output error summary info to `stderr` during the loop:
24
+
25
+ (1..5).rescue_each :stderr => true do |i|
26
+ sleep 1
27
+ raise 'example'
28
+ end
29
+
30
+ You'll probably find this handy if your batch task normally has its own status output.
31
+
32
+ ### Note on Patches/Pull Requests
33
+
34
+ * Fork the project.
35
+ * Make your feature addition or bug fix.
36
+ * Add tests for it. This is important so I don't break it in a
37
+ future version unintentionally.
38
+ * Commit, do not mess with rakefile, version, or history.
39
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
40
+ * Send me a pull request. Bonus points for topic branches.
41
+
42
+ ### Copyright
43
+
44
+ Copyright (c) 2010 Jason Weathered. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the rescue_each plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ task :test => :check_dependencies
17
+
18
+ begin
19
+ require 'jeweler'
20
+ Jeweler::Tasks.new do |gem|
21
+ gem.name = "rescue_each"
22
+ gem.summary = "Rescue multiple exceptions when working with Enumerable objects"
23
+ gem.email = "jason@jasoncodes.com"
24
+ gem.homepage = "http://github.com/jasoncodes/rescue_each"
25
+ gem.authors = ["Jason Weathered"]
26
+ gem.has_rdoc = false
27
+ gem.add_dependency 'activesupport'
28
+ end
29
+ Jeweler::GemcutterTasks.new
30
+ rescue LoadError
31
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
32
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,93 @@
1
+ require 'active_support'
2
+
3
+ module RescueEach
4
+ class Error < StandardError
5
+
6
+ attr_reader :errors
7
+
8
+ def initialize(errors)
9
+ @errors = errors
10
+ end
11
+
12
+ class Item < Struct.new :exception, :args
13
+
14
+ def title
15
+ "#{exception.message} (#{exception.class})"
16
+ end
17
+ def args_short
18
+ args_str = args.map do |arg|
19
+ lines = arg.inspect.lines.collect
20
+ if lines.size == 1
21
+ lines.first
22
+ else
23
+ lines.first + " [#{lines.size-1} more...]"
24
+ end
25
+ end
26
+ "args: " + args_str.join(", ")
27
+ end
28
+ def args_full
29
+ "args: #{args.inspect}"
30
+ end
31
+ def backtrace_s
32
+ "\t#{exception.backtrace.join "\n\t"}"
33
+ end
34
+
35
+ def short_message
36
+ "#{title} (#{args_short})"
37
+ end
38
+
39
+ def message
40
+ "#{title}\n#{args_full}\n#{backtrace_s}"
41
+ end
42
+
43
+ def to_s
44
+ "\n#{message}"
45
+ end
46
+
47
+ end
48
+
49
+ def to_s
50
+ msg = []
51
+ errors.each_with_index do |error, idx|
52
+ msg << "rescue_each catch ##{idx+1}: "
53
+ msg << error.to_s
54
+ msg << "\n"
55
+ end
56
+ msg << "rescue_each caught #{errors.size} errors"
57
+ msg.join
58
+ end
59
+
60
+ end
61
+ end
62
+
63
+ module Enumerable
64
+
65
+ def rescue_each(options = {})
66
+
67
+ options.assert_valid_keys :stderr, :method
68
+ options.reverse_merge! :method => :each
69
+
70
+ errors = []
71
+ send options[:method] do |*args|
72
+ begin
73
+ yield *args
74
+ rescue Exception => e
75
+ item = RescueEach::Error::Item.new e, args
76
+ if options[:stderr] == :full
77
+ $stderr.puts "rescue_each error: #{item}" if options[:stderr]
78
+ elsif options[:stderr]
79
+ $stderr.puts "rescue_each error: #{item.short_message}"
80
+ end
81
+ errors << item
82
+ end
83
+ end
84
+ raise RescueEach::Error, errors unless errors.empty?
85
+ self
86
+ end
87
+
88
+ def rescue_each_with_index(options = {}, &block)
89
+ options = options.reverse_merge :method => :each_with_index
90
+ rescue_each(options, &block)
91
+ end
92
+
93
+ end
@@ -0,0 +1,100 @@
1
+ require 'test_helper'
2
+
3
+ class RescueEachTest < ActiveSupport::TestCase
4
+
5
+ test "return value" do
6
+ enum = (1..5)
7
+ assert_equal enum, enum.each(&:nil?)
8
+ end
9
+
10
+ test "calls block" do
11
+ output = []
12
+ (1..5).rescue_each do |x|
13
+ output << x
14
+ end
15
+ assert_equal (1..5).collect, output
16
+ end
17
+
18
+ test "continues after an error" do
19
+ output = []
20
+ assert_raise RescueEach::Error do
21
+ (1..5).rescue_each do |x|
22
+ output << x
23
+ raise 'test' if x == 3
24
+ end
25
+ end
26
+ assert_equal (1..5).collect, output
27
+ end
28
+
29
+ test "empty array doesn't call block" do
30
+ [].rescue_each do
31
+ raise 'test'
32
+ end
33
+ end
34
+
35
+ test "empty block doesn't raise" do
36
+ [42].rescue_each do
37
+ end
38
+ end
39
+
40
+ test "no param block can raise" do
41
+ assert_raise RescueEach::Error do
42
+ [42].rescue_each do
43
+ raise 'test'
44
+ end
45
+ end
46
+ end
47
+
48
+ test "each_with_index args pass through correctly" do
49
+ output = []
50
+ [:foo, :bar].rescue_each_with_index do |obj,i|
51
+ output << [obj,i]
52
+ end
53
+ expected = [[:foo, 0], [:bar, 1]]
54
+ assert_equal expected, output
55
+ end
56
+
57
+ test "error object contains args that triggered error" do
58
+ error_object = nil
59
+ begin
60
+ (1..10).rescue_each do |i|
61
+ raise 'foo' if (i%2) == 0
62
+ end
63
+ rescue RescueEach::Error => e
64
+ error_object = e
65
+ end
66
+ assert_equal [[2],[4],[6],[8],[10]], error_object.errors.map(&:args)
67
+ end
68
+
69
+ def foo_abc
70
+ bar_def
71
+ end
72
+
73
+ def bar_def
74
+ raise 'baz'
75
+ end
76
+
77
+ test "captured error message and backtrace" do
78
+
79
+ error_object = nil
80
+ begin
81
+ [42].rescue_each do |i|
82
+ foo_abc
83
+ end
84
+ rescue RescueEach::Error => e
85
+ error_object = e
86
+ end
87
+
88
+ assert_equal 1, error_object.errors.size
89
+ the_exception = error_object.errors.first.exception
90
+
91
+ assert_kind_of RuntimeError, the_exception
92
+ assert_equal 'baz', the_exception.message
93
+
94
+ assert_true the_exception.backtrace.size > 2
95
+ assert_match /:in `bar_def'\Z/, the_exception.backtrace[0]
96
+ assert_match /:in `foo_abc'\Z/, the_exception.backtrace[1]
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ gem 'test-unit'
3
+ require 'test/unit'
4
+ require 'active_support'
5
+ require 'active_support/test_case'
6
+ require 'rescue_each'
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rescue_each
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jason Weathered
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-15 00:00:00 +10:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email: jason@jasoncodes.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.markdown
34
+ files:
35
+ - .gitignore
36
+ - LICENSE
37
+ - README.markdown
38
+ - Rakefile
39
+ - VERSION
40
+ - lib/rescue_each.rb
41
+ - test/rescue_each_test.rb
42
+ - test/test_helper.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/jasoncodes/rescue_each
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.5
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Rescue multiple exceptions when working with Enumerable objects
71
+ test_files:
72
+ - test/rescue_each_test.rb
73
+ - test/test_helper.rb