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/rbx/directory.fy
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
Directory = Dir
|
|
2
|
+
|
|
1
3
|
class Directory {
|
|
4
|
+
forwards_unary_ruby_methods
|
|
5
|
+
metaclass forwards_unary_ruby_methods
|
|
6
|
+
|
|
2
7
|
def self create: dirname {
|
|
3
8
|
"""
|
|
4
9
|
@dirname Path of @Directory@ to create.
|
|
@@ -39,7 +44,7 @@ class Directory {
|
|
|
39
44
|
|
|
40
45
|
try {
|
|
41
46
|
Dir delete(dirname)
|
|
42
|
-
} catch
|
|
47
|
+
} catch StandardError => e {
|
|
43
48
|
IOError new: (e message) . raise!
|
|
44
49
|
}
|
|
45
50
|
}
|
|
@@ -49,8 +54,8 @@ class Directory {
|
|
|
49
54
|
@pattern Directory pattern or name containing files to be returned as an @Array@.
|
|
50
55
|
@return @Array@ of files matching directory @pattern.
|
|
51
56
|
|
|
52
|
-
Example
|
|
53
|
-
|
|
57
|
+
Example:
|
|
58
|
+
Directory list: \"tests/**/*.fy\" # => [\"tests/file1.fy\", \"tests/more/file2.fy\"]
|
|
54
59
|
"""
|
|
55
60
|
|
|
56
61
|
match pattern {
|
data/lib/rbx/documentation.fy
CHANGED
data/lib/rbx/file.fy
CHANGED
|
@@ -126,6 +126,19 @@ class File {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
def File delete!: filename {
|
|
130
|
+
"""
|
|
131
|
+
@filename Path to @File@ to be deleted.
|
|
132
|
+
|
|
133
|
+
Deletes a @File@ with a given @filename. If an @IOError@ occurs,
|
|
134
|
+
it gets ignored.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
File delete: filename
|
|
139
|
+
} catch IOError {}
|
|
140
|
+
}
|
|
141
|
+
|
|
129
142
|
def File directory?: path {
|
|
130
143
|
"""
|
|
131
144
|
@path Path to check if it's a @Directory@.
|
|
@@ -148,6 +161,15 @@ class File {
|
|
|
148
161
|
File rename(old_name, new_name)
|
|
149
162
|
}
|
|
150
163
|
|
|
164
|
+
def File absolute_path: filename {
|
|
165
|
+
"""
|
|
166
|
+
@filename Name of @File@ to get absolute path for.
|
|
167
|
+
@return Absolute (expanded) path for @filename.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
File expand_path: filename
|
|
171
|
+
}
|
|
172
|
+
|
|
151
173
|
def initialize: path {
|
|
152
174
|
initialize(path)
|
|
153
175
|
}
|
data/lib/rbx/integer.fy
CHANGED
data/lib/rbx/match_data.fy
CHANGED
data/lib/rbx/method.fy
CHANGED
|
@@ -75,6 +75,10 @@ class Method {
|
|
|
75
75
|
ruby_alias: 'executable
|
|
76
76
|
include: MethodMixin
|
|
77
77
|
forwards_unary_ruby_methods
|
|
78
|
+
|
|
79
|
+
def call: args ([]) {
|
|
80
|
+
call(*args)
|
|
81
|
+
}
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
class UnboundMethod {
|
|
@@ -86,4 +90,26 @@ class UnboundMethod {
|
|
|
86
90
|
ruby_alias: 'executable
|
|
87
91
|
include: MethodMixin
|
|
88
92
|
forwards_unary_ruby_methods
|
|
93
|
+
|
|
94
|
+
alias_method: 'bind: for_ruby: 'bind
|
|
95
|
+
|
|
96
|
+
def call: args ([]) {
|
|
97
|
+
call(*args)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
def selector_with_args {
|
|
101
|
+
match name {
|
|
102
|
+
case ":[]" -> return "[arg_0]"
|
|
103
|
+
case "[]:" -> return "[arg_0]: arg_1"
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
match arity {
|
|
107
|
+
case 0 -> name rest
|
|
108
|
+
case _ ->
|
|
109
|
+
selectors = name split: ":"
|
|
110
|
+
(0..arity - 1) map: |i| {
|
|
111
|
+
"#{selectors[i]}: arg_#{i}"
|
|
112
|
+
} . join: " "
|
|
113
|
+
}
|
|
114
|
+
}
|
|
89
115
|
}
|
data/lib/rbx/object.fy
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
class Object {
|
|
2
|
-
ruby_aliases: [ '==, '===, 'class, 'inspect, 'object_id, 'instance_variables ]
|
|
2
|
+
ruby_aliases: [ '==, '===, 'class, 'inspect, 'object_id, 'instance_variables, 'methods, 'instance_variable_get, 'instance_variable_set ]
|
|
3
3
|
|
|
4
4
|
def initialize {
|
|
5
5
|
initialize()
|
|
@@ -14,8 +14,13 @@ class Object {
|
|
|
14
14
|
Fancy CodeLoader require: file_path
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
def
|
|
18
|
-
"
|
|
17
|
+
def dup {
|
|
18
|
+
"""
|
|
19
|
+
@return Copy (clone) of self.
|
|
20
|
+
|
|
21
|
+
Returns a deep clone of self using Ruby's Marshal class.
|
|
22
|
+
"""
|
|
23
|
+
|
|
19
24
|
Marshal load(Marshal dump(self))
|
|
20
25
|
}
|
|
21
26
|
|
data/lib/rbx/regexp.fy
CHANGED
|
@@ -6,9 +6,8 @@ class Regexp {
|
|
|
6
6
|
ruby_alias: 'inspect
|
|
7
7
|
ruby_alias: 'to_s
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
9
|
+
alias_method: 'match: for_ruby: 'match
|
|
10
|
+
alias_method: '=== for_ruby: 'match
|
|
12
11
|
|
|
13
12
|
def i {
|
|
14
13
|
Regexp new(source(), true)
|
|
@@ -29,4 +28,8 @@ class Regexp {
|
|
|
29
28
|
def Regexp [string] {
|
|
30
29
|
new(string)
|
|
31
30
|
}
|
|
31
|
+
|
|
32
|
+
def call: args {
|
|
33
|
+
args first =~ self
|
|
34
|
+
}
|
|
32
35
|
}
|
data/lib/rbx/string.fy
CHANGED
|
@@ -3,12 +3,13 @@ class String {
|
|
|
3
3
|
# prepend a : to fancy version of ruby methods.
|
|
4
4
|
ruby_aliases: [
|
|
5
5
|
'==, 'upcase, 'downcase, '=~, 'to_i, 'to_f,
|
|
6
|
-
'chomp, 'inspect, 'to_sym, '<, '
|
|
6
|
+
'chomp, 'inspect, 'to_sym, '<, '>, '<=, '>=, '<=>
|
|
7
7
|
]
|
|
8
8
|
|
|
9
9
|
alias_method: 'ruby_idx: for_ruby: '[]
|
|
10
10
|
alias_method: '[]: for_ruby: '[]=
|
|
11
11
|
alias_method: 'scan: for_ruby: 'scan
|
|
12
|
+
alias_method: 'to_i: for_ruby: 'to_i
|
|
12
13
|
alias_method: 'uppercase for: 'upcase
|
|
13
14
|
alias_method: 'lowercase for: 'downcase
|
|
14
15
|
|
|
@@ -166,4 +167,11 @@ class String {
|
|
|
166
167
|
def message_name {
|
|
167
168
|
self to_sym message_name to_s
|
|
168
169
|
}
|
|
170
|
+
|
|
171
|
+
def to_fancy_message {
|
|
172
|
+
match self {
|
|
173
|
+
case /^:/ -> rest to_sym
|
|
174
|
+
case _ -> self
|
|
175
|
+
}
|
|
176
|
+
}
|
|
169
177
|
}
|
data/lib/rbx/stringio.fy
CHANGED
|
@@ -12,6 +12,18 @@ class StringIO {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
def each_line: block {
|
|
15
|
+
"""
|
|
16
|
+
@block @Block@ to be called with each line in @self.
|
|
17
|
+
"""
|
|
18
|
+
|
|
15
19
|
each_line(&block)
|
|
16
20
|
}
|
|
21
|
+
|
|
22
|
+
def string: str {
|
|
23
|
+
"""
|
|
24
|
+
@str @String@ to set @string in @self to.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
string=(str)
|
|
28
|
+
}
|
|
17
29
|
}
|
data/lib/rbx/symbol.fy
CHANGED
data/lib/stack.fy
CHANGED
data/lib/string.fy
CHANGED
|
@@ -198,4 +198,38 @@ class String {
|
|
|
198
198
|
|
|
199
199
|
File expand_path: $ File dirname(self) + "/" + path
|
|
200
200
|
}
|
|
201
|
+
|
|
202
|
+
def multiline? {
|
|
203
|
+
"""
|
|
204
|
+
@return @true if @self is a multiline string, @false otherwise.
|
|
205
|
+
|
|
206
|
+
Example:
|
|
207
|
+
\"foo\nbar\" multiline? # => true
|
|
208
|
+
\"foo bar\" multiline? # => false
|
|
209
|
+
\"\" multiline? # => false
|
|
210
|
+
\"\n\n\n\" multiline? # => true
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
grep: /\n/ . size > 0
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
def main? {
|
|
217
|
+
"""
|
|
218
|
+
@return @true if @self is the filename of the script that got executed initially.
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
File expand_path: (ARGV[0] to_s) == self
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
def if_main: main_block else: else_block ({}) {
|
|
225
|
+
"""
|
|
226
|
+
@main_block @Block@ to be run if @String#:main?@ returns true.
|
|
227
|
+
@else_block @Block@ to be called otherwise.
|
|
228
|
+
|
|
229
|
+
Same as:
|
|
230
|
+
if: main? then: else_block else: else_block
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
if: main? then: main_block else: else_block
|
|
234
|
+
}
|
|
201
235
|
}
|
data/lib/stringio.fy
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
require: "rbx/stringio"
|
|
1
|
+
require: "rbx/stringio"
|
data/lib/symbol.fy
CHANGED
|
@@ -8,8 +8,11 @@ class Symbol {
|
|
|
8
8
|
|
|
9
9
|
def call: arg {
|
|
10
10
|
"""
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
@arg Argument to send @self to.
|
|
12
|
+
@return Value of sending @self as message to @arg.
|
|
13
|
+
|
|
14
|
+
This allows Symbols to be used like Blocks (e.g. in all methods of Enumerable).
|
|
15
|
+
|
|
13
16
|
Example:
|
|
14
17
|
[1, 2, 3] map: 'squared # => [1, 4, 9]
|
|
15
18
|
"""
|
|
@@ -24,6 +27,7 @@ class Symbol {
|
|
|
24
27
|
def call {
|
|
25
28
|
"""
|
|
26
29
|
Sends @self as message to the sender in its context.
|
|
30
|
+
|
|
27
31
|
Example:
|
|
28
32
|
'foo call
|
|
29
33
|
# => same as
|
data/lib/system.fy
CHANGED
|
@@ -12,11 +12,25 @@ class System {
|
|
|
12
12
|
"""
|
|
13
13
|
@message Error message to be printed before aborting programm execution.
|
|
14
14
|
|
|
15
|
-
Prints
|
|
15
|
+
Prints @message on @\*stderr\* and exits with an exit code of 1 (indicating
|
|
16
|
+
failure).
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
*stderr* println: message
|
|
20
|
+
abort
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
def System aborting: message do: block {
|
|
24
|
+
"""
|
|
25
|
+
@message Message to print on @*stderr* before calling @block and exiting.
|
|
26
|
+
@block @Block@ to be called before exiting execution.
|
|
27
|
+
|
|
28
|
+
Prints @message on @\*stderr\*, calls @block and finally exits with an exit
|
|
16
29
|
code of 1 (indicating failure).
|
|
17
30
|
"""
|
|
18
31
|
|
|
19
32
|
*stderr* println: message
|
|
33
|
+
block call
|
|
20
34
|
abort
|
|
21
35
|
}
|
|
22
36
|
}
|
data/lib/tuple.fy
CHANGED
data/lib/version.fy
CHANGED
data/ruby_lib/fdoc
CHANGED
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
# -*- ruby -*-
|
|
1
|
+
#!/usr/bin/env fancy
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
class Fancy::Parser; end
|
|
6
|
-
|
|
7
|
-
# fdoc is a documentation generator for fancy.
|
|
8
|
-
# This is a ruby script because we need to setup a hook
|
|
9
|
-
# BEFORE any fancy code is loaded. So we can create
|
|
10
|
-
# documentation for Fancy's builtin objects as well.
|
|
11
|
-
# See fdoc.
|
|
12
|
-
base = File.expand_path("../boot", File.dirname(__FILE__))
|
|
13
|
-
require File.expand_path("rbx-compiler/parser/fancy_parser", base)
|
|
14
|
-
require File.expand_path("rbx-compiler/compiler", base)
|
|
15
|
-
require File.expand_path("code_loader", base)
|
|
16
|
-
require File.expand_path("fancy_ext", base)
|
|
17
|
-
|
|
18
|
-
Fancy::CodeLoader.load_compiled_file File.expand_path("../lib/rbx/documentation.fyc", base)
|
|
19
|
-
Fancy::CodeLoader.load_compiled_file File.expand_path("../lib/fdoc_hook.fyc", base)
|
|
20
|
-
|
|
21
|
-
Fancy::CodeLoader.load_compiled_file File.expand_path("../lib/rbx.fyc", base)
|
|
22
|
-
|
|
23
|
-
Fancy::CodeLoader.load_compiled_file File.expand_path("../lib/fdoc.fyc", base)
|
|
3
|
+
require: "../lib/fdoc"
|
data/tests/array.fy
CHANGED
|
@@ -122,6 +122,9 @@ FancySpec describe: Array with: {
|
|
|
122
122
|
arr index: 3 . is: 3
|
|
123
123
|
arr index: 4 . is: 4
|
|
124
124
|
arr index: 'foo . is: nil
|
|
125
|
+
|
|
126
|
+
arr index: @{ is_a?: Symbol } . is: 2
|
|
127
|
+
arr index: @{ is_a?: String } . is: nil
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
it: "returns an Array of all its indices" with: 'indices when: {
|
|
@@ -395,15 +398,6 @@ FancySpec describe: Array with: {
|
|
|
395
398
|
arr is: [3,2,1]
|
|
396
399
|
}
|
|
397
400
|
|
|
398
|
-
it: "takes elements from itself as long a block yields true" with: 'take_while: when: {
|
|
399
|
-
1 upto: 15 . take_while: |x| { x < 10 } . is: (1 upto: 9)
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
it: "drops elements from itself as long a block yields true" with: 'drop_while: when: {
|
|
404
|
-
1 upto: 15 . drop_while: |x| { x < 10 } . is: (10 upto: 15)
|
|
405
|
-
}
|
|
406
|
-
|
|
407
401
|
it: "partitions an array via a given block" with: 'partition_by: when: {
|
|
408
402
|
arr = [1,2,2,3,3,3,4,4,4,4,5]
|
|
409
403
|
arr partition_by: 'identity . is: [[1], [2,2], [3,3,3], [4,4,4,4], [5]]
|
|
@@ -547,14 +541,6 @@ FancySpec describe: Array with: {
|
|
|
547
541
|
arr sort_by: 'second . is: sorted
|
|
548
542
|
}
|
|
549
543
|
|
|
550
|
-
it: "returns the array in groups of 3" with: 'in_groups_of: when: {
|
|
551
|
-
['a,'b,'c] in_groups_of: 1 . is: [['a],['b],['c]]
|
|
552
|
-
array = 1 upto: 10
|
|
553
|
-
array in_groups_of: 3 . is: [[1,2,3], [4,5,6], [7,8,9], [10]]
|
|
554
|
-
|
|
555
|
-
(20,30,40) in_groups_of: 2 . is: [[20,30], [40]]
|
|
556
|
-
}
|
|
557
|
-
|
|
558
544
|
it: "returns a hash" with: 'to_hash when: {
|
|
559
545
|
[] to_hash is: <[]>
|
|
560
546
|
[[1,2],[3,4]] to_hash is: <[1 => 2, 3 => 4]>
|
data/tests/class.fy
CHANGED
|
@@ -244,10 +244,8 @@ FancySpec describe: Class with: {
|
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
it: "is a subclass of another Class" with: 'subclass?: when: {
|
|
247
|
-
class Super
|
|
248
|
-
|
|
249
|
-
class Sub : Super {
|
|
250
|
-
}
|
|
247
|
+
class Super
|
|
248
|
+
class Sub : Super
|
|
251
249
|
|
|
252
250
|
Super subclass?: Object . is: true
|
|
253
251
|
Sub subclass?: Object . is: true
|
|
@@ -450,12 +448,9 @@ FancySpec describe: Class with: {
|
|
|
450
448
|
}
|
|
451
449
|
|
|
452
450
|
it: "has the correct list of ancestors" with: 'ancestors when: {
|
|
453
|
-
class A
|
|
454
|
-
|
|
455
|
-
class
|
|
456
|
-
}
|
|
457
|
-
class C : B {
|
|
458
|
-
}
|
|
451
|
+
class A
|
|
452
|
+
class B : A
|
|
453
|
+
class C : B
|
|
459
454
|
|
|
460
455
|
A ancestors is: [A, Object, Kernel]
|
|
461
456
|
B ancestors is: [B, A, Object, Kernel]
|
|
@@ -478,6 +473,20 @@ FancySpec describe: Class with: {
|
|
|
478
473
|
{ x b } raises: NoMethodError
|
|
479
474
|
AClassWithPrivateMethods instance_method: 'a . private? is: true
|
|
480
475
|
AClassWithPrivateMethods instance_method: 'b . private? is: true
|
|
476
|
+
|
|
477
|
+
class AClassWithPrivateMethods {
|
|
478
|
+
private: {
|
|
479
|
+
def c {
|
|
480
|
+
"private c"
|
|
481
|
+
}
|
|
482
|
+
def d {
|
|
483
|
+
"private d"
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
AClassWithPrivateMethods instance_method: 'c . private? is: true
|
|
489
|
+
AClassWithPrivateMethods instance_method: 'd . private? is: true
|
|
481
490
|
}
|
|
482
491
|
|
|
483
492
|
it: "makes methods protected" with: 'protected: when: {
|
|
@@ -498,6 +507,25 @@ FancySpec describe: Class with: {
|
|
|
498
507
|
AClassWithProtectedMethods instance_method: 'b . private? is: false
|
|
499
508
|
AClassWithProtectedMethods instance_method: 'a . protected? is: true
|
|
500
509
|
AClassWithProtectedMethods instance_method: 'b . protected? is: true
|
|
510
|
+
|
|
511
|
+
class AClassWithProtectedMethods {
|
|
512
|
+
protected: {
|
|
513
|
+
def c {
|
|
514
|
+
"in c"
|
|
515
|
+
}
|
|
516
|
+
def d {
|
|
517
|
+
"in d"
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
{ x a } raises: NoMethodError
|
|
523
|
+
{ x b } raises: NoMethodError
|
|
524
|
+
AClassWithProtectedMethods instance_method: 'c . private? is: false
|
|
525
|
+
AClassWithProtectedMethods instance_method: 'd . private? is: false
|
|
526
|
+
AClassWithProtectedMethods instance_method: 'c . protected? is: true
|
|
527
|
+
AClassWithProtectedMethods instance_method: 'd . protected? is: true
|
|
528
|
+
|
|
501
529
|
}
|
|
502
530
|
|
|
503
531
|
it: "makes methods public" with: 'public: when: {
|
|
@@ -521,6 +549,26 @@ FancySpec describe: Class with: {
|
|
|
521
549
|
AClassWithPublicMethods instance_method: 'b . protected? is: false
|
|
522
550
|
AClassWithPublicMethods instance_method: 'a . public? is: true
|
|
523
551
|
AClassWithPublicMethods instance_method: 'b . public? is: true
|
|
552
|
+
|
|
553
|
+
class AClassWithPublicMethods {
|
|
554
|
+
public: {
|
|
555
|
+
def c {
|
|
556
|
+
"in c"
|
|
557
|
+
}
|
|
558
|
+
def d {
|
|
559
|
+
"in d"
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
{ x c } does_not raise: NoMethodError
|
|
565
|
+
{ x d } does_not raise: NoMethodError
|
|
566
|
+
AClassWithPublicMethods instance_method: 'c . private? is: false
|
|
567
|
+
AClassWithPublicMethods instance_method: 'd . private? is: false
|
|
568
|
+
AClassWithPublicMethods instance_method: 'c . protected? is: false
|
|
569
|
+
AClassWithPublicMethods instance_method: 'd . protected? is: false
|
|
570
|
+
AClassWithPublicMethods instance_method: 'c . public? is: true
|
|
571
|
+
AClassWithPublicMethods instance_method: 'd . public? is: true
|
|
524
572
|
}
|
|
525
573
|
|
|
526
574
|
it: "defines a class without a body" when: {
|
|
@@ -646,4 +694,258 @@ FancySpec describe: Class with: {
|
|
|
646
694
|
NoMethods instance_methods is: $ Object instance_methods
|
|
647
695
|
Set[OneMethod instance_methods] is: $ Set[Object instance_methods + (OneMethod instance_methods: false)]
|
|
648
696
|
}
|
|
697
|
+
|
|
698
|
+
it: "defines a before_method handler" with: 'before_method:run: when: {
|
|
699
|
+
class BeforeMethodClass {
|
|
700
|
+
read_slot: 'x
|
|
701
|
+
def initialize: @x
|
|
702
|
+
def before: arr {
|
|
703
|
+
arr << "Before Method: #{@x}"
|
|
704
|
+
}
|
|
705
|
+
def my_method: arr {
|
|
706
|
+
arr << "My Method: #{@x}"
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
before_method: 'my_method: run: 'before:
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
b1 = BeforeMethodClass new: 1
|
|
713
|
+
b2 = BeforeMethodClass new: 2
|
|
714
|
+
|
|
715
|
+
array = []
|
|
716
|
+
|
|
717
|
+
b1 my_method: array
|
|
718
|
+
b2 my_method: array
|
|
719
|
+
|
|
720
|
+
array is: [
|
|
721
|
+
"Before Method: 1", "My Method: 1",
|
|
722
|
+
"Before Method: 2", "My Method: 2"
|
|
723
|
+
]
|
|
724
|
+
|
|
725
|
+
# we can also pass blocks
|
|
726
|
+
|
|
727
|
+
BeforeMethodClass before_method: 'my_method: run: |receiver array| {
|
|
728
|
+
array << "Before Block: #{receiver x}"
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
array = []
|
|
732
|
+
|
|
733
|
+
b1 my_method: array
|
|
734
|
+
b2 my_method: array
|
|
735
|
+
|
|
736
|
+
array is: [
|
|
737
|
+
"Before Block: 1", "Before Method: 1", "My Method: 1",
|
|
738
|
+
"Before Block: 2", "Before Method: 2", "My Method: 2"
|
|
739
|
+
]
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
it: "defines an after_method handler" with: 'after_method:run: when: {
|
|
743
|
+
class AfterMethodClass {
|
|
744
|
+
read_slot: 'x
|
|
745
|
+
def initialize: @x
|
|
746
|
+
def after: arr {
|
|
747
|
+
arr << "After Method: #{@x}"
|
|
748
|
+
}
|
|
749
|
+
def my_method: arr {
|
|
750
|
+
arr << "My Method: #{@x}"
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
after_method: 'my_method: run: 'after:
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
b1 = AfterMethodClass new: 1
|
|
757
|
+
b2 = AfterMethodClass new: 2
|
|
758
|
+
|
|
759
|
+
array = []
|
|
760
|
+
|
|
761
|
+
b1 my_method: array
|
|
762
|
+
b2 my_method: array
|
|
763
|
+
|
|
764
|
+
array is: [
|
|
765
|
+
"My Method: 1", "After Method: 1",
|
|
766
|
+
"My Method: 2", "After Method: 2"
|
|
767
|
+
]
|
|
768
|
+
|
|
769
|
+
AfterMethodClass after_method: 'my_method: run: |receiver array| {
|
|
770
|
+
"block getting called yo"
|
|
771
|
+
array << "After Block: #{receiver x}"
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
array = []
|
|
775
|
+
|
|
776
|
+
b1 my_method: array
|
|
777
|
+
b2 my_method: array
|
|
778
|
+
|
|
779
|
+
array is: [
|
|
780
|
+
"My Method: 1", "After Method: 1", "After Block: 1",
|
|
781
|
+
"My Method: 2", "After Method: 2", "After Block: 2"
|
|
782
|
+
]
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
it: "defines an around_method handler" with: 'around_method:run: when: {
|
|
787
|
+
class AroundMethodClass {
|
|
788
|
+
read_slot: 'x
|
|
789
|
+
def initialize: @x
|
|
790
|
+
def around: arr {
|
|
791
|
+
arr << "Around Method: #{@x}"
|
|
792
|
+
}
|
|
793
|
+
def my_method: arr {
|
|
794
|
+
arr << "My Method: #{@x}"
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
around_method: 'my_method: run: 'around:
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
b1 = AroundMethodClass new: 1
|
|
801
|
+
b2 = AroundMethodClass new: 2
|
|
802
|
+
|
|
803
|
+
array = []
|
|
804
|
+
|
|
805
|
+
b1 my_method: array
|
|
806
|
+
b2 my_method: array
|
|
807
|
+
|
|
808
|
+
array is: [
|
|
809
|
+
"Around Method: 1", "My Method: 1", "Around Method: 1",
|
|
810
|
+
"Around Method: 2", "My Method: 2", "Around Method: 2"
|
|
811
|
+
]
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
AroundMethodClass around_method: 'my_method: run: |receiver array| {
|
|
815
|
+
array << "Around Block: #{receiver x}"
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
array = []
|
|
819
|
+
|
|
820
|
+
b1 my_method: array
|
|
821
|
+
b2 my_method: array
|
|
822
|
+
|
|
823
|
+
array is: [
|
|
824
|
+
"Around Block: 1", "Around Method: 1", "My Method: 1", "Around Method: 1", "Around Block: 1",
|
|
825
|
+
"Around Block: 2", "Around Method: 2", "My Method: 2", "Around Method: 2", "Around Block: 2"
|
|
826
|
+
]
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
it: "defines a custom calling chain for a method" with: 'define_calling_chain:for_method: when: {
|
|
830
|
+
class CallingChainClass {
|
|
831
|
+
def foo: arr { arr << "foo" }
|
|
832
|
+
def bar: arr { arr << "bar" }
|
|
833
|
+
def baz: arr { arr << "baz" }
|
|
834
|
+
|
|
835
|
+
define_calling_chain: ('foo:, 'bar:, 'baz:) for_method: 'foo:
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
arr = []
|
|
839
|
+
CallingChainClass new foo: arr
|
|
840
|
+
arr is: ["foo", "bar", "baz"]
|
|
841
|
+
|
|
842
|
+
CallingChainClass define_calling_chain: [|receiver arr|{ receiver baz: arr }, 'bar:] for_method: 'bar:
|
|
843
|
+
|
|
844
|
+
arr = []
|
|
845
|
+
CallingChainClass new bar: arr
|
|
846
|
+
arr is: ["baz", "bar"]
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
it: "exposes a Fancy method as a Ruby method to Ruby" with: 'expose_to_ruby:as: when: {
|
|
850
|
+
class ExposeToRuby {
|
|
851
|
+
def my_method { "in my_method" }
|
|
852
|
+
expose_to_ruby: 'my_method
|
|
853
|
+
def == other { true }
|
|
854
|
+
expose_to_ruby: '== as: 'ruby_==
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
ExposeToRuby new tap: @{
|
|
858
|
+
my_method is: "in my_method"
|
|
859
|
+
send('my_method) is: "in my_method"
|
|
860
|
+
== 1 is: true
|
|
861
|
+
send('ruby_==, 1) is: true
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
it: "rebinds an instance method within a block" with: 'rebind_instance_method:with:within: when: {
|
|
866
|
+
class RebindInstanceMethod {
|
|
867
|
+
def foo: msg ("foo!") {
|
|
868
|
+
msg println
|
|
869
|
+
}
|
|
870
|
+
def bar: msg {
|
|
871
|
+
"bar: #{msg}" println
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
rim = RebindInstanceMethod new
|
|
876
|
+
s = StringIO new
|
|
877
|
+
let: '*stdout* be: s in: {
|
|
878
|
+
rim foo
|
|
879
|
+
rim foo: "hello!"
|
|
880
|
+
s string is: "foo!\nhello!\n"
|
|
881
|
+
s string: ""
|
|
882
|
+
|
|
883
|
+
RebindInstanceMethod rebind_instance_method: 'foo: with: |msg| {
|
|
884
|
+
msg * 2 println
|
|
885
|
+
} within: {
|
|
886
|
+
let: '*stdout* be: s in: {
|
|
887
|
+
rim foo: "hello!"
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
s string is: "hello!hello!\n"
|
|
891
|
+
|
|
892
|
+
s string: ""
|
|
893
|
+
rim foo: "hello!"
|
|
894
|
+
s string is: "hello!\n"
|
|
895
|
+
|
|
896
|
+
s string: ""
|
|
897
|
+
RebindInstanceMethod rebind_instance_method: 'foo: with: 'bar: within: {
|
|
898
|
+
rim foo: "Test"
|
|
899
|
+
}
|
|
900
|
+
s string is: "bar: Test\n"
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
it: "removes defined slot accessor methods" with: 'remove_slot_accessors_for: when: {
|
|
905
|
+
class SlotAccessors {
|
|
906
|
+
read_write_slots: ('rw1, 'rw2)
|
|
907
|
+
read_slots: ('r1, 'r2)
|
|
908
|
+
write_slots: ('w1, 'w2)
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
sa = SlotAccessors new
|
|
912
|
+
{
|
|
913
|
+
sa rw1 is: nil
|
|
914
|
+
sa rw2 is: nil
|
|
915
|
+
sa r1 is: nil
|
|
916
|
+
sa r2 is: nil
|
|
917
|
+
|
|
918
|
+
sa rw1: "rw1"
|
|
919
|
+
sa rw2: "rw2"
|
|
920
|
+
sa w1: "w1"
|
|
921
|
+
sa w2: "w2"
|
|
922
|
+
|
|
923
|
+
sa rw1 is: "rw1"
|
|
924
|
+
sa rw2 is: "rw2"
|
|
925
|
+
sa r1 is: nil
|
|
926
|
+
sa r2 is: nil
|
|
927
|
+
} does_not raise: NoMethodError
|
|
928
|
+
|
|
929
|
+
{ sa w1 } raises: NoMethodError
|
|
930
|
+
{ sa w2 } raises: NoMethodError
|
|
931
|
+
|
|
932
|
+
SlotAccessors remove_slot_accessors_for: ('rw1, 'r1, 'w1)
|
|
933
|
+
|
|
934
|
+
{ sa rw1 } raises: NoMethodError
|
|
935
|
+
{ sa rw1: "foo"} raises: NoMethodError
|
|
936
|
+
|
|
937
|
+
{
|
|
938
|
+
sa rw2
|
|
939
|
+
sa rw2: "foo"
|
|
940
|
+
} does_not raise: NoMethodError
|
|
941
|
+
|
|
942
|
+
{ sa r1 } raises: NoMethodError
|
|
943
|
+
{ sa r2 } does_not raise: NoMethodError
|
|
944
|
+
|
|
945
|
+
{ sa w1 } raises: NoMethodError
|
|
946
|
+
{ sa w1: "foo" } raises: NoMethodError
|
|
947
|
+
|
|
948
|
+
{ sa w2 } raises: NoMethodError
|
|
949
|
+
{ sa w2: "foo" } does_not raise: NoMethodError
|
|
950
|
+
}
|
|
649
951
|
}
|