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
@@ -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
  }