fancy 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +4 -1
  3. data/Rakefile +0 -52
  4. data/bin/fspec +22 -12
  5. data/bin/ifancy +1 -1
  6. data/boot/fancy_ext/class.rb +1 -0
  7. data/boot/fancy_ext/object.rb +8 -6
  8. data/boot/rbx-compiler/compiler/ast/method_def.rb +2 -0
  9. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  10. data/boot/rbx-compiler/parser/parser.y +9 -0
  11. data/doc/api/fancy.jsonp +1 -1
  12. data/examples/stupid_quicksort.fy +11 -9
  13. data/lib/array.fy +26 -58
  14. data/lib/block.fy +0 -1
  15. data/lib/boot.fy +2 -2
  16. data/lib/class.fy +85 -0
  17. data/lib/compiler/ast/class_def.fy +1 -1
  18. data/lib/compiler/ast/expression_list.fy +4 -12
  19. data/lib/compiler/ast/identifier.fy +3 -3
  20. data/lib/compiler/ast/method_def.fy +3 -1
  21. data/lib/compiler/ast/singleton_method_def.fy +4 -1
  22. data/lib/contracts.fy +53 -56
  23. data/lib/dynamic_slot_object.fy +39 -3
  24. data/lib/enumerable.fy +144 -47
  25. data/lib/fancy_spec.fy +2 -6
  26. data/lib/file.fy +67 -0
  27. data/lib/future.fy +42 -3
  28. data/lib/hash.fy +35 -29
  29. data/lib/html.fy +1 -1
  30. data/lib/integer.fy +34 -0
  31. data/lib/main.fy +13 -7
  32. data/lib/message_sink.fy +1 -1
  33. data/lib/number.fy +10 -0
  34. data/lib/object.fy +27 -1
  35. data/lib/package.fy +2 -0
  36. data/lib/package/handler.fy +56 -0
  37. data/lib/package/installer.fy +21 -51
  38. data/lib/package/specification.fy +12 -5
  39. data/lib/package/uninstaller.fy +22 -3
  40. data/lib/parser/ext/parser.y +9 -0
  41. data/lib/proxy.fy +25 -2
  42. data/lib/rbx.fy +2 -1
  43. data/lib/rbx/array.fy +16 -1
  44. data/lib/rbx/class.fy +34 -9
  45. data/lib/rbx/file.fy +2 -2
  46. data/lib/rbx/fixnum.fy +1 -11
  47. data/lib/rbx/io.fy +4 -0
  48. data/lib/rbx/module.fy +11 -0
  49. data/lib/rbx/object.fy +12 -12
  50. data/lib/rbx/proc.fy +7 -0
  51. data/lib/rbx/string.fy +5 -1
  52. data/lib/rbx/symbol.fy +9 -0
  53. data/lib/string.fy +1 -1
  54. data/lib/tuple.fy +37 -35
  55. data/lib/version.fy +6 -5
  56. data/tests/array.fy +14 -2
  57. data/tests/class.fy +79 -0
  58. data/tests/dynamic_key_hash.fy +16 -0
  59. data/tests/dynamic_slot_object.fy +28 -0
  60. data/tests/dynamic_value_array.fy +12 -0
  61. data/tests/enumerable.fy +46 -0
  62. data/tests/file.fy +38 -0
  63. data/tests/fixnum.fy +22 -0
  64. data/tests/future.fy +40 -0
  65. data/tests/hash.fy +8 -7
  66. data/tests/object.fy +31 -5
  67. data/tests/set.fy +1 -1
  68. data/tests/string.fy +18 -2
  69. data/tests/tuple.fy +7 -0
  70. data/tools/fancy-mode.el +10 -0
  71. metadata +9 -12
  72. data/examples/99bottles.fy +0 -5
  73. data/examples/conditions_exceptions.fy +0 -9
  74. data/examples/conditions_parsing.fy +0 -68
  75. data/examples/dynamic.fy +0 -8
  76. data/examples/greeter.fy +0 -9
  77. data/examples/parsing.fy +0 -1
  78. data/lib/rbx/process.fy +0 -13
  79. data/lib/remote_object.fy +0 -59
