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/tests/contracts.fy
ADDED
|
@@ -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
|
+
}
|
data/tests/enumerable.fy
CHANGED
|
@@ -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
|
}
|
data/tests/exception.fy
CHANGED
|
@@ -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
|
}
|
data/tests/fixnum.fy
CHANGED
|
@@ -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: '
|
|
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
|
data/tests/hash.fy
CHANGED
|
@@ -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"
|
|
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
|
}
|
data/tests/integer.fy
ADDED
|
@@ -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
|
+
}
|
data/tests/matchers.fy
ADDED
|
@@ -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
|
+
}
|
data/tests/method.fy
CHANGED
|
@@ -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
|
|
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
|
-
|
|
95
|
-
|
|
88
|
+
|
|
89
|
+
def protected_bar
|
|
96
90
|
protected: 'protected_bar
|
|
97
91
|
}
|
|
98
92
|
|
data/tests/object.fy
CHANGED
|
@@ -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"
|
|
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
|
}
|