fancy 0.7.0 → 0.8.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.
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
  }