xqsr3 0.17.2 → 0.18.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 18672bcef5bd6994d1ff9c2dc5be6289ca79042e
4
- data.tar.gz: cc79b90f538dbdc1273853d73d4b13cea0fab110
3
+ metadata.gz: fdaa43c901071d88f6fe3737998e4cd6a741c69b
4
+ data.tar.gz: c6876d3f0814a79a4c9a37bcb313c834ebae4096
5
5
  SHA512:
6
- metadata.gz: 16ae7d901c5ef0a916497c34fb9edfb342c0f774071a1b6f3de6a922c452d1de639caee0e587c18e566a7164b4b5303dff2ab09acb03624dc4edcb1df954cde4
7
- data.tar.gz: d77073d7e4fdcc461c75b5ab6d2e522573f113647b72cf7db16e3e7c8c209403cb37d5bbac96fda35cf697594f84b0ae88864e06a975785f7cbd6838de5352a6
6
+ metadata.gz: 308f153ed24f39fa50494df2099e8978b5aa55c99b5b016a48ab03e73f9cff058f00d8056364a87695fe16497a0c1b3d70225c9146b4fb1e23bd4fd2cef250ca
7
+ data.tar.gz: 7590f907009d95b6057aec1573d7841c39ea2bbd8ff0713fa29356ae3d3836e39121c587285144db6d6f8e05019744caf493c6ead4682d1e648354b2e66c4c46
@@ -0,0 +1,194 @@
1
+
2
+ # ######################################################################## #
3
+ # File: lib/xqsr3/diagnostics/exceptions/with_cause.rb
4
+ #
5
+ # Purpose: Definition of the WithCause inclusion module
6
+ #
7
+ # Created: 16th December 2017
8
+ # Updated: 17th December 2017
9
+ #
10
+ # Home: http://github.com/synesissoftware/xqsr3
11
+ #
12
+ # Author: Matthew Wilson
13
+ #
14
+ # Copyright (c) 2017, Matthew Wilson and Synesis Software
15
+ # All rights reserved.
16
+ #
17
+ # Redistribution and use in source and binary forms, with or without
18
+ # modification, are permitted provided that the following conditions are
19
+ # met:
20
+ #
21
+ # * Redistributions of source code must retain the above copyright notice,
22
+ # this list of conditions and the following disclaimer.
23
+ #
24
+ # * Redistributions in binary form must reproduce the above copyright
25
+ # notice, this list of conditions and the following disclaimer in the
26
+ # documentation and/or other materials provided with the distribution.
27
+ #
28
+ # * Neither the names of the copyright holder nor the names of its
29
+ # contributors may be used to endorse or promote products derived from
30
+ # this software without specific prior written permission.
31
+ #
32
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
33
+ # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
34
+ # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
35
+ # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
36
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
37
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
38
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
39
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
40
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
41
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
+ #
44
+ # ######################################################################## #
45
+
46
+
47
+ # ##########################################################
48
+ # ::Xqsr3::Diagnostics::Exceptions::WithCause
49
+
50
+ =begin
51
+ =end
52
+
53
+ module Xqsr3
54
+ module Diagnostics
55
+ module Exceptions
56
+
57
+ # This inclusion module adds to an exception class the means to chain a
58
+ # cause (aka inner-exception), which is then exposed with the +cause+
59
+ # attribute
60
+ #
61
+ # *Examples:*
62
+ #
63
+ # Passing an exception cause as a parameter
64
+ #
65
+ #
66
+ #
67
+ module WithCause
68
+
69
+ # Defines an initializer for an exception class that allows a cause (aka
70
+ # an inner exception) to be specified, either as the first or last
71
+ # argument or as a +:cause+ option
72
+ #
73
+ # === Signature
74
+ #
75
+ # * *Parameters:*
76
+ # -
77
+ # - +option+::
78
+ #
79
+ # * *Options:*
80
+ # - +:cause+ - The exception to be used as a cause, and ensures that
81
+ # that is not inferred from the arguments. May be +nil+ to ensure
82
+ # that no cause is inferred
83
+ def initialize(*args, **options)
84
+
85
+ @uses_cause_message = false
86
+
87
+ cz = options[:cause]
88
+
89
+ if cz
90
+
91
+ options = options.reject { |k, v| k == :cause }
92
+
93
+ @has_implicit_message = args.empty?
94
+
95
+ super *args
96
+
97
+ warn 'unexpected implicit message' if @has_implicit_message && self.message != self.class.to_s
98
+
99
+ @cause = cz
100
+ else
101
+
102
+ cz_ix = args.index { |arg| ::Exception === arg }
103
+
104
+ if cz_ix
105
+
106
+ args = args.dup
107
+
108
+ cz = args.delete_at cz_ix
109
+
110
+ if args.empty?
111
+
112
+ if !(cz.message || '').empty? && cz.class.to_s != cz.message
113
+
114
+ @uses_cause_message = true
115
+
116
+ args = [ cz.message ]
117
+ end
118
+ end
119
+ else
120
+
121
+ cz = $!
122
+ end
123
+
124
+ @has_implicit_message = args.empty?
125
+
126
+ super *args
127
+
128
+ warn 'unexpected implicit message' if @has_implicit_message && self.message != self.class.to_s
129
+
130
+ @cause = cz
131
+ end
132
+
133
+ @options = options
134
+ end
135
+
136
+ # The cause / inner-exception, if any, specified to the instance
137
+ # initialiser
138
+ attr_reader :cause
139
+
140
+ # The options passed to the initialiser, with +:cause+ removed, if
141
+ # present
142
+ attr_reader :options
143
+
144
+ def chained_message **options
145
+
146
+ return message unless cause
147
+ return message if @uses_cause_message
148
+
149
+ m = message
150
+ c = cause
151
+ cm = c.respond_to?(:chained_message) ? c.chained_message(**options) : c.message
152
+
153
+ return m if (cm || '').empty?
154
+ return cm if (m || '').empty?
155
+
156
+ sep = options[:separator] || ': '
157
+
158
+ "#{m}#{sep}#{cm}"
159
+ end
160
+
161
+ # An array of exceptions in the chain, excluding +self+
162
+ def chainees
163
+
164
+ return [] unless cause
165
+
166
+ r = [ cause ]
167
+
168
+ r += cause.chainees if cause.respond_to? :chainees
169
+
170
+ r
171
+ end
172
+
173
+ # An array of exceptions in the chain, including +self+
174
+ def exceptions
175
+
176
+ [ self ] + chainees
177
+ end
178
+
179
+ # A combination of the backtrace(s) of all chained exception(s)
180
+ def chained_backtrace
181
+
182
+ b = backtrace
183
+
184
+ return b unless cause
185
+
186
+ cb = cause.respond_to?(:chained_backtrace) ? cause.chained_backtrace : cause.backtrace
187
+
188
+ (cb - b) + b
189
+ end
190
+ end
191
+
192
+ end # module Exceptions
193
+ end # module Diagnostics
194
+ end # module Xqsr3
data/lib/xqsr3/version.rb CHANGED
@@ -50,7 +50,7 @@
50
50
  module Xqsr3
