fancy 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/AUTHORS +2 -0
  2. data/README.md +6 -1
  3. data/bin/fancy +6 -0
  4. data/bin/ifancy +44 -3
  5. data/boot/fancy_ext/module.rb +4 -0
  6. data/boot/fancy_ext/object.rb +4 -0
  7. data/boot/rbx-compiler/compiler/ast/block.rb +29 -1
  8. data/boot/rbx-compiler/compiler/ast/identifier.rb +6 -0
  9. data/boot/rbx-compiler/compiler/ast/message_send.rb +1 -0
  10. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  11. data/boot/rbx-compiler/parser/lexer.lex +2 -0
  12. data/boot/rbx-compiler/parser/parser.rb +6 -0
  13. data/boot/rbx-compiler/parser/parser.y +14 -1
  14. data/doc/api/fancy.jsonp +1 -1
  15. data/doc/features.md +24 -0
  16. data/examples/99bottles.fy +5 -0
  17. data/examples/conditions_exceptions.fy +9 -0
  18. data/examples/conditions_parsing.fy +68 -0
  19. data/examples/greeter.fy +9 -0
  20. data/examples/html_generator.fy +59 -29
  21. data/examples/webserver/webserver.fy +8 -11
  22. data/lib/argv.fy +6 -0
  23. data/lib/array.fy +17 -35
  24. data/lib/block.fy +82 -1
  25. data/lib/boot.fy +4 -2
  26. data/lib/compiler.fy +2 -2
  27. data/lib/compiler/ast/block.fy +24 -20
  28. data/lib/compiler/ast/message_send.fy +11 -0
  29. data/lib/contracts.fy +60 -0
  30. data/lib/dynamic_slot_object.fy +61 -0
  31. data/lib/enumerable.fy +432 -394
  32. data/lib/enumerator.fy +152 -150
  33. data/lib/fdoc.fy +4 -17
  34. data/lib/fiber.fy +4 -10
  35. data/lib/file.fy +33 -25
  36. data/lib/future.fy +59 -5
  37. data/lib/hash.fy +54 -1
  38. data/lib/html.fy +107 -0
  39. data/lib/kvo.fy +173 -0
  40. data/lib/main.fy +6 -2
  41. data/lib/message_sink.fy +19 -0
  42. data/lib/number.fy +48 -0
  43. data/lib/object.fy +65 -13
  44. data/lib/package.fy +12 -2
  45. data/lib/package/dependency.fy +13 -0
  46. data/lib/package/dependency_installer.fy +27 -0
  47. data/lib/package/installer.fy +4 -10
  48. data/lib/package/uninstaller.fy +1 -3
  49. data/lib/parser/ext/lexer.lex +8 -3
  50. data/lib/parser/ext/parser.y +4 -1
  51. data/lib/parser/methods.fy +7 -3
  52. data/lib/range.fy +1 -1
  53. data/lib/rbx.fy +2 -1
  54. data/lib/rbx/array.fy +28 -12
  55. data/lib/rbx/bignum.fy +1 -1
  56. data/lib/rbx/block.fy +27 -0
  57. data/lib/rbx/console.fy +6 -6
  58. data/lib/rbx/date.fy +6 -1
  59. data/lib/rbx/documentation.fy +8 -3
  60. data/lib/rbx/exception.fy +5 -0
  61. data/lib/rbx/file.fy +40 -7
  62. data/lib/rbx/fixnum.fy +12 -1
  63. data/lib/rbx/method.fy +9 -2
  64. data/lib/rbx/module.fy +24 -0
  65. data/lib/rbx/regexp.fy +8 -0
  66. data/lib/rbx/string.fy +23 -7
  67. data/lib/rbx/tcp_server.fy +4 -2
  68. data/lib/rbx/tcp_socket.fy +14 -0
  69. data/lib/remote_object.fy +59 -0
  70. data/lib/set.fy +15 -4
  71. data/lib/string.fy +38 -5
  72. data/lib/stringio.fy +1 -0
  73. data/lib/symbol.fy +4 -0
  74. data/lib/system.fy +22 -0
  75. data/lib/thread_pool.fy +2 -2
  76. data/lib/tuple.fy +18 -1
  77. data/lib/vars.fy +17 -0
  78. data/lib/version.fy +1 -1
  79. data/ruby_lib/fancy +6 -0
  80. data/tests/array.fy +30 -0
  81. data/tests/block.fy +106 -0
  82. data/tests/class.fy +19 -0
  83. data/tests/enumerable.fy +1 -1
  84. data/tests/enumerator.fy +5 -5
  85. data/tests/file.fy +28 -0
  86. data/tests/fixnum.fy +0 -50
  87. data/tests/future.fy +9 -24
  88. data/tests/hash.fy +35 -0
  89. data/tests/html.fy +33 -0
  90. data/tests/kvo.fy +101 -0
  91. data/tests/number.fy +75 -0
  92. data/tests/object.fy +50 -3
  93. data/tests/string.fy +19 -10
  94. data/tests/symbol.fy +5 -0
  95. data/tests/tuple.fy +7 -0
  96. data/tools/fancy-mode.el +5 -1
  97. metadata +22 -21
  98. data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
  99. data/boot/rbx-compiler/parser/Makefile +0 -156
  100. data/boot/rbx-compiler/parser/lexer.c +0 -2310
  101. data/boot/rbx-compiler/parser/lexer.h +0 -315
  102. data/boot/rbx-compiler/parser/parser.c +0 -2946
  103. data/boot/rbx-compiler/parser/parser.h +0 -151
  104. data/lib/fiber_pool.fy +0 -78
  105. data/lib/method.fy +0 -6
  106. data/lib/parser/ext/Makefile +0 -156
  107. data/lib/parser/ext/fancy_parser.bundle +0 -0
  108. data/lib/parser/ext/lexer.c +0 -2392
  109. data/lib/parser/ext/lexer.h +0 -315
  110. data/lib/parser/ext/parser.c +0 -3251
  111. data/lib/parser/ext/parser.h +0 -161
