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.
- data/README.md +38 -86
- data/bin/fdoc +2 -22
- data/bin/fspec +8 -3
- data/bin/ifancy +1 -1
- data/boot/fancy_ext.rb +1 -0
- data/boot/fancy_ext/array.rb +19 -0
- data/boot/fancy_ext/class.rb +2 -4
- data/boot/fancy_ext/module.rb +2 -0
- data/boot/fancy_ext/object.rb +0 -17
- data/boot/rbx-compiler/compiler/ast/method_def.rb +0 -4
- data/boot/rbx-compiler/compiler/ast/singleton_method_def.rb +0 -7
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/fancy_parser.c +1 -0
- data/doc/api/fancy.css +10 -1
- data/doc/api/fancy.jsonp +1 -1
- data/doc/api/fdoc.js +22 -9
- data/doc/api/octocat.png +0 -0
- data/doc/features.md +1 -2
- data/examples/actors.fy +1 -2
- data/examples/armstrong_numbers.fy +7 -3
- data/examples/blocks.fy +3 -3
- data/examples/distributing_proxy.fy +31 -0
- data/examples/future_sends.fy +15 -0
- data/examples/person.fy +1 -2
- data/lib/argv.fy +1 -7
- data/lib/array.fy +7 -11
- data/lib/block.fy +15 -0
- data/lib/boot.fy +4 -3
- data/lib/class.fy +354 -10
- data/lib/compiler.fy +1 -1
- data/lib/compiler/ast/assign.fy +4 -8
- data/lib/compiler/ast/async_send.fy +1 -2
- data/lib/compiler/ast/block.fy +5 -0
- data/lib/compiler/ast/class_def.fy +2 -1
- data/lib/compiler/ast/expression_list.fy +1 -2
- data/lib/compiler/ast/future_send.fy +1 -2
- data/lib/compiler/ast/identifier.fy +34 -17
- data/lib/compiler/ast/literals.fy +31 -19
- data/lib/compiler/ast/match.fy +5 -4
- data/lib/compiler/ast/message_send.fy +3 -5
- data/lib/compiler/ast/method_def.fy +0 -3
- data/lib/compiler/ast/range.fy +2 -4
- data/lib/compiler/ast/return.fy +2 -4
- data/lib/compiler/ast/script.fy +2 -4
- data/lib/compiler/ast/singleton_method_def.fy +0 -3
- data/lib/compiler/ast/string_interpolation.fy +2 -2
- data/lib/compiler/ast/super.fy +2 -4
- data/lib/compiler/ast/try_catch.fy +13 -9
- data/lib/compiler/ast/tuple_literal.fy +1 -2
- data/lib/compiler/compiler.fy +2 -2
- data/lib/compiler/stages.fy +3 -6
- data/lib/contracts.fy +89 -57
- data/lib/dynamic_slot_object.fy +21 -3
- data/lib/enumerable.fy +140 -4
- data/lib/enumerator.fy +1 -1
- data/lib/eval.fy +23 -9
- data/lib/exception.fy +16 -0
- data/lib/false_class.fy +36 -5
- data/lib/fancy_spec.fy +64 -34
- data/lib/fdoc.fy +85 -24
- data/lib/file.fy +19 -0
- data/lib/future.fy +4 -46
- data/lib/hash.fy +113 -0
- data/lib/integer.fy +25 -6
- data/lib/iteration.fy +3 -3
- data/lib/main.fy +5 -0
- data/lib/matchers.fy +79 -0
- data/lib/nil_class.fy +8 -0
- data/lib/object.fy +109 -18
- data/lib/option_parser.fy +118 -0
- data/lib/package/dependency.fy +4 -8
- data/lib/package/dependency_installer.fy +1 -1
- data/lib/package/handler.fy +6 -0
- data/lib/package/installer.fy +43 -16
- data/lib/package/list.fy +1 -2
- data/lib/package/specification.fy +5 -5
- data/lib/package/uninstaller.fy +9 -2
- data/lib/parser.fy +1 -3
- data/lib/parser/ext/ext.c +1 -0
- data/lib/parser/ext/lexer.lex +5 -0
- data/lib/parser/methods.fy +48 -46
- data/lib/proxies.fy +151 -0
- data/lib/rbx.fy +1 -0
- data/lib/rbx/actor.fy +16 -18
- data/lib/rbx/array.fy +18 -3
- data/lib/rbx/block.fy +1 -7
- data/lib/rbx/class.fy +54 -9
- data/lib/rbx/code_loader.fy +2 -5
- data/lib/rbx/compiled_method.fy +31 -0
- data/lib/rbx/debugger.fy +66 -0
- data/lib/rbx/directory.fy +8 -3
- data/lib/rbx/documentation.fy +1 -1
- data/lib/rbx/file.fy +22 -0
- data/lib/rbx/integer.fy +1 -1
- data/lib/rbx/match_data.fy +2 -1
- data/lib/rbx/method.fy +26 -0
- data/lib/rbx/object.fy +8 -3
- data/lib/rbx/regexp.fy +6 -3
- data/lib/rbx/string.fy +9 -1
- data/lib/rbx/stringio.fy +12 -0
- data/lib/rbx/symbol.fy +4 -0
- data/lib/stack.fy +1 -1
- data/lib/string.fy +34 -0
- data/lib/stringio.fy +1 -1
- data/lib/symbol.fy +6 -2
- data/lib/system.fy +15 -1
- data/lib/tuple.fy +5 -2
- data/lib/version.fy +1 -1
- data/ruby_lib/fdoc +2 -22
- data/tests/array.fy +3 -17
- data/tests/class.fy +312 -10
- data/tests/contracts.fy +51 -0
- data/tests/distributing_proxy.fy +28 -0
- data/tests/enumerable.fy +104 -1
- data/tests/exception.fy +35 -0
- data/tests/fixnum.fy +1 -1
- data/tests/hash.fy +81 -1
- data/tests/integer.fy +9 -0
- data/tests/matchers.fy +18 -0
- data/tests/method.fy +8 -14
- data/tests/object.fy +76 -2
- data/tests/option_parser.fy +80 -0
- data/tests/string.fy +21 -0
- data/tests/stringio.fy +1 -1
- data/tests/tuple.fy +1 -1
- metadata +21 -44
- data/examples/arithmetic.fy +0 -7
- data/examples/array.fy +0 -50
- data/examples/boolean.fy +0 -24
- data/examples/class.fy +0 -68
- data/examples/constant_access.fy +0 -15
- data/examples/default_args.fy +0 -20
- data/examples/define_methods.fy +0 -15
- data/examples/dynamic_output.fy +0 -15
- data/examples/empty_catch.fy +0 -4
- data/examples/exception.fy +0 -9
- data/examples/files.fy +0 -23
- data/examples/finally.fy +0 -5
- data/examples/future.fy +0 -30
- data/examples/future_composition.fy +0 -20
- data/examples/futures.fy +0 -9
- data/examples/game_of_life.fy +0 -148
- data/examples/html_generator.fy +0 -84
- data/examples/implicit_return.fy +0 -3
- data/examples/matchers.fy +0 -6
- data/examples/nested_try.fy +0 -9
- data/examples/numbers.fy +0 -12
- data/examples/rbx/and_or.fy +0 -7
- data/examples/rbx/blocks.fy +0 -22
- data/examples/rbx/classes.fy +0 -32
- data/examples/rbx/hello.fy +0 -8
- data/examples/rbx/include.fy +0 -12
- data/examples/rbx/inherit.fy +0 -11
- data/examples/rbx/methods.fy +0 -15
- data/examples/rbx/nested_classes.fy +0 -9
- data/examples/rbx/require.fy +0 -3
- data/examples/rbx/strings.fy +0 -5
- data/examples/require.fy +0 -7
- data/examples/return.fy +0 -13
- data/examples/singleton_methods.fy +0 -21
- data/examples/threads.fy +0 -18
- data/examples/tuple.fy +0 -8
- data/examples/webserver/webserver.fy +0 -15
- data/lib/proxy.fy +0 -86
- data/lib/thread_pool.fy +0 -102
data/lib/file.fy
CHANGED
|
@@ -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
|
data/lib/future.fy
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
class FutureSend {
|
|
2
2
|
"""
|
|
3
|
-
A @FutureSend@ gets created whenever an asynchronous message via the
|
|
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
|
|
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
|
|
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 }
|
data/lib/hash.fy
CHANGED
|
@@ -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
|
}
|
data/lib/integer.fy
CHANGED
|
@@ -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
|
|
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
|
|
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
|
}
|
data/lib/iteration.fy
CHANGED
|
@@ -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
|
"""
|
data/lib/main.fy
CHANGED
|
@@ -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
|
data/lib/matchers.fy
ADDED
|
@@ -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
|
+
}
|
data/lib/nil_class.fy
CHANGED
data/lib/object.fy
CHANGED
|
@@ -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
|
|
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
|
-
|
|
589
|
+
return block call: [self]
|
|
591
590
|
} finally {
|
|
592
|
-
|
|
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
|
|
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
|
-
|
|
694
|
-
|
|
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
|
}
|