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
@@ -1,15 +1,15 @@
1
1
  # blocks.fy
2
2
  # Examples of fancy code blocks
3
3
 
4
- x = { Console println: "Println from within block!" }
4
+ x = { "Println from within block!" println }
5
5
  x call # calls x and prints: "Println from within block!"
6
6
 
7
- y = |x y| { Console println: $ x + y }
7
+ y = |x y| { x + y println }
8
8
  y call: [2, 3] # calls y and prints: 5
9
9
 
10
10
  # prints numbers 0 to 20
11
11
  num = 0
12
12
  while: { num <= 20 } do: {
13
- Console println: num
13
+ num println
14
14
  num = num + 1
15
15
  }
@@ -0,0 +1,31 @@
1
+ class Worker {
2
+ def initialize: @name supervisor: @supervisor
3
+ def work! {
4
+ Thread sleep: 0.5
5
+ @supervisor @@ done: @name
6
+ }
7
+ }
8
+
9
+ class Supervisor {
10
+ def initialize: @amount {
11
+ @done = []
12
+ @workers = Proxies DistributingProxy new: $ (1..@amount) map: |i| { Worker new: i supervisor: self }
13
+ }
14
+
15
+ def start {
16
+ "Starting: #{(0..@amount) to_a inspect}" println
17
+ @amount times: {
18
+ @workers @@ work!
19
+ }
20
+ }
21
+
22
+ def done: worker {
23
+ @done << worker
24
+ if: (@done size == @amount) then: {
25
+ "Done: #{@done inspect}" println
26
+ }
27
+ }
28
+ }
29
+
30
+ Supervisor new: 10 . start
31
+ Console readln
@@ -0,0 +1,15 @@
1
+ class Bar {
2
+ def foo {
3
+ Thread sleep: 5
4
+ 42
5
+ }
6
+ }
7
+
8
+ b = Bar new
9
+ f = b @ foo timeouts: <[
10
+ 3.5 => { "3.5 secs passed!" println; System abort: "Timeout" }
11
+ ]>
12
+
13
+ f value inspect println
14
+
15
+ Console readln: "..."
@@ -3,8 +3,7 @@
3
3
 
