return_bang 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
@@ -1,2 +1,3 @@
1
- 9LC��M}
2
- ߁Z�z��ܦ/⊢V��U�^�׭����בlRg�-�$��6���)�G(�s�i�
1
+ 7d+��*"��������N֝��W4�����YH�<!���־�b��5
2
+ k���Sκ������O�4���@M>�~r��e1S��F[y_�Ɓ���e8ӊ�z���� ޒ򔦛��:���{Ϥ�/R�����I��O`�������S�\
3
+ �d���6E<Tr&�d����"\�m�P�C4����|���V��^����e����N��Ty�w���$�2<$�w�|��dJ�)]A8�)�����{?��
@@ -1,5 +1,12 @@
1
+ === 1.1 / 2012-04-01
2
+
3
+ * Minor enhancements
4
+ * Added raise! to raise exceptions
5
+ * Added rescue! to rescue exceptions raised
6
+ * Added ensure! to always execute a block of code to perform cleanup
7
+
1
8
  === 1.0 / 2011-12-20
2
9
 
3
- * Major enhancements
10
+ * Major enhancement
4
11
  * Birthday!
5
12
 
@@ -6,16 +6,26 @@ bugs :: https://github.com/drbrain/return_bang/issues
6
6
 
7
7
  == Description
8
8
 
9
- return_bang implements non-local exits from methods. Use return_bang to exit
10
- back to a processing loop from deeply nested code, or just to confound your
11
- enemies *and* your friends! What could possibly go wrong?
9
+ return_bang implements non-local exits for methods. As a bonus, you also get
10
+ exception handling that ignores standard Ruby's inflexible begin; rescue;
11
+ ensure; end syntax.
12
+
13
+ Use return_bang to exit back to a processing loop from deeply nested code, or
14
+ just to confound your enemies *and* your friends! What could possibly go
15
+ wrong?
12
16
 
13
17
  == Features
14
18
 
15
19
  * Implements non-local exits for methods
16
20
  * Nestable
17
21
  * Named and stack-based exit points, go exactly where you need to be
18
- * Ignores pesky ensure blocks for when you really, really need to return
22
+ * Full exception handling support through raise!, rescue! and ensure!
23
+ * Ignores pesky ensure, rescue and require blocks for when you really, really
24
+ need to return
25
+
26
+ == Problems
27
+
28
+ * Not enough use of continuations
19
29
 
20
30
  == Synopsis
21
31
 
data/Rakefile CHANGED
@@ -5,14 +5,14 @@ require 'hoe'
5
5
 
6
6
  Hoe.plugin :minitest
7
7
  Hoe.plugin :git
8
+ Hoe.plugin :travis
8
9
 
9
10
  Hoe.spec 'return_bang' do
10
11
  developer 'Eric Hodel', 'drbrain@segment7.net'
11
12
 
12
13
  rdoc_locations << 'docs.seattlerb.org:/data/www/docs.seattlerb.org/return_bang/'
13
14
 
14
- self.readme_file = 'README.rdoc'
15
- self.extra_rdoc_files << 'README.rdoc'
15
+ spec_extras['required_ruby_version'] = '>= 1.9.2'
16
16
  end
17
17
 
18
18
  # vim: syntax=ruby
@@ -1,59 +1,78 @@
1
- begin
2
- require 'continuation'
3
- rescue LoadError
4
- # in 1.8 it's built-in
5
- end
1
+ require 'continuation'
6
2
 
7
3
  ##
8
4
  # ReturnBang is allows you to perform non-local exits from your methods. One
9
5
  # potential use of this is in a web framework so that a framework-provided
10
6
  # utility methods can jump directly back to the request loop.
11
7
  #
12
- # return_here is used to designate where execution should be resumed. Return
13
- # points may be arbitrarily nested. #return! resumes at the previous resume
14
- # point, #return_to returns to a named return point.
8
+ # Since providing just non-local exits is insufficient for modern Ruby
9
+ # development, full exception handling support is also provided via #raise!,
10
+ # #rescue! and #ensure!. This exception handling support completely bypasses
11
+ # Ruby's strict <tt>begin; rescue; ensure; return</tt> handling.
15
12
  #
16
13
  # require 'return_bang' gives you a module you may include only in your
17
14
  # application or library code. require 'return_bang/everywhere' includes
18
15
  # ReturnBang in Object, so it is only recommended for application code use.
19
16
  #
20
- # Example:
17
+ # == Methods
18
+ #
19
+ # return_here is used to designate where execution should be resumed. Return
20
+ # points may be arbitrarily nested. #return! resumes at the previous resume
21
+ # point, #return_to returns to a named return point.
22
+ #
23
+ # #raise! is used to indicate an exceptional situation has occurred and you
24
+ # would like to skip the rest of the execution.
25
+ #
26
+ # #rescue! is used to rescue exceptions if you have a way to handle them.
27
+ #
28
+ # #ensure! is used when you need to perform cleanup where an exceptional
29
+ # situation may occur.
30
+ #
31
+ # == Example
21
32
  #
22
33
  # include ReturnBang
23
34
  #
24
35
  # def framework_loop
25
36
  # loop do
26
- # # setup code
27
- #
28
37
  # return_here do
29
- # user_code
30
- # end
38
+ # # setup this request
31
39
  #
32
- # # resume execution here
33
- # end
34
- # end
40
+ # ensure! do
41
+ # # clean up this request
42
+ # end
43
+ #
44
+ # rescue! FrameworkError do
45
+ # # display framework error
46
+ # end
35
47
  #
36
- # def render_error_and_return message
37
- # # generate error
48
+ # rescue! do
49
+ # # display application error
50
+ # end
38
51
  #
39
- # return!
52
+ # user_code
53
+ # end
54
+ # end
40
55
  # end
41
56
  #
42
57
  # def user_code
43
58
  # user_utility_method
44
- # # these lines never reached
45
- # # ...
59
+ #
60
+ # other_condition = some_more code
61
+ #
62
+ # return! if other_condition
63
+ #
64
+ # # rest of user method
46
65
  # end
47
66
  #
48
67
  # def user_utility_method
49
- # render_error_and_return "blah" if some_condition
50
- # # these lines never reached
51
- # # ...
68
+ # raise! "there was an error" if some_condition
69
+ #
70
+ # # rest of utility method
52
71
  # end
53
72
 
54
73
  module ReturnBang
55
74
 
56
- VERSION = '1.0'
75
+ VERSION = '1.1'
57
76
 
58
77
  ##
59
78
  # Raised when attempting to return! when you haven't registered a location
@@ -63,31 +82,185 @@ module ReturnBang
63
82
  class NonLocalJumpError < StandardError
64
83
  end
65
84
 
85
+ def _make_exception args # :nodoc:
86
+ case args.length
87
+ when 0 then
88
+ if exception = Thread.current[:current_exception] then
89
+ exception
90
+ else
91
+ RuntimeError.new
92
+ end
93
+ when 1 then # exception or string
94
+ arg = args.first
95
+
96
+ case arg = args.first
97
+ when Class then
98
+ unless Exception >= arg then
99
+ raise TypeError,
100
+ "exception class/object expected (not #{arg.inspect})"
101
+ end
102
+ arg.new
103
+ else
104
+ RuntimeError.new arg
105
+ end
106
+ when 2 then # exception, string
107
+ klass, message = args
108
+ klass.new message
109
+ else
110
+ raise ArgumentError, 'too many arguments to raise!'
111
+ end
112
+ end
113
+
114
+ ##
115
+ # Executes the ensure blocks in +frames+ in the correct order.
116
+
117
+ def _return_bang_cleanup frames # :nodoc:
118
+ chunked = frames.chunk do |type,|
119
+ type
120
+ end
121
+
122
+ chunked.reverse_each do |type, chunk_frames|
123
+ case type
124
+ when :ensure then
125
+ chunk_frames.each do |_, block|
126
+ block.call
127
+ end
128
+ when :rescue then
129
+ if exception = Thread.current[:current_exception] then
130
+ frame = chunk_frames.find do |_, block, objects|
131
+ objects.any? do |object|
132
+ object === exception
133
+ end
134
+ end
135
+
136
+ next unless frame
137
+
138
+ # rebuild stack since we've got a handler for the exception.
139
+ unexecuted = frames[0, frames.index(frame) - 1]
140
+ _return_bang_stack.concat unexecuted if unexecuted
141
+
142
+ _, handler, = frame
143
+ handler.call exception
144
+
145
+ return # the exception was handled, don't continue up the stack
146
+ end
147
+ when :return then
148
+ # ignore
149
+ else
150
+ raise "[bug] unknown return_bang frame type #{type}"
151
+ end
152
+ end
153
+ end
154
+
66
155
  def _return_bang_names # :nodoc:
67
156
  Thread.current[:return_bang_names] ||= {}
68
157
  end
69
158
 
70
- if {}.respond_to? :key then # 1.9
71
- def _return_bang_pop # :nodoc:
72
- return_point = _return_bang_stack.pop
159
+ def _return_bang_pop # :nodoc:
160
+ frame = _return_bang_stack.pop
161
+
162
+ _return_bang_names.delete _return_bang_names.key _return_bang_stack.length
163
+
164
+ frame
165
+ end
166
+
167
+ def _return_bang_stack # :nodoc:
168
+ Thread.current[:return_bang_stack] ||= []
169
+ end
170
+
171
+ ##
172
+ # Unwinds the stack to +continuation+ including trimming the stack above the
173
+ # continuation, removing named return_heres that can't be reached and
174
+ # executing any ensures in the trimmed stack.
73
175
 
74
- _return_bang_names.delete _return_bang_names.key _return_bang_stack.length
176
+ def _return_bang_unwind_to continuation # :nodoc:
177
+ found = false
75
178
 
76
- return_point
179
+ frames = _return_bang_stack.select do |_, block|
180
+ found || found = block == continuation
77
181
  end
78
- else # 1.8
79
- def _return_bang_pop # :nodoc:
80
- return_point = _return_bang_stack.pop
81
- value = _return_bang_stack.length
82
182
 
83
- _return_bang_names.delete _return_bang_names.index value
183
+ start = _return_bang_stack.length - frames.length
184
+
185
+ _return_bang_stack.slice! start, frames.length
84
186
 
85
- return_point
187
+ frames.each_index do |index|
188
+ offset = start + index
189
+
190
+ _return_bang_names.delete _return_bang_names.key offset
86
191
  end
192
+
193
+ _return_bang_cleanup frames
87
194
  end
88
195
 
89
- def _return_bang_stack # :nodoc:
90
- Thread.current[:return_bang_stack] ||= []
196
+ ##
197
+ # Adds an ensure block that will be run when exiting this return_here block.
198
+ #
199
+ # ensure! blocks run in the order defined and can be added at any time. If
200
+ # an exception is raised before an ensure! block is encountered, that block
201
+ # will not be executed.
202
+ #
203
+ # Example:
204
+ #
205
+ # return_here do
206
+ # ensure! do
207
+ # # this ensure! will be executed
208
+ # end
209
+ #
210
+ # raise! "uh-oh!"
211
+ #
212
+ # ensure! do
213
+ # # this ensure! will not be executed
214
+ # end
215
+ # end
216
+
217
+ def ensure! &block
218
+ _return_bang_stack.push [:ensure, block]
219
+ end
220
+
221
+ ##
222
+ # Raises an exception like Kernel#raise.
223
+ #
224
+ # ensure! blocks and rescue! exception handlers will be run as the exception
225
+ # is propagated up the stack.
226
+
227
+ def raise! *args
228
+ Thread.current[:current_exception] = _make_exception args
229
+
230
+ type, = _return_bang_stack.first
231
+
232
+ _, final = _return_bang_stack.shift if type == :return
233
+
234
+ frames = _return_bang_stack.dup
235
+
236
+ _return_bang_stack.clear
237
+
238
+ _return_bang_cleanup frames
239
+
240
+ final.call if final
241
+ end
242
+
243
+ ##
244
+ # Rescues +exceptions+ raised by raise! and yields the exception caught to
245
+ # the block given.
246
+ #
247
+ # If no exceptions are given, StandardError is rescued (like the rescue
248
+ # keyword).
249
+ #
250
+ # Example:
251
+ #
252
+ # return_here do
253
+ # rescue! do |e|
254
+ # puts "handled exception #{e.class}: #{e}"
255
+ # end
256
+ #
257
+ # raise! "raising an exception"
258
+ # end
259
+
260
+ def rescue! *exceptions, &block
261
+ exceptions = [StandardError] if exceptions.empty?
262
+
263
+ _return_bang_stack.push [:rescue, block, exceptions]
91
264
  end
92
265
 
93
266
  ##
@@ -99,7 +272,13 @@ module ReturnBang
99
272
  raise NonLocalJumpError, 'nowhere to return to' if
100
273
  _return_bang_stack.empty?
101
274
 
102
- _return_bang_pop.call value
275
+ _, continuation, = _return_bang_stack.reverse.find do |type,|
276
+ type == :return
277
+ end
278
+
279
+ _return_bang_unwind_to continuation
280
+
281
+ continuation.call value
103
282
  end
104
283
 
105
284
  ##
@@ -112,15 +291,21 @@ module ReturnBang
112
291
 
113
292
  value = callcc do |cc|
114
293
  _return_bang_names[name] = _return_bang_stack.length if name
115
- _return_bang_stack.push cc
294
+ _return_bang_stack.push [:return, cc]
116
295
 
117
296
  begin
118
297
  yield
119
298
  ensure
120
- _return_bang_pop
299
+ _return_bang_unwind_to cc
121
300
  end
122
301
  end
123
302
 
303
+ if exception = Thread.current[:current_exception] then
304
+ Thread.current[:current_exception] = nil
305
+
306
+ raise exception
307
+ end
308
+
124
309
  # here is where the magic happens
125
310
  unwind_to = Thread.current[:unwind_to]
126
311
 
@@ -13,6 +13,324 @@ class TestReturnBang < MiniTest::Unit::TestCase
13
13
  def teardown
14
14
  assert_empty _return_bang_stack
15
15
  assert_empty _return_bang_names
16
+ assert_nil Thread.current[:current_exception]
17
+ end
18
+
19
+ def test__make_exception
20
+ e = _make_exception []
21
+
22
+ assert_instance_of RuntimeError, e
23
+ end
24
+
25
+ def test__make_exception_class
26
+ e = _make_exception [StandardError]
27
+
28
+ assert_instance_of StandardError, e
29
+ end
30
+
31
+ def test__make_exception_class_message
32
+ e = _make_exception [StandardError, 'hello']
33
+
34
+ assert_instance_of StandardError, e
35
+
36
+ assert_equal 'hello', e.message
37
+ end
38
+
39
+ def test__make_exception_current_exception
40
+ expected = ArgumentError.new
41
+ Thread.current[:current_exception] = expected
42
+
43
+ e = _make_exception []
44
+
45
+ assert_same expected, e
46
+ ensure
47
+ Thread.current[:current_exception] = nil
48
+ end
49
+
50
+ def test__make_exception_message
51
+ e = _make_exception %w[hello]
52
+
53
+ assert_instance_of RuntimeError, e
54
+ assert_equal 'hello', e.message
55
+ end
56
+
57
+ def test__make_exception_non_Exception
58
+ e = assert_raises TypeError do
59
+ _make_exception [String]
60
+ end
61
+
62
+ assert_equal 'exception class/object expected (not String)', e.message
63
+ end
64
+
65
+ def test_ensure_bang
66
+ ensured = false
67
+
68
+ return_here do
69
+ ensure! do
70
+ ensured = true
71
+ end
72
+ end
73
+
74
+ assert ensured, 'ensured was not executed'
75
+ end
76
+
77
+ def test_ensure_bang_multiple
78
+ ensured = []
79
+
80
+ return_here do
81
+ ensure! do
82
+ ensured << 1
83
+ end
84
+ ensure! do
85
+ ensured << 2
86
+ end
87
+ end
88
+
89
+ assert_equal [1, 2], ensured
90
+ end
91
+
92
+ def test_ensure_bang_multiple_return
93
+ ensured = []
94
+
95
+ return_here do
96
+ ensure! do
97
+ ensured << 1
98
+ end
99
+ ensure! do
100
+ ensured << 2
101
+ end
102
+
103
+ return!
104
+ end
105
+
106
+ assert_equal [1, 2], ensured
107
+ end
108
+
109
+ def test_ensure_bang_nest
110
+ ensured = []
111
+
112
+ return_here do
113
+ ensure! do
114
+ ensured << 2
115
+ end
116
+ return_here do
117
+ ensure! do
118
+ ensured << 1
119
+ end
120
+ end
121
+ end
122
+
123
+ assert_equal [1, 2], ensured
124
+ end
125
+
126
+ def test_ensure_bang_nest_raise
127
+ ensured = []
128
+
129
+ assert_raises RuntimeError do
130
+ return_here do
131
+ ensure! do
132
+ ensured << 2
133
+ end
134
+ return_here do
135
+ ensure! do
136
+ ensured << 1
137
+ end
138
+
139
+ raise!
140
+ end
141
+ end
142
+ end
143
+
144
+ assert_equal [1, 2], ensured
145
+ end
146
+
147
+ def test_ensure_bang_raise_after
148
+ ensured = false
149
+
150
+ assert_raises RuntimeError do
151
+ return_here do
152
+ ensure! do
153
+ ensured = true
154
+ end
155
+
156
+ refute ensured, 'ensure! executed too soon'
157
+
158
+ raise!
159
+ end
160
+ end
161
+
162
+ assert ensured, 'ensure! not executed'
163
+ end
164
+
165
+ def test_ensure_bang_raise_before
166
+ ensured = false
167
+
168
+ assert_raises RuntimeError do
169
+ return_here do
170
+ raise!
171
+
172
+ ensure! do
173
+ ensured = true
174
+ end
175
+ end
176
+ end
177
+
178
+ refute ensured, 'ensure! must not be executed'
179
+ end
180
+
181
+ def test_ensure_bang_raise_in_ensure
182
+ ensured = []
183
+
184
+ assert_raises RuntimeError do
185
+ return_here do
186
+ ensure! do
187
+ ensured << 2
188
+ end
189
+
190
+ return_here do
191
+ ensure! do
192
+ ensured << 1
193
+ raise!
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ assert_equal [1, 2], ensured
200
+ end
201
+
202
+ def test_raise_bang
203
+ e = assert_raises RuntimeError do
204
+ return_here do
205
+ raise! 'hello'
206
+ end
207
+ end
208
+
209
+ assert_equal 'hello', e.message
210
+ end
211
+
212
+ def test_raise_bang_ignore_rescue
213
+ assert_raises RuntimeError do
214
+ return_here do
215
+ begin
216
+ raise! 'hello'
217
+ rescue
218
+ flunk 'must not execute rescue body'
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ def test_raise_bang_re_raise
225
+ rescues = []
226
+
227
+ assert_raises ArgumentError do
228
+ return_here do
229
+ rescue! do
230
+ rescues << 2
231
+ end
232
+
233
+ return_here do
234
+ rescue! do
235
+ rescues << 1
236
+
237
+ raise!
238
+ end
239
+
240
+ raise! ArgumentError, 'hello'
241
+ end
242
+ end
243
+ end
244
+
245
+ assert_equal [1, 2], rescues
246
+ end
247
+
248
+ def test_rescue_bang
249
+ rescued = false
250
+
251
+ assert_raises RuntimeError do
252
+ return_here do
253
+ rescue! do
254
+ rescued = true
255
+ end
256
+
257
+ raise! 'hello'
258
+ end
259
+ end
260
+
261
+ assert rescued, 'rescue not executed'
262
+ end
263
+
264
+ def test_rescue_bang_default
265
+ rescued = false
266
+
267
+ assert_raises Exception do
268
+ return_here do
269
+ rescue! do
270
+ rescued = true
271
+ end
272
+
273
+ raise! Exception
274
+ end
275
+ end
276
+
277
+ refute rescued, 'rescue must default to StandardError'
278
+ end
279
+
280
+ def test_rescue_bang_exceptions
281
+ rescued = false
282
+ ensured = true
283
+
284
+ return_here do
285
+ rescue! do
286
+ rescued = true
287
+ end
288
+
289
+ ensure! do
290
+ ensured = true
291
+ end
292
+
293
+ return!
294
+ end
295
+
296
+ refute rescued, 'rescue! must not execute'
297
+ assert ensured, 'ensure! must execute'
298
+ end
299
+
300
+ def test_rescue_bang_multiple
301
+ rescued = false
302
+
303
+ assert_raises TypeError do
304
+ return_here do
305
+ rescue! ArgumentError, TypeError do
306
+ rescued = true
307
+ end
308
+
309
+ raise! TypeError
310
+ end
311
+ end
312
+
313
+ assert rescued, 'rescue not executed'
314
+ end
315
+
316
+ def test_rescue_bang_type
317
+ rescued = false
318
+
319
+ assert_raises StandardError do
320
+ return_here do
321
+ rescue! StandardError do
322
+ rescued = true
323
+ end
324
+
325
+ rescue! RuntimeError do
326
+ flunk 'wrong rescue! executed'
327
+ end
328
+
329
+ raise! StandardError
330
+ end
331
+ end
332
+
333
+ assert rescued, 'StandardError exception not rescued'
16
334
  end
17
335
 
18
336
  def test_return_bang_no_return_here
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: return_bang
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 0
9
- version: "1.0"
8
+ - 1
9
+ version: "1.1"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Eric Hodel
@@ -15,9 +15,9 @@ bindir: bin
15
15
  cert_chain:
16
16
  - |
17
17
  -----BEGIN CERTIFICATE-----
18
- MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
18
+ MIIDeDCCAmCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBBMRAwDgYDVQQDDAdkcmJy
19
19
  YWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZFgNu
20
- ZXQwHhcNMDcxMjIxMDIwNDE0WhcNMDgxMjIwMDIwNDE0WjBBMRAwDgYDVQQDDAdk
20
+ ZXQwHhcNMTIwMjI4MTc1NDI1WhcNMTMwMjI3MTc1NDI1WjBBMRAwDgYDVQQDDAdk
21
21
  cmJyYWluMRgwFgYKCZImiZPyLGQBGRYIc2VnbWVudDcxEzARBgoJkiaJk/IsZAEZ
22
22
  FgNuZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCbbgLrGLGIDE76
23
23
  LV/cvxdEzCuYuS3oG9PrSZnuDweySUfdp/so0cDq+j8bqy6OzZSw07gdjwFMSd6J
@@ -25,17 +25,18 @@ cert_chain:
25
25
  Gj/okWrQl0NjYOYBpDi+9PPmaH2RmLJu0dB/NylsDnW5j6yN1BEI8MfJRR+HRKZY
26
26
  mUtgzBwF1V4KIZQ8EuL6I/nHVu07i6IkrpAgxpXUfdJQJi0oZAqXurAV3yTxkFwd
27
27
  g62YrrW26mDe+pZBzR6bpLE+PmXCzz7UxUq3AE0gPHbiMXie3EFE0oxnsU3lIduh
28
- sCANiQ8BAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
29
- BBS5k4Z75VSpdM0AclG2UvzFA/VW5DANBgkqhkiG9w0BAQUFAAOCAQEAHagT4lfX
30
- kP/hDaiwGct7XPuVGbrOsKRVD59FF5kETBxEc9UQ1clKWngf8JoVuEoKD774dW19
31
- bU0GOVWO+J6FMmT/Cp7nuFJ79egMf/gy4gfUfQMuvfcr6DvZUPIs9P/TlK59iMYF
32
- DIOQ3DxdF3rMzztNUCizN4taVscEsjCcgW6WkUJnGdqlu3OHWpQxZBJkBTjPCoc6
33
- UW6on70SFPmAy/5Cq0OJNGEWBfgD9q7rrs/X8GGwUWqXb85RXnUVi/P8Up75E0ag
34
- 14jEc90kN+C7oI/AGCBN0j6JnEtYIEJZibjjDJTSMWlUKKkj30kq7hlUC2CepJ4v
35
- x52qPcexcYZR7w==
28
+ sCANiQ8BAgMBAAGjezB5MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
29
+ BBS5k4Z75VSpdM0AclG2UvzFA/VW5DAfBgNVHREEGDAWgRRkcmJyYWluQHNlZ21l
30
+ bnQ3Lm5ldDAfBgNVHRIEGDAWgRRkcmJyYWluQHNlZ21lbnQ3Lm5ldDANBgkqhkiG
31
+ 9w0BAQUFAAOCAQEAPeWzFnrcvC6eVzdlhmjUub2s6qieBkongKRDHQz5MEeQv4LS
32
+ SARnoHY+uCAVL/1xGAhmpzqQ3fJGWK9eBacW/e8E5GF9xQcV3mE1bA0WNaiDlX5j
33
+ U2aI+ZGSblqvHUCxKBHR1s7UMHsbz1saOmgdRTyPx0juJs68ocbUTeYBLWu9V4KP
34
+ zdGAG2JXO2gONg3b4tYDvpBLbry+KOX27iAJulUaH9TiTOULL4ITJVFsK0mYVqmR
35
+ Q8Tno9S3e4XGGP1ZWfLrTWEJbavFfhGHut2iMRwfC7s/YILAHNATopaJdH9DNpd1
36
+ U81zGHMUBOvz/VGT6wJwYJ3emS2nfA2NOHFfgA==
36
37
  -----END CERTIFICATE-----
37
38
 
38
- date: 2011-12-21 00:00:00 Z
39
+ date: 2012-04-01 00:00:00 Z
39
40
  dependencies:
40
41
  - !ruby/object:Gem::Dependency
41
42
  name: minitest
@@ -45,32 +46,51 @@ dependencies:
45
46
  requirements:
46
47
  - - ~>
47
48
  - !ruby/object:Gem::Version
48
- hash: 15
49
+ hash: 21
49
50
  segments:
50
51
  - 2
51
- - 6
52
- version: "2.6"
52
+ - 11
53
+ version: "2.11"
53
54
  type: :development
54
55
  version_requirements: *id001
55
56
  - !ruby/object:Gem::Dependency
56
- name: hoe
57
+ name: rdoc
57
58
  prerelease: false
58
59
  requirement: &id002 !ruby/object:Gem::Requirement
59
60
  none: false
60
61
  requirements:
61
62
  - - ~>
62
63
  - !ruby/object:Gem::Version
63
- hash: 27
64
+ hash: 19
64
65
  segments:
65
- - 2
66
- - 12
67
- version: "2.12"
66
+ - 3
67
+ - 10
68
+ version: "3.10"
68
69
  type: :development
69
70
  version_requirements: *id002
71
+ - !ruby/object:Gem::Dependency
72
+ name: hoe
73
+ prerelease: false
74
+ requirement: &id003 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ hash: 35
80
+ segments:
81
+ - 2
82
+ - 16
83
+ version: "2.16"
84
+ type: :development
85
+ version_requirements: *id003
70
86
  description: |-
71
- return_bang implements non-local exits from methods. Use return_bang to exit
72
- back to a processing loop from deeply nested code, or just to confound your
73
- enemies *and* your friends! What could possibly go wrong?
87
+ return_bang implements non-local exits for methods. As a bonus, you also get
88
+ exception handling that ignores standard Ruby's inflexible begin; rescue;
89
+ ensure; end syntax.
90
+
91
+ Use return_bang to exit back to a processing loop from deeply nested code, or
92
+ just to confound your enemies *and* your friends! What could possibly go
93
+ wrong?
74
94
  email:
75
95
  - drbrain@segment7.net
76
96
  executables: []
@@ -105,10 +125,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
105
125
  requirements:
106
126
  - - ">="
107
127
  - !ruby/object:Gem::Version
108
- hash: 3
128
+ hash: 55
109
129
  segments:
110
- - 0
111
- version: "0"
130
+ - 1
131
+ - 9
132
+ - 2
133
+ version: 1.9.2
112
134
  required_rubygems_version: !ruby/object:Gem::Requirement
113
135
  none: false
114
136
  requirements:
@@ -121,9 +143,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
143
  requirements: []
122
144
 
123
145
  rubyforge_project: return_bang
124
- rubygems_version: 1.8.12
146
+ rubygems_version: 1.8.21
125
147
  signing_key:
126
148
  specification_version: 3
127
- summary: return_bang implements non-local exits from methods
149
+ summary: return_bang implements non-local exits for methods
128
150
  test_files:
129
151
  - test/test_return_bang.rb
metadata.gz.sig CHANGED
@@ -1,2 +1,4 @@
1
- `"t�TW��nW��G$��c�=gTV�=�z|��t"�;� ��Jv�_�X2��:����,����V��|c��xD��ܫ�s�]�}F�$�E�'uJ�{���۔Y���t������4KϞ2���E�j����u�ԕ�'U �A��y����$��ޅ
2
- 稼�F�D�!�c����9 RsJ��҇�AF�a��y�=s`O�YQ�Z�w��~�~j�otɋ[1�臼�A��[�a_�`
1
+ V���Ɗ`�`u�LN]n��ԙ�
2
+ 1��j%>��
3
+ p�-ZyQ��
4
+ �*�o�辵�2�ϸg�_���Q��]