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
@@ -97,7 +97,7 @@ class Object {
97
97
  Dynamically sends a given message (without parameters) to @self.
98
98
  """
99
99
 
100
- send(message_name: message)
100
+ __send__(message message_name)
101
101
  }
102
102
 
103
103
  def receive_message: message with_params: params {
@@ -108,16 +108,7 @@ class Object {
108
108
  Dynamically sends a given message with parameters to @self.
109
109
  """
110
110
 
111
- ruby: (message_name: message) args: params
112
- }
113
-
114
- def message_name: symbol {
115
- symbol = symbol to_s
116
- val = symbol include?(":")
117
- match val {
118
- case true -> symbol
119
- case false -> ":" <<(symbol)
120
- }
111
+ ruby: (message message_name) args: params
121
112
  }
122
113
 
123
114
  def responds_to?: message {
@@ -128,7 +119,7 @@ class Object {
128
119
  Indicates if an object responds to a given message.
129
120
  """
130
121
 
131
- respond_to?(message_name: message)
122
+ respond_to?(message message_name)
132
123
  }
133
124
 
134
125
  def extend: class {
@@ -140,4 +131,13 @@ class Object {
140
131
 
141
132
  metaclass include: class
142
133
  }
134
+
135
+ def lambda: block {
136
+ """
137
+ @block @Block@ to be used as the lambda's body.
138
+ @return @Proc@ with Ruby's lambda semantics (e.g. @return always becomes @return_local)
139
+ """
140
+
141
+ lambda(&block)
142
+ }
143
143
  }
@@ -0,0 +1,7 @@
1
+ class Proc {
2
+ forwards_unary_ruby_methods
3
+ alias_method: 'call for_ruby: 'call
4
+ def call: args {
5
+ call(*args)
6
+ }
7
+ }
@@ -24,7 +24,7 @@ class String {
24
24
  match index {
25
25
  case Array -> from: (index[0]) to: (index[1])
26
26
  case Tuple -> ruby_idx: index
27
- case _ -> ruby_idx: index . chr()
27
+ case _ -> if: (ruby_idx: index) then: @{ chr() }
28
28
  }
29
29
  }
30
30
 
@@ -162,4 +162,8 @@ class String {
162
162
 
163
163
  gsub(substring, substitution)
164
164
  }
165
+
166
+ def message_name {
167
+ self to_sym message_name to_s
168
+ }
165
169
  }
@@ -23,4 +23,13 @@ class Symbol {
23
23
 
24
24
  binding send('self) class const_defined?(self)
25
25
  }
26
+
27
+ def message_name {
28
+ symbol = self to_s
29
+ val = symbol include?(":")
30
+ match val {
31
+ case true -> symbol to_sym
32
+ case false -> ":" <<(symbol) to_sym
33
+ }
34
+ }
26
35
  }
@@ -5,7 +5,7 @@ class String {
5
5
  class.
6
6
 
7
7
  They also include @Fancy::Enumerable@, which means you can use all the
8
- common sequence methods on them, like +map:+, +select:+ etc.
8
+ common sequence methods on them, like @Fancy::Enumerable#map:@, @Fancy::Enumerable#select:@ etc.
9
9
  """
10
10
 
11
11
  include: Fancy Enumerable
@@ -1,3 +1,5 @@
1
+ ObjectBoundsExceededError = Rubinius ObjectBoundsExceededError
2
+
1
3
  class Tuple {
2
4
  """
3
5
  Tuples are fixed-size containers providing index-based access to its
@@ -23,44 +25,54 @@ class Tuple {
23
25
  t
24
26
  }
25
27
 
26
- def [idx] {
27
- """
28
- Forwards to @Tuple@#at:.
28
+ def Tuple === obj {
29
29
  """
30
+ Matches @Tuple@ class against an object.
31
+ If the given object is a Tuple instance, return a Tuple object.
30
32
 
31
- at: idx
32
- }
33
-
34
- def first {
35
- """
36
- @return The first element in @self.
33
+ @obj Object to be matched against
34
+ @return Tuple instance containing the values of @obj to be used in pattern matching.
37
35
  """
38
36
 
39
- at: 0
37
+ if: (obj is_a?: Tuple) then: {
38
+ [obj] + (obj map: 'identity)
39
+ }
40
40
  }
41
41
 
42
- def second {
43
- """
44
- @return The second element in @self.
45
- """
46
-
47
- at: 1
42
+ def Tuple name {
43
+ "Tuple"
48
44
  }
49
45
 
50
- def third {
46
+ def [idx] {
51
47
  """
52
- @return The third element in @self.
48
+ Forwards to @Tuple@#at:.
53
49
  """
54
50
 
55
- at: 2
51
+ at: idx
56
52
  }
57
53
 
58
- def fourth {
54
+ def from: from to: to {
59
55
  """
60
- @return The fourth element in @self.
56
+ @from Start index for sub-array.
57
+ @to End index ofr sub-array.
58
+
59
+ Returns sub-array starting at from: and going to to:
61
60
  """
62
61
 
63
- at: 3
62
+ if: (from < 0) then: {
63
+ from = size + from
64
+ }
65
+ if: (to < 0) then: {
66
+ to = size + to
67
+ }
68
+ subarr = []
69
+ try {
70
+ from upto: to do: |i| {
71
+ subarr << (at: i)
72
+ }
73
+ } catch ObjectBoundsExceededError {
74
+ }
75
+ subarr
64
76
  }
65
77
 
66
78
  def each: block {
@@ -129,21 +141,11 @@ class Tuple {
129
141
  str
130
142
  }
131
143
 
132
- def Tuple === obj {
144
+ def to_s {
133
145
  """
134
- Matches @Tuple@ class against an object.
135
- If the given object is a Tuple instance, return a Tuple object.
136
-
137
- @obj Object to be matched against
138
- @return Tuple instance containing the values of @obj to be used in pattern matching.
146
+ @return @String@ concatenation of elements in @self.
139
147
  """
140
148
 
141
- if: (obj is_a?: Tuple) then: {
142
- [obj] + (obj map: 'identity)
143
- }
144
- }
145
-
146
- def Tuple name {
147
- "Tuple"
149
+ join
148
150
  }
149
151
  }
@@ -1,6 +1,7 @@
1
- VERSION_MAJOR = 0
2
- VERSION_MINOR = 6
3
- VERSION_PATCH = 0
4
- VERSION_SUFFIX = "alpha"
1
+ class Fancy {
2
+ VERSION_MAJOR = 0
3
+ VERSION_MINOR = 7
4
+ VERSION_PATCH = 0
5
5
 
6
- FANCY_VERSION = [VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH] join: "." ++ " " ++ VERSION_SUFFIX
6
+ VERSION = [VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH] join: "."
7
+ }
@@ -195,9 +195,9 @@ FancySpec describe: Array with: {
195
195
  arr values_at: [1, 3, 4, 10] . is: [2, 'foo, "bar", nil]
196
196
  }
197
197
 
198
- it: "returns unique values only" with: 'uniq when: {
198
+ it: "returns unique values only" with: 'unique when: {
199
199
  arr = ['foo, 'bar, "baz", 'foo, "baz", "hello", 1, 0, 0, 1, 'bar, 'foo, "hello"]
200
- arr uniq is: ['foo, 'bar, "baz", "hello", 1, 0]
200
+ arr unique is: ['foo, 'bar, "baz", "hello", 1, 0]
201
201
  }
202
202
 
203
203
  it: "prepends self to another array" with: '>> when: {
@@ -225,6 +225,10 @@ FancySpec describe: Array with: {
225
225
  arr[[-1,-1]] is: [arr last]
226
226
  arr[[-2,-1]] is: ['bar, 'baz]
227
227
  arr[[-2,-1]] is: (arr last: 2)
228
+ # works with any Enumerable as argument:
229
+ arr[(0,2)] is: $ arr[[0,2]]
230
+ arr[(1,2)] is: $ arr[[1,2]]
231
+ arr[(0,-1)] is: $ arr[[0,-1]]
228
232
  }
229
233
 
230
234
  it: "joins all elements with a string to a new string" with: 'join: when: {
@@ -329,6 +333,14 @@ FancySpec describe: Array with: {
329
333
  ([1,2,3,4] + [-1,-2,-3,-4]) is: [1,2,3,4,-1,-2,-3,-4]
330
334
  }
331
335
 
336
+ it: "returns all elements not in another collection" with: '- when: {
337
+ [] - [] is: []
338
+ [] - [0] is: []
339
+ [1,2,3,4] - [2,4] is: [1,3]
340
+ [1,2,3] - [1,2,3,5] is: []
341
+ ["foo", "bar", "baz"] - ["bar"] is: ["foo", "baz"]
342
+ }
343
+
332
344
  it: "returns true for all elements" with: 'all?: when: {
333
345
  [1,2,3,4] all?: |x| { x < 5 } . is: true
334
346
  [1,2,3,4] all?: |x| { x > 0 } . is: true
@@ -567,4 +567,83 @@ FancySpec describe: Class with: {
567
567
  WithConstants["Nested"] is_a?: Class . is: true
568
568
  WithConstants["Nested"] is: WithConstants Nested
569
569
  }
570
+
571
+ it: "sets a constants value" with: '[]: when: {
572
+ Kernel["Object"] is: Object
573
+ { Kernel["Something"] } raises: NameError
574
+ Kernel["Something"]: Array
575
+ { Kernel["Something"] is: Array } does_not raise: NameError
576
+ }
577
+
578
+ it: "delegates methods correctly" with: 'delegate:to_slot: when: {
579
+ class Delegation {
580
+ delegate: ('[], '[]:, '<<, 'to_s, 'to_s:, 'inspect, 'each:in_between:) to_slot: 'object
581
+ def initialize: @object
582
+ }
583
+
584
+ d = Delegation new: "hello, world!"
585
+ d to_s is: "hello, world!"
586
+ d inspect is: $ "hello, world!" inspect
587
+ d = Delegation new: 2
588
+ d to_s is: "2"
589
+ d inspect is: "2"
590
+ d to_s: 2 . is: "10"
591
+ d = Delegation new: [1,2,3]
592
+ d << 5
593
+ d get_slot: 'object . is: [1,2,3,5]
594
+ d << nil
595
+ d get_slot: 'object . is: [1,2,3,5, nil]
596
+ d[2]: "foo"
597
+ d get_slot: 'object . is: [1,2,"foo",5,nil]
598
+ d[1] is: 2
599
+ }
600
+
601
+ it: "allows delegating only a single method" with: 'delegate:to_slot: when: {
602
+ class Delegation {
603
+ delegate: 'to_s to_slot: 'number
604
+ read_write_slot: 'number
605
+ }
606
+
607
+ d = Delegation new
608
+ d number: 5
609
+ d to_s is: $ 5 to_s
610
+ }
611
+
612
+ it: "defines a lazy slot" with: 'lazy_slot:value: when: {
613
+ class LazyClass {
614
+ lazy_slot: 'foo value: { Thread sleep: 0.01; 42 * @count }
615
+ def initialize: @count
616
+ }
617
+
618
+ f = LazyClass new: 2
619
+ start = Time now
620
+ f foo is: 84
621
+ Time now - start >= 0.01 is: true
622
+ start = Time now
623
+ f foo is: 84
624
+ Time now - start <= 0.01 is: true
625
+ }
626
+
627
+ it: "returns a string representation of itself and its superclass, if any" with: 'inspect when: {
628
+ class MySuperClass
629
+ class MySubClass : MySuperClass
630
+
631
+ Fixnum inspect is: "Fixnum : Integer"
632
+ MySuperClass inspect is: "MySuperClass : Object"
633
+ MySubClass inspect is: "MySubClass : MySuperClass"
634
+ Object inspect is: "Object"
635
+ }
636
+
637
+ it: "returns the right amount of instance methods" with: 'instance_methods: when: {
638
+ class NoMethods
639
+ class OneMethod {
640
+ def bar
641
+ }
642
+
643
+ NoMethods instance_methods: false . size is: 0
644
+ OneMethod instance_methods: false . size is: 1
645
+
646
+ NoMethods instance_methods is: $ Object instance_methods
647
+ Set[OneMethod instance_methods] is: $ Set[Object instance_methods + (OneMethod instance_methods: false)]
648
+ }
570
649
  }
@@ -0,0 +1,16 @@
1
+ FancySpec describe: DynamicKeyHash with: {
2
+ it: "has the correct keys & values defined" when: {
3
+ dkh = DynamicKeyHash new
4
+ dkh tap: @{
5
+ name: "Chris"
6
+ age: 25
7
+ country: "Germany"
8
+ }
9
+
10
+ hash = dkh hash
11
+ Set[hash keys] is: $ Set[['name, 'age, 'country]]
12
+ hash['name] is: "Chris"
13
+ hash['age] is: 25
14
+ hash['country] is: "Germany"
15
+ }
16
+ }
@@ -0,0 +1,28 @@
1
+ FancySpec describe: DynamicSlotObject with: {
2
+ it: "has the correct slots defined" when: {
3
+ dso = DynamicSlotObject new
4
+ dso tap: @{
5
+ name: "Chris"
6
+ age: 25
7
+ country: "Germany"
8
+ }
9
+
10
+ dso object tap: @{
11
+ slots is: ['name, 'age, 'country]
12
+ class is: Object
13
+
14
+ # getters
15
+ name is: "Chris"
16
+ age is: 25
17
+ country is: "Germany"
18
+
19
+ # setters
20
+ name: "Jack"
21
+ name is: "Jack"
22
+ age: 26
23
+ age is: 26
24
+ country: "USA"
25
+ country is: "USA"
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,12 @@
1
+ FancySpec describe: DynamicValueArray with: {
2
+ it: "has the correct values defined" when: {
3
+ dva = DynamicValueArray new
4
+ dva tap: @{
5
+ name: "Chris"
6
+ age: 25
7
+ country: "Germany"
8
+ another_symbol
9
+ and_another_one
10
+ } . array is: [['name, "Chris"], ['age, 25], ['country, "Germany"], 'another_symbol, 'and_another_one]
11
+ }
12
+ }
@@ -5,4 +5,50 @@ FancySpec describe: Fancy Enumerable with: {
5
5
  [[1,2], [2,3,4], [], [1]] superior_by: '> taking: 'size . is: [2,3,4]
6
6
  [[1,2], [2,3,4], [-1]] superior_by: '< taking: 'first . is: [-1]
7
7
  }
8
+
9
+ it: "chain-maps all blocks on all values" with: 'map_chained: when: {
10
+ (1,2,3) map_chained: ('doubled, 'squared, 'to_s) . is: ["4", "16", "36"]
11
+ (1,2,3) map_chained: (@{ + 1 }, 'to_s) . is: ["2", "3", "4"]
12
+ [] map_chained: ('class, 'name) . is: []
13
+ [1, "foo", 'hello] map_chained: ('class, 'name) . is: ["Fixnum", "String", "Symbol"]
14
+ }
15
+
16
+ it: "maps over its elements with their index" with: 'map_with_index: when: {
17
+ (1,2,3) map_with_index: |x i| {
18
+ x + i
19
+ } . is: [1,3,5]
20
+
21
+ [1,2,3,4] map_with_index: |x i| {
22
+ i
23
+ } . is: [0,1,2,3]
24
+
25
+ [] map_with_index: |x i| { i } . is: []
26
+ }
27
+
28
+ it: "counts the amount of elements for which a block yields true" with: 'count: when: {
29
+ [1,2,3] count: @{ even? } . is: 1
30
+ (0..10) count: @{ even? } . is: 6
31
+ (0..10) count: @{ odd? } . is: 5
32
+ "foo" count: @{ == "o" } . is: 2
33
+ "foo" count: @{ != "o" } . is: 1
34
+ (1,2,3) count: @{ < 2 } . is: 1
35
+ [] count: { true } . is: 0
36
+ [1] count: { true } . is: 1
37
+ [1] count: { false } . is: 0
38
+ }
39
+
40
+ it: "returns a string concatenation of all elements in self" with: 'to_s when: {
41
+ (1,2,3) to_s is: "123"
42
+ [1,2,3] to_s is: "123"
43
+ "foo" to_s is: "foo"
44
+ [] to_s is: ""
45
+
46
+ class MyCollection {
47
+ include: Fancy Enumerable
48
+ def each: block {
49
+ (0..5) each: block
50
+ }
51
+ }
52
+ MyCollection new to_s is: "012345"
53
+ }
8
54
  }