fancy 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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 {