@@ -18,7 +18,7 @@ class Fancy AST {
18
18
 
19
19
  def bytecode: g {
20
20
  pos(g)
21
- docstring = body() body() shift_docstring
21
+ docstring = body() body() docstring
22
22
  docstring if_true: {
23
23
  setdoc = MessageSend new: @line \
24
24
  message: (Identifier from: "for:append:" line: @line) \
@@ -20,11 +20,7 @@ class Fancy AST {
20
20
  def bytecode: g {
21
21
  pos(g)
22
22
  size = @expressions size
23
- @expressions each: |expr| {
24
- size = size - 1
25
- expr bytecode: g
26
- { g pop() } if: (size > 0)
27
- }
23
+ @expressions each: @{ bytecode: g } in_between: { g pop() }
28
24
  }
29
25
 
30
26
  # This method is only used by Rubinius' compiler classes and
@@ -33,13 +29,9 @@ class Fancy AST {
33
29
  []
34
30
  }
35
31
 
36
- # If this expression list contains more than one expression
37
- # and the first one is an string literal, it'll be used as doc.
38
- # This method removes the first documentation string.
39
- def shift_docstring {
40
- if: ((@expressions first kind_of?(Rubinius AST StringLiteral)) && \
41
- (@expressions size > 1)) then: {
42
- @expressions shift()
32
+ def docstring {
33
+ if: (@expressions first kind_of?(Rubinius AST StringLiteral)) then: {
34
+ @expressions first
43
35
  }
44
36
  }
45
37
  }
@@ -57,9 +57,9 @@ class Fancy AST {
57
57
  def bytecode: g {
58
58
  pos(g)
59
59
  match @string {
60
- # case "true" -> g push_true()
61
- # case "false" -> g push_false()
62
- # case "nil" -> g push_nil()
60
+ case "true" -> g push_true()
61
+ case "false" -> g push_false()
62
+ case "nil" -> g push_nil()
63
63
  case _ ->
64
64
  if: (g state() scope() search_local(name)) then: {
65
65
  Rubinius AST LocalVariableAccess new(@line, name) bytecode(g)
@@ -3,7 +3,7 @@ class Fancy AST {
3
3
  def initialize: @line name: @name args: @arguments (MethodArgs new: @line) body: @body (ExpressionList new: @line) access: @access ('public) {
4
4
  { @body = ExpressionList new: @line } unless: @body
5
5
  @name = @name method_name: nil
6
- @docstring = @body shift_docstring
6
+ @docstring = @body docstring
7
7
  generate_ivar_assignment
8
8
 
9
9
  if: (@body empty?) then: {
@@ -71,6 +71,7 @@ class Fancy AST {
71
71
  to: (Self new: @line) \
72
72
  args: (MessageArgs new: @line args: [method_ident])
73
73
  ms bytecode: g
74
+ g pop()
74
75
  }
75
76
 
76
77
  def define_method_missing: g {
@@ -79,6 +80,7 @@ class Fancy AST {
79
80
  to: (Self new: @line) \
80
81
  args: (MessageArgs new: @line)
81
82
  ms bytecode: g
83
+ g pop()
82
84
  }
83
85
  }
84
86
 
@@ -16,6 +16,9 @@ class Fancy AST {
16
16
 
17
17
  class SingletonMethodDefScope : Rubinius AST DefineSingletonScope {
18
18
  def initialize: @line name: @name args: @arguments body: @body {
19
+ if: (@body empty?) then: {
20
+ @body unshift_expression: $ NilLiteral new: @line
21
+ }
19
22
  }
20
23
 
21
24
  define_method("bytecode") |g, recv| {
@@ -24,7 +27,7 @@ class Fancy AST {
24
27
 
25
28
  def bytecode: g receiver: receiver {
26
29
  pos(g)
27
- docstring = @body shift_docstring
30
+ docstring = @body docstring
28
31
  sup = Rubinius AST DefineSingletonScope instance_method('bytecode)
29
32
  sup bind(self) call(g, receiver)
30
33
  MethodDef set: g docstring: docstring line: @line argnames: $ @arguments names()
@@ -1,60 +1,57 @@
1
- class Object {
2
- def require: require_block ensure: ensure_block body: body_block {
3
- requirement = Contract Requirement new: require_block
4
- ensurance = Contract Requirement new: ensure_block
5
- retval = nil
6
- requirement if_fullfilled: {
7
- retval = body_block call
8
- }
9
- ensure_block if_fullfilled: {
10
- retval
11
- }
12
- }
13
-
14
- def require: require_block body: body_block {
15
- requirement = Contract Requirement new: require_block
16
- requirement if_fullfilled: {
17
- body_block call
18
- }
19
- }
20
-
21
- def ensure: ensure_block body: body_block {
22
- require: ensure_block body: body_block
23
- }
24
- }
25
-
26
- class Contract {
27
- class RequirementError : RuntimeError
28
- class Requirement {
29
- def initialize: @block
30
- def if_fullfilled: block {
31
- @block call: [self]
32
- block call
33
- }
34
- def true: expr {
35
- { RequirementError new: "#{expr} not true" . raise! } unless: expr
36
- }
37
- def false: expr {
38
- { RequirementError new: "#{expr} not false" . raise! } if: expr
39
- }
40
- }
41
- }
42
-
43
- # # usage:
44
- # class Fixnum {
45
- # def / other {
46
- # require: @{
47
- # true: $ other is_a?: Fixnum
48
- # true: $ other > 0
49
- # # better:
50
- # other class is: Fixnum
51
- # other is > 0
52
- #
53
- # } body: {
54
- # "foo" println
1
+ # class Class {
2
+ # class Contracts {
3
+ # class ConditionBuilder : Proxy {
4
+ # def initialize: block for: @method class: @class {
5
+ # @conditions = <[]>
6
+ # block call: [self]
7
+ # insert_validations
8
+ # }
9
+
10
+ # def unknown_message: m with_params: p {
11
+ # if: (p size > 0 ) then: {
12
+ # @conditions[m to_s[[0,-2]]]: $ p first
13
+ # }
14
+ # }
15
+
16
+ # def insert_validations {
17
+ # name = @method name()
18
+ # alias_name = "__#{name}__orig__"
19
+ # conditions = @conditions
20
+
21
+ # @class alias_method: alias_name for: name
22
+ # @class define_method: name with: |p| {
23
+ # conditions each: |attr block| {
24
+ # # TODO
25
+ # }
26
+ # receive_message: alias_name with_params: p
27
+ # }
28
+ # }
55
29
  # }
56
30
  # }
31
+
32
+ # def preconditions: block for: method {
33
+ # Contracts ConditionBuilder new: block for: method class: self
34
+ # }
35
+
36
+ # def postconditions: block for: method {
37
+ # Contracts ConditionBuilder new: block for: method class: self
38
+ # }
57
39
  # }
58
40
 
59
- # f = 10 / 2
60
- # g = 10 / 0 # requirement error
41
+ # # example
42
+
43
+ # class Person {
44
+ # read_slots: ('name, 'age)
45
+
46
+ # preconditions: @{
47
+ # name: @{ blank? not }
48
+ # age: @{ > 0 }
49
+ # } for: $ def initialize: @name age: @age
50
+ # }
51
+
52
+
53
+ # p = Person new: "chris" age: 25
54
+ # p inspect println
55
+
56
+
57
+ nil
@@ -1,9 +1,21 @@
1
- class DynamicSlotObject : BasicObject {
1
+ class DynamicSlotObject : Fancy BasicObject {
2
+ """
3
+ Helper class to dynamically create @Object@s with slots defined by sending messages to it.
4
+
5
+ Example:
6
+ dso = DynamicSlotObject new
7
+ dso name: \"Chris\"
8
+ dso age: 25
9
+ dso country: \"Germany\"
10
+ dso object # => Object with slots 'name, 'age and 'country defined
11
+ """
12
+
2
13
  def initialize {
3
14
  @object = Object new
4
15
  }
5
16
 
6
17
  def object {
18
+ @object metaclass read_write_slots: (@object slots)
7
19
  @object
8
20
  }
9
21
 
@@ -14,7 +26,18 @@ class DynamicSlotObject : BasicObject {
14
26
  }
15
27
  }
16
28
 
17
- class DynamicKeyHash : BasicObject {
29
+ class DynamicKeyHash : Fancy BasicObject {
30
+ """
31
+ Helper class to dynamically create @Hash@es with keys and values defined by sending messages to it.
32
+
33
+ Example:
34
+ dkh = DynamicKeyHash new
35
+ dkh name: \"Chris\"
36
+ dkh age: 25
37
+ dkh country: \"Germany\"
38
+ dkh hash # => <['name => \"Chris\", 'age => 25, 'country => \"Germany\"]>
39
+ """
40
+
18
41
  def initialize: @deep (false) {
19
42
  @hash = <[]>
20
43
  }
@@ -36,7 +59,20 @@ class DynamicKeyHash : BasicObject {
36
59
  }
37
60
  }
38
61
 
39
- class DynamicValueArray : BasicObject {
62
+ class DynamicValueArray : Fancy BasicObject {
63
+ """
64
+ Helper class to dynamically create @Array@s with values defined by sending messages to it.
65
+
66
+ Example:
67
+ dva = DynamicValueArray new
68
+ dva name: \"Chris\"
69
+ dva age: 25
70
+ dva country: \"Germany\"
71
+ dva something_else
72
+
73
+ dva array # => [['name, \"Chris\"], ['age, 25], ['country, \"Germany\"], 'something_else]
74
+ """
75
+
40
76
  def initialize {
41
77
  @arr = []
42
78
  }
@@ -4,6 +4,24 @@ class Fancy {
4
4
  Mixin-Class with useful methods for collections that implement an @each:@ method.
5
5
  """
6
6
 
7
+ def at: index {
8
+ """
9
+ @index @Fixnum@ that is the 0-based index into @self.
10
+ @return Value in @self at 0-based position defined by @index.
11
+
12
+ Example:
13
+ \"foo\” at: 2 # => \"o\"
14
+ \"foo\” at: 3 # => nil
15
+ """
16
+
17
+ i = 0
18
+ each: |x| {
19
+ { return x } if: $ i == index
20
+ i = i + 1
21
+ }
22
+ return nil
23
+ }
24
+
7
25
  def each_with_index: block {
8
26
  """
9
27
  @block @Block@ to be called with each element and its index in the @self.
@@ -20,6 +38,48 @@ class Fancy {
20
38
  }
21
39
  }
22
40
 
41
+ def first {
42
+ """
43
+ @return The first element in the @Fancy::Enumerable@.
44
+ """
45
+ at: 0
46
+ }
47
+
48
+ def second {
49
+ """
50
+ @return The second element in the @Fancy::Enumerable@.
51
+ """
52
+ at: 1
53
+ }
54
+
55
+ def third {
56
+ """
57
+ @return The third element in the @Fancy::Enumerable@.
58
+ """
59
+ at: 2
60
+ }
61
+
62
+ def fourth {
63
+ """
64
+ @return The fourth element in the @Fancy::Enumerable@.
65
+ """
66
+ at: 3
67
+ }
68
+
69
+ def last {
70
+ """
71
+ @return Last element in @self or @nil, if empty.
72
+
73
+ Returns the last element in a @Fancy::Enumerable@.
74
+ """
75
+
76
+ item = nil
77
+ each: |x| {
78
+ item = x
79
+ }
80
+ item
81
+ }
82
+
23
83
  def includes?: item {
24
84
  """
25
85
  @item Item to check if it's included in @self.
@@ -28,7 +88,7 @@ class Fancy {
28
88
  Indicates, if a collection includes a given element.
29
89
  """
30
90
 
31
- any?: |x| { item == x }
91
+ any?: |x| { x == item }
32
92
  }
33
93
 
34
94
  def each: each_block in_between: between_block {
@@ -44,7 +104,7 @@ class Fancy {
44
104
  }
45
105
  }
46
106
 
47
- def join: str {
107
+ def join: str ("") {
48
108
  """
49
109
  @str Value (usually a @String@) to be used for the joined @String@.
50
110
  @return @String@ containing all elements in @self interspersed with @str.
@@ -144,6 +204,38 @@ class Fancy {
144
204
  coll
145
205
  }
146
206
 
207
+ def map_with_index: block {
208
+ """
209
+ @block A @Block@ that gets called with each element and its index in @self.
210
+ @return An @Array@ containing all values of calling @block with each element and its index in @self.
211
+
212
+ Returns a new @Array@ with the results of calling a given block for every element and its index.
213
+ """
214
+
215
+ coll = []
216
+ each_with_index: |x i| {
217
+ coll << (block call: [x, i])
218
+ }
219
+ coll
220
+ }
221
+
222
+ def map_chained: blocks {
223
+ """
224
+ @blocks Collection of @Block@s to be called sequentially for every element in @self.
225
+ @return Collection of all values in @self successively called with all blocks in @blocks.
226
+
227
+ Example:
228
+ (1,2,3) map_chained: (@{ + 1 }, 'to_s, @{ * 2 })
229
+ # => [\"22\", \"33\", \"44\"]
230
+ """
231
+
232
+ map: |v| {
233
+ blocks inject: v into: |acc b| {
234
+ b call: [acc]
235
+ }
236
+ }
237
+ }
238
+
147
239
  def select: condition {
148
240
  """
149
241
  @condition A @Block@ that is used as a filter on all elements in @self.
@@ -285,23 +377,23 @@ class Fancy {
285
377
  reduce: block init_val: val
286
378
  }
287
379
 
288
- def uniq {
380
+ def unique {
289
381
  """
290
382
  @return @Array@ of all unique elements in @self.
291
383
 
292
384
  Returns a new Array with all unique values (double entries are skipped).
293
385
 
294
386
  Example:
295
- [1,2,1,2,3] uniq # => [1,2,3]
387
+ [1,2,1,2,3] unique # => [1,2,3]
296
388
  """
297
389
 
298
- uniq_vals = []
390
+ unique_vals = []
299
391
  each: |x| {
300
- unless: (uniq_vals includes?: x) do: {
301
- uniq_vals << x
392
+ unless: (unique_vals includes?: x) do: {
393
+ unique_vals << x
302
394
  }
303
395
  }
304
- uniq_vals
396
+ unique_vals
305
397
  }
306
398
 
307
399
  def size {
@@ -312,7 +404,7 @@ class Fancy {
312
404
  """
313
405
 
314
406
  i = 0
315
- each: |x| {
407
+ each: {
316
408
  i = i + 1
317
409
  }
318
410
  i
@@ -328,31 +420,6 @@ class Fancy {
328
420
  size == 0
329
421
  }
330
422
 
331
- def first {
332
- """
333
- @return First element in @self or @nil, if empty.
334
- """
335
-
336
- each: |x| {
337
- return x
338
- }
339
- nil
340
- }
341
-
342
- def last {
343
- """
344
- @return Last element in @self or @nil, if empty.
345
-
346
- Returns the last element in an Enumerable.
347
- """
348
-
349
- item = nil
350
- each: |x| {
351
- item = x
352
- }
353
- item
354
- }
355
-
356
423
  def compact {
357
424
  """
358
425
  @return @Array@ with all non-nil elements in @self.
@@ -363,16 +430,16 @@ class Fancy {
363
430
  [1,2,nil,3,nil] compact # => [1,2,3]
364
431
  """
365
432
 
366
- reject: |x| { x nil? }
433
+ reject: @{ nil? }
367
434
  }
368
435
 
369
- def superior_by: comparison_block taking: selection_block ('identity) {
436
+ def superior_by: comparison_block taking: selection_block (@{ identity }) {
370
437
  """
371
438
  @comparison_block @Block@ to be used for comparison.
372
- @selection_block @Block@ to be used for selecting the values to be used for comparison by @comparison_bock.
439
+ @selection_block @Block@ to be used for selecting the values to be used for comparison by @comparison_block.
373
440
  @return Superior element in @self in terms of @comparison_block.
374
441
 
375
- Returns the superior element in the @Enumerable that has met
442
+ Returns the superior element in the @Fancy::Enumerable@ that has met
376
443
  the given comparison block with all other elements,
377
444
  applied to whatever @selection_block returns for each element.
378
445
  @selection_block defaults to @identity.
@@ -424,7 +491,7 @@ class Fancy {
424
491
  (assuming them to be @Number@s (implementing '+' & '*')).
425
492
  """
426
493
 
427
- reduce: '+ init_val: 0
494
+ inject: 0 into: '+
428
495
  }
429
496
 
430
497
  def product {
@@ -433,7 +500,7 @@ class Fancy {
433
500
  (assuming them to be @Number@s (implementing @+ & @*)).
434
501
  """
435
502
 
436
- reduce: '* init_val: 1
503
+ inject: 1 into: '*
437
504
  }
438
505
 
439
506
  def average {
@@ -451,7 +518,7 @@ class Fancy {
451
518
  @return @Array@ of @Array@s, partitioned by equal return values of calling @block with each element
452
519
 
453
520
  Example:
454
- 0 upto: 10 . partition_by: |x| { x < 3 } # => [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9, 10]]
521
+ (0..10) partition_by: @{ < 3 } # => [[0, 1, 2], [3, 4, 5, 6, 7, 8, 9, 10]]
455
522
  """
456
523
  last = block call: [first]
457
524
  coll = []
@@ -475,7 +542,7 @@ class Fancy {
475
542
  @return Random element in @self.
476
543
  """
477
544
 
478
- at: (rand(size))
545
+ at: $ size random
479
546
  }
480
547
 
481
548
  def sort_by: block {
@@ -534,8 +601,7 @@ class Fancy {
534
601
  In either case, it simply converts @self to an @Array@ and returns it in reversed order.
535
602
  """
536
603
 
537
- rev = self to_a
538
- rev reverse
604
+ self to_a reverse
539
605
  }
540
606
 
541
607
  def to_hash: block {
@@ -548,12 +614,12 @@ class Fancy {
548
614
  # => <[3 => \"foo\", 5 => \"hello\", 2 => \"ok\", 0 => \"\"]>
549
615
  """
550
616
 
551
- h = <[]>
552
- self each: |val| {
617
+
618
+ inject: <[]> into: |h val| {
553
619
  key = block call: [val]
554
620
  h[key]: val
621
+ h
555
622
  }
556
- h
557
623
  }
558
624
 
559
625
  def reverse_each: block {
@@ -567,5 +633,36 @@ class Fancy {
567
633
 
568
634
  reverse each: block
569
635
  }
636
+
637
+ def count: block {
638
+ """
639
+ @block Predicate @Block@ called with each element.
640
+ @return @Fixnum@ that is the amount of elements in @self for which @block yields @true.
641
+
642
+ Example:
643
+ (0..10) count: @{ even? } # => 6 (even numbers are: 0,2,4,6,8,10)
644
+ [1,2,3] count: @{ odd? } # => 2
645
+ [1,2, \"foo\"] count: @{ class == String } # => 1
646
+ """
647
+
648
+ count = 0
649
+ each: |x| {
650
+ { count = count + 1 } if: $ block call: [x]
651
+ }
652
+ count
653
+ }
654
+
655
+ def to_s {
656
+ """
657
+ @return @String@ concatenation of elements in @self.
658
+
659
+ Example:
660
+ (1,2,3) to_s # => \"123\"
661
+ [1,2,3] to_s # => \"123\"
662
+ \"foo\" to_s # => \"foo\"
663
+ """
664
+
665
+ join
666
+ }
570
667
  }
571
668
  }