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
@@ -0,0 +1,51 @@
1
+ FancySpec describe: Class Contracts with: {
2
+ it: "fails inclusion" when: {
3
+ {
4
+ class A {
5
+ include: Fancy Enumerable
6
+ }
7
+ } raises: Class Contracts InterfaceNotImplementedError
8
+ }
9
+
10
+ it: "doesn't fail inclusion" when: {
11
+ {
12
+ class A {
13
+ def each: block
14
+ include: Fancy Enumerable
15
+ }
16
+ } does_not raise: Class Contracts InterfaceNotImplementedError
17
+
18
+ {
19
+ class B {
20
+ provides_interface: 'each:
21
+ include: Fancy Enumerable
22
+ }
23
+ } does_not raise: Class Contracts InterfaceNotImplementedError
24
+ }
25
+
26
+ it: "returns the amount of not implemented interface methods" with: 'missing_methods_for_interface: when: {
27
+ class Interface {
28
+ expects_interface_on_inclusion: ['hello, 'world]
29
+ }
30
+ {
31
+ class C {
32
+ include: Interface
33
+ }
34
+ } raises: Class Contracts InterfaceNotImplementedError with: |e| {
35
+ e methods is: ['hello, 'world]
36
+ e interface is: Interface
37
+ e including_class is: C
38
+ }
39
+
40
+ {
41
+ class D {
42
+ def hello
43
+ include: Interface
44
+ }
45
+ } raises: Class Contracts InterfaceNotImplementedError with: |e| {
46
+ e methods is: ['world]
47
+ e interface is: Interface
48
+ e including_class is: D
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,28 @@
1
+ FancySpec describe: Proxies DistributingProxy with: {
2
+ it: "forwards messages to each element in turn" when: {
3
+ p = Proxies DistributingProxy new: [1,2,3]
4
+ p is: 1
5
+ p is: 2
6
+ p is: 3
7
+ # and again
8
+ p is: 1
9
+ p is: 2
10
+ p is: 3
11
+ # and once more
12
+ p class is: Fixnum
13
+ p inspect is: "2"
14
+ p to_s is: "3"
15
+ }
16
+
17
+ it: "waits appropriately if all elements are currently in use" when: {
18
+ p = Proxies DistributingProxy new: ["foo", "bar", "baz"]
19
+ results = []
20
+ threads = (1..10) map: |i| {
21
+ Thread new: {
22
+ results << (i, p * 2)
23
+ }
24
+ }
25
+ threads each: @{ join }
26
+ results size is: 10
27
+ }
28
+ }
@@ -44,11 +44,114 @@ FancySpec describe: Fancy Enumerable with: {
44
44
  [] to_s is: ""
45
45
 
46
46
  class MyCollection {
47
- include: Fancy Enumerable
48
47
  def each: block {
49
48
  (0..5) each: block
50
49
  }
50
+ include: Fancy Enumerable
51
51
  }
52
52
  MyCollection new to_s is: "012345"
53
53
  }
54
+
55
+ it: "returns the array in groups of 3" with: 'in_groups_of: when: {
56
+ ['a,'b,'c] in_groups_of: 1 . is: [['a],['b],['c]]
57
+ array = 1 upto: 10
58
+ array in_groups_of: 3 . is: [[1,2,3], [4,5,6], [7,8,9], [10]]
59
+
60
+ (20,30,40) in_groups_of: 2 . is: [[20,30], [40]]
61
+
62
+ [1,2,3] in_groups_of: -1 . is: []
63
+ [1,2,3] in_groups_of: 0 . is: []
64
+ [1,2,3] in_groups_of: 1 . is: [[1],[2],[3]]
65
+
66
+ [] in_groups_of: -1 . is: []
67
+ [] in_groups_of: 0 . is: []
68
+ [] in_groups_of: 1 . is: []
69
+ }
70
+
71
+ it: "indicates if it's sorted" with: 'sorted? when: {
72
+ [] sorted? is: true
73
+ [1] sorted? is: true
74
+ [1,2] sorted? is: true
75
+ [2,1] sorted? is: false
76
+
77
+ (1,2,3) sorted? is: true
78
+ (1,3,2) sorted? is: false
79
+
80
+ "" sorted? is: true
81
+ "a" sorted? is: true
82
+ "abc" sorted? is: true
83
+ "fabc" sorted? is: false
84
+ }
85
+
86
+ it: "splits a collection at an index" with: 'split_at: when: {
87
+ [] split_at: 0 . is: [[],[]]
88
+ [1] split_at: 0 . is: [[],[1]]
89
+ [1] split_at: 1 . is: [[1],[]]
90
+
91
+ (1,2,3) split_at: 1 . is: [[1], [2,3]]
92
+ (1,2,3) split_at: 2 . is: [[1,2], [3]]
93
+
94
+ "foo" split_at: 1 . is: [["f"], ["o", "o"]]
95
+ }
96
+
97
+ it: "splits a collection based on a predicate block" with: 'split_with: when: {
98
+ [] split_with: @{ true } . is: [[],[]]
99
+ [] split_with: @{ false } . is: [[],[]]
100
+ [1] split_with: @{ true } . is: [[1], []]
101
+ [1] split_with: @{ false } . is: [[], [1]]
102
+ [1,2,3] split_with: @{ < 2 } . is: [[1], [2,3]]
103
+ [1,2,3] split_with: @{ <= 2 } . is: [[1,2], [3]]
104
+
105
+ "" split_with: @{ true } . is: [[], []]
106
+ "a" split_with: @{ true } . is: [["a"], []]
107
+ "a" split_with: @{ false } . is: [[], ["a"]]
108
+ "abcde" split_with: @{ <= "c" } . is: [["a", "b", "c"], ["d", "e"]]
109
+ }
110
+
111
+ it: "takes elements from itself as long a block yields true" with: 'take_while: when: {
112
+ (1..15) take_while: |x| { x < 10 } . is: (1 upto: 9)
113
+ }
114
+
115
+ it: "drops elements from itself as long a block yields true" with: 'drop_while: when: {
116
+ (1..15) drop_while: |x| { x < 10 } . is: (10 upto: 15)
117
+ }
118
+
119
+ it: "returns the first n elements" with: 'first: when: {
120
+ (1,2,3) first: 0 . is: []
121
+ (1,2,3) first: 1 . is: [1]
122
+ (1,2,3) first: 2 . is: [1,2]
123
+ (1,2,3) first: 3 . is: [1,2,3]
124
+ (1,2,3) first: 4 . is: [1,2,3]
125
+ }
126
+
127
+ it: "returns the last n elements" with: 'last: when: {
128
+ (1,2,3) last: 0 . is: []
129
+ (1,2,3) last: 1 . is: [3]
130
+ (1,2,3) last: 2 . is: [2,3]
131
+ (1,2,3) last: 3 . is: [1,2,3]
132
+ (1,2,3) last: 4 . is: [1,2,3]
133
+ }
134
+
135
+ it: "returns the elements for which a pattern matches" with: 'grep: when: {
136
+ "hello world" grep: /[a-h]/ . is: ["h", "e", "d"]
137
+ ["hello", "world", 1, 2, 3] grep: String . is: ["hello", "world"]
138
+ (1,2,3,4,5) grep: @{ < 2 } . is: [1] # blocks can be used as patterns, too :)
139
+ (1,2,3) grep: String . is: []
140
+ (1,2,3,4) grep: (2..3) . is: [2, 3]
141
+ }
142
+
143
+ it: "returns the values of calling a block for all elements for which a pattern matches" with: 'grep:taking: when: {
144
+ "hello world" grep: /[a-h]/ taking: 'upcase . is: ["H", "E", "D"]
145
+ ["hello", "world", 1, 2, 3] grep: String taking: 'upcase . is: ["HELLO", "WORLD"]
146
+ (1,2,3,4,5) grep: @{ < 2 } taking: 'doubled . is: [2]
147
+ (1,2,3) grep: String taking: 'to_s . is: []
148
+ (1,2,3,4) grep: (2..3) taking: 'to_s . is: ["2", "3"]
149
+ }
150
+
151
+ it: "joins all elements by a block" with: 'join_by: when: {
152
+ (1,2,3) join_by: '+ . is: $ (1,2,3) sum
153
+ ("foo", "bar", "baz") join_by: '+ . is: "foobarbaz"
154
+ [NoMethodError, IOError, ZeroDivisionError] join_by: '>< . is: (NoMethodError >< IOError >< ZeroDivisionError)
155
+ [NoMethodError, IOError, ZeroDivisionError] join_by: '<> . is: (NoMethodError <> IOError <> ZeroDivisionError)
156
+ }
54
157
  }
