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
@@ -1,9 +1,11 @@
1
- require("socket")
2
-
3
1
  class TCPServer {
4
2
  """
5
3
  TCP Server
6
4
  """
7
5
 
8
6
  ruby_alias: 'accept
7
+
8
+ def TCPServer new: host port: port {
9
+ new(host, port)
10
+ }
9
11
  }
@@ -5,6 +5,8 @@ class TCPSocket {
5
5
  TCP Socket class.
6
6
  """
7
7
 
8
+ forwards_unary_ruby_methods
9
+
8
10
  def TCPSocket open: server port: port {
9
11
  """
10
12
  @server Server hostname to open Socket on.
@@ -15,4 +17,16 @@ class TCPSocket {
15
17
 
16
18
  open(server, port)
17
19
  }
20
+
21
+ def send: msg flags: flags (0) {
22
+ send(msg, flags)
23
+ }
24
+
25
+ def recv: maxlen {
26
+ recv(maxlen)
27
+ }
28
+
29
+ def read: n {
30
+ read(n)
31
+ }
18
32
  }
@@ -0,0 +1,59 @@
1
+ require: "fyzmq"
2
+
3
+ class RemoteObject : BasicObject {
4
+ def initialize {
5
+ @context = ZMQ Context new
6
+ @sock = @context socket: ZMQ PAIR
7
+ Thread new: { self receive_remote }
8
+ }
9
+
10
+ def bind: port {
11
+ bind_addr = "ipc://127.0.0.1:#{port}"
12
+ "Binding #{self} to #{bind_addr}" println
13
+ @sock bind: bind_addr
14
+ }
15
+
16
+ def connect_port: port {
17
+ connect: "ipc://127.0.0.1:#{port}"
18
+ }
19
+
20
+ def connect: addr {
21
+ @sock connect: addr
22
+ "Connected #{self} to #{addr}" println
23
+ }
24
+
25
+ def receive_remote {
26
+ loop: {
27
+ "waiting" println
28
+ msg = @sock recv
29
+ "Got: #{msg inspect}" println
30
+ }
31
+ }
32
+
33
+ def send_async: message with_params: p {
34
+ "sending" println
35
+ @sock send: "foo" # ('send, message, p inspect)
36
+ }
37
+
38
+ def to_s {
39
+ "#<RemoteObject:#{object_id to_s: 16}>"
40
+ }
41
+
42
+ def inspect {
43
+ to_s
44
+ }
45
+ }
46
+
47
+ r = RemoteObject new
48
+
49
+ if: (ARGV includes?: "bind") then: {
50
+ r bind: 3001
51
+ } else: {
52
+ r connect_port: 3001
53
+ }
54
+
55
+ Thread sleep: 2
56
+
57
+ r send_async: 'to_s: with_params: 16
58
+
59
+ Thread sleep: 2
data/lib/set.fy CHANGED
@@ -3,11 +3,11 @@ class Set {
3
3
  A simple Set data structure class.
4
4
  """
5
5
 
6
- include: FancyEnumerable
6
+ include: Fancy Enumerable
7
7
 
8
8
  def initialize: values {
9
9
  """
10
- @values @FancyEnumerable@ of values to be used as values for @self.
10
+ @values @Fancy::Enumerable@ of values to be used as values for @self.
11
11
 
12
12
  Initialize a new Set with a given collection of values.
13
13
  """
@@ -70,7 +70,7 @@ class Set {
70
70
 
71
71
  def Set [values] {
72
72
  """
73
- @values @FancyEnumerable@ of values used for new Set.
73
+ @values @Fancy::Enumerable@ of values used for new Set.
74
74
 
75
75
  Initialize a new Set with a given collection of values.
76
76
  """
@@ -95,12 +95,23 @@ class Set {
95
95
  @value Value to be checked for if included in @self.
96
96
  @return @true if @value in @self, @false otherwise.
97
97
 
98
- Indicates, if the Set includes a given value.
98
+ Indicates, if the Set includes @value.
99
99
  """
100
100
 
101
101
  @hash includes?: value
102
102
  }
103
103
 
