execute_with_rescue 0.0.1

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.
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: