fancy 0.6.0 → 0.7.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 (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
  }