@@ -129,4 +129,39 @@ FancySpec describe: StdError with: {
129
129
  e message is: msg
130
130
  }
131
131
  }
132
+
133
+ it: "always executes the finally block, even when raise_returning from within the try block" when: {
134
+ def do_something {
135
+ try {
136
+ return "Ok"
137
+ } finally {
138
+ @ran_finally? = true
139
+ }
140
+ }
141
+ @ran_finally? = false
142
+ do_something is: "Ok"
143
+ @ran_finally? is: true
144
+ }
145
+
146
+ it: "always executes the finally block, even when raising from within a catch block" when: {
147
+ def do_something {
148
+ try {
149
+ 10 / 0
150
+ } catch ZeroDivisionError => e {
151
+ IOError new: (e message) . raise!
152
+ } finally {
153
+ @ran_finally? = true
154
+ }
155
+ }
156
+ @ran_finally? = false
157
+ { do_something } raises: IOError
158
+ @ran_finally? is: true
159
+ }
160
+
161
+ it: "raises an exception" with: 'raise: when: {
162
+ { StandardError raise: "error" } raises: Exception with: @{ message is: "error" }
163
+ { StandardError raise: "error" } raises: StandardError with: @{ message is: "error" }
164
+ { ArgumentError raise: "error2" } raises: ArgumentError with: @{ message is: "error2" }
165
+ { IOError raise: "bar" } raises: IOError with: @{ message is: "bar" }
166
+ }
132
167
  }
