fancy 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. data/README.md +38 -86
  2. data/bin/fdoc +2 -22
  3. data/bin/fspec +8 -3
  4. data/bin/ifancy +1 -1
  5. data/boot/fancy_ext.rb +1 -0
  6. data/boot/fancy_ext/array.rb +19 -0
  7. data/boot/fancy_ext/class.rb +2 -4
  8. data/boot/fancy_ext/module.rb +2 -0
  9. data/boot/fancy_ext/object.rb +0 -17
  10. data/boot/rbx-compiler/compiler/ast/method_def.rb +0 -4
  11. data/boot/rbx-compiler/compiler/ast/singleton_method_def.rb +0 -7
  12. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  13. data/boot/rbx-compiler/parser/fancy_parser.c +1 -0
  14. data/doc/api/fancy.css +10 -1
  15. data/doc/api/fancy.jsonp +1 -1
  16. data/doc/api/fdoc.js +22 -9
  17. data/doc/api/octocat.png +0 -0
  18. data/doc/features.md +1 -2
  19. data/examples/actors.fy +1 -2
  20. data/examples/armstrong_numbers.fy +7 -3
  21. data/examples/blocks.fy +3 -3
  22. data/examples/distributing_proxy.fy +31 -0
  23. data/examples/future_sends.fy +15 -0
  24. data/examples/person.fy +1 -2
  25. data/lib/argv.fy +1 -7
  26. data/lib/array.fy +7 -11
  27. data/lib/block.fy +15 -0
  28. data/lib/boot.fy +4 -3
  29. data/lib/class.fy +354 -10
  30. data/lib/compiler.fy +1 -1
  31. data/lib/compiler/ast/assign.fy +4 -8
  32. data/lib/compiler/ast/async_send.fy +1 -2
  33. data/lib/compiler/ast/block.fy +5 -0
  34. data/lib/compiler/ast/class_def.fy +2 -1
  35. data/lib/compiler/ast/expression_list.fy +1 -2
  36. data/lib/compiler/ast/future_send.fy +1 -2
  37. data/lib/compiler/ast/identifier.fy +34 -17
  38. data/lib/compiler/ast/literals.fy +31 -19
  39. data/lib/compiler/ast/match.fy +5 -4
  40. data/lib/compiler/ast/message_send.fy +3 -5
  41. data/lib/compiler/ast/method_def.fy +0 -3
  42. data/lib/compiler/ast/range.fy +2 -4
  43. data/lib/compiler/ast/return.fy +2 -4
  44. data/lib/compiler/ast/script.fy +2 -4
  45. data/lib/compiler/ast/singleton_method_def.fy +0 -3
  46. data/lib/compiler/ast/string_interpolation.fy +2 -2
  47. data/lib/compiler/ast/super.fy +2 -4
  48. data/lib/compiler/ast/try_catch.fy +13 -9
  49. data/lib/compiler/ast/tuple_literal.fy +1 -2
  50. data/lib/compiler/compiler.fy +2 -2
  51. data/lib/compiler/stages.fy +3 -6
  52. data/lib/contracts.fy +89 -57
  53. data/lib/dynamic_slot_object.fy +21 -3
  54. data/lib/enumerable.fy +140 -4
  55. data/lib/enumerator.fy +1 -1
  56. data/lib/eval.fy +23 -9
  57. data/lib/exception.fy +16 -0
  58. data/lib/false_class.fy +36 -5
  59. data/lib/fancy_spec.fy +64 -34
  60. data/lib/fdoc.fy +85 -24
  61. data/lib/file.fy +19 -0
  62. data/lib/future.fy +4 -46
  63. data/lib/hash.fy +113 -0
  64. data/lib/integer.fy +25 -6
  65. data/lib/iteration.fy +3 -3
  66. data/lib/main.fy +5 -0
  67. data/lib/matchers.fy +79 -0
  68. data/lib/nil_class.fy +8 -0
  69. data/lib/object.fy +109 -18
  70. data/lib/option_parser.fy +118 -0
  71. data/lib/package/dependency.fy +4 -8
  72. data/lib/package/dependency_installer.fy +1 -1
  73. data/lib/package/handler.fy +6 -0
  74. data/lib/package/installer.fy +43 -16
  75. data/lib/package/list.fy +1 -2
  76. data/lib/package/specification.fy +5 -5
  77. data/lib/package/uninstaller.fy +9 -2
  78. data/lib/parser.fy +1 -3
  79. data/lib/parser/ext/ext.c +1 -0
  80. data/lib/parser/ext/lexer.lex +5 -0
  81. data/lib/parser/methods.fy +48 -46
  82. data/lib/proxies.fy +151 -0
  83. data/lib/rbx.fy +1 -0
  84. data/lib/rbx/actor.fy +16 -18
  85. data/lib/rbx/array.fy +18 -3
  86. data/lib/rbx/block.fy +1 -7
  87. data/lib/rbx/class.fy +54 -9
  88. data/lib/rbx/code_loader.fy +2 -5
  89. data/lib/rbx/compiled_method.fy +31 -0
  90. data/lib/rbx/debugger.fy +66 -0
  91. data/lib/rbx/directory.fy +8 -3
  92. data/lib/rbx/documentation.fy +1 -1
  93. data/lib/rbx/file.fy +22 -0
  94. data/lib/rbx/integer.fy +1 -1
  95. data/lib/rbx/match_data.fy +2 -1
  96. data/lib/rbx/method.fy +26 -0
  97. data/lib/rbx/object.fy +8 -3
  98. data/lib/rbx/regexp.fy +6 -3
  99. data/lib/rbx/string.fy +9 -1
  100. data/lib/rbx/stringio.fy +12 -0
  101. data/lib/rbx/symbol.fy +4 -0
  102. data/lib/stack.fy +1 -1
  103. data/lib/string.fy +34 -0
  104. data/lib/stringio.fy +1 -1
  105. data/lib/symbol.fy +6 -2
  106. data/lib/system.fy +15 -1
  107. data/lib/tuple.fy +5 -2
  108. data/lib/version.fy +1 -1
  109. data/ruby_lib/fdoc +2 -22
  110. data/tests/array.fy +3 -17
  111. data/tests/class.fy +312 -10
  112. data/tests/contracts.fy +51 -0
  113. data/tests/distributing_proxy.fy +28 -0
  114. data/tests/enumerable.fy +104 -1
  115. data/tests/exception.fy +35 -0
  116. data/tests/fixnum.fy +1 -1
  117. data/tests/hash.fy +81 -1
  118. data/tests/integer.fy +9 -0
  119. data/tests/matchers.fy +18 -0
  120. data/tests/method.fy +8 -14
  121. data/tests/object.fy +76 -2
  122. data/tests/option_parser.fy +80 -0
  123. data/tests/string.fy +21 -0
  124. data/tests/stringio.fy +1 -1
  125. data/tests/tuple.fy +1 -1
  126. metadata +21 -44
  127. data/examples/arithmetic.fy +0 -7
  128. data/examples/array.fy +0 -50
  129. data/examples/boolean.fy +0 -24
  130. data/examples/class.fy +0 -68
  131. data/examples/constant_access.fy +0 -15
  132. data/examples/default_args.fy +0 -20
  133. data/examples/define_methods.fy +0 -15
  134. data/examples/dynamic_output.fy +0 -15
  135. data/examples/empty_catch.fy +0 -4
  136. data/examples/exception.fy +0 -9
  137. data/examples/files.fy +0 -23
  138. data/examples/finally.fy +0 -5
  139. data/examples/future.fy +0 -30
  140. data/examples/future_composition.fy +0 -20
  141. data/examples/futures.fy +0 -9
  142. data/examples/game_of_life.fy +0 -148
  143. data/examples/html_generator.fy +0 -84
  144. data/examples/implicit_return.fy +0 -3
  145. data/examples/matchers.fy +0 -6
  146. data/examples/nested_try.fy +0 -9
  147. data/examples/numbers.fy +0 -12
  148. data/examples/rbx/and_or.fy +0 -7
  149. data/examples/rbx/blocks.fy +0 -22
  150. data/examples/rbx/classes.fy +0 -32
  151. data/examples/rbx/hello.fy +0 -8
  152. data/examples/rbx/include.fy +0 -12
  153. data/examples/rbx/inherit.fy +0 -11
  154. data/examples/rbx/methods.fy +0 -15
  155. data/examples/rbx/nested_classes.fy +0 -9
  156. data/examples/rbx/require.fy +0 -3
  157. data/examples/rbx/strings.fy +0 -5
  158. data/examples/require.fy +0 -7
  159. data/examples/return.fy +0 -13
  160. data/examples/singleton_methods.fy +0 -21
  161. data/examples/threads.fy +0 -18
  162. data/examples/tuple.fy +0 -8
  163. data/examples/webserver/webserver.fy +0 -15
  164. data/lib/proxy.fy +0 -86
  165. data/lib/thread_pool.fy +0 -102