104
+ def [value] {
105
+ """
106
+ @value Value to be checked for if included in @self.
107
+ @return @true if @value is in @self, @nil otherwise.
108
+
109
+ Indicates, if the Set includes @value.
110
+ """
111
+
112
+ @hash[value]
113
+ }
114
+
104
115
  def each: block {
105
116
  """
106
117
  @block @Block@ to be called with each value in @self.
@@ -4,11 +4,29 @@ class String {
4
4
  All literal Strings within Fancy code are instances of the String
5
5
  class.
6
6
 
7
- They also include FancyEnumerable, which means you can use all the
7
+ They also include @Fancy::Enumerable@, which means you can use all the
8
8
  common sequence methods on them, like +map:+, +select:+ etc.
9
9
  """
10
10
 
11
- include: FancyEnumerable
11
+ include: Fancy Enumerable
12
+
13
+ instance_method: '== . documentation: """
14
+ Compares @self to another @String@ and returns @true, if equal, @false otherwise.
15
+ """
16
+
17
+ instance_method: 'uppercase . documentation: """
18
+ @return Uppercased version of @self.
19
+
20
+ Example:
21
+ \"hello world\" uppercase # => \"HELLO WORLD\"
22
+ """
23
+
24
+ instance_method: 'lowercase . documentation: """
25
+ @return Lowercased version of @self.
26
+
27
+ Example:
28
+ \"HELLO WORLD\" lowercase # => \"hello world\"
29
+ """
12
30
 
13
31
  def ++ other {
14
32
  """
@@ -52,7 +70,9 @@ class String {
52
70
  @return @String@ that is the num-fold concatenation of @self.
53
71
 
54
72
  Returns a @String@ that is the num-fold concatenation of itself.
55
- \"foo\" * 3 # => \”foofoofoo\"
73
+
74
+ Example:
75
+ \"foo\" * 3 # => \"foofoofoo\"
56
76
  """
57
77
 
58
78
  str = ""
@@ -66,6 +86,7 @@ class String {
66
86
  """
67
87
  @return @Array@ of all the whitespace seperated words in @self.
68
88
 
89
+ Example:
69
90
  \"hello world\" words # => [\"hello\", \"world\"]
70
91
  """
71
92
 
@@ -156,13 +177,25 @@ class String {
156
177
 
157
178
  def bytes {
158
179
  """
159
- @return @FancyEnumerator@ of all bytes (@Fixnum@ values) in @self.
180
+ @return @Fancy::Enumerator@ of all bytes (@Fixnum@ values) in @self.
160
181
  """
161
182
 
162
183
  enum = bytes()
163
184
  def enum each: block {
164
185
  each(&block)
165
186
  }
166
- FancyEnumerator new: enum
187
+ Fancy Enumerator new: enum
188
+ }
189
+
190
+ def relative_path: path {
191
+ """
192
+ @path Relative path to @self.
193
+ @return Absolute @File@ path relative to @self.
194
+
195
+ Example:
196
+ __FILE__ relative: \"../foo/bar\"
197
+ """
198
+
199
+ File expand_path: $ File dirname(self) + "/" + path
167
200
  }
168
201
  }
@@ -0,0 +1 @@
1
+ require: "rbx/stringio"
@@ -44,4 +44,8 @@ class Symbol {
44
44
  def arity {
45
45
  1
46
46
  }
47
+
48
+ def to_sym {
49
+ self
50
+ }
47
51
  }
@@ -0,0 +1,22 @@
1
+ class System {
2
+ def System abort {
3
+ """
4
+ Exits the current running Fancy process (application) with an exit
5
+ code of 1 (indicating failure).
6
+ """
7
+
8
+ exit: 1
9
+ }
10
+
11
+ def System abort: message {
12
+ """
13
+ @message Error message to be printed before aborting programm execution.
14
+
15
+ Prints a given message on @*stderr* and then exits with an exit
16
+ code of 1 (indicating failure).
17
+ """
18
+
19
+ *stderr* println: message
20
+ abort
21
+ }
22
+ }
@@ -76,12 +76,12 @@ class ThreadPool {
76
76
 
77
77
  # Kills all threads
78
78
  def close {
79
- @executors each: |e| { e close }
79
+ @executors each: @{ close }
80
80
  }
81
81
 
82
82
  # Sleeps and blocks until the task queue is finished executing
83
83
  def join {
84
- { Thread sleep: 0.1 } until: { { @queue empty? } && { @executors all?: |e| { e active not } } }
84
+ { Thread sleep: 0.1 } until: { { @queue empty? } && { @executors all?: @{ active not } } }
85
85
  }
86
86
 
87
87
  class Completable {
@@ -4,7 +4,24 @@ class Tuple {
4
4
  elements.
5
5
  """
6
6
 
7
- include: FancyEnumerable
7
+ include: Fancy Enumerable
8
+
9
+ def Tuple with_values: values {
10
+ """
11
+ @values Values of the @Tuple@ to be created.
12
+
13
+ Creates a new @Tuple@ with the @values passed in.
14
+
15
+ Example:
16
+ Tuple with_values: [1,2,3] # => (1,2,3)
17
+ """
18
+
19
+ t = Tuple new: $ values size
20
+ values each_with_index: |v i| {
21
+ t[i]: v
22
+ }
23
+ t
24
+ }
8
25
 
9
26
  def [idx] {
10
27
  """
@@ -1,3 +1,20 @@
1
1
  *stdin* = STDIN
2
2
  *stdout* = STDOUT
3
3
  *stderr* = STDERR
4
+
5
+ __AFTER__BOOTSTRAP__: {
6
+ *stdin* documentation: """
7
+ The Standard Input stream.
8
+ Can be rebound to any @IO@ stream via @Object#let:be:in:@.
9
+ """
10
+
11
+ *stdout* documentation: """
12
+ The Standard Output stream.
13
+ Can be rebound to any @IO@ stream via @Object#let:be:in:@.
14
+ """
15
+
16
+ *stderr* documentation: """
17
+ The Standard Error Output stream.
18
+ Can be rebound to any @IO@ stream via @Object#let:be:in:@.
19
+ """
20
+ }
@@ -1,5 +1,5 @@
1
1
  VERSION_MAJOR = 0
2
- VERSION_MINOR = 4
2
+ VERSION_MINOR = 6
3
3
  VERSION_PATCH = 0
4
4
  VERSION_SUFFIX = "alpha"
5
5
 
@@ -4,6 +4,12 @@
4
4
  base = File.dirname(__FILE__)
5
5
  require File.expand_path("../boot/fancy_ext", base)
6
6
 
7
+ class Object
8
+ define_method("__AFTER__BOOTSTRAP__:") do |block|
9
+ block.call
10
+ end
11
+ end
12
+
7
13
  # Use the bootstrapping code loader.
8
14
  require File.expand_path("../boot/load", base)
9
15
 
@@ -61,6 +61,26 @@ FancySpec describe: Array with: {
61
61
  arr size is: 0
62
62
  }
63
63
 
64
+ it: "creates a new array with a given default value" with: 'new: when: {
65
+ arr = Array new: 5
66
+ arr size is: 5
67
+ arr each: |x| {
68
+ x is: nil
69
+ }
70
+
71
+ arr = Array new: 5 with: "hello"
72
+ arr size is: 5
73
+ arr each: |x| {
74
+ x is: "hello"
75
+ }
76
+
77
+ arr = Array new: 5 with: { 2 + 3 }
78
+ arr size is: 5
79
+ arr each: |x| {
80
+ x is: 5
81
+ }
82
+ }
83
+
64
84
  it: "returns the correct value via index access" with: 'at: when: {
65
85
  arr = ['a, 10, "hello, world"]
66
86
  arr at: 2 . is: "hello, world"
@@ -522,4 +542,14 @@ FancySpec describe: Array with: {
522
542
 
523
543
  (20,30,40) in_groups_of: 2 . is: [[20,30], [40]]
524
544
  }
545
+
546
+ it: "returns a hash" with: 'to_hash when: {
547
+ [] to_hash is: <[]>
548
+ [[1,2],[3,4]] to_hash is: <[1 => 2, 3 => 4]>
549
+ }
550
+
551
+ it: "returns a hash based on a key-block" with: 'to_hash: when: {
552
+ [] to_hash: @{ size } . is: <[]>
553
+ [[1,2],[3,4,5]] to_hash: @{ size } . is: <[2 => [1,2], 3 => [3,4,5]]>
554
+ }
525
555
  }
@@ -113,6 +113,28 @@ FancySpec describe: Block with: {
113
113
  [1,2,3] map: @{to_s * 3} . is: ["111", "222", "333"]
114
114
  }
115
115
 
116
+ it: "calls the block as a partial block, converting it to implicit message sends to the first argument" when: {
117
+ b = @{
118
+ inspect println
119
+ class println
120
+ * 2 println
121
+ 'test println
122
+ }
123
+
124
+ require: "stringio"
125
+
126
+ out = StringIO new
127
+ let: '*stdout* be: out in: {
128
+ b call: ["Hello, World"]
129
+ b call: [1]
130
+ b call: [1, 2, 3]
131
+ }
132
+ expected_output = ["\"Hello, World\"\nString\nHello, WorldHello, World\ntest\n",
133
+ "1\nFixnum\n2\ntest\n",
134
+ "[1, 2, 3]\nArray\n1\n2\n3\n1\n2\n3\ntest\n"] join
135
+ out string is: expected_output
136
+ }
137
+
116
138
  it: "executes a match clause if the block returns a true-ish value" with: '=== when: {
117
139
  def do_match: val {
118
140
  match val {
@@ -196,4 +218,88 @@ FancySpec describe: Block with: {
196
218
  b2("hello") is: ("hello" * 5)
197
219
  b2("foo") is: (b2 call: ["foo"])
198
220
  }
221
+
222
+ it: "dynamically creates a object with slots defined in a Block" with: 'to_object when: {
223
+ o = {
224
+ name: "John Connor"
225
+ age: 12
226
+ city: "Los Angeles"
227
+ persecuted_by: $ {
228
+ name: "The Terminator"
229
+ age: 'unknown
230
+ } to_object
231
+ } to_object
232
+
233
+ o name is: "John Connor"
234
+ o age is: 12
235
+ o city is: "Los Angeles"
236
+ o persecuted_by do: {
237
+ name is: "The Terminator"
238
+ age is: 'unknown
239
+ }
240
+ }
241
+
242
+ it: "dynamically creates a hash with keys and values defined in a Block" with: 'to_hash when: {
243
+ { } to_hash is: <[]>
244
+ { foo: "bar" } to_hash is: <['foo => "bar"]>
245
+ { foo: "bar"; bar: "baz" } to_hash is: <['foo => "bar", 'bar => "baz"]>
246
+ h = {
247
+ name: "John Connor"
248
+ age: 12
249
+ city: "Los Angeles"
250
+ persecuted_by: $ {
251
+ name: "The Terminator"
252
+ age: 'unknown
253
+ } to_hash
254
+ } to_hash
255
+
256
+ h is: <['name => "John Connor",
257
+ 'age => 12,
258
+ 'city => "Los Angeles",
259
+ 'persecuted_by => <[
260
+ 'name => "The Terminator",
261
+ 'age => 'unknown
262
+ ]>
263
+ ]>
264
+ }
265
+
266
+ it: "dynamically creates a hash with keys and values defined in a Block (deep)" with: 'to_hash_deep when: {
267
+ { } to_hash_deep is: <[]>
268
+ { foo: "bar" } to_hash_deep is: <['foo => "bar"]>
269
+ h = {
270
+ name: "John Connor"
271
+ age: 12
272
+ city: "Los Angeles"
273
+ persecuted_by: {
274
+ name: "The Terminator"
275
+ age: 'unknown
276
+ }
277
+ } to_hash_deep
278
+
279
+ h is: <['name => "John Connor",
280
+ 'age => 12,
281
+ 'city => "Los Angeles",
282
+ 'persecuted_by => <[
283
+ 'name => "The Terminator",
284
+ 'age => 'unknown
285
+ ]>
286
+ ]>
287
+ h['persecuted_by] is: <['name => "The Terminator", 'age => 'unknown]>
288
+ }
289
+
290
+ it: "dynamically creates an array with values defined in a Block" with: 'to_a when: {
291
+ { } to_a is: []
292
+ { foo } to_a is: ['foo]
293
+ { foo; bar; baz } to_a is: ['foo, 'bar, 'baz]
294
+ { foo bar baz } to_a is: ['foo, 'bar, 'baz]
295
+ {
296
+ name: "Chris"
297
+ age: 24
298
+ city: "San Francisco"
299
+ male; programmer; happy
300
+ } to_a is: [['name, "Chris"],
301
+ ['age, 24],
302
+ ['city, "San Francisco"],
303
+ 'male, 'programmer, 'happy]
304
+ }
199
305
  }