@@ -118,7 +118,7 @@ FancySpec describe: Fixnum with: {
118
118
  sum is: ((10..19) sum)
119
119
  }
120
120
 
121
- it: "tries to run a code block self amount of times or fails" with: 'try_times: when: {
121
+ it: "tries to run a code block self amount of times or fails" with: 'times_try: when: {
122
122
  { -2 times_try: { 2 / 0 } } does_not raise: Exception
123
123
  { -1 times_try: { 2 / 0 } } does_not raise: Exception
124
124
  { 0 times_try: { 2 / 0 } } does_not raise: Exception
@@ -131,7 +131,7 @@ FancySpec describe: Hash with: {
131
131
  h includes?: nil . is: false
132
132
  }
133
133
 
134
- it: "returns an object with slots based on key-value pairs in Hash" for: 'to_object when: {
134
+ it: "returns an object with slots based on key-value pairs in Hash" with: 'to_object when: {
135
135
  <[]> to_object slots empty? is: true
136
136
  <['name => "Chris"]> to_object tap: @{
137
137
  slots is: ['name]
@@ -151,4 +151,84 @@ FancySpec describe: Hash with: {
151
151
  b is: "hello"
152
152
  }
153
153
  }
154
+
155
+ it: "returns a hash with all entries for which a block yields true" with: 'select_keys: when: {
156
+ <[]> select_keys: { true } . is: <[]>
157
+ <[]> select_keys: { false } . is: <[]>
158
+ <['hello => "world"]> select_keys: { true } . is: <['hello => "world"]>
159
+ <['hello => "world"]> select_keys: { false } . is: <[]>
160
+ <['hello => "world", "world" => 'hello]> select_keys: @{ is_a?: Symbol } . is: <['hello => "world"]>
161
+ <[5 => 1, 4 => 2, 3 => 3, 2 => 4, 1 => 5]> select_keys: @{ <= 3 } . is: <[1 => 5, 2 => 4, 3 => 3]>
162
+ }
163
+
164
+ it: "returns a hash with all entries for which a block yields false" with: 'reject_keys: when: {
165
+ <[]> reject_keys: { true } . is: <[]>
166
+ <[]> reject_keys: { false } . is: <[]>
167
+ <['hello => "world"]> reject_keys: { true } . is: <[]>
168
+ <['hello => "world"]> reject_keys: { false } . is: <['hello => "world"]>
169
+ <['hello => "world", "world" => 'hello]> reject_keys: @{ is_a?: Symbol } . is: <["world" => 'hello]>
170
+ <[5 => 1, 4 => 2, 3 => 3, 2 => 4, 1 => 5]> reject_keys: @{ <= 3 } . is: <[5 => 1, 4 => 2]>
171
+ }
172
+
173
+ class HashCallable {
174
+ read_write_slots: ('foo, 'bar)
175
+ }
176
+
177
+ it: "is callable, like a block" with: 'call: when: {
178
+ hc = HashCallable new
179
+
180
+ hc foo is: nil
181
+ hc bar is: nil
182
+
183
+ <['foo: => "bar", 'bar: => 123]> call: [hc] . is: hc
184
+
185
+ hc foo is: "bar"
186
+ hc bar is: 123
187
+
188
+ <['foo => "foobar", 'bar => 456]> call: [hc]
189
+
190
+ hc foo is: "foobar"
191
+ hc bar is: 456
192
+ }
193
+
194
+ it: "returns itself as a block" with: 'to_block when: {
195
+ hc = HashCallable new
196
+
197
+ hc foo is: nil
198
+ hc bar is: nil
199
+
200
+ <['foo: => "hello", 'bar: => "world"]> tap: |hash| {
201
+ block = hash to_block
202
+ block is_a?: Block . is: true
203
+ block arity is: 1
204
+ block call: [hc] . is: hc
205
+ }
206
+
207
+ hc foo is: "hello"
208
+ hc bar is: "world"
209
+
210
+ <['foo => 123, 'bar => 'baz]> to_block call: [hc]
211
+
212
+ hc foo is: 123
213
+ hc bar is: 'baz
214
+ }
215
+
216
+ it: "returns a nested Hash" with: 'to_hash_deep when: {
217
+ <[]> to_hash_deep is: <[]>
218
+ <['foo => "bar"]> to_hash_deep is: <['foo => "bar"]>
219
+ <['foo => {bar: "baz"}]> to_hash_deep is: <['foo => <['bar => "baz"]>]>
220
+ <[
221
+ 'foo => {
222
+ bar: {
223
+ baz: "quux"
224
+ }
225
+ }
226
+ ]> to_hash_deep is: <[
227
+ 'foo => <[
228
+ 'bar => <[
229
+ 'baz => "quux"
230
+ ]>
231
+ ]>
232
+ ]>
233
+ }
154
234
  }
