absolver 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c76e2d96ca20824c08be83d405a482c3868f17f734d7bd8bde2c167b7da5595a
4
+ data.tar.gz: cddc7a5991121d3bcdfddfde761399211df4f4410860e3a9b6b04b45ae597d11
5
+ SHA512:
6
+ metadata.gz: 0d38a00d96c571ce019ace9a2a21145ed8c390d932f71aebfcaea9d191602542732515fafd9baed186cc72f74c8ba66ce23562db75b6b591f0346bd24cc2cdd9
7
+ data.tar.gz: b5e418beeb6af4ed83c1582cfcf2d3723b6761d8be8df0094a48111cc94fc4c408d20042c94cd5bcb3bdc81cc8016b6da32e7b266f60d5eec9367c65560487de
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,59 @@
1
+ absolver
2
+ ===
3
+
4
+ Absolver is a small little gem that allows setting the cause of a Ruby exception. Consider this example:
5
+
6
+ ```ruby
7
+ err = begin
8
+ begin
9
+ 1 / 0
10
+ rescue => e
11
+ raise RuntimeError, 'foo'
12
+ end
13
+ rescue => e
14
+ e
15
+ end
16
+ ```
17
+
18
+ Notice that I raised a `RuntimeError` _inside_ a `rescue` block. In Ruby 2.1 and later, doing so will set the inner exception's `#cause` attribute to the outer exception. In other words:
19
+
20
+ ```ruby
21
+ err # => #<RuntimeError: foo>
22
+ err.cause # => #<ZeroDivisionError: divided by 0>
23
+ ```
24
+
25
+ Cool, thanks Ruby!
26
+
27
+ What if I want to change the cause though? Maybe I don't really want to include the cause when reporting to an external error monitoring service, for example. Sadly, Ruby doesn't let you do that:
28
+
29
+ ```ruby
30
+ err.cause = nil
31
+ # NoMethodError (undefined method `cause=' for #<RuntimeError: foo>)
32
+ ```
33
+
34
+ What's a programmer to do? Use absolver!
35
+
36
+ ```ruby
37
+ require 'absolver'
38
+
39
+ Absolver.set_cause(err, nil)
40
+
41
+ err.cause # => nil
42
+ ```
43
+
44
+ Absolver uses [Fiddle](https://ruby-doc.org/stdlib-2.5.0/libdoc/fiddle/rdoc/Fiddle.html) to safely set the `cause` attribute of the `Exception` object. Basically it reaches down into Ruby's internals to adjust the value of the `cause` instance variable, which normally isn't exposed to your program.
45
+
46
+ Absolver also includes a small monkeypatch that adds `cause=` to `Exception`. Because many people dislike monkeypatches, you have to opt-in:
47
+
48
+ ```ruby
49
+ require 'absolver/exception'
50
+ err.cause = nil
51
+ ```
52
+
53
+ ## License
54
+
55
+ Licensed under the MIT license. See LICENSE for details.
56
+
57
+ ## Authors
58
+
59
+ * Cameron C. Dutro: http://github.com/camertron
@@ -0,0 +1,15 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+
3
+ require 'bundler'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubygems/package_task'
6
+ require 'absolver'
7
+
8
+ Bundler::GemHelper.install_tasks
9
+
10
+ task default: :spec
11
+
12
+ desc 'Run specs'
13
+ RSpec::Core::RakeTask.new do |t|
14
+ t.pattern = './spec/**/*_spec.rb'
15
+ end
@@ -0,0 +1,21 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+ require 'absolver/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'absolver'
6
+ s.version = ::Absolver::VERSION
7
+ s.authors = ['Cameron Dutro']
8
+ s.email = ['camertron@gmail.com']
9
+ s.homepage = 'http://github.com/camertron/absolver'
10
+
11
+ s.description = s.summary = 'Allows setting the cause of Ruby exceptions.'
12
+
13
+ s.platform = Gem::Platform::RUBY
14
+ s.has_rdoc = true
15
+
16
+ s.add_development_dependency 'rake'
17
+ s.add_development_dependency 'rspec'
18
+
19
+ s.require_path = 'lib'
20
+ s.files = Dir['{lib,spec}/**/*', 'Gemfile', 'README.md', 'Rakefile', 'absolver.gemspec']
21
+ end
@@ -0,0 +1,38 @@
1
+ require 'fiddle'
2
+
3
+ module Absolver
4
+ class << self
5
+ def set_cause(exc, new_cause)
6
+ rb_ivar_set(exc, 'cause', new_cause)
7
+ end
8
+
9
+ private
10
+
11
+ def rb_ivar_set(mod, str, new_val)
12
+ id = rb_intern_str(str)
13
+ m = Fiddle.dlwrap(mod)
14
+ nv = Fiddle.dlwrap(new_val)
15
+ Fiddle.dlunwrap(rb_ivar_set_func.call(m, id, nv))
16
+ end
17
+
18
+ def rb_ivar_set_func
19
+ @rb_ivar_set_func ||= Fiddle::Function.new(
20
+ Fiddle::Handle::DEFAULT['rb_ivar_set'],
21
+ [Fiddle::TYPE_VOIDP] * 3, # arguments
22
+ Fiddle::TYPE_VOIDP # return type
23
+ )
24
+ end
25
+
26
+ def rb_intern_str(str)
27
+ rb_intern_str_func.call(Fiddle.dlwrap(str))
28
+ end
29
+
30
+ def rb_intern_str_func
31
+ @rb_intern_str_func ||= Fiddle::Function.new(
32
+ Fiddle::Handle::DEFAULT['rb_intern_str'],
33
+ [Fiddle::TYPE_VOIDP], # arguments
34
+ Fiddle::TYPE_VOIDP # return type
35
+ )
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ require 'absolver'
2
+
3
+ class Exception
4
+ def cause=(new_cause)
5
+ Absolver.set_cause(self, new_cause)
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Absolver
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Absolver do
4
+ describe '.set_cause' do
5
+ let(:exc) { begin; 1 / 0; rescue => e; e; end }
6
+ let(:cause) { RuntimeError.new('foobar') }
7
+
8
+ it 'sets the cause on an exception' do
9
+ expect { Absolver.set_cause(exc, cause) }.to(
10
+ change { exc.cause }.from(nil).to(cause)
11
+ )
12
+ end
13
+
14
+ it 'allows the cause to be set to nil' do
15
+ Absolver.set_cause(exc, cause)
16
+
17
+ expect { Absolver.set_cause(exc, nil) }.to(
18
+ change { exc.cause }.from(cause).to(nil)
19
+ )
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Exception do
4
+ describe '#cause=' do
5
+ let(:exc) { begin; 1 / 0; rescue => e; e; end }
6
+ let(:cause) { RuntimeError.new('foobar') }
7
+
8
+ it 'allows the cause to be set' do
9
+ expect { exc.cause = cause }.to(
10
+ change { exc.cause }.from(nil).to(cause)
11
+ )
12
+ end
13
+
14
+ it 'allows the cause to be set to nil' do
15
+ exc.cause = cause
16
+
17
+ expect { exc.cause = nil }.to(
18
+ change { exc.cause }.from(cause).to(nil)
19
+ )
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,8 @@
1
+ $:.push(__dir__)
2
+
3
+ require 'rspec'
4
+ require 'absolver'
5
+ require 'absolver/exception'
6
+
7
+ RSpec.configure do |config|
8
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: absolver
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Cameron Dutro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-02-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Allows setting the cause of Ruby exceptions.
42
+ email:
43
+ - camertron@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - Gemfile
49
+ - README.md
50
+ - Rakefile
51
+ - absolver.gemspec
52
+ - lib/absolver.rb
53
+ - lib/absolver/exception.rb
54
+ - lib/absolver/version.rb
55
+ - spec/absolver_spec.rb
56
+ - spec/exception_spec.rb
57
+ - spec/spec_helper.rb
58
+ homepage: http://github.com/camertron/absolver
59
+ licenses: []
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.7.6
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Allows setting the cause of Ruby exceptions.
81
+ test_files: []