fancy 0.5.0 → 0.6.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.
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
  }