@@ -0,0 +1,9 @@
1
+ FancySpec describe: Integer with: {
2
+ it: "returns its decimals as an array" with: 'decimals when: {
3
+ (0..9) each: |i| { i decimals is: [i] }
4
+ 10 decimals is: [1, 0]
5
+ 100 decimals is: [1, 0, 0]
6
+ 123 decimals is: [1, 2, 3]
7
+ 998811 decimals is: [9, 9, 8, 8, 1, 1]
8
+ }
9
+ }
@@ -0,0 +1,18 @@
1
+ FancySpec describe: Matchers with: {
2
+ it: "matches with any value defined matching" when: {
3
+ m = Matchers MatchAny new: 1 with: 2
4
+ m === 0 is: false
5
+ m === 1 is: true
6
+ m === 2 is: true
7
+ m === 3 is_not: true
8
+ }
9
+
10
+ it: "matches only with all values defined matching" when: {
11
+ m = Matchers MatchAll new: Integer with: Fixnum
12
+ m === -1 is: true
13
+ m === 0 is: true
14
+ m === 1 is: true
15
+ m === 2.1 is_not: true
16
+ m === 0.0 is_not: true
17
+ }
18
+ }
@@ -16,14 +16,10 @@ FancySpec describe: Method with: {
16
16
 
17
17
  it: "returns the amount of arguments a Method takes" with: 'arity when: {
18
18
  class Foo {
19
- def no_args {
20
- }
21
- def one_arg: yo {
22
- }
23
- def two: a args: b {
24
- }
25
- def three: a args: b ok: c {
26
- }
19
+ def no_args
20
+ def one_arg: yo
21
+ def two: a args: b
22
+ def three: a args: b ok: c
27
23
  }
28
24
 
29
25
  Foo instance_method: 'no_args . arity is: 0
@@ -86,13 +82,11 @@ FancySpec describe: Method with: {
86
82
  }
87
83
 
88
84
  class Foo {
89
- def bar {
90
- }
91
- def private_bar {
92
- }
85
+ def bar
86
+ def private_bar
93
87
  private: 'private_bar
94
- def protected_bar {
95
- }
88
+
89
+ def protected_bar
96
90
  protected: 'protected_bar
97
91
  }
98
92
 
@@ -215,6 +215,22 @@ FancySpec describe: Object with: {
215
215
  }
216
216
  }