@@ -15,6 +15,17 @@ class File {
15
15
  File open: filename modes: ['write] with: block
16
16
  }
17
17
 
18
+ def File append: filename with: block {
19
+ """
20
+ @filename Filename of @File@ to append to.
21
+ @block @Block@ called with a @File@ object to append to.
22
+
23
+ Opens a @File@ for appending and calls @block with it.
24
+ """
25
+
26
+ File open: filename modes: ['append] with: block
27
+ }
28
+
18
29
  def File read: filename with: block {
19
30
  """
20
31
  @filename Filename of @File@ to read from.
@@ -38,6 +49,14 @@ class File {
38
49
  }
39
50
 
40
51
  def File read_binary: filename {
52
+ """
53
+ @filename Filename of @File@ to read from.
54
+ @return @String@ that is the binary data in @filename.
55
+
56
+ Opens and reads the contents of a @File@ in binary mode and
57
+ returns its binary contents as a @String@.
58
+ """
59
+
41
60
  content = nil
42
61
  File read_binary: filename with: |f| {
43
62
  content = f read
@@ -1,6 +1,6 @@
1
1
  class FutureSend {
2
2
  """
3
- A @FutureSend@ gets created whenever an asynchronous message via the @@ operator gets sent, yielding a @FutureSend@.
3
+ A @FutureSend@ gets created whenever an asynchronous message via the @ operator gets sent, yielding a @FutureSend@.
4
4
  They represent Futures/Promises in Fancy.
5
5
 
6
6
  Example:
@@ -41,13 +41,13 @@ class FutureSend {
41
41
  if: @failed then: {
42
42
  try {
43
43
  @fail_continuations each: @{ call: [@fail_reason] }
44
- } catch Exception => ex {
44
+ } catch StandardError => ex {
45
45
  *stderr* println: "Error in FutureSend#completed! while calling fail continuations: #{ex}"
46
46
  }
47
47
  } else: {
48
48
  try {
49
49
  @continuations each: @{ call: [@value] }
50
- } catch Exception => ex {
50
+ } catch StandardError => ex {
51
51
  *stderr* println: "Error in FutureSend#completed! while calling success continuations: #{ex}"
52
52
  }
53
53
  }
@@ -185,52 +185,10 @@ class FutureSend {
185
185
  }
186
186
  }
187
187
 
188
- class PooledFuture {
189
- @@thread_pool = nil
190
- @@pool_size = 10
191
- WaitInterval = 0.1
192
-
193
- def PooledFuture pool: n {
194
- @@pool_size = match n {
195
- case 0 -> 10
196
- case _ -> n
197
- }
198
- }
199
-
200
- def PooledFuture join! {
201
- @@thread_pool join
202
- }
203
-
204
- def initialize: @block {
205
- { @@thread_pool = ThreadPool new: @@pool_size } unless: @@thread_pool
206
- @@thread_pool execute: @block
207
- }
208
-
209
- def when_done: block {
210
- PooledFuture new: {
211
- block call: [value]
212
- }
213
- }
214
-
215
- def && block {
216
- when_done: block
217
- }
218
-
219
- def completed? {
220
- @block complete?
221
- }
222
-
223
- def value {
224
- { Thread sleep: WaitInterval } until: { completed? }
225
- @block completed_value
226
- }
227
- }
228
-
229
188
  class FutureCollection {
230
189
  include: Fancy Enumerable
231
190
 
232
- def initialize: @futures {
233
- }
191
+ def initialize: @futures
234
192
 
235
193
  def each: block {
236
194
  @futures each: @{ when_done: block }
@@ -163,4 +163,117 @@ class Hash {
163
163
 
164
164
  keys map: |k| { at: k }
165
165
  }
166
+
167
+ def select_keys: block {
168
+ """
169
+ @block @Block@ to be called with each key in @self.
170
+ @return @Hash@ of entries for which @block called with its key yields @true.
171
+
172
+ Example:
173
+ h = <['a => 1, 42 => (1,2,3), 'b => \"hello\"]>
174
+ h select_keys: @{ is_a?: Symbol } # => <['a => 1, 'b => \"hello\"]>
175
+ """
176
+
177
+ h = <[]>
178
+ keys each: |k| {
179
+ if: (block call: [k]) then: {
180
+ h[k]: $ self[k]
181
+ }
182
+ }
183
+ h
184
+ }
185
+
186
+ def reject_keys: block {
187
+ """
188
+ @block @Block@ to be called with each key in @self.
189
+ @return @Hash@ of entries for which @block called with its key yields @false.
190
+
191
+ Example:
192
+ h = <['a => 1, 42 => (1,2,3), 'b => \"hello\"]>
193
+ h reject_keys: @{ is_a?: Symbol } # => <[42 => (1,2,3)]>
194
+ """
195
+
196
+ select_keys: |k| { block call: [k] . not }
197
+ }
198
+
199
+ def random_key {
200
+ """
201
+ @return Random key in @self.
202
+ """
203
+
204
+ keys random
205
+ }
206
+
207
+ def random_value {
208
+ """
209
+ @return Random value in @self.
210
+ """
211
+
212
+ values random
213
+ }
214
+
215
+ def random {
216
+ """
217
+ @return Random value in @self.
218
+
219
+ Same as @Hash#random_value@.
220
+ """
221
+
222
+ random_value
223
+ }
224
+
225
+ def call: receiver {
226
+ """
227
+ @receiver Receiver to apply @self to.
228
+ @return @receiver.
229
+
230
+ Sends each key-value pair as a message (with one argument) to @receiver.
231
+
232
+ Example:
233
+ Person = Struct new: ('firstname, 'lastname)
234
+ p = Person new
235
+ <['firstname => \"Tom\", 'lastname => \"Cruise\"]> call: [p]
236
+
237
+ p firstname # => \"Tom\"
238
+ p lastname # => \"Cruise\"
239
+ """
240
+
241
+ to_block call: receiver
242
+ }
243
+
244
+ def to_hash_deep {
245
+ h = dup
246
+ h each: |k v| {
247
+ match v {
248
+ case Block -> h[k]: $ v to_hash_deep
249
+ }
250
+ }
251
+ h
252
+ }
253
+
254
+ def to_block {
255
+ """
256
+ @return @Block@ that sends each key-value pair in @self as a message (with one argument) to its argument.
257
+
258
+ Example:
259
+ <['x => 100, 'y => 150]> to_block
260
+ # would be the same as:
261
+ |receiver| {
262
+ receiver tap: @{
263
+ x: 100
264
+ y: 150
265
+ }
266
+ }
267
+ """
268
+
269
+ |receiver| {
270
+ each: |k v| {
271
+ match k to_s {
272
+ case /:/ -> receiver receive_message: k with_params: [v]
273
+ case _ -> receiver receive_message: "#{k}:" with_params: [v]
274
+ }
275
+ }
276
+ receiver
277
+ }
278
+ }
166
279
  }
@@ -21,11 +21,10 @@ class Integer {
21
21
  """
22
22
  @block @Block@ to be called and retries @self amount of times if exceptions get thrown.
23
23
  @retry_block @Block@ to be called before retrying execution of @block. Defaults to an empty @Block@.
24
- @return Return value of calling @block or raises an exception after @self tries.
25
- Returns @nil if @self <= 0.
24
+ @return Return value of calling @block or raises an exception after @self tries. Returns @nil if @self <= 0.
26
25
 
27
26
  Tries to call a @Block@ @self amount of times, returning its return
28
- value or raising the last exception raised frin @block after @self tries.
27
+ value or raising the last exception raised from @block after @self tries.
29
28
 
30
29
  Example:
31
30
  2 times_try: {
@@ -41,13 +40,33 @@ class Integer {
41
40
  value = nil
42
41
  try {
43
42
  value = block call: [max_retries]
44
- } catch Exception => e {
43
+ } catch StandardError => e {
45
44
  max_retries = max_retries - 1
46
45
  { e raise! } unless: $ max_retries > 0
47
46
  retry_block call
48
47
  retry
49
- } finally {
50
- return value
51
48
  }
49
+ value
50
+ }
51
+
52
+ def decimals {
53
+ """
54
+ @return @Array@ of all decimals of @self.
55
+
56
+ Returns all decimals of an Integer as an Array.
57
+
58
+ Example:
59
+ 100 decimals # => [1, 0, 0]
60
+ 12345 decimals # => [1, 2, 3, 4, 5]
61
+ """
62
+
63
+ decimals = []
64
+ tmp = self
65
+ while: { tmp >= 10 } do: {
66
+ decimals << (tmp modulo: 10)
67
+ tmp = tmp div: 10
68
+ }
69
+ decimals << tmp
70
+ decimals reverse
52
71
  }
53
72
  }
@@ -22,7 +22,7 @@ class Fancy {
22
22
  """
23
23
 
24
24
  read_slots: ['result]
25
- def initialize: @result {}
25
+ def initialize: @result
26
26
  }
27
27
 
28
28
  class NextIteration : StdError {
@@ -32,7 +32,7 @@ class Fancy {
32
32
  """
33
33
 
34
34
  read_slots: ['result]
35
- def initialize: @result {}
35
+ def initialize: @result
36
36
  }
37
37
 
38
38
  class StopIteration : StdError {
@@ -54,7 +54,7 @@ class Fancy {
54
54
  """
55
55
 
56
56
  def initialize { @result = nil }
57
- def initialize: @result { }
57
+ def initialize: @result
58
58
 
59
59
  def result {
60
60
  """
@@ -21,6 +21,7 @@ if: (ARGV size == 1) then: {
21
21
  " -e 'command' One line of Fancy code that gets evaluated immediately",
22
22
  " -c [filenames] Compile given files to Rubinius bytecode",
23
23
  " -cv [filenames] Compile given files to Rubinius bytecode verbosely (outputting the generated bytecode)",
24
+ " -debug Start the Rubinius Debugger with Fancy",
24
25
  "",
25
26
  "Fancy package management:",
26
27
  " install [packagename] Install a Fancy package with a given name to $FANCYPACK_DIR",
@@ -65,6 +66,10 @@ ARGV for_option: "-cv" do: {
65
66
  System exit
66
67
  }
67
68
 
69
+ ARGV for_option: "-debug" do: {
70
+ require: "rbx/debugger"
71
+ }
72
+
68
73
  ARGV for_option: "install" do: |package_name| {
69
74
  match package_name {
70
75
  case "--deps" -> Fancy Package install_dependencies
@@ -0,0 +1,79 @@
1
+ class Matchers {
2
+ class MatchAny {
3
+ """
4
+ MatchAny matcher. Matches any of the 2 values associated with it.
5
+
6
+ Example:
7
+ m = MatchAny new: 1 with: 2
8
+ m === 1 # => true
9
+ m === 2 # => true
10
+
11
+ There's also a shorthand method defined with @Object#><@:
12
+
13
+ Example:
14
+ m = 1 >< 2
15
+ m === 1 # => true
16
+ m === 2 # => true
17
+ """
18
+
19
+ read_slots: ('a, 'b)
20
+ def initialize: @a with: @b
21
+
22
+ def === object {
23
+ """
24
+ @other Object to match against.
25
+ @return @true if @objects matches either @a or @b in @self.
26
+ """
27
+
28
+ if: (@a === object) then: @{ return } else: {
29
+ @b === object
30
+ }
31
+ }
32
+
33
+ expose_to_ruby: '===
34
+
35
+ def == other {
36
+ match other {
37
+ case MatchAny -> @a == (other a) && { @b == (other b)}
38
+ case _ -> false
39
+ }
40
+ }
41
+ }
42
+
43
+ class MatchAll {
44
+ """
45
+ MatchAll matcher. Matches only if all of the 2 values associated with it match a given value.
46
+
47
+ Example:
48
+ m = MatchAll new: Array with: Enumerable
49
+ m === \"foo\" # => false
50
+ m === [1,2,3] # => true
51
+
52
+ There's also a shorthand method defined with @Object#<>@:
53
+
54
+ Example:
55
+ (Array <> Enumerable) === [1,2,3] # => true
56
+ """
57
+
58
+ read_slots: ('a, 'b)
59
+ def initialize: @a with: @b
60
+
61
+ def === object {
62
+ """
63
+ @object Object to match against.
64
+ @return @true if it matches both @a and @b in @self.
65
+ """
66
+
67
+ if: (@a === object) then: { @b === object }
68
+ }
69
+
70
+ expose_to_ruby: '===
71
+
72
+ def == other {
73
+ match other {
74
+ case MatchAll -> @a == (other a) && { @b == (other b)}
75
+ case _ -> nil
76
+ }
77
+ }
78
+ }
79
+ }
@@ -79,6 +79,14 @@ class NilClass {
79
79
  []
80
80
  }
81
81
 
82
+ def to_hash {
83
+ """
84
+ @return An empty @Hash@.
85
+ """
86
+
87
+ <[]>
88
+ }
89
+
82
90
  def not {
83
91
  """
84
92
  @return @true.
@@ -355,9 +355,9 @@ class Object {
355
355
 
356
356
  def if_responds? {
357
357
  """
358
- @return RespondsToProxy for @self
358
+ @return @Proxies::RespondsToProxy@ for @self
359
359
 
360
- Returns a @RespondsToProxy@ for @self that forwards any messages
360
+ Returns a @Proxies::RespondsToProxy@ for @self that forwards any messages
361
361
  only if @self responds to them.
362
362
 
363
363
  Example:
@@ -365,7 +365,7 @@ class Object {
365
365
  object if_responds? some_message: some_parameter
366
366
  """
367
367
 
368
- RespondsToProxy new: self
368
+ Proxies RespondsToProxy new: self
369
369
  }
370
370
 
371
371
  def backtick: str {
@@ -466,7 +466,7 @@ class Object {
466
466
  val = self receive_message: msg with_params: params
467
467
  sender completed: val
468
468
  }
469
- } catch Exception => e {
469
+ } catch StandardError => e {
470
470
  { sender failed: e } if: sender
471
471
  die!
472
472
  e raise!
@@ -585,15 +585,10 @@ class Object {
585
585
  """
586
586
 
587
587
  metaclass read_write_slots: slotnames
588
- val = nil
589
588
  try {
590
- val = block call: [self]
589
+ return block call: [self]
591
590
  } finally {
592
- slotnames each: |s| {
593
- metaclass undefine_method: s
594
- metaclass undefine_method: "#{s}:"
595
- }
596
- return val
591
+ metaclass remove_slot_accessors_for: slotnames
597
592
  }
598
593
  }
599
594
  private: 'with_mutable_slots:do:
@@ -627,9 +622,21 @@ class Object {
627
622
  some_complex_object method_1: arg1
628
623
  some_complex_object method_2: arg2
629
624
  some_complex_object method_3: arg3
625
+
626
+ If you pass it a block with 1 argument this method behaves exactly like @Object#tap:@
627
+
628
+ Example:
629
+ some_complex_object do: @{
630
+ method_1: arg1
631
+ method_2: arg2
632
+ method_3: arg3
633
+ }
630
634
  """
631
635
 
632
- block call_with_receiver: self
636
+ match block arity {
637
+ case 0 -> block call_with_receiver: self
638
+ case _ -> block call: [self]
639
+ }
633
640
  self
634
641
  }
635
642
 
@@ -663,14 +670,17 @@ class Object {
663
670
  Thread sleep: seconds
664
671
  }
665
672
 
666
- def let: var_name be: value in: block (nil) {
673
+ def let: var_name be: value in: block (nil) ensuring: ensure_block ({}) {
667
674
  """
668
675
  @var_name @Symbol@ that represents the name of the dynamic variable to be set.
669
676
  @value Value for the variable.
670
677
  @block @Block@ in which @var_name will be dynamically bound to @value.
678
+ @ensure_block @Block@ to be always called, even when @block raised an exception.
671
679
  @return Returns @value
672
680
 
673
681
  Dynamically rebinds @var_name as dynamic variable with @value as the value within @block.
682
+ Exceptions raised within @ensure_block are ignored.
683
+ Those raised in @block will be reraised up the callstack.
674
684
 
675
685
  Example:
676
686
  File write: \"/tmp/output.txt\" with: |f| {
@@ -687,15 +697,13 @@ class Object {
687
697
  }
688
698
 
689
699
  oldval = Thread current[var_name]
690
- retval = nil
691
700
  try {
692
701
  Thread current[var_name]: value
693
- retval = block call
694
- } catch Exception => e {
695
- e raise!
702
+ block call
703
+ return value
696
704
  } finally {
705
+ try { ensure_block call } catch {}
697
706
  Thread current[var_name]: oldval
698
- return retval
699
707
  }
700
708
  }
701
709
 
@@ -721,4 +729,87 @@ class Object {
721
729
  let: '*stdout* be: f in: block
722
730
  }
723
731
  }
732
+
733
+ def fancy_methods {
734
+ """
735
+ @return @Array@ of all class methods defined in Fancy.
736
+ """
737
+
738
+ methods select: @{ includes?: ":" }
739
+ }
740
+
741
+ def ruby_methods {
742
+ """
743
+ @return @Array@ of all class methods defined in Ruby.
744
+ """
745
+
746
+ methods - fancy_methods
747
+ }
748
+
749
+ def >< other {
750
+ """
751
+ @other Other @Object@ to create a @MatchAny@ matcher with.
752
+
753
+ Shorthand for: `MatchAny new: self with: other`
754
+ """
755
+
756
+ Matchers MatchAny new: self with: other
757
+ }
758
+
759
+ def <> other {
760
+ """
761
+ @other Other @Object@ to create a @MatchAll@ matcher with.
762
+
763
+ Shorthand for: `MatchAll new: self with: other`
764
+ """
765
+
766
+ Matchers MatchAll new: self with: other
767
+ }
768
+
769
+ def ignoring: exception_classes do: block {
770
+ """
771
+ @exception_classes @Fancy::Enumerable@ of @Exception@s to ignore within @block.
772
+ @block @Block@ to be executed while ignoring (catching but not handling) @Exception@s defined in @exception_classes.
773
+
774
+ Example:
775
+ ignoring: (IOError, ZeroDivisionError) in: {
776
+ # do something
777
+ }
778
+ """
779
+
780
+ try {
781
+ block call
782
+ } catch (exception_classes to_a join_by: '><) {}
783
+ }
784
+
785
+ def rebind_method: method_name with: rebind_callable within: within_block {
786
+ """
787
+ @method_name Name of (singleton) method to rebind for @self.
788
+ @rebind_callable Name of method or @Block@ to rebind @method_name to.
789
+ @within_block @Block@ in which @method_name is rebound to @rebind_callable.
790
+ @return Value of calling @within_block with @self.
791
+
792
+ If @within_block takes an argument, it is called with @self.
793
+
794
+ Example:
795
+ class MyRebindableClass {
796
+ def foo {
797
+ 42
798
+ }
799
+ }
800
+
801
+ r = MyRebindableClass new
802
+ r rebind_method: 'foo with: { 0 } within: @{ foo } # => 0
803
+ """
804
+
805
+ metaclass rebind_instance_method: method_name with: rebind_callable within: within_block receiver: self
806
+ }
807
+
808
+ def _ {
809
+ """
810
+ @return @Object@.
811
+ """
812
+
813
+ Object
814
+ }
724
815
  }