@@ -0,0 +1,5 @@
1
+ # see http://bottles.heroku.com/wall/99
2
+ 99 downto: 2 do: |i| {
3
+ "#{i} bottles of beer on the wall, #{i} bottles of beer." println
4
+ "Take one down and pass it around, #{i - 1} bottles of beer on the wall.\n" println
5
+ }
@@ -0,0 +1,9 @@
1
+ with_handlers: @{
2
+ when: ZeroDivisionError do: { restart: 'default }
3
+ } do: {
4
+ with_restarts: {
5
+ default: { 1 }
6
+ } do: {
7
+ 10 / 0 inspect println println
8
+ }
9
+ }
@@ -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
@@ -0,0 +1,9 @@
1
+ class Greeter {
2
+ def initialize: @name
3
+ def greet {
4
+ "Hello, #{@name}" println
5
+ }
6
+ }
7
+
8
+ g = Greeter new: "World!"
9
+ g greet # => "Hello, World!"
@@ -10,45 +10,75 @@ class String {
10
10
  }
11
11
 
12
12
  class HTML {
13
- def open_tag: name {
14
- "<" ++ (name but_last) ++ ">"
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
- "</" ++ (name but_last) ++ ">"
37
+ @buf << "</" << (name but_last) << ">"
19
38
  }
20
39
 
21
- def unknown_message: name with_params: params {
22
- name = name to_s
23
- str = open_tag: name
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
- body = params first call
26
- if: (body is_a?: Array) then: {
27
- body = body join
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
- str ++ body ++ (close_tag: name)
60
+ def to_s {
61
+ @buf
31
62
  }
32
63
  }
33
64
 
34
- # lets generate some simple HTML output )
35
- h = HTML new
36
- h html: {
37
- h body: {
38
- [
39
- h div: {
40
- "hello, world!"
41
- },
42
- h div: {
43
- h p: {
44
- "OKIDOKI"
45
- }
46
- },
47
- h div: {
48
- h h3: {
49
- "oh no!"
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
- require("socket")
5
- host = "127.0.0.1"
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
- session print: "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n"
12
- request = session readln
13
- filename = "examples/webserver/index.html"
14
- displayfile = File open(filename, "r")
15
- content = displayfile read
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
  }
@@ -39,3 +39,9 @@ def ARGV for_options: op_names do: block {
39
39
  }
40
40
  }
41
41
  }
42
+
43
+ def ARGV main?: filename {
44
+ if: (ARGV[0]) then: {
45
+ File expand_path: (ARGV[0]) . == filename
46
+ }
47
+ }
@@ -5,7 +5,7 @@ class Array {
5
5
  index-based access to members.
6
6
  """
7
7
 
8
- include: FancyEnumerable
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.
@@ -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
+ }
@@ -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
 
@@ -8,7 +8,7 @@ require: "compiler/ast"
8
8
 
9
9
  require: "parser"
10
10
 
11
- if: (__FILE__ == (ARGV[0])) then: {
11
+ if: (ARGV main?: __FILE__) then: {
12
12
  require: "compiler/command"
13
- Fancy Compiler Command run: ARGV
13
+ Fancy Compiler Command run: (ARGV rest)
14
14
  }