execute_with_rescue 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6567bf06706ae0cc18b48601c95d7a8de4fdaf63
4
+ data.tar.gz: 70a5d62da3282a7851d3c07f5d12f88f29f66cb1
5
+ SHA512:
6
+ metadata.gz: a787b094e8f6c46239b5f067e59bc27375484720c2ddda02beda5082bf1de00622832c9cb59ad0aa1a88cb50e0ae9d0cb62b363f2ed7a6e77581130229968be4
7
+ data.tar.gz: 5446a8050f2c55fcc4a91bfddc6fe50b073f39be067a6d22adf447ead5826888fc08f78fab257cb4db9dc0fd4f1dec2566c5a3abf14fe29245bc92e16a7bd200
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ cache:
3
+ - bundler
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.0
8
+ - 2.1.1
9
+ gemfile:
10
+ - gemfiles/rails_3_2.gemfile
11
+ - gemfiles/rails_4_0.gemfile
12
+ - gemfiles/rails_4_1.gemfile
13
+
data/Appraisals ADDED
@@ -0,0 +1,11 @@
1
+ appraise "rails-3-2" do
2
+ gem "activesupport", "3.2.17"
3
+ end
4
+
5
+ appraise "rails-4-0" do
6
+ gem "activesupport", "4.0.4"
7
+ end
8
+
9
+ appraise "rails-4-1" do
10
+ gem "activesupport", "4.1.0.rc1"
11
+ end
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ### Changelog
2
+
3
+
4
+ - **0.0.1**
5
+ - Initail Release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in execute_with_rescue.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 PikachuEXE
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # ExecuteWithRescue
2
+
3
+ Saves your from writing `begin...rescue...ensure...end` everywhere.
4
+ This assumes you know how to use `rescue_from` not just within a controller.
5
+
6
+ I write this "gem" because I enocunter this pattern in many background worker and service classes.
7
+ (I use [`interactor`](https://github.com/collectiveidea/interactor) for service classes btw)
8
+ I use this gem, [`rescue_from`](http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html) and a custom [`airbrake`](https://github.com/airbrake/airbrake) adapter to add options to Airbrake when notifying, since otherwise you will have to call `Airbrake.notify_or_ignore` manually in `rescue` and pass the options.
9
+ Calling `airbrake` manually sometimes is the best option, but not all the time.
10
+ I might release another gem for that airbrake adapter.
11
+
12
+
13
+ ## Support
14
+ ===========
15
+ Tested against:
16
+ - Active Support of version `3.2`, `4.0` and `4.1` (pre-3.2 got wrong dependency & I don't want to support)
17
+ - MRI `1.9.3`, `2.0.0`, `2.1.0`, `2.1.1`
18
+
19
+ [![Build Status](http://img.shields.io/travis/PikachuEXE/execute_with_rescue.svg)](https://travis-ci.org/PikachuEXE/execute_with_rescue)
20
+ [![Gem Version](http://img.shields.io/gem/v/execute_with_rescue.svg)](http://badge.fury.io/rb/execute_with_rescue)
21
+ [![Dependency Status](http://img.shields.io/gemnasium/PikachuEXE/execute_with_rescue.svg)](https://gemnasium.com/PikachuEXE/execute_with_rescue)
22
+ [![Coverage Status](http://img.shields.io/coveralls/PikachuEXE/execute_with_rescue.svg)](https://coveralls.io/r/PikachuEXE/execute_with_rescue)
23
+ [![Code Climate](http://img.shields.io/codeclimate/github/PikachuEXE/execute_with_rescue.svg)](https://codeclimate.com/github/PikachuEXE/execute_with_rescue)
24
+
25
+
26
+ ## Installation
27
+
28
+ Add this line to your application's Gemfile:
29
+
30
+ ```ruby
31
+ gem 'execute_with_rescue'
32
+ ```
33
+
34
+ And then execute:
35
+
36
+ $ bundle
37
+
38
+ Or install it yourself as:
39
+
40
+ $ gem install execute_with_rescue
41
+
42
+ ## Usage
43
+
44
+ ### `#execute_with_rescue`
45
+ **Private** method to be called with a block
46
+ You still have to call `rescue_from` at class level yourself (no magic here)
47
+ ```ruby
48
+ class SomeServiceClass
49
+ include ExecuteWithRescue::Mixins::Core
50
+
51
+ # then run code with possible errors
52
+ def perform
53
+ execute_with_rescue do
54
+ # Something that might causes error
55
+ end
56
+ end
57
+ end
58
+ ```
59
+
60
+ ## Class Methods for adding hooks
61
+ "Hooks" are just things to be run before the block and after the block (in `ensure`)
62
+ Beware that the "hooks" execution order are like [`ActiveSupport::Callbacks`](http://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html)
63
+
64
+ ### `.add_execute_with_rescue_before_hooks`
65
+ Alias: `.add_execute_with_rescue_before_hook`
66
+ Execution order: Add first, run first
67
+ ```ruby
68
+ class SomeServiceClass
69
+ # Either add hooks by using method names in symbol
70
+ add_execute_with_rescue_before_hook :report_start_by_logging
71
+
72
+ # Or add more
73
+ add_execute_with_rescue_before_hooks :do_more, :do_even_more
74
+
75
+ # Or in block
76
+ add_execute_with_rescue_before_hook do
77
+ Rails.logger.debug("Some job started")
78
+ end
79
+
80
+ private
81
+
82
+ def report_start_by_logging
83
+ Rails.logger.debug("Some job started")
84
+ end
85
+
86
+ def do_more
87
+ # This execute earlier
88
+ end
89
+ def do_even_more
90
+ # This execute later
91
+ end
92
+ end
93
+ ```
94
+
95
+ ### `.add_execute_with_rescue_after_hooks`
96
+ Alias: `.add_execute_with_rescue_after_hook`
97
+ Execution order: Add first, run last
98
+ ```ruby
99
+ class SomeServiceClass
100
+ # Either add hooks by using method names in symbol
101
+ add_execute_with_rescue_after_hook :report_end_by_logging
102
+
103
+ # Or add more
104
+ add_execute_with_rescue_after_hooks :clean_up_base, :clean_up_more
105
+
106
+ # Or in block
107
+ add_execute_with_rescue_after_hook do
108
+ Rails.logger.debug("Some job ended")
109
+ end
110
+
111
+ private
112
+
113
+ def report_end_by_logging
114
+ Rails.logger.debug("Some job ended")
115
+ end
116
+
117
+ def clean_up_base
118
+ # This execute later
119
+ end
120
+ def clean_up_more
121
+ # This execute earlier
122
+ end
123
+ end
124
+ ```
125
+
126
+ ## Contributing
127
+
128
+ 1. Fork it
129
+ 2. Create your feature branch (`git checkout -b feature/my-new-feature`)
130
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
131
+ 4. Push to the branch (`git push origin feature/my-new-feature`)
132
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+ require "rubygems"
3
+ require "bundler/setup"
4
+
5
+ require "rspec/core/rake_task"
6
+ require "appraisal"
7
+
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
11
+ task :default do
12
+ sh "rake appraisal:install && rake appraisal spec"
13
+ end
14
+ else
15
+ task :default => :spec
16
+ end
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'execute_with_rescue/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "execute_with_rescue"
8
+ spec.version = ExecuteWithRescue::VERSION
9
+ spec.authors = ["PikachuEXE"]
10
+ spec.email = ["pikachuexe@gmail.com"]
11
+ spec.summary = %q{Execute code without writting rescue in methods with before and after hooks. You can also create some extensions yourself.}
12
+ spec.description = <<-DESC
13
+ Saves your from writing `begin...rescue...ensure...end` everywhere.
14
+ This assumes you know how to use `rescue_from` not just within a controller.
15
+ DESC
16
+ spec.homepage = "http://github.com/PikachuEXE/execute_with_rescue"
17
+ spec.license = "MIT"
18
+
19
+ spec.files = `git ls-files -z`.split("\x0")
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "activesupport", ">= 3.2.0", "< 5.0.0"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.5"
27
+ spec.add_development_dependency "rake"
28
+ spec.add_development_dependency "appraisal", ">= 0.5.2"
29
+ spec.add_development_dependency "rspec", "~> 2.14.0"
30
+ spec.add_development_dependency "coveralls", ">= 0.7"
31
+ spec.add_development_dependency "gem-release", ">= 0.7"
32
+
33
+ spec.required_ruby_version = ">= 1.9.3"
34
+
35
+ spec.required_rubygems_version = ">= 1.4.0"
36
+ end
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "3.2.17"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "4.0.4"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "4.1.0.rc1"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,6 @@
1
+ require 'execute_with_rescue/version'
2
+ require 'execute_with_rescue/errors'
3
+ require 'execute_with_rescue/mixins/core'
4
+
5
+ module ExecuteWithRescue
6
+ end
@@ -0,0 +1,6 @@
1
+ module ExecuteWithRescue
2
+ module Errors
3
+ NoHookMethod = Class.new(NoMethodError)
4
+ UnsupportedHookValue = Class.new(ArgumentError)
5
+ end
6
+ end
@@ -0,0 +1,172 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/rescuable'
3
+ require 'active_support/core_ext/class/attribute'
4
+
5
+ require 'execute_with_rescue/errors'
6
+
7
+ module ExecuteWithRescue
8
+ module Mixins
9
+ module Core
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ include ActiveSupport::Rescuable
14
+
15
+ # Use active support or inheritance will be broken
16
+ class_attribute :_execute_with_rescue_before_hooks,
17
+ instance_reader: true,
18
+ instance_writer: false
19
+ self._execute_with_rescue_before_hooks = []
20
+ class_attribute :_execute_with_rescue_after_hooks,
21
+ instance_reader: true,
22
+ instance_writer: false
23
+ self._execute_with_rescue_after_hooks = []
24
+
25
+ class << self
26
+ # Pass method names or/and a block to be executed before yield
27
+ #
28
+ # @param method_names [Array<Symbol>]
29
+ # instance methods names to be run before yield
30
+ # @param block [Proc]
31
+ # a block to be executed with no argument
32
+ # in the instance before yield
33
+ # It will be appended after method_names if both given
34
+ #
35
+ # @note These hooks are inherited
36
+ #
37
+ # @example Add a hook to begin some logging
38
+ # add_execute_with_rescue_before_hooks(:log_start)
39
+ #
40
+ # @raise [ArgumentError]
41
+ # if neither method_names and block is given
42
+ def add_execute_with_rescue_before_hooks(*method_names, &block)
43
+ _validate_execute_with_rescue_hook!(method_names, block)
44
+
45
+ # Must use setter to avoid changing parent setting
46
+ self._execute_with_rescue_before_hooks =
47
+ [
48
+ self._execute_with_rescue_before_hooks,
49
+ # Add method names first, block later
50
+ method_names,
51
+ block,
52
+ ].flatten.compact
53
+ end
54
+ alias_method :add_execute_with_rescue_before_hook,
55
+ :add_execute_with_rescue_before_hooks
56
+
57
+ # Pass method names or/and a block to be executed after yield
58
+ # Similar to add_execute_with_rescue_before_hooks
59
+ #
60
+ # @see add_execute_with_rescue_before_hooks
61
+ def add_execute_with_rescue_after_hooks(*method_names, &block)
62
+ _validate_execute_with_rescue_hook!(method_names, block)
63
+
64
+ # Must use setter to avoid changing parent setting
65
+ self._execute_with_rescue_after_hooks =
66
+ [
67
+ self._execute_with_rescue_after_hooks,
68
+ # Add method names first, block later
69
+ method_names,
70
+ block,
71
+ ].flatten.compact
72
+ end
73
+ alias_method :add_execute_with_rescue_after_hook,
74
+ :add_execute_with_rescue_after_hooks
75
+
76
+ # @private
77
+ # @discuss
78
+ # Should this moved into another module?
79
+ # (without being mixed in)
80
+ def _validate_execute_with_rescue_hook!(method_names, block)
81
+ raise ArgumentError if (method_names.empty? && block.nil?)
82
+ raise ExecuteWithRescue::Errors::UnsupportedHookValue unless
83
+ method_names.all?{|m| m.is_a?(Symbol)}
84
+ end
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ # Wrapper method for rescuing known errors
91
+ # after you have call `rescue_from` at class level
92
+ # This saves you from typing:
93
+ # ```
94
+ # being
95
+ # # Some code that might cause exception
96
+ # rescue
97
+ # rescue_with_handler(exception) || raise
98
+ # end
99
+ # ````
100
+ # Remember to `next` instead of `return` if you want to terminate
101
+ #
102
+ # You can use `alias_method` to create a shorter alias, I use `execute`
103
+ # But some gem might use that name already, so be careful
104
+ #
105
+ # @param block [Proc]
106
+ # a block to be executed
107
+ #
108
+ # @note
109
+ # Use `next` for termination, since `return` in block does not work
110
+ # @note
111
+ # Although we rescue Exception here,
112
+ # but normally we should NOT handle them without re-raise
113
+ #
114
+ # @example Use with gem `interactor`
115
+ # class DoSomething
116
+ # include Interactor
117
+ # include ExecuteWithRescue::Mixins::Core
118
+ #
119
+ # def perform
120
+ # execute_with_rescue do
121
+ # # Do something
122
+ # end
123
+ # end
124
+ # end
125
+ #
126
+ # @raise [LocalJumpError]
127
+ # When you call return in block
128
+ def execute_with_rescue
129
+ _run_execute_with_rescue_before_hooks
130
+ yield
131
+ rescue Exception => exception
132
+ rescue_with_handler(exception) || raise
133
+ ensure
134
+ _run_execute_with_rescue_after_hooks
135
+ end
136
+
137
+ # @private
138
+ def _run_execute_with_rescue_before_hooks
139
+ _execute_with_rescue_before_hooks.each do |before_hook|
140
+ _run_execute_with_rescue_hook(before_hook)
141
+ end
142
+ end
143
+
144
+ # @private
145
+ def _run_execute_with_rescue_after_hooks
146
+ _execute_with_rescue_after_hooks.reverse.each do |after_hook|
147
+ _run_execute_with_rescue_hook(after_hook)
148
+ end
149
+ end
150
+
151
+ # @private
152
+ def _run_execute_with_rescue_hook(method_name_or_block)
153
+ case method_name_or_block
154
+ when Symbol
155
+ begin
156
+ self.send(method_name_or_block)
157
+ rescue NoMethodError
158
+ raise ExecuteWithRescue::Errors::NoHookMethod,
159
+ "method `#{method_name_or_block}` does not exists"
160
+ end
161
+ # block are converted to Proc as argument
162
+ when Proc
163
+ instance_eval(&method_name_or_block)
164
+ else
165
+ # This should not happen unless someone tamper the class attribute
166
+ # without using the provided methods
167
+ raise ExecuteWithRescue::Errors::UnsupportedHookValue
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,3 @@
1
+ module ExecuteWithRescue
2
+ VERSION = "0.0.1"
3
+ end
data/spec/core_spec.rb ADDED
@@ -0,0 +1,215 @@
1
+ require 'spec_helper'
2
+
3
+ describe ExecuteWithRescue::Mixins::Core do
4
+ describe '#execute_with_rescue' do
5
+ let!(:service_instance) { service_class.new }
6
+ def service_call
7
+ service_instance.call
8
+ end
9
+
10
+ context 'without a block' do
11
+ let!(:service_class) { TestServiceWithoutBlockInExecute }
12
+
13
+ specify do
14
+ expect { service_call }
15
+ .to raise_error(LocalJumpError)
16
+ end
17
+ end
18
+
19
+ context 'with private method call' do
20
+ let!(:service_class) { TestServiceWithPrivateMethodCallInExecute }
21
+
22
+ specify do
23
+ expect { service_call }
24
+ .to_not raise_error
25
+ end
26
+ end
27
+
28
+ context 'without calling rescue_from' do
29
+ let!(:service_class) { TestServiceWithError }
30
+
31
+ specify do
32
+ expect { service_call }
33
+ .to raise_error(StandardError)
34
+ end
35
+ end
36
+
37
+ context 'with calling rescue_from' do
38
+ let!(:service_class) { TestServiceWithRescue }
39
+
40
+ specify do
41
+ expect { service_call }
42
+ .to raise_error(TestServiceWithRescue::CustomError)
43
+ end
44
+
45
+ context 'with single hook' do
46
+ context 'with nothing' do
47
+ describe 'in before hook' do
48
+ specify do
49
+ expect do
50
+ TestService.class_eval do
51
+ add_execute_with_rescue_before_hook
52
+ end
53
+ end.to raise_error(ArgumentError)
54
+ end
55
+ end
56
+ describe 'in after hook' do
57
+ specify do
58
+ expect do
59
+ TestService.class_eval do
60
+ add_execute_with_rescue_after_hook
61
+ end
62
+ end.to raise_error(ArgumentError)
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'with symbol of a non-existing method name' do
68
+ let!(:temp_class) do
69
+ Class.new(TestServiceWithPrivateMethodCallInExecute).tap do |klass|
70
+ klass.class_eval do
71
+ add_execute_with_rescue_after_hook(:non_existing_method)
72
+ end
73
+ end
74
+ end
75
+ let!(:service_class) { temp_class }
76
+
77
+ specify do
78
+ expect { service_call }
79
+ .to raise_error(ExecuteWithRescue::Errors::NoHookMethod)
80
+ end
81
+ end
82
+
83
+ context 'with symbol of an existing method name' do
84
+ context 'with before hook' do
85
+ let!(:service_class) { TestServiceWithSymbolBeforeHook }
86
+
87
+ specify do
88
+ expect { service_call }
89
+ .to change{ service_instance.hook_exec_count }.from(0).to(1)
90
+ end
91
+ end
92
+
93
+ context 'with after hook' do
94
+ let!(:service_class) { TestServiceWithSymbolAfterHook }
95
+
96
+ specify do
97
+ expect { service_call }
98
+ .to change{ service_instance.hook_exec_count }.from(0).to(1)
99
+ end
100
+ end
101
+
102
+ context 'with before & after hook' do
103
+ let!(:service_class) { TestServiceWithSymbolBeforeAfterHook }
104
+
105
+ specify do
106
+ expect { service_call }
107
+ .to change{ service_instance.hook_exec_count }.from(0).to(2)
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'with block' do
113
+ context 'with before hook' do
114
+ let!(:service_class) { TestServiceWithBlockBeforeHook }
115
+
116
+ specify do
117
+ expect { service_call }
118
+ .to change{ service_instance.hook_exec_count }.from(0).to(1)
119
+ end
120
+ end
121
+
122
+ context 'with after hook' do
123
+ let!(:service_class) { TestServiceWithBlockAfterHook }
124
+
125
+ specify do
126
+ expect { service_call }
127
+ .to change{ service_instance.hook_exec_count }.from(0).to(1)
128
+ end
129
+ end
130
+
131
+ context 'with before & after hook' do
132
+ let!(:service_class) { TestServiceWithBlockBeforeAfterHook }
133
+
134
+ specify do
135
+ expect { service_call }
136
+ .to change{ service_instance.hook_exec_count }.from(0).to(2)
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'with other type of things' do
142
+ let!(:temp_class){ Class.new(TestService) }
143
+
144
+ specify do
145
+ expect do
146
+ temp_class.add_execute_with_rescue_before_hook(1)
147
+ end.to raise_error(ExecuteWithRescue::Errors::UnsupportedHookValue)
148
+ end
149
+ end
150
+ end
151
+
152
+ context 'with multiple hooks' do
153
+ context 'without inheritance' do
154
+ let!(:service_class) { TestServiceWithManySymbolBeforeHook }
155
+
156
+ specify do
157
+ expect { service_call }
158
+ .to change{ service_instance.hook_exec_count }.from(0).to(3)
159
+ end
160
+ end
161
+ context 'with inheritance' do
162
+ let!(:service_class) { TestServiceWithManySymbolBeforeHookInherited }
163
+
164
+ specify do
165
+ expect { service_call }
166
+ .to change{ service_instance.hook_exec_count }.from(0).to(5)
167
+ end
168
+ end
169
+ end
170
+
171
+ context 'with tampered internal class attribuite' do
172
+ let!(:temp_class) do
173
+ Class.new(TestServiceWithPrivateMethodCallInExecute).tap do |klass|
174
+ klass.class_eval do
175
+ _execute_with_rescue_before_hooks << Hash.new
176
+ end
177
+ end
178
+ end
179
+ let!(:service_class) { temp_class }
180
+
181
+ specify 'after hooks run in reverse order of the define order' do
182
+ expect { service_call }
183
+ .to raise_error(ExecuteWithRescue::Errors::UnsupportedHookValue)
184
+ end
185
+ end
186
+
187
+
188
+
189
+ describe 'after hook execution' do
190
+ describe 'after an error is raised in block' do
191
+
192
+ let!(:service_class) { TestServiceWithErrorAndAfterHook }
193
+
194
+ specify 'after hooks are run after exception is raised' do
195
+ expect(service_instance.hook_exec_count).to eq(0)
196
+
197
+ expect { service_call }
198
+ .to raise_error(RuntimeError)
199
+
200
+ expect(service_instance.hook_exec_count).to eq(1)
201
+ end
202
+ end
203
+
204
+ describe 'order' do
205
+ let!(:service_class) { TestServiceWithManyAfterHooks }
206
+
207
+ specify 'after hooks run in reverse order of the define order' do
208
+ expect { service_call }
209
+ .to change{ service_instance.some_data_array }.from([]).to([2,1])
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,119 @@
1
+ class TestService
2
+ include ExecuteWithRescue::Mixins::Core
3
+
4
+ def call
5
+ # To be overidden
6
+ end
7
+ end
8
+ class TestServiceWithoutBlockInExecute < TestService
9
+ def call
10
+ execute_with_rescue
11
+ end
12
+ end
13
+ class TestServiceWithPrivateMethodCallInExecute < TestService
14
+ def call
15
+ execute_with_rescue do
16
+ do_something_privately
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def do_something_privately
23
+ # do nothing
24
+ end
25
+ end
26
+
27
+ class TestServiceWithError < TestService
28
+ include ExecuteWithRescue::Mixins::Core
29
+
30
+ def call
31
+ execute_with_rescue do
32
+ raise StandardError
33
+ end
34
+ end
35
+ end
36
+ class TestServiceWithRescue < TestServiceWithError
37
+ rescue_from StandardError, with: :handle_error
38
+
39
+ CustomError = Class.new(StandardError)
40
+
41
+ private
42
+
43
+ def handle_error
44
+ raise CustomError
45
+ end
46
+ end
47
+ class TestServiceWithHook < TestServiceWithRescue
48
+ def initialize
49
+ @hook_exec_count = 0
50
+ end
51
+
52
+ attr_reader :hook_exec_count
53
+
54
+ private
55
+
56
+ def handle_error
57
+ # do nothing
58
+ end
59
+ def inc_hook_exec_count
60
+ @hook_exec_count += 1
61
+ end
62
+ end
63
+ class TestServiceWithSymbolBeforeHook < TestServiceWithHook
64
+ add_execute_with_rescue_before_hook(:inc_hook_exec_count)
65
+ end
66
+ class TestServiceWithSymbolAfterHook < TestServiceWithHook
67
+ add_execute_with_rescue_after_hook(:inc_hook_exec_count)
68
+ end
69
+ class TestServiceWithSymbolBeforeAfterHook < TestServiceWithHook
70
+ add_execute_with_rescue_before_hook(:inc_hook_exec_count)
71
+ add_execute_with_rescue_after_hook(:inc_hook_exec_count)
72
+ end
73
+ class TestServiceWithBlockBeforeHook < TestServiceWithHook
74
+ add_execute_with_rescue_before_hook { inc_hook_exec_count }
75
+ end
76
+ class TestServiceWithBlockAfterHook < TestServiceWithHook
77
+ add_execute_with_rescue_after_hook { inc_hook_exec_count }
78
+ end
79
+ class TestServiceWithBlockBeforeAfterHook < TestServiceWithHook
80
+ add_execute_with_rescue_before_hook { inc_hook_exec_count }
81
+ add_execute_with_rescue_after_hook { inc_hook_exec_count }
82
+ end
83
+
84
+ class TestServiceWithManySymbolBeforeHook < TestServiceWithHook
85
+ add_execute_with_rescue_before_hooks(:inc_hook_exec_count,
86
+ :inc_hook_exec_count,
87
+ :inc_hook_exec_count)
88
+ end
89
+ class TestServiceWithManySymbolBeforeHookInherited <
90
+ TestServiceWithManySymbolBeforeHook
91
+ add_execute_with_rescue_before_hook(:inc_hook_exec_count)
92
+ add_execute_with_rescue_before_hook(:inc_hook_exec_count)
93
+ end
94
+
95
+ class TestServiceWithManyAfterHooks < TestServiceWithHook
96
+ add_execute_with_rescue_after_hooks do
97
+ push_some_data(1)
98
+ end
99
+ add_execute_with_rescue_after_hooks do
100
+ push_some_data(2)
101
+ end
102
+
103
+ def some_data_array
104
+ @some_data_array ||= []
105
+ end
106
+
107
+ private
108
+
109
+ def push_some_data(data)
110
+ some_data_array << data
111
+ end
112
+ end
113
+
114
+
115
+ class TestServiceWithErrorAndAfterHook < TestServiceWithBlockAfterHook
116
+ def handle_error
117
+ raise RuntimeError
118
+ end
119
+ end
@@ -0,0 +1,14 @@
1
+ if ENV["TRAVIS"]
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+ end
5
+
6
+ require 'execute_with_rescue'
7
+
8
+ require 'fixtures/test_service_classes'
9
+ require 'rspec'
10
+
11
+ require 'logger'
12
+
13
+ RSpec.configure do |config|
14
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: execute_with_rescue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - PikachuEXE
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: 5.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 5.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: '1.5'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '1.5'
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: appraisal
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '>='
66
+ - !ruby/object:Gem::Version
67
+ version: 0.5.2
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: 0.5.2
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ~>
80
+ - !ruby/object:Gem::Version
81
+ version: 2.14.0
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: 2.14.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: coveralls
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0.7'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0.7'
103
+ - !ruby/object:Gem::Dependency
104
+ name: gem-release
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0.7'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0.7'
117
+ description: |2
118
+ Saves your from writing `begin...rescue...ensure...end` everywhere.
119
+ This assumes you know how to use `rescue_from` not just within a controller.
120
+ email:
121
+ - pikachuexe@gmail.com
122
+ executables: []
123
+ extensions: []
124
+ extra_rdoc_files: []
125
+ files:
126
+ - .gitignore
127
+ - .rspec
128
+ - .travis.yml
129
+ - Appraisals
130
+ - CHANGELOG.md
131
+ - Gemfile
132
+ - LICENSE.txt
133
+ - README.md
134
+ - Rakefile
135
+ - execute_with_rescue.gemspec
136
+ - gemfiles/rails_3_2.gemfile
137
+ - gemfiles/rails_4_0.gemfile
138
+ - gemfiles/rails_4_1.gemfile
139
+ - lib/execute_with_rescue.rb
140
+ - lib/execute_with_rescue/errors.rb
141
+ - lib/execute_with_rescue/mixins/core.rb
142
+ - lib/execute_with_rescue/version.rb
143
+ - spec/core_spec.rb
144
+ - spec/fixtures/test_service_classes.rb
145
+ - spec/spec_helper.rb
146
+ homepage: http://github.com/PikachuEXE/execute_with_rescue
147
+ licenses:
148
+ - MIT
149
+ metadata: {}
150
+ post_install_message:
151
+ rdoc_options: []
152
+ require_paths:
153
+ - lib
154
+ required_ruby_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - '>='
157
+ - !ruby/object:Gem::Version
158
+ version: 1.9.3
159
+ required_rubygems_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - '>='
162
+ - !ruby/object:Gem::Version
163
+ version: 1.4.0
164
+ requirements: []
165
+ rubyforge_project:
166
+ rubygems_version: 2.2.2
167
+ signing_key:
168
+ specification_version: 4
169
+ summary: Execute code without writting rescue in methods with before and after hooks.
170
+ You can also create some extensions yourself.
171
+ test_files:
172
+ - spec/core_spec.rb
173
+ - spec/fixtures/test_service_classes.rb
174
+ - spec/spec_helper.rb
175
+ has_rdoc: