fancy 0.7.0 → 0.8.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 (165) hide show
  1. data/README.md +38 -86
  2. data/bin/fdoc +2 -22
  3. data/bin/fspec +8 -3
  4. data/bin/ifancy +1 -1
  5. data/boot/fancy_ext.rb +1 -0
  6. data/boot/fancy_ext/array.rb +19 -0
  7. data/boot/fancy_ext/class.rb +2 -4
  8. data/boot/fancy_ext/module.rb +2 -0
  9. data/boot/fancy_ext/object.rb +0 -17
  10. data/boot/rbx-compiler/compiler/ast/method_def.rb +0 -4
  11. data/boot/rbx-compiler/compiler/ast/singleton_method_def.rb +0 -7
  12. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  13. data/boot/rbx-compiler/parser/fancy_parser.c +1 -0
  14. data/doc/api/fancy.css +10 -1
  15. data/doc/api/fancy.jsonp +1 -1
  16. data/doc/api/fdoc.js +22 -9
  17. data/doc/api/octocat.png +0 -0
  18. data/doc/features.md +1 -2
  19. data/examples/actors.fy +1 -2
  20. data/examples/armstrong_numbers.fy +7 -3
  21. data/examples/blocks.fy +3 -3
  22. data/examples/distributing_proxy.fy +31 -0
  23. data/examples/future_sends.fy +15 -0
  24. data/examples/person.fy +1 -2
  25. data/lib/argv.fy +1 -7
  26. data/lib/array.fy +7 -11
  27. data/lib/block.fy +15 -0
  28. data/lib/boot.fy +4 -3
  29. data/lib/class.fy +354 -10
  30. data/lib/compiler.fy +1 -1
  31. data/lib/compiler/ast/assign.fy +4 -8
  32. data/lib/compiler/ast/async_send.fy +1 -2
  33. data/lib/compiler/ast/block.fy +5 -0
  34. data/lib/compiler/ast/class_def.fy +2 -1
  35. data/lib/compiler/ast/expression_list.fy +1 -2
  36. data/lib/compiler/ast/future_send.fy +1 -2
  37. data/lib/compiler/ast/identifier.fy +34 -17
  38. data/lib/compiler/ast/literals.fy +31 -19
  39. data/lib/compiler/ast/match.fy +5 -4
  40. data/lib/compiler/ast/message_send.fy +3 -5
  41. data/lib/compiler/ast/method_def.fy +0 -3
  42. data/lib/compiler/ast/range.fy +2 -4
  43. data/lib/compiler/ast/return.fy +2 -4
  44. data/lib/compiler/ast/script.fy +2 -4
  45. data/lib/compiler/ast/singleton_method_def.fy +0 -3
  46. data/lib/compiler/ast/string_interpolation.fy +2 -2
  47. data/lib/compiler/ast/super.fy +2 -4
  48. data/lib/compiler/ast/try_catch.fy +13 -9
  49. data/lib/compiler/ast/tuple_literal.fy +1 -2
  50. data/lib/compiler/compiler.fy +2 -2
  51. data/lib/compiler/stages.fy +3 -6
  52. data/lib/contracts.fy +89 -57
  53. data/lib/dynamic_slot_object.fy +21 -3
  54. data/lib/enumerable.fy +140 -4
  55. data/lib/enumerator.fy +1 -1
  56. data/lib/eval.fy +23 -9
  57. data/lib/exception.fy +16 -0
  58. data/lib/false_class.fy +36 -5
  59. data/lib/fancy_spec.fy +64 -34
  60. data/lib/fdoc.fy +85 -24
  61. data/lib/file.fy +19 -0
  62. data/lib/future.fy +4 -46
  63. data/lib/hash.fy +113 -0
  64. data/lib/integer.fy +25 -6
  65. data/lib/iteration.fy +3 -3
  66. data/lib/main.fy +5 -0
  67. data/lib/matchers.fy +79 -0
  68. data/lib/nil_class.fy +8 -0
  69. data/lib/object.fy +109 -18
  70. data/lib/option_parser.fy +118 -0
  71. data/lib/package/dependency.fy +4 -8
  72. data/lib/package/dependency_installer.fy +1 -1
  73. data/lib/package/handler.fy +6 -0
  74. data/lib/package/installer.fy +43 -16
  75. data/lib/package/list.fy +1 -2
  76. data/lib/package/specification.fy +5 -5
  77. data/lib/package/uninstaller.fy +9 -2
  78. data/lib/parser.fy +1 -3
  79. data/lib/parser/ext/ext.c +1 -0
  80. data/lib/parser/ext/lexer.lex +5 -0
  81. data/lib/parser/methods.fy +48 -46
  82. data/lib/proxies.fy +151 -0
  83. data/lib/rbx.fy +1 -0
  84. data/lib/rbx/actor.fy +16 -18
  85. data/lib/rbx/array.fy +18 -3
  86. data/lib/rbx/block.fy +1 -7
  87. data/lib/rbx/class.fy +54 -9
  88. data/lib/rbx/code_loader.fy +2 -5
  89. data/lib/rbx/compiled_method.fy +31 -0
  90. data/lib/rbx/debugger.fy +66 -0
  91. data/lib/rbx/directory.fy +8 -3
  92. data/lib/rbx/documentation.fy +1 -1
  93. data/lib/rbx/file.fy +22 -0
  94. data/lib/rbx/integer.fy +1 -1
  95. data/lib/rbx/match_data.fy +2 -1
  96. data/lib/rbx/method.fy +26 -0
  97. data/lib/rbx/object.fy +8 -3
  98. data/lib/rbx/regexp.fy +6 -3
  99. data/lib/rbx/string.fy +9 -1
  100. data/lib/rbx/stringio.fy +12 -0
  101. data/lib/rbx/symbol.fy +4 -0
  102. data/lib/stack.fy +1 -1
  103. data/lib/string.fy +34 -0
  104. data/lib/stringio.fy +1 -1
  105. data/lib/symbol.fy +6 -2
  106. data/lib/system.fy +15 -1
  107. data/lib/tuple.fy +5 -2
  108. data/lib/version.fy +1 -1
  109. data/ruby_lib/fdoc +2 -22
  110. data/tests/array.fy +3 -17
  111. data/tests/class.fy +312 -10
  112. data/tests/contracts.fy +51 -0
  113. data/tests/distributing_proxy.fy +28 -0
  114. data/tests/enumerable.fy +104 -1
  115. data/tests/exception.fy +35 -0
  116. data/tests/fixnum.fy +1 -1
  117. data/tests/hash.fy +81 -1
  118. data/tests/integer.fy +9 -0
  119. data/tests/matchers.fy +18 -0
  120. data/tests/method.fy +8 -14
  121. data/tests/object.fy +76 -2
  122. data/tests/option_parser.fy +80 -0
  123. data/tests/string.fy +21 -0
  124. data/tests/stringio.fy +1 -1
  125. data/tests/tuple.fy +1 -1
  126. metadata +21 -44
  127. data/examples/arithmetic.fy +0 -7
  128. data/examples/array.fy +0 -50
  129. data/examples/boolean.fy +0 -24
  130. data/examples/class.fy +0 -68
  131. data/examples/constant_access.fy +0 -15
  132. data/examples/default_args.fy +0 -20
  133. data/examples/define_methods.fy +0 -15
  134. data/examples/dynamic_output.fy +0 -15
  135. data/examples/empty_catch.fy +0 -4
  136. data/examples/exception.fy +0 -9
  137. data/examples/files.fy +0 -23
  138. data/examples/finally.fy +0 -5
  139. data/examples/future.fy +0 -30
  140. data/examples/future_composition.fy +0 -20
  141. data/examples/futures.fy +0 -9
  142. data/examples/game_of_life.fy +0 -148
  143. data/examples/html_generator.fy +0 -84
  144. data/examples/implicit_return.fy +0 -3
  145. data/examples/matchers.fy +0 -6
  146. data/examples/nested_try.fy +0 -9
  147. data/examples/numbers.fy +0 -12
  148. data/examples/rbx/and_or.fy +0 -7
  149. data/examples/rbx/blocks.fy +0 -22
  150. data/examples/rbx/classes.fy +0 -32
  151. data/examples/rbx/hello.fy +0 -8
  152. data/examples/rbx/include.fy +0 -12
  153. data/examples/rbx/inherit.fy +0 -11
  154. data/examples/rbx/methods.fy +0 -15
  155. data/examples/rbx/nested_classes.fy +0 -9
  156. data/examples/rbx/require.fy +0 -3
  157. data/examples/rbx/strings.fy +0 -5
  158. data/examples/require.fy +0 -7
  159. data/examples/return.fy +0 -13
  160. data/examples/singleton_methods.fy +0 -21
  161. data/examples/threads.fy +0 -18
  162. data/examples/tuple.fy +0 -8
  163. data/examples/webserver/webserver.fy +0 -15
  164. data/lib/proxy.fy +0 -86
  165. data/lib/thread_pool.fy +0 -102
