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
@@ -1,8 +1,5 @@
1
- require("yaml")
2
- require("open-uri")
3
-
4
1
  class Fancy Package {
5
- class Installer {
2
+ class Installer : Handler {
6
3
  """
7
4
 
8
5
  @Fancy::Package@ installer.
@@ -21,26 +18,7 @@ class Fancy Package {
21
18
  Fancy packages).
22
19
  """
23
20
 
24
- splitted = @package_name split: "/"
25
- @user, @repository = splitted
26
-
27
- # check for version, e.g. when passing in:
28
- # $ fancy install bakkdoor/fyzmq=1.0.1
29
- splitted = @repository split: "="
30
- if: (splitted size > 1) then: {
31
- @repository, @version = splitted
32
- @package_name = @user + "/" + @repository
33
- }
34
-
35
- @install_path if_nil: {
36
- @install_path = Fancy Package DEFAULT_PACKAGES_PATH
37
- Directory create!: $ Fancy Package DEFAULT_FANCY_ROOT
38
- Directory create!: $ Fancy Package DEFAULT_PACKAGES_PATH
39
- Directory create!: $ Fancy Package DEFAULT_PACKAGES_LIB_PATH
40
- Directory create!: $ Fancy Package DEFAULT_PACKAGES_PATH ++ "/downloads"
41
- }
42
-
43
- @download_path = @install_path ++ "/downloads"
21
+ initialize: @package_name install_path: @install_path
44
22
  }
45
23
 
46
24
  def run {
@@ -69,7 +47,13 @@ class Fancy Package {
69
47
  # now unpack & check for dependencies
70
48
  unpack_dir = unpack_file: filename
71
49
  rename_dir: unpack_dir
72
- load_fancypack
50
+ load_fancypack: |spec| {
51
+ fulfill_spec: spec
52
+ spec gh_user: @user
53
+ Specification save: spec to: $ Fancy Package package_list_file
54
+ } else: {
55
+ "Something wen't wrong. Did not find a fancypack specification for package: " ++ @repository . raise!
56
+ }
73
57
  } else: {
74
58
  STDERR println: "Installation aborted."
75
59
  STDERR println: "Got error while trying to install #{@package_name} with version: #{@version}"
@@ -88,6 +72,9 @@ class Fancy Package {
88
72
  def tags {
89
73
  "Returns a list of tags the repository has on Github."
90
74
 
75
+ require("yaml")
76
+ require("open-uri")
77
+
91
78
  url = "http://github.com/api/v2/yaml/repos/show/" ++ @package_name ++ "/tags/"
92
79
  YAML load_stream(open(url)) documents() first at: "tags"
93
80
  }
@@ -141,13 +128,6 @@ class Fancy Package {
141
128
  dirname = output readlines first chomp
142
129
  }
143
130
 
144
- def installed_path {
145
- @install_path + "/" + @user + "_" + @repository + "-" + @version
146
- }
147
-
148
- def lib_path {
149
- @install_path + "/lib"
150
- }
151
131
 
152
132
  def rename_dir: dirname {
153
133
  """
@@ -158,25 +138,6 @@ class Fancy Package {
158
138
  System do: $ ["mv ", @install_path, "/", dirname, " ", installed_path] join
159
139
  }
160
140
 
161
- def load_fancypack {
162
- """
163
- Loads the @.fancypack file within the downloaded package directory.
164
- If no @.fancypack file is found, raise an error.
165
- """
166
-
167
- Dir glob(installed_path ++ "/*.fancypack") first if_true: |fpackfile| {
168
- require: fpackfile
169
- }
170
-
171
- if: (Specification[@repository]) then: |spec| {
172
- fulfill_spec: spec
173
- spec gh_user: @user
174
- Specification save: spec to: $ Fancy Package package_list_file
175
- } else: {
176
- "Something wen't wrong. Did not find a fancypack specification for package: " ++ @repository . raise!
177
- }
178
- }
179
-
180
141
  def fulfill_spec: spec {
181
142
  unless: (spec include_files empty?) do: {
182
143
  File open: (lib_path + "/" + (spec package_name)) modes: ['write] with: |f| {
@@ -196,6 +157,15 @@ class Fancy Package {
196
157
  }
197
158
  }
198
159
 
160
+ spec bin_files each: |bf| {
161
+ basename = File basename(bf)
162
+ orig_path = "#{installed_path}/#{bf}"
163
+ link_path = "#{bin_path}/#{basename}"
164
+ "Creating symlink #{link_path} for #{orig_path}" println
165
+ { File delete: link_path } if: $ File exists?: link_path
166
+ File symlink(orig_path, link_path)
167
+ }
168
+
199
169
  spec dependencies each: |dep| {
200
170
  Package install: dep
201
171
  }
@@ -62,12 +62,19 @@ class Fancy Package {
62
62
  }
63
63
  }
64
64
 
65
- def self delete: spec_name from: specs_file {
66
- File open: specs_file modes: ['read, 'write] with: |f| {
67
- f readlines reject: |l| { l includes?: "name=#{spec_name}" } . each: |l| {
68
- f writeln: l
69
- }
65
+ def self delete_specs_from: specs_file if: filter_block {
66
+ lines = File read: specs_file . lines reject: filter_block
67
+ File write: specs_file with: |f| {
68
+ lines each: |l| { f writeln: l }
70
69
  }
71
70
  }
71
+
72
+ def self delete: spec_name from: specs_file {
73
+ delete_specs_from: specs_file if: @{ includes?: "name=#{spec_name}" }
74
+ }
75
+
76
+ def self delete_specification: spec from: specs_file {
77
+ delete_specs_from: specs_file if: @{ includes?: "name=#{spec package_name} version=#{spec version}" }
78
+ }
72
79
  }
73
80
  }
@@ -1,13 +1,32 @@
1
1
  class Fancy Package {
2
- class Uninstaller {
2
+ class Uninstaller : Handler {
3
3
  """
4
4
  @Fancy::Package@ Uninstaller.
5
5
  """
6
6
 
7
- def initialize: @package_name {
7
+ def run {
8
+ load_fancypack: |spec| {
9
+ Specification delete_specification: spec from: $ Fancy Package package_list_file
10
+ delete_package_dir
11
+ delete_lib_file: (spec package_name)
12
+ "Successfully uninstalled package #{spec package_name} with version: #{spec version}." println
13
+ } else: {
14
+ System abort: "No package found for #{@package_name} with version '#{@version}'."
15
+ }
8
16
  }
9
17
 
10
- def run {
18
+ def delete_package_dir {
19
+ require("FileUtils")
20
+ if: (Directory exists?: installed_path) then: {
21
+ "Deleting directory: #{installed_path}" println
22
+ FileUtils rm_rf(installed_path)
23
+ }
24
+ }
25
+
26
+ def delete_lib_file: package_name {
27
+ lib_file = "#{lib_path}/#{package_name}"
28
+ "Deleting: #{lib_file}" println
29
+ File delete: lib_file
11
30
  }
12
31
  }
13
32
  }
@@ -786,6 +786,15 @@ key_value_list: exp space ARROW space exp {
786
786
  | key_value_list COMMA space exp space ARROW space exp {
787
787
  $$ = rb_funcall(self, rb_intern("ast:key:value:into:"), 4, INT2NUM(yylineno), $4, $8, $1);
788
788
  }
789
+ | key_value_list space COMMA space {
790
+ $$ = $1;
791
+ }
792
+ | key_value_list COMMA space {
793
+ $$ = $1;
794
+ }
795
+ | key_value_list COMMA {
796
+ $$ = $1;
797
+ }
789
798
  ;
790
799
 
791
800
  match_expr: MATCH exp LCURLY space match_body space RCURLY {
@@ -1,4 +1,4 @@
1
- class ProxyReceiver : BasicObject {
1
+ class ProxyReceiver : Fancy BasicObject {
2
2
  """
3
3
  A ProxyReceiver is an object which proxies all message sends to it to 2 other objects.
4
4
  It will send each message first to its @proxy instance variable and then to the @obj instance variable.
@@ -30,7 +30,7 @@ class ProxyReceiver : BasicObject {
30
30
 
31
31
  Proxy = ProxyReceiver
32
32
 
33
- class RespondsToProxy : BasicObject {
33
+ class RespondsToProxy : Fancy BasicObject {
34
34
  """
35
35
  A RespondsToProxy is a Proxy that forwards any message sent to it to it's @target instance variable
36
36
  only if it responds to that message. Any messages that @target doesn't respond to simply won't be sent
@@ -60,4 +60,27 @@ class RespondsToProxy : BasicObject {
60
60
  @target receive_message: msg with_params: params
61
61
  }
62
62
  }
63
+ }
64
+
65
+ class ActorProxy : Fancy BasicObject {
66
+ """
67
+ A ActorProxy is a Proxy that forwards any message sent to it to it's
68
+ @target instance variable as a future send by default.
69
+ If explicitly sent an async message, it will forward the async send
70
+ to @target, returning nil instead of a @FutureSend@, as expected.
71
+ """
72
+
73
+ def initialize: @target
74
+
75
+ def send_future: m with_params: p {
76
+ @target send_future: m with_params: p
77
+ }
78
+
79
+ def send_async: m with_params: p {
80
+ @target send_async: m with_params: p
81
+ }
82
+
83
+ def unknown_message: m with_params: p {
84
+ @target send_future: m with_params: p
85
+ }
63
86
  }
data/lib/rbx.fy CHANGED
@@ -8,12 +8,12 @@
8
8
  require: "rbx/alpha"
9
9
  require: "rbx/documentation"
10
10
  require: "rbx/object"
11
+ require: "rbx/symbol"
11
12
  require: "rbx/class"
12
13
  require: "rbx/console"
13
14
  require: "rbx/array"
14
15
  require: "rbx/hash"
15
16
  require: "rbx/string"
16
- require: "rbx/symbol"
17
17
  require: "rbx/integer"
18
18
  require: "rbx/fixnum"
19
19
  require: "rbx/float"
@@ -41,3 +41,4 @@ require: "rbx/time"
41
41
  require: "rbx/actor"
42
42
  require: "rbx/mutex"
43
43
  require: "rbx/module"
44
+ require: "rbx/proc"
@@ -103,12 +103,27 @@ class Array {
103
103
  @return Joined @String@ with all elements with @join_str.
104
104
 
105
105
  Joins all elements in the Array with a given @String@.
106
- [1,2,3] join: \", \” # => \”1, 2, 3\"
106
+
107
+ Example:
108
+ [1,2,3] join: \", \” # => \”1, 2, 3\"
107
109
  """
108
110
 
109
111
  join(join_str)
110
112
  }
111
113
 
114
+ def join {
115
+ """
116
+ @return Elements of @Array@ joined to a @String@.
117
+
118
+ Joins all elements with the empty @String@.
119
+
120
+ Example:
121
+ [\"hello\", \"world\", \"!\"] join # => \"hello,world!\"
122
+ """
123
+
124
+ join: ""
125
+ }
126
+
112
127
  def unshift: value {
113
128
  """
114
129
  @value Value to be added at the front of @self.
@@ -1,5 +1,5 @@
1
1
  class Class {
2
- ruby_aliases: [ 'superclass, '===, 'ancestors, 'instance_methods, 'methods, 'inspect, 'to_s ]
2
+ ruby_aliases: [ 'superclass, '===, 'ancestors, 'instance_methods, 'methods, 'to_s ]
3
3
 
4
4
  def new {
5
5
  """
@@ -63,7 +63,7 @@ class Class {
63
63
  body.
64
64
  """
65
65
 
66
- define_method(message_name: name, &block)
66
+ define_method(name message_name, &block)
67
67
  }
68
68
 
69
69
  def undefine_method: name {
@@ -73,7 +73,7 @@ class Class {
73
73
  Undefines an instance method on a Class with a given name.
74
74
  """
75
75
 
76
- remove_method(message_name: name)
76
+ remove_method(name message_name)
77
77
  }
78
78
 
79
79
  def define_class_method: name with: block {
@@ -127,7 +127,7 @@ class Class {
127
127
  Returns an instance method for a @Class@ with a given name.
128
128
  """
129
129
 
130
- instance_method(message_name: name)
130
+ instance_method(name message_name)
131
131
  }
132
132
 
133
133
  def alias_method_rbx: new_method_name for: old_method_name {
@@ -136,14 +136,14 @@ class Class {
136
136
  reasons. Should not be used directly.
137
137
  """
138
138
 
139
- alias_method(message_name: new_method_name, message_name: old_method_name)
139
+ alias_method(new_method_name message_name, old_method_name message_name)
140
140
  }
141
141
 
142
142
  def alias_method: new_method_name for_ruby: ruby_method_name {
143
143
  """
144
144
  Creates a method alias for a Ruby method.
145
145
  """
146
- alias_method(message_name: new_method_name, ruby_method_name)
146
+ alias_method(new_method_name message_name, ruby_method_name)
147
147
  }
148
148
 
149
149
  def public: method_names {
@@ -154,7 +154,7 @@ class Class {
154
154
  """
155
155
 
156
156
  method_names = method_names to_a()
157
- method_names = method_names map: |m| { message_name: m }
157
+ method_names = method_names map: |m| { m message_name }
158
158
  public(*method_names)
159
159
  }
160
160
 
@@ -166,7 +166,7 @@ class Class {
166
166
  """
167
167
 
168
168
  method_names = method_names to_a()
169
- method_names = method_names map() |m| { message_name: m }
169
+ method_names = method_names map() |m| { m message_name }
170
170
  private(*method_names)
171
171
  }
172
172
 
@@ -178,10 +178,28 @@ class Class {
178
178
  """
179
179
 
180
180
  method_names = method_names to_a()
181
- method_names = method_names map() |m| { message_name: m }
181
+ method_names = method_names map() |m| { m message_name }
182
182
  protected(*method_names)
183
183
  }
184
184
 
185
+ def instance_methods: include_superclasses? (true) {
186
+ """
187
+ @include_superclasses? Boolean indicating if instance methods of all superclasses should be included (defaults to @true).
188
+ @return @Array@ of all instance method names for this @Class@.
189
+ """
190
+
191
+ instance_methods(include_superclasses?)
192
+ }
193
+
194
+ def methods: include_superclasses? (true) {
195
+ """
196
+ @include_superclasses? Boolean indicating if methods of all superclasses should be included (defaults to @true).
197
+ @return @Array@ of all class method names for this @Class@.
198
+ """
199
+
200
+ methods(include_superclasses?)
201
+ }
202
+
185
203
  def forwards_unary_ruby_methods {
186
204
  """
187
205
  Creates ruby_alias methods for any unary ruby methods of a class.
@@ -195,4 +213,11 @@ class Class {
195
213
  ruby_alias: m
196
214
  }
197
215
  }
216
+
217
+ def class_eval: str_or_block {
218
+ match str_or_block {
219
+ case Block -> class_eval(&str_or_block)
220
+ case _ -> class_eval(str_or_block)
221
+ }
222
+ }
198
223
  }
@@ -75,7 +75,7 @@ class File {
75
75
  File read(filename, length, offset)
76
76
  }
77
77
 
78
- def File open: filename modes: modes_arr {
78
+ def File open: filename modes: modes_arr (('read, 'binary)) {
79
79
  """
80
80
  @filename Filename to open/create.
81
81
  @modes_arr Array of symbols that describe the desired operations to perform.
@@ -109,7 +109,7 @@ class File {
109
109
  modes_arr each: |m| {
110
110
  str << (@@open_mode_conversions[m])
111
111
  }
112
- str uniq join: ""
112
+ str unique join: ""
113
113
  }
114
114
 
115
115
  def File delete: filename {
@@ -10,21 +10,11 @@ class Fixnum {
10
10
  ruby_aliases: [
11
11
  '==, '-, '+, '*, '/, '<, '>, '<=, '>=,
12
12
  '===, 'chr, 'to_i, 'to_f, '**, '&, '|,
13
- '<<, '>>
13
+ '^, '<<, '>>
14
14
  ]
15
15
 
16
16
  alias_method: 'to_s: for: 'to_s
17
17
  alias_method: 'modulo: for: 'modulo
18
18
  alias_method: ":%" for: "modulo:" # use a : so we dont overwrite ruby's % operator
19
19
  alias_method: 'div: for: 'div
20
-
21
- def random {
22
- """
23
- @return Random number between 0 and @self.
24
-
25
- Returns a random number between 0 and @self.
26
- """
27
-
28
- rand(self)
29
- }
30
20
  }
@@ -1,4 +1,8 @@
1
1
  class IOMixin {
2
+ def read: amount_bytes {
3
+ read(amount_bytes)
4
+ }
5
+
2
6
  def readln {
3
7
  readline
4
8
  }
@@ -12,6 +12,17 @@ class Module {
12
12
  const_get(constant_name)
13
13
  }
14
14
 
15
+ def [constant_name]: value {
16
+ """
17
+ @constant_name Name (@String@) of constant's name.
18
+ @value New value of constant to be used.
19
+
20
+ Sets the value of a constant with the given name in @self.
21
+ """
22
+
23
+ const_set(constant_name, value)
24
+ }
25
+
15
26
  def included: module {
16
27
  """
17
28
  @module @Module@ or @Class@ that has been included into @self.