217
217
 
218
+ it: "calls a given block with self if the block takes an argument" with: 'do: when: {
219
+ arr = []
220
+ arr do: @{
221
+ << 1
222
+ << 2
223
+ << 3
224
+ select!: 'even?
225
+ } . is: [2]
226
+
227
+ arr do: @{
228
+ is: [2] # same
229
+ }
230
+
231
+ 2 do: @{ inspect } . is: 2
232
+ }
233
+
218
234
  it: "calls a given block with the receiver before returning itself" with: 'tap: when: {
219
235
  10 + 2 tap: |x| {
220
236
  x is: 12
@@ -259,7 +275,7 @@ FancySpec describe: Object with: {
259
275
  o2 get_slot: 'slot2 == (o1 slot2) is: true
260
276
  }
261
277
 
262
- it: "returns itself when return is send as a message" with: 'return when: {
278
+ it: "returns itself when return is send as a message" when: {
263
279
  def foo: array {
264
280
  array each: @{ return }
265
281
  }
@@ -277,7 +293,7 @@ FancySpec describe: Object with: {
277
293
  v is: [1]
278
294
  }
279
295
 
280
- it: "provides temporarily mutable slots" with: 'with_mutable_slots: when: {
296
+ it: "provides temporarily mutable slots" with: 'with_mutable_slots:do: when: {
281
297
  class Student {
282
298
  read_slots: ('name, 'age, 'city)
283
299
  def initialize: block {
@@ -304,4 +320,62 @@ FancySpec describe: Object with: {
304
320
  p age is: 24
305
321
  p city is: "Osnabrück"
306
322
  }
323
+
324
+ it: "ignores all specified exception types" with: 'ignoring:do: when: {
325
+ {
326
+ [{ 2 / 0 }, { "foo" unknown_method_on_string! }] each: |b| {
327
+ ignoring: (ZeroDivisionError, NoMethodError) do: b
328
+ }
329
+ } does_not raise: Exception
330
+ }
331
+
332
+ it: "rebinds a singleton method within a block" with: 'rebind_method:with:within: when: {
333
+ s = "foo"
334
+ s rebind_method: 'hello with: { 42 } within: {
335
+ s hello is: 42
336
+ }
337
+
338
+ s rebind_method: 'hello with: 'to_s within: {
339
+ s hello is: "foo"
340
+ }
341
+
342
+ { s hello } raises: NoMethodError
343
+
344
+ def s bar {
345
+ "bar!"
346
+ }
347
+
348
+ s bar is: "bar!"
349
+
350
+ s rebind_method: 'bar with: { "new bar!" } within: {
351
+ s bar is: "new bar!"
352
+ }
353
+
354
+ s rebind_method: 'bar with: { "another bar!" } within: |x| { x bar } . is: "another bar!"
355
+
356
+ s bar is: "bar!"
357
+ }
358
+
359
+ it: "binds a dynvar correctly" with: 'let:be:in:ensuring: when: {
360
+ *var* is: nil
361
+ let: '*var* be: 'hello in: {
362
+ *var* is: 'hello
363
+ } ensuring: {
364
+ *var* is: 'hello
365
+ }
366
+ *var* is: nil
367
+
368
+ @val = nil
369
+ def check {
370
+ *var* is: @val
371
+ }
372
+
373
+ check
374
+ @val = "test"
375
+ let: '*var* be: @val in: {
376
+ check
377
+ }
378
+ @val = nil
379
+ check
380
+ }
307
381
  }