fancy 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +2 -0
- data/README.md +6 -1
- data/bin/fancy +6 -0
- data/bin/ifancy +44 -3
- data/boot/fancy_ext/module.rb +4 -0
- data/boot/fancy_ext/object.rb +4 -0
- data/boot/rbx-compiler/compiler/ast/block.rb +29 -1
- data/boot/rbx-compiler/compiler/ast/identifier.rb +6 -0
- data/boot/rbx-compiler/compiler/ast/message_send.rb +1 -0
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/lexer.lex +2 -0
- data/boot/rbx-compiler/parser/parser.rb +6 -0
- data/boot/rbx-compiler/parser/parser.y +14 -1
- data/doc/api/fancy.jsonp +1 -1
- data/doc/features.md +24 -0
- data/examples/99bottles.fy +5 -0
- data/examples/conditions_exceptions.fy +9 -0
- data/examples/conditions_parsing.fy +68 -0
- data/examples/greeter.fy +9 -0
- data/examples/html_generator.fy +59 -29
- data/examples/webserver/webserver.fy +8 -11
- data/lib/argv.fy +6 -0
- data/lib/array.fy +17 -35
- data/lib/block.fy +82 -1
- data/lib/boot.fy +4 -2
- data/lib/compiler.fy +2 -2
- data/lib/compiler/ast/block.fy +24 -20
- data/lib/compiler/ast/message_send.fy +11 -0
- data/lib/contracts.fy +60 -0
- data/lib/dynamic_slot_object.fy +61 -0
- data/lib/enumerable.fy +432 -394
- data/lib/enumerator.fy +152 -150
- data/lib/fdoc.fy +4 -17
- data/lib/fiber.fy +4 -10
- data/lib/file.fy +33 -25
- data/lib/future.fy +59 -5
- data/lib/hash.fy +54 -1
- data/lib/html.fy +107 -0
- data/lib/kvo.fy +173 -0
- data/lib/main.fy +6 -2
- data/lib/message_sink.fy +19 -0
- data/lib/number.fy +48 -0
- data/lib/object.fy +65 -13
- data/lib/package.fy +12 -2
- data/lib/package/dependency.fy +13 -0
- data/lib/package/dependency_installer.fy +27 -0
- data/lib/package/installer.fy +4 -10
- data/lib/package/uninstaller.fy +1 -3
- data/lib/parser/ext/lexer.lex +8 -3
- data/lib/parser/ext/parser.y +4 -1
- data/lib/parser/methods.fy +7 -3
- data/lib/range.fy +1 -1
- data/lib/rbx.fy +2 -1
- data/lib/rbx/array.fy +28 -12
- data/lib/rbx/bignum.fy +1 -1
- data/lib/rbx/block.fy +27 -0
- data/lib/rbx/console.fy +6 -6
- data/lib/rbx/date.fy +6 -1
- data/lib/rbx/documentation.fy +8 -3
- data/lib/rbx/exception.fy +5 -0
- data/lib/rbx/file.fy +40 -7
- data/lib/rbx/fixnum.fy +12 -1
- data/lib/rbx/method.fy +9 -2
- data/lib/rbx/module.fy +24 -0
- data/lib/rbx/regexp.fy +8 -0
- data/lib/rbx/string.fy +23 -7
- data/lib/rbx/tcp_server.fy +4 -2
- data/lib/rbx/tcp_socket.fy +14 -0
- data/lib/remote_object.fy +59 -0
- data/lib/set.fy +15 -4
- data/lib/string.fy +38 -5
- data/lib/stringio.fy +1 -0
- data/lib/symbol.fy +4 -0
- data/lib/system.fy +22 -0
- data/lib/thread_pool.fy +2 -2
- data/lib/tuple.fy +18 -1
- data/lib/vars.fy +17 -0
- data/lib/version.fy +1 -1
- data/ruby_lib/fancy +6 -0
- data/tests/array.fy +30 -0
- data/tests/block.fy +106 -0
- data/tests/class.fy +19 -0
- data/tests/enumerable.fy +1 -1
- data/tests/enumerator.fy +5 -5
- data/tests/file.fy +28 -0
- data/tests/fixnum.fy +0 -50
- data/tests/future.fy +9 -24
- data/tests/hash.fy +35 -0
- data/tests/html.fy +33 -0
- data/tests/kvo.fy +101 -0
- data/tests/number.fy +75 -0
- data/tests/object.fy +50 -3
- data/tests/string.fy +19 -10
- data/tests/symbol.fy +5 -0
- data/tests/tuple.fy +7 -0
- data/tools/fancy-mode.el +5 -1
- metadata +22 -21
- data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/Makefile +0 -156
- data/boot/rbx-compiler/parser/lexer.c +0 -2310
- data/boot/rbx-compiler/parser/lexer.h +0 -315
- data/boot/rbx-compiler/parser/parser.c +0 -2946
- data/boot/rbx-compiler/parser/parser.h +0 -151
- data/lib/fiber_pool.fy +0 -78
- data/lib/method.fy +0 -6
- data/lib/parser/ext/Makefile +0 -156
- data/lib/parser/ext/fancy_parser.bundle +0 -0
- data/lib/parser/ext/lexer.c +0 -2392
- data/lib/parser/ext/lexer.h +0 -315
- data/lib/parser/ext/parser.c +0 -3251
- data/lib/parser/ext/parser.h +0 -161
@@ -0,0 +1,68 @@
|
|
1
|
+
class MalformedLogEntry : Error {
|
2
|
+
read_slot: 'text
|
3
|
+
def initialize: @text
|
4
|
+
}
|
5
|
+
|
6
|
+
class LogEntry {
|
7
|
+
read_write_slots: ('word, 'number)
|
8
|
+
|
9
|
+
def LogEntry parse_entry: text {
|
10
|
+
word, number = text split: "|"
|
11
|
+
number = number to_i
|
12
|
+
if: (word && number) then: {
|
13
|
+
LogEntry new do: {
|
14
|
+
word: word
|
15
|
+
number: number
|
16
|
+
}
|
17
|
+
} else: {
|
18
|
+
MalformedLogEntry new: text signal!
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
class LogFile {
|
24
|
+
read_slots: ('filename, 'entries)
|
25
|
+
def initialize: @filename entries: @entries ([]);
|
26
|
+
def parse {
|
27
|
+
@text = File read: @filename
|
28
|
+
with_restarts: {
|
29
|
+
skip_entry: { nil }
|
30
|
+
} do: {
|
31
|
+
@text lines each: |line| {
|
32
|
+
@entries << (LogEntry parse_entry: line)
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
class LogAnalyzer {
|
39
|
+
read_slots: ('words, 'numbers)
|
40
|
+
def initialize: @logfiles {
|
41
|
+
@words = <[]>
|
42
|
+
@numbers = <[]>
|
43
|
+
}
|
44
|
+
def analyze_all {
|
45
|
+
@entries = @logfiles map: |f| {
|
46
|
+
LogFile new: f . do: { parse } . entries
|
47
|
+
} flatten
|
48
|
+
|
49
|
+
@entries each: |e| { analyze: e }
|
50
|
+
}
|
51
|
+
def analyze: entry {
|
52
|
+
if: (@words[entry word]) then: |val| {
|
53
|
+
@words[entry word]: (val + 1)
|
54
|
+
} else: {
|
55
|
+
@words[entry word]: 1
|
56
|
+
}
|
57
|
+
if: (@numbers[entry number]) then: |val| {
|
58
|
+
@numbers[entry number]: (val + 1)
|
59
|
+
} else: {
|
60
|
+
@numbers[entry number]: 1
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
l = LogAnalyzer new: ["examples/conditions_parsing_log.log"]
|
66
|
+
l analyze_all
|
67
|
+
" words: #{l words to_a sort_by: 'second reverse inspect}" println
|
68
|
+
"numbers: #{l numbers to_a sort_by: 'second reverse inspect}" println
|
data/examples/greeter.fy
ADDED
data/examples/html_generator.fy
CHANGED
@@ -10,45 +10,75 @@ class String {
|
|
10
10
|
}
|
11
11
|
|
12
12
|
class HTML {
|
13
|
-
def
|
14
|
-
|
13
|
+
def initialize {
|
14
|
+
@buf = ""
|
15
|
+
}
|
16
|
+
|
17
|
+
def initialize: block {
|
18
|
+
initialize
|
19
|
+
block call_with_receiver: self
|
20
|
+
self
|
21
|
+
}
|
22
|
+
|
23
|
+
def open_tag: name attrs: attrs (<[]>) {
|
24
|
+
@buf << "<" << (name but_last)
|
25
|
+
unless: (attrs empty?) do: {
|
26
|
+
@buf << " "
|
27
|
+
attrs each: |k v| {
|
28
|
+
@buf << k << "=" << (v inspect)
|
29
|
+
} in_between: {
|
30
|
+
@buf << " "
|
31
|
+
}
|
32
|
+
}
|
33
|
+
@buf << ">"
|
15
34
|
}
|
16
35
|
|
17
36
|
def close_tag: name {
|
18
|
-
"</"
|
37
|
+
@buf << "</" << (name but_last) << ">"
|
19
38
|
}
|
20
39
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
40
|
+
def html_block: tag body: body attrs: attrs (<[]>) {
|
41
|
+
open_tag: tag attrs: attrs
|
42
|
+
match body first {
|
43
|
+
case Block -> @buf << (body first call)
|
44
|
+
case _ -> @buf << (body first)
|
45
|
+
}
|
46
|
+
close_tag: tag
|
47
|
+
}
|
24
48
|
|
25
|
-
|
26
|
-
|
27
|
-
|
49
|
+
def unknown_message: m with_params: p {
|
50
|
+
match m to_s {
|
51
|
+
case /with:$/ ->
|
52
|
+
tag = m to_s substitute: /with:$/ with: ""
|
53
|
+
html_block: tag body: (p rest) attrs: (p first)
|
54
|
+
case _ ->
|
55
|
+
html_block: (m to_s) body: p
|
28
56
|
}
|
57
|
+
nil
|
58
|
+
}
|
29
59
|
|
30
|
-
|
60
|
+
def to_s {
|
61
|
+
@buf
|
31
62
|
}
|
32
63
|
}
|
33
64
|
|
34
|
-
# lets generate some simple HTML output )
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
]
|
65
|
+
# lets generate some simple HTML output :)
|
66
|
+
HTML new: |h| {
|
67
|
+
html: {
|
68
|
+
body: <['id => "body id" ]> with: {
|
69
|
+
div: {
|
70
|
+
"hello, world!"
|
71
|
+
}
|
72
|
+
div: {
|
73
|
+
p: {
|
74
|
+
"OKIDOKI"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
div: {
|
78
|
+
h3: {
|
79
|
+
"oh no!"
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
53
83
|
}
|
54
84
|
} . println
|
@@ -1,18 +1,15 @@
|
|
1
1
|
# webserver.fy
|
2
2
|
# Example of a simple webserver written in fancy, using Ruby socket library
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
port = 3000
|
7
|
-
webserver = TCPServer new(host, port)
|
4
|
+
host, port = "127.0.0.1", 3000
|
5
|
+
webserver = TCPServer new: host port: port
|
8
6
|
"Webserver running at: #{host}:#{port}" println
|
7
|
+
|
9
8
|
loop: {
|
10
9
|
session = webserver accept
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
session print: content
|
17
|
-
session close
|
10
|
+
Thread new: {
|
11
|
+
session print: "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n"
|
12
|
+
session print: $ File read: "examples/webserver/index.html"
|
13
|
+
session close
|
14
|
+
}
|
18
15
|
}
|
data/lib/argv.fy
CHANGED
data/lib/array.fy
CHANGED
@@ -5,7 +5,7 @@ class Array {
|
|
5
5
|
index-based access to members.
|
6
6
|
"""
|
7
7
|
|
8
|
-
include:
|
8
|
+
include: Fancy Enumerable
|
9
9
|
|
10
10
|
def Array new: size {
|
11
11
|
"""
|
@@ -160,22 +160,6 @@ class Array {
|
|
160
160
|
self
|
161
161
|
}
|
162
162
|
|
163
|
-
def each_with_index: block {
|
164
|
-
"""
|
165
|
-
@block @Block@ to be called with each element and its inde in the @Array@.
|
166
|
-
@return @self
|
167
|
-
|
168
|
-
Iterate over all elements in @Array@.
|
169
|
-
Calls a given @Block@ with each element and its index.
|
170
|
-
"""
|
171
|
-
|
172
|
-
i = 0
|
173
|
-
each: |x| {
|
174
|
-
block call: [x, i]
|
175
|
-
i = i + 1
|
176
|
-
}
|
177
|
-
}
|
178
|
-
|
179
163
|
def =? other {
|
180
164
|
"""
|
181
165
|
@other Other @Array@ to compare this one to.
|
@@ -441,24 +425,6 @@ class Array {
|
|
441
425
|
subarr
|
442
426
|
}
|
443
427
|
|
444
|
-
def select: block {
|
445
|
-
"""
|
446
|
-
@block Predicate @Block@ to be used as filter.
|
447
|
-
@return @Array@ of all the elements for which @block doesn't yield @false or @nil.
|
448
|
-
|
449
|
-
Returns a new Array with all the elements in self that yield a
|
450
|
-
true-ish value when called with the given Block.
|
451
|
-
"""
|
452
|
-
|
453
|
-
tmp = []
|
454
|
-
each: |x| {
|
455
|
-
if: (block call: [x]) then: {
|
456
|
-
tmp << x
|
457
|
-
}
|
458
|
-
}
|
459
|
-
return tmp
|
460
|
-
}
|
461
|
-
|
462
428
|
def select_with_index: block {
|
463
429
|
"""
|
464
430
|
Same as #select:, just gets also called with an additional argument
|
@@ -474,6 +440,22 @@ class Array {
|
|
474
440
|
tmp
|
475
441
|
}
|
476
442
|
|
443
|
+
def to_hash {
|
444
|
+
"""
|
445
|
+
Returns a @Hash@ with each key-value pair in @self.
|
446
|
+
|
447
|
+
Example:
|
448
|
+
[[1,2],[3,4]] to_hash # => <[1 => 2, 3 => 4]>
|
449
|
+
"""
|
450
|
+
|
451
|
+
h = <[]>
|
452
|
+
self each: |pair| {
|
453
|
+
k,v = pair
|
454
|
+
h[k]: v
|
455
|
+
}
|
456
|
+
h
|
457
|
+
}
|
458
|
+
|
477
459
|
def Array === object {
|
478
460
|
"""
|
479
461
|
@object Object to match @self against.
|
data/lib/block.fy
CHANGED
@@ -120,7 +120,88 @@ class Block {
|
|
120
120
|
call: [val]
|
121
121
|
}
|
122
122
|
|
123
|
+
def Block inspect {
|
124
|
+
name
|
125
|
+
}
|
126
|
+
|
123
127
|
def Block name {
|
124
128
|
"Block"
|
125
129
|
}
|
126
|
-
|
130
|
+
|
131
|
+
def [args] {
|
132
|
+
"""
|
133
|
+
Same as Block#call:
|
134
|
+
"""
|
135
|
+
|
136
|
+
call: args
|
137
|
+
}
|
138
|
+
|
139
|
+
def to_object {
|
140
|
+
"""
|
141
|
+
Creates and returns a new @Object@ with slots defined dynamically in @self.
|
142
|
+
Looks and feels similar to Javascript object literals.
|
143
|
+
|
144
|
+
Example:
|
145
|
+
o = {
|
146
|
+
something: \"foo bar baz\"
|
147
|
+
with: 42
|
148
|
+
} to_object
|
149
|
+
|
150
|
+
o something # => \"foo bar baz\"
|
151
|
+
o with # => 42
|
152
|
+
"""
|
153
|
+
|
154
|
+
obj = DynamicSlotObject new do: self . object
|
155
|
+
obj metaclass read_write_slots: (obj slots)
|
156
|
+
obj
|
157
|
+
}
|
158
|
+
|
159
|
+
def to_hash {
|
160
|
+
"""
|
161
|
+
Creates and returns a new @Hash@ with keys and values defined dynamically in @self.
|
162
|
+
Similar to @Block#object@ but returning a @Hash@ instead of an @Object@
|
163
|
+
|
164
|
+
Example:
|
165
|
+
o = {
|
166
|
+
something: \"foo bar baz\"
|
167
|
+
with: 42
|
168
|
+
} to_hash # => <['something => \"foo bar baz\", 'with => 42]>
|
169
|
+
"""
|
170
|
+
|
171
|
+
DynamicKeyHash new do: self . hash
|
172
|
+
}
|
173
|
+
|
174
|
+
def to_hash_deep {
|
175
|
+
"""
|
176
|
+
Creates and returns a new @Hash@ with keys and values defined dynamically in @self.
|
177
|
+
Similar to @Block#to_hash@ but converting any value that's a @Block@ to a @Hash@ as well.
|
178
|
+
|
179
|
+
Example:
|
180
|
+
o = {
|
181
|
+
something: \"foo bar baz\"
|
182
|
+
with: 42
|
183
|
+
and: {
|
184
|
+
another: 'field
|
185
|
+
}
|
186
|
+
} to_hash_deep # => <['something => \"foo bar baz\", 'with => 42, 'and => <['another => 'field]>]>
|
187
|
+
"""
|
188
|
+
|
189
|
+
DynamicKeyHash new: true . do: self . hash
|
190
|
+
}
|
191
|
+
|
192
|
+
def to_a {
|
193
|
+
"""
|
194
|
+
Creates and returns a new @Array@ with values defined dynamically in @self.
|
195
|
+
Similar to @Block#to_hash@ but returning an @Array@ instead of a @Hash@
|
196
|
+
|
197
|
+
Example:
|
198
|
+
a = {
|
199
|
+
something: \"foo bar baz\"
|
200
|
+
with: 42
|
201
|
+
something; else
|
202
|
+
} to_a # => [['something, \"foo bar baz\"], ['with, 42], 'something, 'else]
|
203
|
+
"""
|
204
|
+
|
205
|
+
DynamicValueArray new do: self . array
|
206
|
+
}
|
207
|
+
}
|
data/lib/boot.fy
CHANGED
@@ -24,6 +24,7 @@ require: "string"
|
|
24
24
|
require: "array"
|
25
25
|
require: "range"
|
26
26
|
require: "tuple"
|
27
|
+
require: "dynamic_slot_object"
|
27
28
|
require: "block"
|
28
29
|
require: "iteration"
|
29
30
|
require: "integer"
|
@@ -33,19 +34,20 @@ require: "directory"
|
|
33
34
|
require: "hash"
|
34
35
|
require: "set"
|
35
36
|
require: "symbol"
|
36
|
-
require: "method"
|
37
37
|
require: "stack"
|
38
38
|
require: "proxy"
|
39
39
|
require: "thread_pool"
|
40
40
|
require: "fiber"
|
41
|
-
require: "fiber_pool"
|
42
41
|
require: "future"
|
43
42
|
require: "struct"
|
43
|
+
require: "message_sink"
|
44
|
+
require: "kvo"
|
44
45
|
|
45
46
|
# version holds fancy's version number
|
46
47
|
require: "version"
|
47
48
|
require: "argv"
|
48
49
|
require: "vars"
|
50
|
+
require: "system"
|
49
51
|
|
50
52
|
require: "documentation"
|
51
53
|
|
data/lib/compiler.fy
CHANGED