fancy 0.6.0 → 0.7.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/LICENSE +1 -1
- data/README.md +4 -1
- data/Rakefile +0 -52
- data/bin/fspec +22 -12
- data/bin/ifancy +1 -1
- data/boot/fancy_ext/class.rb +1 -0
- data/boot/fancy_ext/object.rb +8 -6
- data/boot/rbx-compiler/compiler/ast/method_def.rb +2 -0
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/parser.y +9 -0
- data/doc/api/fancy.jsonp +1 -1
- data/examples/stupid_quicksort.fy +11 -9
- data/lib/array.fy +26 -58
- data/lib/block.fy +0 -1
- data/lib/boot.fy +2 -2
- data/lib/class.fy +85 -0
- data/lib/compiler/ast/class_def.fy +1 -1
- data/lib/compiler/ast/expression_list.fy +4 -12
- data/lib/compiler/ast/identifier.fy +3 -3
- data/lib/compiler/ast/method_def.fy +3 -1
- data/lib/compiler/ast/singleton_method_def.fy +4 -1
- data/lib/contracts.fy +53 -56
- data/lib/dynamic_slot_object.fy +39 -3
- data/lib/enumerable.fy +144 -47
- data/lib/fancy_spec.fy +2 -6
- data/lib/file.fy +67 -0
- data/lib/future.fy +42 -3
- data/lib/hash.fy +35 -29
- data/lib/html.fy +1 -1
- data/lib/integer.fy +34 -0
- data/lib/main.fy +13 -7
- data/lib/message_sink.fy +1 -1
- data/lib/number.fy +10 -0
- data/lib/object.fy +27 -1
- data/lib/package.fy +2 -0
- data/lib/package/handler.fy +56 -0
- data/lib/package/installer.fy +21 -51
- data/lib/package/specification.fy +12 -5
- data/lib/package/uninstaller.fy +22 -3
- data/lib/parser/ext/parser.y +9 -0
- data/lib/proxy.fy +25 -2
- data/lib/rbx.fy +2 -1
- data/lib/rbx/array.fy +16 -1
- data/lib/rbx/class.fy +34 -9
- data/lib/rbx/file.fy +2 -2
- data/lib/rbx/fixnum.fy +1 -11
- data/lib/rbx/io.fy +4 -0
- data/lib/rbx/module.fy +11 -0
- data/lib/rbx/object.fy +12 -12
- data/lib/rbx/proc.fy +7 -0
- data/lib/rbx/string.fy +5 -1
- data/lib/rbx/symbol.fy +9 -0
- data/lib/string.fy +1 -1
- data/lib/tuple.fy +37 -35
- data/lib/version.fy +6 -5
- data/tests/array.fy +14 -2
- data/tests/class.fy +79 -0
- data/tests/dynamic_key_hash.fy +16 -0
- data/tests/dynamic_slot_object.fy +28 -0
- data/tests/dynamic_value_array.fy +12 -0
- data/tests/enumerable.fy +46 -0
- data/tests/file.fy +38 -0
- data/tests/fixnum.fy +22 -0
- data/tests/future.fy +40 -0
- data/tests/hash.fy +8 -7
- data/tests/object.fy +31 -5
- data/tests/set.fy +1 -1
- data/tests/string.fy +18 -2
- data/tests/tuple.fy +7 -0
- data/tools/fancy-mode.el +10 -0
- metadata +9 -12
- data/examples/99bottles.fy +0 -5
- data/examples/conditions_exceptions.fy +0 -9
- data/examples/conditions_parsing.fy +0 -68
- data/examples/dynamic.fy +0 -8
- data/examples/greeter.fy +0 -9
- data/examples/parsing.fy +0 -1
- data/lib/rbx/process.fy +0 -13
- data/lib/remote_object.fy +0 -59
data/lib/rbx/object.fy
CHANGED
@@ -97,7 +97,7 @@ class Object {
|
|
97
97
|
Dynamically sends a given message (without parameters) to @self.
|
98
98
|
"""
|
99
99
|
|
100
|
-
|
100
|
+
__send__(message message_name)
|
101
101
|
}
|
102
102
|
|
103
103
|
def receive_message: message with_params: params {
|
@@ -108,16 +108,7 @@ class Object {
|
|
108
108
|
Dynamically sends a given message with parameters to @self.
|
109
109
|
"""
|
110
110
|
|
111
|
-
|
112
|
-
}
|
113
|
-
|
114
|
-
def message_name: symbol {
|
115
|
-
symbol = symbol to_s
|
116
|
-
val = symbol include?(":")
|
117
|
-
match val {
|
118
|
-
case true -> symbol
|
119
|
-
case false -> ":" <<(symbol)
|
120
|
-
}
|
111
|
+
ruby: (message message_name) args: params
|
121
112
|
}
|
122
113
|
|
123
114
|
def responds_to?: message {
|
@@ -128,7 +119,7 @@ class Object {
|
|
128
119
|
Indicates if an object responds to a given message.
|
129
120
|
"""
|
130
121
|
|
131
|
-
respond_to?(message_name
|
122
|
+
respond_to?(message message_name)
|
132
123
|
}
|
133
124
|
|
134
125
|
def extend: class {
|
@@ -140,4 +131,13 @@ class Object {
|
|
140
131
|
|
141
132
|
metaclass include: class
|
142
133
|
}
|
134
|
+
|
135
|
+
def lambda: block {
|
136
|
+
"""
|
137
|
+
@block @Block@ to be used as the lambda's body.
|
138
|
+
@return @Proc@ with Ruby's lambda semantics (e.g. @return always becomes @return_local)
|
139
|
+
"""
|
140
|
+
|
141
|
+
lambda(&block)
|
142
|
+
}
|
143
143
|
}
|
data/lib/rbx/proc.fy
ADDED
data/lib/rbx/string.fy
CHANGED
@@ -24,7 +24,7 @@ class String {
|
|
24
24
|
match index {
|
25
25
|
case Array -> from: (index[0]) to: (index[1])
|
26
26
|
case Tuple -> ruby_idx: index
|
27
|
-
case _ -> ruby_idx: index
|
27
|
+
case _ -> if: (ruby_idx: index) then: @{ chr() }
|
28
28
|
}
|
29
29
|
}
|
30
30
|
|
@@ -162,4 +162,8 @@ class String {
|
|
162
162
|
|
163
163
|
gsub(substring, substitution)
|
164
164
|
}
|
165
|
+
|
166
|
+
def message_name {
|
167
|
+
self to_sym message_name to_s
|
168
|
+
}
|
165
169
|
}
|
data/lib/rbx/symbol.fy
CHANGED
data/lib/string.fy
CHANGED
@@ -5,7 +5,7 @@ class String {
|
|
5
5
|
class.
|
6
6
|
|
7
7
|
They also include @Fancy::Enumerable@, which means you can use all the
|
8
|
-
common sequence methods on them, like
|
8
|
+
common sequence methods on them, like @Fancy::Enumerable#map:@, @Fancy::Enumerable#select:@ etc.
|
9
9
|
"""
|
10
10
|
|
11
11
|
include: Fancy Enumerable
|
data/lib/tuple.fy
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
ObjectBoundsExceededError = Rubinius ObjectBoundsExceededError
|
2
|
+
|
1
3
|
class Tuple {
|
2
4
|
"""
|
3
5
|
Tuples are fixed-size containers providing index-based access to its
|
@@ -23,44 +25,54 @@ class Tuple {
|
|
23
25
|
t
|
24
26
|
}
|
25
27
|
|
26
|
-
def
|
27
|
-
"""
|
28
|
-
Forwards to @Tuple@#at:.
|
28
|
+
def Tuple === obj {
|
29
29
|
"""
|
30
|
+
Matches @Tuple@ class against an object.
|
31
|
+
If the given object is a Tuple instance, return a Tuple object.
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def first {
|
35
|
-
"""
|
36
|
-
@return The first element in @self.
|
33
|
+
@obj Object to be matched against
|
34
|
+
@return Tuple instance containing the values of @obj to be used in pattern matching.
|
37
35
|
"""
|
38
36
|
|
39
|
-
|
37
|
+
if: (obj is_a?: Tuple) then: {
|
38
|
+
[obj] + (obj map: 'identity)
|
39
|
+
}
|
40
40
|
}
|
41
41
|
|
42
|
-
def
|
43
|
-
""
|
44
|
-
@return The second element in @self.
|
45
|
-
"""
|
46
|
-
|
47
|
-
at: 1
|
42
|
+
def Tuple name {
|
43
|
+
"Tuple"
|
48
44
|
}
|
49
45
|
|
50
|
-
def
|
46
|
+
def [idx] {
|
51
47
|
"""
|
52
|
-
|
48
|
+
Forwards to @Tuple@#at:.
|
53
49
|
"""
|
54
50
|
|
55
|
-
at:
|
51
|
+
at: idx
|
56
52
|
}
|
57
53
|
|
58
|
-
def
|
54
|
+
def from: from to: to {
|
59
55
|
"""
|
60
|
-
@
|
56
|
+
@from Start index for sub-array.
|
57
|
+
@to End index ofr sub-array.
|
58
|
+
|
59
|
+
Returns sub-array starting at from: and going to to:
|
61
60
|
"""
|
62
61
|
|
63
|
-
|
62
|
+
if: (from < 0) then: {
|
63
|
+
from = size + from
|
64
|
+
}
|
65
|
+
if: (to < 0) then: {
|
66
|
+
to = size + to
|
67
|
+
}
|
68
|
+
subarr = []
|
69
|
+
try {
|
70
|
+
from upto: to do: |i| {
|
71
|
+
subarr << (at: i)
|
72
|
+
}
|
73
|
+
} catch ObjectBoundsExceededError {
|
74
|
+
}
|
75
|
+
subarr
|
64
76
|
}
|
65
77
|
|
66
78
|
def each: block {
|
@@ -129,21 +141,11 @@ class Tuple {
|
|
129
141
|
str
|
130
142
|
}
|
131
143
|
|
132
|
-
def
|
144
|
+
def to_s {
|
133
145
|
"""
|
134
|
-
|
135
|
-
If the given object is a Tuple instance, return a Tuple object.
|
136
|
-
|
137
|
-
@obj Object to be matched against
|
138
|
-
@return Tuple instance containing the values of @obj to be used in pattern matching.
|
146
|
+
@return @String@ concatenation of elements in @self.
|
139
147
|
"""
|
140
148
|
|
141
|
-
|
142
|
-
[obj] + (obj map: 'identity)
|
143
|
-
}
|
144
|
-
}
|
145
|
-
|
146
|
-
def Tuple name {
|
147
|
-
"Tuple"
|
149
|
+
join
|
148
150
|
}
|
149
151
|
}
|
data/lib/version.fy
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
class Fancy {
|
2
|
+
VERSION_MAJOR = 0
|
3
|
+
VERSION_MINOR = 7
|
4
|
+
VERSION_PATCH = 0
|
5
5
|
|
6
|
-
|
6
|
+
VERSION = [VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH] join: "."
|
7
|
+
}
|
data/tests/array.fy
CHANGED
@@ -195,9 +195,9 @@ FancySpec describe: Array with: {
|
|
195
195
|
arr values_at: [1, 3, 4, 10] . is: [2, 'foo, "bar", nil]
|
196
196
|
}
|
197
197
|
|
198
|
-
it: "returns unique values only" with: '
|
198
|
+
it: "returns unique values only" with: 'unique when: {
|
199
199
|
arr = ['foo, 'bar, "baz", 'foo, "baz", "hello", 1, 0, 0, 1, 'bar, 'foo, "hello"]
|
200
|
-
arr
|
200
|
+
arr unique is: ['foo, 'bar, "baz", "hello", 1, 0]
|
201
201
|
}
|
202
202
|
|
203
203
|
it: "prepends self to another array" with: '>> when: {
|
@@ -225,6 +225,10 @@ FancySpec describe: Array with: {
|
|
225
225
|
arr[[-1,-1]] is: [arr last]
|
226
226
|
arr[[-2,-1]] is: ['bar, 'baz]
|
227
227
|
arr[[-2,-1]] is: (arr last: 2)
|
228
|
+
# works with any Enumerable as argument:
|
229
|
+
arr[(0,2)] is: $ arr[[0,2]]
|
230
|
+
arr[(1,2)] is: $ arr[[1,2]]
|
231
|
+
arr[(0,-1)] is: $ arr[[0,-1]]
|
228
232
|
}
|
229
233
|
|
230
234
|
it: "joins all elements with a string to a new string" with: 'join: when: {
|
@@ -329,6 +333,14 @@ FancySpec describe: Array with: {
|
|
329
333
|
([1,2,3,4] + [-1,-2,-3,-4]) is: [1,2,3,4,-1,-2,-3,-4]
|
330
334
|
}
|
331
335
|
|
336
|
+
it: "returns all elements not in another collection" with: '- when: {
|
337
|
+
[] - [] is: []
|
338
|
+
[] - [0] is: []
|
339
|
+
[1,2,3,4] - [2,4] is: [1,3]
|
340
|
+
[1,2,3] - [1,2,3,5] is: []
|
341
|
+
["foo", "bar", "baz"] - ["bar"] is: ["foo", "baz"]
|
342
|
+
}
|
343
|
+
|
332
344
|
it: "returns true for all elements" with: 'all?: when: {
|
333
345
|
[1,2,3,4] all?: |x| { x < 5 } . is: true
|
334
346
|
[1,2,3,4] all?: |x| { x > 0 } . is: true
|
data/tests/class.fy
CHANGED
@@ -567,4 +567,83 @@ FancySpec describe: Class with: {
|
|
567
567
|
WithConstants["Nested"] is_a?: Class . is: true
|
568
568
|
WithConstants["Nested"] is: WithConstants Nested
|
569
569
|
}
|
570
|
+
|
571
|
+
it: "sets a constants value" with: '[]: when: {
|
572
|
+
Kernel["Object"] is: Object
|
573
|
+
{ Kernel["Something"] } raises: NameError
|
574
|
+
Kernel["Something"]: Array
|
575
|
+
{ Kernel["Something"] is: Array } does_not raise: NameError
|
576
|
+
}
|
577
|
+
|
578
|
+
it: "delegates methods correctly" with: 'delegate:to_slot: when: {
|
579
|
+
class Delegation {
|
580
|
+
delegate: ('[], '[]:, '<<, 'to_s, 'to_s:, 'inspect, 'each:in_between:) to_slot: 'object
|
581
|
+
def initialize: @object
|
582
|
+
}
|
583
|
+
|
584
|
+
d = Delegation new: "hello, world!"
|
585
|
+
d to_s is: "hello, world!"
|
586
|
+
d inspect is: $ "hello, world!" inspect
|
587
|
+
d = Delegation new: 2
|
588
|
+
d to_s is: "2"
|
589
|
+
d inspect is: "2"
|
590
|
+
d to_s: 2 . is: "10"
|
591
|
+
d = Delegation new: [1,2,3]
|
592
|
+
d << 5
|
593
|
+
d get_slot: 'object . is: [1,2,3,5]
|
594
|
+
d << nil
|
595
|
+
d get_slot: 'object . is: [1,2,3,5, nil]
|
596
|
+
d[2]: "foo"
|
597
|
+
d get_slot: 'object . is: [1,2,"foo",5,nil]
|
598
|
+
d[1] is: 2
|
599
|
+
}
|
600
|
+
|
601
|
+
it: "allows delegating only a single method" with: 'delegate:to_slot: when: {
|
602
|
+
class Delegation {
|
603
|
+
delegate: 'to_s to_slot: 'number
|
604
|
+
read_write_slot: 'number
|
605
|
+
}
|
606
|
+
|
607
|
+
d = Delegation new
|
608
|
+
d number: 5
|
609
|
+
d to_s is: $ 5 to_s
|
610
|
+
}
|
611
|
+
|
612
|
+
it: "defines a lazy slot" with: 'lazy_slot:value: when: {
|
613
|
+
class LazyClass {
|
614
|
+
lazy_slot: 'foo value: { Thread sleep: 0.01; 42 * @count }
|
615
|
+
def initialize: @count
|
616
|
+
}
|
617
|
+
|
618
|
+
f = LazyClass new: 2
|
619
|
+
start = Time now
|
620
|
+
f foo is: 84
|
621
|
+
Time now - start >= 0.01 is: true
|
622
|
+
start = Time now
|
623
|
+
f foo is: 84
|
624
|
+
Time now - start <= 0.01 is: true
|
625
|
+
}
|
626
|
+
|
627
|
+
it: "returns a string representation of itself and its superclass, if any" with: 'inspect when: {
|
628
|
+
class MySuperClass
|
629
|
+
class MySubClass : MySuperClass
|
630
|
+
|
631
|
+
Fixnum inspect is: "Fixnum : Integer"
|
632
|
+
MySuperClass inspect is: "MySuperClass : Object"
|
633
|
+
MySubClass inspect is: "MySubClass : MySuperClass"
|
634
|
+
Object inspect is: "Object"
|
635
|
+
}
|
636
|
+
|
637
|
+
it: "returns the right amount of instance methods" with: 'instance_methods: when: {
|
638
|
+
class NoMethods
|
639
|
+
class OneMethod {
|
640
|
+
def bar
|
641
|
+
}
|
642
|
+
|
643
|
+
NoMethods instance_methods: false . size is: 0
|
644
|
+
OneMethod instance_methods: false . size is: 1
|
645
|
+
|
646
|
+
NoMethods instance_methods is: $ Object instance_methods
|
647
|
+
Set[OneMethod instance_methods] is: $ Set[Object instance_methods + (OneMethod instance_methods: false)]
|
648
|
+
}
|
570
649
|
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
FancySpec describe: DynamicKeyHash with: {
|
2
|
+
it: "has the correct keys & values defined" when: {
|
3
|
+
dkh = DynamicKeyHash new
|
4
|
+
dkh tap: @{
|
5
|
+
name: "Chris"
|
6
|
+
age: 25
|
7
|
+
country: "Germany"
|
8
|
+
}
|
9
|
+
|
10
|
+
hash = dkh hash
|
11
|
+
Set[hash keys] is: $ Set[['name, 'age, 'country]]
|
12
|
+
hash['name] is: "Chris"
|
13
|
+
hash['age] is: 25
|
14
|
+
hash['country] is: "Germany"
|
15
|
+
}
|
16
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
FancySpec describe: DynamicSlotObject with: {
|
2
|
+
it: "has the correct slots defined" when: {
|
3
|
+
dso = DynamicSlotObject new
|
4
|
+
dso tap: @{
|
5
|
+
name: "Chris"
|
6
|
+
age: 25
|
7
|
+
country: "Germany"
|
8
|
+
}
|
9
|
+
|
10
|
+
dso object tap: @{
|
11
|
+
slots is: ['name, 'age, 'country]
|
12
|
+
class is: Object
|
13
|
+
|
14
|
+
# getters
|
15
|
+
name is: "Chris"
|
16
|
+
age is: 25
|
17
|
+
country is: "Germany"
|
18
|
+
|
19
|
+
# setters
|
20
|
+
name: "Jack"
|
21
|
+
name is: "Jack"
|
22
|
+
age: 26
|
23
|
+
age is: 26
|
24
|
+
country: "USA"
|
25
|
+
country is: "USA"
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
FancySpec describe: DynamicValueArray with: {
|
2
|
+
it: "has the correct values defined" when: {
|
3
|
+
dva = DynamicValueArray new
|
4
|
+
dva tap: @{
|
5
|
+
name: "Chris"
|
6
|
+
age: 25
|
7
|
+
country: "Germany"
|
8
|
+
another_symbol
|
9
|
+
and_another_one
|
10
|
+
} . array is: [['name, "Chris"], ['age, 25], ['country, "Germany"], 'another_symbol, 'and_another_one]
|
11
|
+
}
|
12
|
+
}
|
data/tests/enumerable.fy
CHANGED
@@ -5,4 +5,50 @@ FancySpec describe: Fancy Enumerable with: {
|
|
5
5
|
[[1,2], [2,3,4], [], [1]] superior_by: '> taking: 'size . is: [2,3,4]
|
6
6
|
[[1,2], [2,3,4], [-1]] superior_by: '< taking: 'first . is: [-1]
|
7
7
|
}
|
8
|
+
|
9
|
+
it: "chain-maps all blocks on all values" with: 'map_chained: when: {
|
10
|
+
(1,2,3) map_chained: ('doubled, 'squared, 'to_s) . is: ["4", "16", "36"]
|
11
|
+
(1,2,3) map_chained: (@{ + 1 }, 'to_s) . is: ["2", "3", "4"]
|
12
|
+
[] map_chained: ('class, 'name) . is: []
|
13
|
+
[1, "foo", 'hello] map_chained: ('class, 'name) . is: ["Fixnum", "String", "Symbol"]
|
14
|
+
}
|
15
|
+
|
16
|
+
it: "maps over its elements with their index" with: 'map_with_index: when: {
|
17
|
+
(1,2,3) map_with_index: |x i| {
|
18
|
+
x + i
|
19
|
+
} . is: [1,3,5]
|
20
|
+
|
21
|
+
[1,2,3,4] map_with_index: |x i| {
|
22
|
+
i
|
23
|
+
} . is: [0,1,2,3]
|
24
|
+
|
25
|
+
[] map_with_index: |x i| { i } . is: []
|
26
|
+
}
|
27
|
+
|
28
|
+
it: "counts the amount of elements for which a block yields true" with: 'count: when: {
|
29
|
+
[1,2,3] count: @{ even? } . is: 1
|
30
|
+
(0..10) count: @{ even? } . is: 6
|
31
|
+
(0..10) count: @{ odd? } . is: 5
|
32
|
+
"foo" count: @{ == "o" } . is: 2
|
33
|
+
"foo" count: @{ != "o" } . is: 1
|
34
|
+
(1,2,3) count: @{ < 2 } . is: 1
|
35
|
+
[] count: { true } . is: 0
|
36
|
+
[1] count: { true } . is: 1
|
37
|
+
[1] count: { false } . is: 0
|
38
|
+
}
|
39
|
+
|
40
|
+
it: "returns a string concatenation of all elements in self" with: 'to_s when: {
|
41
|
+
(1,2,3) to_s is: "123"
|
42
|
+
[1,2,3] to_s is: "123"
|
43
|
+
"foo" to_s is: "foo"
|
44
|
+
[] to_s is: ""
|
45
|
+
|
46
|
+
class MyCollection {
|
47
|
+
include: Fancy Enumerable
|
48
|
+
def each: block {
|
49
|
+
(0..5) each: block
|
50
|
+
}
|
51
|
+
}
|
52
|
+
MyCollection new to_s is: "012345"
|
53
|
+
}
|
8
54
|
}
|