@@ -0,0 +1,118 @@
1
+ class OptionParser {
2
+ """
3
+ Parses command-line options from a given @Array@ (usually @ARGV) and
4
+ executes registered handlers for options specified.
5
+ """
6
+
7
+ class Option {
8
+ read_slots: ('option, 'arg, 'doc_string, 'block)
9
+ def initialize: @option arg: @arg doc: @doc_string block: @block
10
+ def name_with_arg {
11
+ if: @arg then: {
12
+ "#{@option} [#{@arg}]"
13
+ } else: {
14
+ @option
15
+ }
16
+ }
17
+ }
18
+
19
+ class InvalidOptionsError : StandardError
20
+
21
+ read_slots: ('options, 'parsed_options)
22
+ read_write_slots: ('banner, 'exit_on_help, 'remove_after_parsed)
23
+
24
+ def initialize: @block (nil) {
25
+ """
26
+ @block (Optional) @Block@ to be called with @self for easy setup.
27
+
28
+ Creates a new OptionParser.
29
+
30
+ Example:
31
+ o = OptionParser new: @{
32
+ with: \"--my-option\" doc: \"Sets some option value\" do: {
33
+ # do stuff in here...
34
+ }
35
+ }
36
+ o parse: ARGV # parse options from ARGV
37
+ """
38
+
39
+ @options = <[]>
40
+ @parsed_options = <[]>
41
+ @banner = nil
42
+ @exit_on_help = true
43
+ @remove_after_parsed = false
44
+
45
+ with: "--help" doc: "Display this information" do: {
46
+ print_help_info
47
+ { System exit } if: @exit_on_help
48
+ }
49
+
50
+ { @block call: [self] } if: @block
51
+ }
52
+
53
+ def with: option_string doc: doc_string do: block {
54
+ """
55
+ @option_string Option flag and (optional) argument within \"[]\", e.g. \"--file [filename]\".
56
+ @doc_string Documentation @String@ for @option_string that is used in the standard @--help option.
57
+ @block @Block@ to be executed if @option_string is matched during parsing. If the option takes an argument it will be passed to @block as an argument.
58
+
59
+ Example:
60
+ o = OptionParser new
61
+ o with: \"--file [filename]\" doc: \"Use this file for processing\" do: |filename| {
62
+ # do something with filename
63
+ }
64
+ """
65
+
66
+ option, arg = option_string split: " "
67
+ if: arg then: {
68
+ match arg {
69
+ case /\[(.+)\]/ -> |_, arg_name|
70
+ arg = arg_name downcase
71
+ case _ -> InvalidOptionsError new: "Could not correctly parse option argument: #{arg}" . raise!
72
+ }
73
+ }
74
+
75
+ o = Option new: option arg: arg doc: doc_string block: block
76
+ @options[option]: o
77
+ }
78
+
79
+ def parse: args {
80
+ """
81
+ @args @Array@ of arguments to parse options from. Typically you'd pass @ARGV here.
82
+
83
+ Parses options from @args and executes registered option handlers.
84
+ """
85
+
86
+ @options each: |name opt| {
87
+ if: (args index: name) then: |idx| {
88
+ block = opt block
89
+ match block arity {
90
+ case 0 -> block call
91
+ case 1 ->
92
+ arg = args at: (idx + 1)
93
+ block call: [arg]
94
+ @parsed_options[name]: arg
95
+ { args remove_at: idx } if: @remove_after_parsed
96
+ }
97
+
98
+ { args remove_at: idx } if: @remove_after_parsed
99
+ }
100
+ }
101
+ }
102
+
103
+ def print_help_info {
104
+ """
105
+ Displays the @--help information on @*stdout* based on all options that were registered via @OptionParser#with:doc:do:@.
106
+ """
107
+
108
+ max_size = @options map: |name opt| { opt name_with_arg size } . max
109
+ if: @banner then: {
110
+ *stdout* println: @banner
111
+ *stdout* println
112
+ }
113
+ @options keys sort each: |name| {
114
+ opt = @options[name]
115
+ *stdout* printf(" %-#{max_size}s %s\n", opt name_with_arg, opt doc_string)
116
+ }
117
+ }
118
+ }
@@ -5,10 +5,8 @@ class Fancy Package {
5
5
  Represents a Dependency to another Package with a given version.
6
6
  """
7
7
 
8
- read_slots: ['name, 'version]
9
-
10
- def initialize: @name version: @version ('latest) {
11
- }
8
+ read_slots: ('name, 'version)
9
+ def initialize: @name version: @version ('latest);
12
10
  }
13
11
 
14
12
  class RubyDependency {
@@ -16,10 +14,8 @@ class Fancy Package {
16
14
  Same as @Fancy::Package::Dependency@, just for rubygem packages.
17
15
  """
18
16
 
19
- read_slots: ['gem_name, 'version]
20
-
21
- def initialize: @gem_name version: @version ('latest) {
22
- }
17
+ read_slots: ('gem_name, 'version)
18
+ def initialize: @gem_name version: @version ('latest);
23
19
 
24
20
  def install {
25
21
  """
@@ -16,7 +16,7 @@ class Fancy {
16
16
  "Installing dependency: #{dep name} (#{dep version})" println
17
17
  Fancy Package install: (dep name) version: (dep version)
18
18
  }
19
- s rubygem_dependencies each: |dep| {
19
+ s ruby_dependencies each: |dep| {
20
20
  "Installing Ruby dependency: #{dep gem_name} (#{dep version})" println
21
21
  dep install
22
22
  }
@@ -52,5 +52,11 @@ class Fancy Package {
52
52
  def bin_path {
53
53
  @install_path + "/bin"
54
54
  }
55
+
56
+ def installed_bin_symlinks: spec {
57
+ spec bin_files map: |bf| {
58
+ "#{bin_path}/#{File basename(bf)}"
59
+ }
60
+ }
55
61
  }
56
62
  }
@@ -12,8 +12,8 @@ class Fancy Package {
12
12
 
13
13
  def initialize: @package_name version: @version ('latest) install_path: @install_path (ENV["FANCY_PACKAGE_DIR"]) {
14
14
  """
15
- Creates a new @Package Installer@ for a given package name, an
16
- optional version (default is 'latest) and an optional
15
+ Creates a new @Fancy::Package@ installer for a given package name, an
16
+ optional version (default is @'latest) and an optional
17
17
  installation path (default is the standard installation path for
18
18
  Fancy packages).
19
19
  """
@@ -61,26 +61,40 @@ class Fancy Package {
61
61
  }
62
62
 
63
63
  def latest_tag {
64
- "Returns the latest tag (sorted alphabetically)."
64
+ """
65
+ Returns the latest tag (sorted alphabetically).
66
+ """
65
67
 
66
- tags = self tags
67
- if: (tags size > 0) then: {
68
- tags keys sort last
69
- }
68
+ tags sort last
70
69
  }
71
70
 
72
71
  def tags {
73
- "Returns a list of tags the repository has on Github."
72
+ """
73
+ @return @Array@ of git tags in the package's Github repository.
74
+ """
74
75
 
75
- require("yaml")
76
76
  require("open-uri")
77
+ require("rubygems")
78
+ require("json")
77
79
 
78
- url = "http://github.com/api/v2/yaml/repos/show/" ++ @package_name ++ "/tags/"
79
- YAML load_stream(open(url)) documents() first at: "tags"
80
+ url = "https://api.github.com/repos/#{@package_name}/git/refs/tags"
81
+
82
+ try {
83
+ return JSON load(open(url)) map: |tag| {
84
+ tag["ref"] split: "refs/tags/" . last
85
+ }
86
+ } catch OpenURI HTTPError {
87
+ return [] # no tags available, default to master (latest)
88
+ }
80
89
  }
81
90
 
82
91
  def has_version?: version {
83
- "Indicates, if a given version is available on Github."
92
+ """
93
+ @version Version of package to check for.
94
+ @return @true, if this package has the given version, @false otherwise.
95
+
96
+ Indicates, if a given version for this package is available on Github.
97
+ """
84
98
 
85
99
  match version {
86
100
  case "master" -> true
@@ -122,6 +136,12 @@ class Fancy Package {
122
136
  }
123
137
 
124
138
  def unpack_file: filename {
139
+ """
140
+ @filename File name of package's downloaded .tar.gz file (from Github) to extract
141
+
142
+ Unpacks the given @filename and installs it into Fancy's package install dir.
143
+ """
144
+
125
145
  "Unpacking " ++ filename println
126
146
  System do: $ ["tar xf ", @download_path, "/", filename, " -C ", @install_path, "/"] join
127
147
  output = System pipe: $ ["tar tf ", @download_path, "/", filename] join
@@ -139,12 +159,19 @@ class Fancy Package {
139
159
  }
140
160
 
141
161
  def fulfill_spec: spec {
162
+ """
163
+ @spec @Fancy::Package::Specification@ to be fulfilled.
164
+
165
+ Installs all dependencies of @spec, sets up symlinks for binary files in @spec,
166
+ as well as installing the include-file into the Fancy package lib dir.
167
+ """
168
+
142
169
  unless: (spec include_files empty?) do: {
143
170
  File open: (lib_path + "/" + (spec package_name)) modes: ['write] with: |f| {
144
171
  spec include_files each: |if| {
145
- unless: (spec rubygem_dependencies empty?) do: {
172
+ unless: (spec ruby_dependencies empty?) do: {
146
173
  f writeln: "require(\"rubygems\")"
147
- spec rubygem_dependencies each: |rd| {
174
+ spec ruby_dependencies each: |rd| {
148
175
  f writeln: "require(\"#{rd gem_name}\")"
149
176
  }
150
177
  }
@@ -167,10 +194,10 @@ class Fancy Package {
167
194
  }
168
195
 
169
196
  spec dependencies each: |dep| {
170
- Package install: dep
197
+ Fancy Package install: (dep name) version: (dep version)
171
198
  }
172
199
 
173
- spec rubygem_dependencies each: |dep| { dep install }
200
+ spec ruby_dependencies each: |dep| { dep install }
174
201
  }
175
202
  }
176
203
  }
@@ -1,7 +1,6 @@
1
1
  class Fancy Package {
2
2
  class List {
3
- def initialize: @package_list_file {
4
- }
3
+ def initialize: @package_list_file
5
4
 
6
5
  def println {
7
6
  packages each: |p| {
@@ -3,13 +3,13 @@ class Fancy Package {
3
3
  @@specs = <[]>
4
4
 
5
5
  read_write_slots: ['author, 'email, 'include_files, 'bin_files,
6
- 'description, 'homepage, 'version, 'gh_user]
6
+ 'description, 'homepage, 'version, 'gh_user, 'package_name]
7
7
 
8
- read_slots: ['package_name, 'dependencies, 'rubygem_dependencies]
8
+ read_slots: ['dependencies, 'ruby_dependencies]
9
9
 
10
10
  def initialize: @package_name with: block {
11
11
  @dependencies = []
12
- @rubygem_dependencies = []
12
+ @ruby_dependencies = []
13
13
  @include_files = []
14
14
  @bin_files = []
15
15
 
@@ -34,7 +34,7 @@ class Fancy Package {
34
34
  version = d second
35
35
  { version = 'latest } unless: version
36
36
  dep = RubyDependency new: gem_name version: version
37
- @rubygem_dependencies << dep
37
+ @ruby_dependencies << dep
38
38
  }
39
39
  }
40
40
 
@@ -45,7 +45,7 @@ class Fancy Package {
45
45
 
46
46
  def add_ruby_dependency: gem_name version: version ('latest) {
47
47
  dep = RubyDependency new: gem_name version: version
48
- @rubygem_dependencies << dep
48
+ @ruby_dependencies << dep
49
49
  }
50
50
 
51
51
  def to_s {
@@ -9,6 +9,7 @@ class Fancy Package {
9
9
  Specification delete_specification: spec from: $ Fancy Package package_list_file
10
10
  delete_package_dir
11
11
  delete_lib_file: (spec package_name)
12
+ delete_bin_files: (installed_bin_symlinks: spec)
12
13
  "Successfully uninstalled package #{spec package_name} with version: #{spec version}." println
13
14
  } else: {
14
15
  System abort: "No package found for #{@package_name} with version '#{@version}'."
@@ -16,7 +17,7 @@ class Fancy Package {
16
17
  }
17
18
 
18
19
  def delete_package_dir {
19
- require("FileUtils")
20
+ require("fileutils")
20
21
  if: (Directory exists?: installed_path) then: {
21
22
  "Deleting directory: #{installed_path}" println
22
23
  FileUtils rm_rf(installed_path)
@@ -26,7 +27,13 @@ class Fancy Package {
26
27
  def delete_lib_file: package_name {
27
28
  lib_file = "#{lib_path}/#{package_name}"
28
29
  "Deleting: #{lib_file}" println
29
- File delete: lib_file
30
+ File delete!: lib_file
31
+ }
32
+
33
+ def delete_bin_files: bin_files {
34
+ bin_files each: |bf| {
35
+ File delete!: bf
36
+ }
30
37
  }
31
38
  }
32
39
  }
@@ -1,4 +1,2 @@
1
-
2
1
  require: "parser/methods"
3
- require(File.expand_path("parser/ext/fancy_parser", File.dirname(__FILE__)))
4
-
2
+ require(File.expand_path("parser/ext/fancy_parser", File.dirname(__FILE__)))
@@ -30,6 +30,7 @@ fancy_parse_file(VALUE self) {
30
30
  yylineno = NUM2INT(lineno);
31
31
  yyparse(self);
32
32
  yy_delete_buffer(buffstate);
33
+ fclose(f);
33
34
  return self;
34
35
  }
35
36
 
@@ -54,6 +54,7 @@ identifier @?@?({lower}|[_&*])({letter}|{digit}|{special_under})*
54
54
  selector ({letter}|[_&*])({letter}|{digit}|{special_under})*":"
55
55
  constant {capital}({letter}|{digit}|{special_under})*
56
56
  nested_constant ({constant}::)+{constant}
57
+ toplevel_constant ::({constant}|{nested_constant})
57
58
  symbol_lit \'({identifier}|{operator}|{constant}|:|"[]"|"|"|".")+
58
59
  ruby_send_open ({constant}|{identifier}){lparen}
59
60
  ruby_oper_open {operator}{lparen}
@@ -166,6 +167,10 @@ escaped_newline "\\".*\n
166
167
  yylval.object = rb_str_new2(yytext);
167
168
  return CONSTANT;
168
169
  }
170
+ {toplevel_constant} {
171
+ yylval.object = rb_str_new2(yytext);
172
+ return CONSTANT;
173
+ }
169
174
  {symbol_lit} {
170
175
  yylval.object = rb_str_new2(yytext);
171
176
  return SYMBOL_LITERAL;
@@ -2,8 +2,10 @@ require: "parse_error"
2
2
 
3
3
  class Fancy {
4
4
  class Parser {
5
- SelectorVarDefault = Struct.new('selector, 'variable, 'default)
5
+ SelectorVarDefault = Struct new('selector, 'variable, 'default)
6
+ SelectorVarDefault read_write_slots: ('selector, 'variable, 'default)
6
7
  SelectorValue = Struct new('selector, 'value)
8
+ SelectorValue read_write_slots: ('selector, 'value)
7
9
 
8
10
  def self parse_file: filename line: line (1) {
9
11
  new: filename line: line . parse_file . script
@@ -17,9 +19,11 @@ class Fancy {
17
19
  ParseError new: line message: text filename: (Thread current['__fancy__parser__filename__]) . raise!
18
20
  }
19
21
 
20
- read_write_slots: ['filename, 'line, 'script]
22
+ read_write_slots: ('filename, 'line, 'script)
21
23
 
22
- def initialize: @filename line: @line { Thread current['__fancy__parser__filename__]: @filename }
24
+ def initialize: @filename line: @line {
25
+ Thread current['__fancy__parser__filename__]: @filename
26
+ }
23
27
 
24
28
  def body: body {
25
29
  @script = AST Script new: @line file: @filename body: body
@@ -33,8 +37,8 @@ class Fancy {
33
37
  def ast: line identity: identity { identity }
34
38
 
35
39
  def ast: line concat: object into: ary ([]) {
36
- if: (object kind_of?(Array)) then: {
37
- ary concat(object)
40
+ if: (object is_a?: Array) then: {
41
+ ary append: object
38
42
  } else: {
39
43
  { ary << object } if: object
40
44
  }
@@ -49,16 +53,16 @@ class Fancy {
49
53
  }
50
54
 
51
55
  def ast: line fixnum: text base: base (10) {
52
- AST FixnumLiteral new: line value: (text to_i(base))
56
+ AST FixnumLiteral new: line value: $ text to_i: base
53
57
  }
54
58
 
55
59
  def ast: line number: text base: base (10) {
56
- AST NumberLiteral new: line value: (text to_f())
60
+ AST NumberLiteral new: line value: $ text to_f
57
61
  }
58
62
 
59
63
  def ast: line symbol: text {
60
64
  str = text from: 1 to: -1
61
- AST SymbolLiteral new: line value: (str to_sym())
65
+ AST SymbolLiteral new: line value: $ str to_sym
62
66
  }
63
67
 
64
68
  def ast: line regexp: text {
@@ -68,41 +72,34 @@ class Fancy {
68
72
 
69
73
  def ast: line string: text {
70
74
  str = text from: 1 to: -2
71
- match str {
72
- # OK, I know this is ugly. But it works for now, so let's just go with it.
73
- # TODO: Clean this up or make it simpler...
74
-
75
- # this case handles string interpolation
76
- case /(.*)#{(.*)}(.*)/m -> |matches|
77
- prefix = matches[1]
78
- interpol_str = matches[2]
79
- suffix = matches[3]
80
-
81
- prefix_str = ast: line string: (" " + prefix + " ") # hack, pre- & append " " since it gets removed
82
- suffix_str = ast: line string: (" " + suffix + " ")
83
- interpol_ast = AST StringInterpolation new: line code: interpol_str
84
- # create messagesend to concatenate:
85
- concat_ident = ast: line identifier: "<<"
86
- interpol_send = AST MessageSend new: line message: concat_ident to: prefix_str args: (AST MessageArgs new: line args: [interpol_ast])
87
-
88
- # don't concatenate suffix if it's empty..
89
- unless: (suffix == "") do: {
90
- interpol_send = AST MessageSend new: line message: concat_ident to: interpol_send args: (AST MessageArgs new: line args: [suffix_str])
91
- }
75
+ match_data = /#{([^}]*)}/ match: str
92
76
 
93
- interpol_send # this shall get returned, yo
94
- case _ ->
95
- AST StringLiteral new: line value: str
77
+ { return AST StringLiteral new: line value: str } unless: match_data
78
+
79
+ # this case handles string interpolation
80
+ prefix_str = ast: line string: $ " " + (match_data pre_match) + " " # hack, pre- & append " " since it gets removed
81
+ suffix_str = ast: line string: $ " " + (match_data post_match) + " "
82
+ interpol_ast = AST StringInterpolation new: line code: (match_data[1]) filename: @filename
83
+
84
+ # create messagesend to concatenate:
85
+ concat_ident = ast: line identifier: "<<"
86
+ interpol_send = AST MessageSend new: line message: concat_ident to: prefix_str args: $ AST MessageArgs new: line args: [interpol_ast]
87
+
88
+ # don't concatenate suffix if it's empty..
89
+ unless: (match_data post_match == "") do: {
90
+ interpol_send = AST MessageSend new: line message: concat_ident to: interpol_send args: $ AST MessageArgs new: line args: [suffix_str]
96
91
  }
92
+
93
+ interpol_send
97
94
  }
98
95
 
99
96
  def ast: line multi_line_string: string {
100
- ast: line string: (string from: 2 to: -3)
97
+ ast: line string: $ string from: 2 to: -3
101
98
  }
102
99
 
103
100
  def ast: line backtick: backtick_string {
104
101
  str = ast: line string: backtick_string
105
- selector = (ast: line identifier: "backtick:")
102
+ selector = ast: line identifier: "backtick:"
106
103
  args = AST MessageArgs new: line args: [str]
107
104
  AST MessageSend new: line message: selector to: (AST Self new: line) args: args
108
105
  }
@@ -194,13 +191,13 @@ class Fancy {
194
191
  AST MessageArgs new: line args: []
195
192
  }
196
193
  name = message
197
- if: (message kind_of?(String)) then: {
194
+ if: (message is_a?: String) then: {
198
195
  name = AST Identifier from: message line: line
199
196
  }
200
- if: (message kind_of?(Array)) then: {
201
- name = message map: |m| { m selector() string } . join
197
+ if: (message is_a?: Array) then: {
198
+ name = message map: |m| { m selector string } . join
202
199
  name = AST Identifier new: line string: name
203
- args = message map: |m| { m value() }
200
+ args = message map: |m| { m value }
204
201
  args = AST MessageArgs new: line args: args
205
202
  }
206
203
  AST MessageSend new: line message: name to: receiver args: args
@@ -217,13 +214,13 @@ class Fancy {
217
214
  }
218
215
 
219
216
  def method_name: margs {
220
- margs map: |a| { a selector() string } . join("")
217
+ margs map: |a| { a selector string } . join("")
221
218
  }
222
219
 
223
220
  def method: margs delegators: block {
224
- idx = margs index() |m| { m default() != nil }
221
+ idx = margs index: |m| { m default != nil }
225
222
  if: idx then: {
226
- line = margs first selector() line
223
+ line = margs first selector line
227
224
  target = method_name: margs
228
225
  (margs size - idx) times: |pos| {
229
226
  required = margs from: 0 to: (idx + pos - 1)
@@ -232,7 +229,7 @@ class Fancy {
232
229
  if: only_default_args then: {
233
230
  required = []
234
231
  }
235
- params = required map: |r| { r variable() } . + $ default map: |d| { d default() }
232
+ params = required map: |r| { r variable } . + $ default map: |d| { d default }
236
233
 
237
234
  forward = AST MessageSend new: line \
238
235
  message: (AST Identifier from: target line: line) \
@@ -245,7 +242,7 @@ class Fancy {
245
242
  # use base method name (e.g. "foo:" -> "foo") for the method to be generated
246
243
  # if there are no more arguments left (only default args left)
247
244
  if: only_default_args then: {
248
- required = AST Identifier from: (margs first selector() string from: 0 to: -2) line: line
245
+ required = AST Identifier from: (margs first selector string from: 0 to: -2) line: line
249
246
  }
250
247
 
251
248
  block call: [required, body]
@@ -275,7 +272,7 @@ class Fancy {
275
272
  } else: {
276
273
  name = method_name: margs
277
274
  name = AST Identifier new: line string: name
278
- args = margs map() |m| { m variable() string }
275
+ args = margs map: |m| { m variable string }
279
276
  args = AST MethodArgs new: line args: args
280
277
  if: owner then: {
281
278
  AST SingletonMethodDef new: line name: name args: args \
@@ -323,12 +320,17 @@ class Fancy {
323
320
  AST MatchClause new: line expr: expr body: body args: match_args
324
321
  }
325
322
 
326
- def ast: line ex_handler: expr_list cond: cond (AST Identifier from: "Object" line: line) var: var (nil) {
323
+ def ast: line ex_handler: expr_list cond: cond (AST Identifier from: "StandardError" line: line) var: var (nil) {
327
324
  AST ExceptionHandler new: line condition: cond var: var body: expr_list
328
325
  }
329
326
 
330
327
  def ast: line try_block: body ex_handlers: handlers finally_block: finaly (AST NilLiteral new: line) {
331
- AST TryCatch new: line body: body handlers: handlers ensure: finaly
328
+ match finaly {
329
+ case AST NilLiteral -> AST TryCatch new: line body: body handlers: handlers ensure: finaly
330
+ case _ ->
331
+ inner = AST TryCatch new: line body: body handlers: handlers ensure: (AST NilLiteral new: line)
332
+ AST TryCatch new: line body: (AST ExpressionList new: line list: [inner]) handlers: [] ensure: finaly
333
+ }
332
334
  }
333
335
 
334
336
  def ast: line ruby_send: text {