4
4
  class City {
5
5
  read_slot: 'name
6
- def initialize: @name {
7
- }
6
+ def initialize: @name
8
7
 
9
8
  def to_s {
10
9
  "City: " ++ @name
@@ -38,10 +38,4 @@ def ARGV for_options: op_names do: block {
38
38
  return true
39
39
  }
40
40
  }
41
- }
42
-
43
- def ARGV main?: filename {
44
- if: (ARGV[0]) then: {
45
- File expand_path: (ARGV[0]) . == filename
46
- }
47
- }
41
+ }
@@ -98,22 +98,18 @@ class Array {
98
98
  def each: block {
99
99
  """
100
100
  @block @Block@ to be called for each element in @self.
101
- @return @self
101
+ @return @self.
102
102
 
103
103
  Calls a given @Block@ with each element in the @Array@.
104
104
  """
105
105
 
106
- try {
107
- size times: |i| {
108
- try {
109
- block call: [at: i]
110
- } catch (Fancy NextIteration) => ex {
111
- }
106
+ size times: |i| {
107
+ try {
108
+ block call: [at: i]
109
+ } catch Fancy NextIteration {
112
110
  }
113
- return self
114
- } catch (Fancy BreakIteration) => ex {
115
- ex result
116
111
  }
112
+ self
117
113
  }
118
114
 
119
115
  def reverse_each: block {
@@ -375,7 +371,7 @@ class Array {
375
371
  def from: from to: to {
376
372
  """
377
373
  @from Start index for sub-array.
378
- @to End index ofr sub-array.
374
+ @to End index for sub-array.
379
375
 
380
376
  Returns sub-array starting at from: and going to to:
381
377
  """
@@ -203,4 +203,19 @@ class Block {
203
203
 
204
204
  DynamicValueArray new do: self . array
205
205
  }
206
+
207
+ def * iterations {
208
+ """
209
+ @iterations @Fixnum@ of amount of iterations to run @self.
210
+
211
+ Runs @self @iteration times.
212
+ Same as: `iterations times: self`
213
+
214
+ Example:
215
+ { \"Hello, World\" println } * 2
216
+ # => prints \"Hello, World\" 2 times
217
+ """
218
+
219
+ iterations times: self
220
+ }
206
221
  }
@@ -18,6 +18,7 @@ require: "class"
18
18
  require: "true_class"
19
19
  require: "nil_class"
20
20
  require: "false_class"
21
+ require: "exception"
21
22
  require: "number"
22
23
  require: "enumerable"
23
24
  require: "string"
@@ -35,8 +36,7 @@ require: "hash"
35
36
  require: "set"
36
37
  require: "symbol"
37
38
  require: "stack"
38
- require: "proxy"
39
- require: "thread_pool"
39
+ require: "proxies"
40
40
  require: "fiber"
41
41
  require: "future"
42
42
  require: "struct"
@@ -50,5 +50,6 @@ require: "vars"
50
50
  require: "system"
51
51
 
52
52
  require: "documentation"
53
-
54
53
  require: "package"
54
+ require: "contracts"
55
+ require: "matchers"
@@ -8,6 +8,112 @@ class Class {
8
8
 
9
9
  forwards_unary_ruby_methods
10
10
 
11
+ alias_method: '__private__: for: 'private:
12
+ alias_method: '__protected__: for: 'protected:
13
+ alias_method: '__public__: for: 'public:
14
+
15
+ def private: private_methods {
16
+ """
17
+ @private_methods @Block@ or @Fancy::Enumerable@ of method names to be private.
18
+
19
+ Sets any given method names to private on this @Class@.
20
+
21
+ Example:
22
+ class MyClass {
23
+ def foo {}
24
+ def bar {}
25
+
26
+ private: 'foo
27
+ private: 'bar
28
+
29
+ # same as:
30
+ private: ('foo, 'bar)
31
+
32
+ # same as:
33
+ private: {
34
+ def foo {}
35
+ def bar {}
36
+ }
37
+ }
38
+ """
39
+
40
+ __private__: $ match private_methods {
41
+ case Block ->
42
+ methods = instance_methods: false
43
+ private_methods call
44
+ instance_methods: false - methods
45
+ case _ -> private_methods
46
+ }
47
+ }
48
+
49
+ def protected: protected_methods {
50
+ """
51
+ @protected_methods @Block@ or @Fancy::Enumerable@ of method names to be protected.
52
+
53
+ Sets any given method names to protected on this @Class@.
54
+
55
+ Example:
56
+ class MyClass {
57
+ def foo {}
58
+ def bar {}
59
+
60
+ protected: 'foo
61
+ protected: 'bar
62
+
63
+ # same as:
64
+ protected: ('foo, 'bar)
65
+
66
+ # same as:
67
+ protected: {
68
+ def foo {}
69
+ def bar {}
70
+ }
71
+ }
72
+ """
73
+
74
+ __protected__: $ match protected_methods {
75
+ case Block ->
76
+ methods = instance_methods: false
77
+ protected_methods call
78
+ instance_methods: false - methods
79
+ case _ -> protected_methods
80
+ }
81
+ }
82
+
83
+ def public: public_methods {
84
+ """
85
+ @public_methods @Block@ or @Fancy::Enumerable@ of method names to be public.
86
+
87
+ Sets any given method names to public on this @Class@.
88
+
89
+ Example:
90
+ class MyClass {
91
+ def foo {}
92
+ def bar {}
93
+
94
+ public: 'foo
95
+ public: 'bar
96
+
97
+ # same as:
98
+ public: ('foo, 'bar)
99
+
100
+ # same as:
101
+ public: {
102
+ def foo {}
103
+ def bar {}
104
+ }
105
+ }
106
+ """
107
+
108
+ __public__: $ match public_methods {
109
+ case Block ->
110
+ methods = instance_methods: false
111
+ public_methods call
112
+ instance_methods: false - methods
113
+ case _ -> public_methods
114
+ }
115
+ }
116
+
11
117
  def define_slot_reader: slotname {
12
118
  """
13
119
  @slotname Name of the slot to define a getter method for.
@@ -125,6 +231,23 @@ class Class {
125
231
  }
126
232
  }
127
233
 
234
+ def remove_slot_accessors_for: slotnames {
235
+ """
236
+ @slotnames Name of slot or @Array@ of slotnames to remove accessor methods for.
237
+
238
+ Removes both reader and writer methods for slots in @slotnames.
239
+ """
240
+
241
+ slotnames to_a each: |s| {
242
+ try {
243
+ undefine_method: s
244
+ } catch NameError {}
245
+ try {
246
+ undefine_method: "#{s}:"
247
+ } catch NameError {}
248
+ }
249
+ }
250
+
128
251
  def subclass?: class_obj {
129
252
  """
130
253
  @class_obj Class object to check for, if @self is a subclass of @class_obj.
@@ -193,16 +316,11 @@ class Class {
193
316
  }
194
317
  }
195
318
 
196
- mdef = "def #{message_with_args}"
197
-
198
- mdef << " {\n"
199
- mdef << "@#{slotname} #{message_with_args}"
200
-
201
- mdef << "\n}"
202
-
203
- class_eval: {
204
- mdef eval
319
+ class_eval: """
320
+ def #{message_with_args} {
321
+ @#{slotname} #{message_with_args}
205
322
  }
323
+ """
206
324
  }
207
325
  }
208
326
 
@@ -221,4 +339,230 @@ class Class {
221
339
  name
222
340
  }
223
341
  }
224
- }
342
+
343
+ def fancy_instance_methods {
344
+ """
345
+ @return @Array@ of all instance methods defined in Fancy.
346
+ """
347
+
348
+ instance_methods select: @{ includes?: ":" }
349
+ }
350
+
351
+ def ruby_instance_methods {
352
+ """
353
+ @return @Array@ of all instance methods defined in Ruby.
354
+ """
355
+
356
+ instance_methods - fancy_instance_methods
357
+ }
358
+
359
+ # dummy methods, get replaced at end of startup in lib/contracts.fy
360
+ def provides_interface: methods {
361
+ @provided_interface_methods = @provided_interface_methods to_a append: (methods to_a)
362
+ }
363
+
364
+ def expects_interface_on_inclusion: methods {
365
+ @expected_interface_methods = methods to_a
366
+ }
367
+ alias_method: 'expects_interface: for: 'expects_interface_on_inclusion:
368
+
369
+ def before_method: method_name run: block_or_method_name {
370
+ """
371
+ @method_name Name of @Method@ to run another @Method@ or @Block@ before, when called.
372
+ @block_or_method_name @Block@ or name of other @Method@ to be called before @method_name.
373
+
374
+ Runs / Calls @block_or_method everytime before running @method_name.
375
+
376
+ Example:
377
+ Array before_method: 'inspect run: 'compact!
378
+ [1, nil, 2, nil, 3] inspect # => \"[1, 2, 3]\"
379
+
380
+ # Or pass a Block:
381
+ Array before_method: 'inspect run: @{ compact! }
382
+ """
383
+
384
+ define_calling_chain: [block_or_method_name, method_name] for_method: method_name
385
+ }
386
+
387
+ def after_method: method_name run: block_or_method_name {
388
+ """
389
+ @method_name Name of @Method@ to run another @Method@ or @Block@ after, when called.
390
+ @block_or_method_name @Block@ or name of other @Method@ to be called after @method_name.
391
+
392
+ Runs / Calls @block_or_method_name everytime after running @method_name.
393
+
394
+ Example:
395
+ Array after_method: 'inspect run: 'compact!
396
+ x = [1, nil, 2, nil, 3]
397
+ x inspect # => \"[1, nil, 2, nil, 3]\"
398
+ x inspect # => \"[1, 2, 3]\"
399
+
400
+ # Or pass a Block:
401
+ Array after_method: 'inspect run: @{ compact! }
402
+ """
403
+
404
+ define_calling_chain: [method_name, block_or_method_name] for_method: method_name
405
+ }
406
+
407
+ def around_method: method_name run: block_or_method_name {
408
+ """
409
+ @method_name Name of @Method@ to run another @Method@ or @Block@ before & after, when called.
410
+ @block_or_method_name @Block@ or name of other @Method@ to be called before & after @method_name.
411
+
412
+ Runs / Calls @block_or_method_name everytime before & after running @method_name.
413
+
414
+ Example:
415
+ class MyController {
416
+ def do_stuff {
417
+ \"Doing stuff\" println
418
+ }
419
+
420
+ def log_data {
421
+ \"Log data\" println
422
+ }
423
+
424
+ around_method: 'do_stuff run: 'log_data
425
+ }
426
+
427
+ controller = MyController new
428
+ controller do_stuff
429
+
430
+ # which will print:
431
+ # Log data
432
+ # Doing stuff
433
+ # Log data
434
+
435
+ # Or pass a Block:
436
+ MyController around_method: 'do_stuff run: { \"Log data\" println }
437
+ """
438
+
439
+ define_calling_chain: [block_or_method_name, method_name, block_or_method_name] for_method: method_name
440
+ }
441
+
442
+ def define_calling_chain: blocks_or_method_names for_method: method_name {
443
+ """
444
+ @blocks_or_method_names @Array@ of either method names or @Block@s to be called in order.
445
+ @method_name Name of method to define calling chain for.
446
+
447
+ Example:
448
+ class Foo {
449
+ def foo { 'foo println }
450
+ def bar { 'bar println }
451
+ def baz { 'baz println }
452
+
453
+ define_calling_chain: ['foo, 'bar, 'baz] for_method: 'foo
454
+ }
455
+
456
+ Foo new foo
457
+ # prints:
458
+ # foo
459
+ # bar
460
+ # baz
461
+
462
+ # You can also pass in Blocks:
463
+ Foo define_calling_chain: [@{ foo }, @{ bar }, @{ baz }] for_method: 'bar
464
+
465
+ Foo new bar
466
+ # prints:
467
+ # foo
468
+ # bar
469
+ # baz
470
+ """
471
+
472
+ # optimize for methods if all arguments are symbols (generate code instead of using dynamic #call: messages)
473
+ if: (blocks_or_method_names all?: @{ is_a?: Symbol }) then: {
474
+ return define_method_calling_chain: blocks_or_method_names for_method: method_name
475
+ }
476
+
477
+ method = instance_method: method_name
478
+
479
+ define_method: (method_name message_name) with: |args1| {
480
+ bound_method = method bind(self)
481
+
482
+ new_method_body = |args2| {
483
+ match bound_method arity {
484
+ case 0 -> args2 = []
485
+ case 1 -> args2 = [args2]
486
+ }
487
+
488
+ args_with_self = args2 dup unshift: self
489
+ return_val = nil
490
+ blocks_or_method_names each: |block| {
491
+ match block {
492
+ case method_name -> return_val = bound_method call: args2
493
+ case _ -> block call: args_with_self
494
+ }
495
+ }
496
+ return_val
497
+ }
498
+
499
+ # define new method body and run it afterwards as we lazily
500
+ # define the method the first time it's called for each new
501
+ # instance of this class
502
+ metaclass define_method: (method_name message_name) with: new_method_body
503
+
504
+ match method arity {
505
+ case 0 -> args1 = []
506
+ case 1 -> args1 = [args1]
507
+ }
508
+
509
+ new_method_body call: args1
510
+ }
511
+ }
512
+
513
+ def define_method_calling_chain: method_names for_method: method_name {
514
+ orig_method_name = "__original__#{method_name}"
515
+ alias_method: orig_method_name for: (method_name message_name)
516
+
517
+ method = instance_method: (method_name message_name)
518
+ orig_method = instance_method: orig_method_name
519
+
520
+ before_methods = method_names take_while: |m| { m != method_name }
521
+ _orig_method, *after_methods = method_names drop_while: |m| { m != method_name }
522
+
523
+ before_methods = before_methods map: |m| { instance_method: m . selector_with_args } . join: ";"
524
+ after_methods = after_methods map: |m| { instance_method: m . selector_with_args } . join: ";"
525
+
526
+ class_eval: """
527
+ def #{method selector_with_args} {
528
+ #{before_methods}
529
+ return_val = #{orig_method selector_with_args}
530
+ #{after_methods}
531
+ return_val
532
+ }
533
+ """
534
+ }
535
+
536
+ def rebind_instance_method: method_name with: rebind_callable within: within_block receiver: receiver (self) {
537
+ """
538
+ @method_name Name of instance method to rebind in @self.
539
+ @rebind_callable Name of method or @Block@ to rebind @method_name to.
540
+ @within_block @Block@ to be called with @receiver or @self.
541
+ @receiver Argument to @within_block. Defaults to @self.
542
+ @return Value of calling @within_block with @receiver.
543
+
544
+ Rebinds @method_name to @rebind_callable within @within_block.
545
+ If @within_block takes an argument, it will be called with @receiver (defaults to @self).
546
+ """
547
+
548
+ try {
549
+ old_method = nil
550
+ try {
551
+ old_method = instance_method: method_name
552
+ } catch NameError {}
553
+
554
+ match rebind_callable {
555
+ case Symbol -> alias_method: method_name for: rebind_callable
556
+ case _ -> define_method: method_name with: rebind_callable
557
+ }
558
+
559
+ return within_block call: [receiver]
560
+ } finally {
561
+ if: old_method then: {
562
+ define_method: method_name with: old_method
563
+ } else: {
564
+ undefine_method: method_name
565
+ }
566
+ }
567
+ }
568
+ }