51
51
 
52
52
  # Current version of the Xqsr3 library
53
- VERSION = '0.17.2'
53
+ VERSION = '0.18.1'
54
54
 
55
55
  private
56
56
  VERSION_PARTS_ = VERSION.split(/[.]/).collect { |n| n.to_i } # :nodoc:
@@ -0,0 +1,262 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '../../../../lib')
4
+
5
+ require 'xqsr3/diagnostics/exceptions/with_cause'
6
+
7
+ require 'test/unit'
8
+
9
+ class Test_WithCause < Test::Unit::TestCase
10
+
11
+ class SomeExceptionWithCause < ::Exception
12
+
13
+ include ::Xqsr3::Diagnostics::Exceptions::WithCause
14
+ end
15
+
16
+ def test_no_ctor_args
17
+
18
+ x = SomeExceptionWithCause.new
19
+
20
+ assert_nil x.cause
21
+ assert_equal SomeExceptionWithCause.to_s, x.message
22
+ assert_equal SomeExceptionWithCause.to_s, x.chained_message
23
+ assert_empty x.chainees
24
+ assert_equal [ x ], x.exceptions
25
+ assert_nil x.backtrace
26
+ assert_empty x.options
27
+ end
28
+
29
+ def test_1_ctor_arg_that_is_a_message
30
+
31
+ msg = 'stuff'
32
+
33
+ x = SomeExceptionWithCause.new msg
34
+
35
+ assert_nil x.cause
36
+ assert_equal msg, x.message
37
+ assert_equal msg, x.chained_message
38
+ assert_empty x.chainees
39
+ assert_equal [ x ], x.exceptions
40
+ assert_nil x.backtrace
41
+ assert_empty x.options
42
+ end
43
+
44
+ def test_1_ctor_arg_that_is_a_cause_and_has_no_message
45
+
46
+ c = RuntimeError.new
47
+
48
+ x = SomeExceptionWithCause.new c
49
+
50
+ assert_not_nil x.cause
51
+ assert_equal SomeExceptionWithCause.to_s, x.message
52
+ assert_equal "#{SomeExceptionWithCause.to_s}: #{RuntimeError.to_s}", x.chained_message
53
+ assert_not_empty x.chainees
54
+ assert_equal [ c ], x.chainees
55
+ assert_equal [ x, c ], x.exceptions
56
+ assert_nil x.backtrace
57
+ assert_empty x.options
58
+ end
59
+
60
+ def test_1_ctor_arg_that_is_a_cause_and_has_a_message
61
+
62
+ c = RuntimeError.new 'blah'
63
+
64
+ x = SomeExceptionWithCause.new c
65
+
66
+ assert_not_nil x.cause
67
+ assert_equal 'blah', x.message
68
+ assert_equal 'blah', x.chained_message
69
+ assert_not_empty x.chainees
70
+ assert_equal [ c ], x.chainees
71
+ assert_equal [ x, c ], x.exceptions
72
+ assert_nil x.backtrace
73
+ assert_empty x.options
74
+ end
75
+
76
+ def test_2_ctor_args_that_are_message_and_cause
77
+
78
+ msg = 'stuff'
79
+
80
+ c = RuntimeError.new
81
+
82
+ x = SomeExceptionWithCause.new msg, c
83
+
84
+ assert_not_nil x.cause
85
+ assert_equal msg, x.message
86
+ assert_equal "#{msg}: #{RuntimeError.to_s}", x.chained_message
87
+ assert_not_empty x.chainees
88
+ assert_equal [ c ], x.chainees
89
+ assert_equal [ x, c ], x.exceptions
90
+ assert_nil x.backtrace
91
+ assert_empty x.options
92
+ end
93
+
94
+ def test_2_ctor_args_that_are_message_and_cause_that_has_a_message
95
+
96
+ msg = 'stuff'
97
+
98
+ c = RuntimeError.new 'blah'
99
+
100
+ x = SomeExceptionWithCause.new msg, c
101
+
102
+ assert_not_nil x.cause
103
+ assert_equal msg, x.message
104
+ assert_equal 'stuff: blah', x.chained_message
105
+
106
+ assert_not_empty x.chainees
107
+ assert_equal [ c ], x.chainees
108
+ assert_equal [ x, c ], x.exceptions
109
+ assert_nil x.backtrace
110
+ assert_empty x.options
111
+ end
112
+
113
+ def test_cause_in_options
114
+
115
+ c = RuntimeError.new 'inner'
116
+
117
+ x = SomeExceptionWithCause.new 'outer', cause: c
118
+
119
+ assert_not_nil x.cause
120
+ assert_equal 'outer', x.message
121
+ assert_equal 'outer: inner', x.chained_message
122
+
123
+ assert_not_empty x.chainees
124
+ assert_equal [ c ], x.chainees
125
+ assert_equal [ x, c ], x.exceptions
126
+ assert_nil x.backtrace
127
+ assert_empty x.options
128
+ end
129
+
130
+
131
+
132
+ class GrandchildException < Exception
133
+
134
+ include ::Xqsr3::Diagnostics::Exceptions::WithCause
135
+ end
136
+
137
+ class ChildException < Exception
138
+
139
+ def initialize(*args, **options)
140
+
141
+ super *args, **options
142
+ end
143
+
144
+ include ::Xqsr3::Diagnostics::Exceptions::WithCause
145
+ end
146
+
147
+ class ParentException < Exception
148
+
149
+ include ::Xqsr3::Diagnostics::Exceptions::WithCause
150
+
151
+ def initialize(*args, **options)
152
+
153
+ super *args, **options
154
+ end
155
+ end
156
+
157
+ class GrandparentException < Exception
158
+
159
+ include ::Xqsr3::Diagnostics::Exceptions::WithCause
160
+ end
161
+
162
+
163
+ def test_four_levels
164
+
165
+ gc = GrandchildException.new 'gc'
166
+
167
+ c = ChildException.new 'c', gc
168
+
169
+ p = ParentException.new c, 'p'
170
+
171
+ gp = GrandparentException.new 'gp', cause: p
172
+
173
+ assert_equal 'gp: p: c: gc', gp.chained_message
174
+ assert_equal 'gp-p-c-gc', gp.chained_message(separator: '-')
175
+ end
176
+ end
177
+
178
+ class Test_WithCause_throwing < Test::Unit::TestCase
179
+
180
+ class SomeExceptionWithCause < ::Exception
181
+
182
+ include ::Xqsr3::Diagnostics::Exceptions::WithCause
183
+ end
184
+
185
+ def f m
186
+
187
+ raise SomeExceptionWithCause, m
188
+ end
189
+
190
+ def g m, n
191
+
192
+ begin
193
+
194
+ f n
195
+ rescue Exception => x
196
+
197
+ raise SomeExceptionWithCause.new m, x
198
+ end
199
+ end
200
+
201
+ def h m, n, o
202
+
203
+ begin
204
+
205
+ g n, 0
206
+ rescue Exception => x
207
+
208
+ raise SomeExceptionWithCause.new m, x
209
+ end
210
+ end
211
+
212
+ def test_one_level
213
+
214
+ begin
215
+
216
+ f 'one-level'
217
+
218
+ assert false, 'should not get here!'
219
+ rescue Exception => x
220
+
221
+ assert_nil x.cause
222
+ assert_equal 'one-level', x.message
223
+ assert_equal 'one-level', x.chained_message
224
+ assert_empty x.chainees
225
+ assert_not_empty x.backtrace
226
+
227
+ x_bt0 = x.backtrace[0]
228
+
229
+ assert /:in\s+\`f\'\s*$/ =~ x_bt0, 'not receieved from f()'
230
+ end
231
+ end
232
+
233
+ def test_two_levels
234
+
235
+ begin
236
+
237
+ g 'two-levels', 'one-level'
238
+
239
+ assert false, 'should not get here!'
240
+ rescue Exception => x
241
+
242
+ assert_not_nil x.cause
243
+ assert_equal 'two-levels', x.message
244
+ assert_equal 'two-levels: one-level', x.chained_message
245
+ assert_not_empty x.chainees
246
+ assert_kind_of SomeExceptionWithCause, x.chainees[0]
247
+ assert_not_empty x.backtrace
248
+ assert_not_empty x.cause.backtrace
249
+
250
+ x_bt0 = x.backtrace[0]
251
+
252
+ assert /:in\s+\`rescue in g\'\s*$/ =~ x_bt0, 'not receieved from g()'
253
+
254
+ c_bt0 = x.cause.backtrace[0]
255
+
256
+ assert /:in\s+\`f\'\s*$/ =~ c_bt0, 'not receieved from f()'
257
+
258
+ assert_not_empty x.chained_backtrace
259
+ end
260
+ end
261
+ end
262
+
@@ -0,0 +1,12 @@
1
+ #! /usr/bin/env ruby
2
+ #
3
+ # executes all other tests
4
+
5
+ this_dir = File.expand_path(File.dirname(__FILE__))
6
+
7
+ # all tc_*rb in current directory
8
+ Dir[File.join(this_dir, 'tc_*rb')].each { |file| require file }
9
+
10
+ # all ts_*rb in immediate sub-directories
11
+ Dir[File.join(this_dir, '*', 'ts_*rb')].each { |file| require file }
12
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xqsr3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.2
4
+ version: 0.18.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Wilson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-16 00:00:00.000000000 Z
11
+ date: 2017-12-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  eXtensions by fine Quantum for Standard Ruby and 3rd-party libraries is a
@@ -25,6 +25,7 @@ files:
25
25
  - lib/xqsr3/containers/multi_map.rb
26
26
  - lib/xqsr3/conversion/bool_parser.rb
27
27
  - lib/xqsr3/diagnostics/exception_utilities.rb
28
+ - lib/xqsr3/diagnostics/exceptions/with_cause.rb
28
29
  - lib/xqsr3/doc_.rb
29
30
  - lib/xqsr3/extensions/array/join_with_or.rb
30
31
  - lib/xqsr3/extensions/enumerable/collect_with_index.rb
@@ -73,6 +74,8 @@ files:
73
74
  - test/unit/containers/ts_all.rb
74
75
  - test/unit/conversion/tc_to_bool.rb
75
76
  - test/unit/conversion/ts_all.rb
77
+ - test/unit/diagnostics/exceptions/tc_with_cause.rb
78
+ - test/unit/diagnostics/exceptions/ts_all.rb
76
79
  - test/unit/diagnostics/tc_exception_utilities.rb
77
80
  - test/unit/diagnostics/ts_all.rb
78
81
  - test/unit/extensions/enumerable/tc_collect_with_index.rb