rspec 0.5.7 → 0.5.8

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 (43) hide show
  1. data/CHANGES +9 -0
  2. data/Rakefile +7 -10
  3. data/bin/spec +1 -1
  4. data/bin/test2spec +93 -0
  5. data/doc/src/default.template +1 -1
  6. data/doc/src/documentation/index.page +37 -37
  7. data/doc/src/documentation/mocks.page +88 -60
  8. data/doc/src/tools/index.page +2 -2
  9. data/doc/src/tools/meta.info +1 -1
  10. data/doc/src/tools/test2spec.page +73 -0
  11. data/doc/src/tutorials/notes.txt +1 -1
  12. data/doc/src/tutorials/stack_01.page +4 -4
  13. data/doc/src/tutorials/stack_02.page +6 -6
  14. data/doc/src/tutorials/stack_03.page +8 -8
  15. data/doc/src/tutorials/stack_04.page +2 -2
  16. data/doc/src/tutorials/stack_05.page +1 -1
  17. data/lib/spec/api/sugar.rb +3 -3
  18. data/lib/spec/runner/base_text_formatter.rb +11 -5
  19. data/lib/spec/runner/option_parser.rb +1 -1
  20. data/lib/spec/runner/progress_bar_formatter.rb +1 -1
  21. data/lib/spec/runner/rdoc_formatter.rb +1 -1
  22. data/lib/spec/runner/reporter.rb +6 -3
  23. data/lib/spec/runner/specdoc_formatter.rb +1 -1
  24. data/lib/spec/runner/specification.rb +1 -0
  25. data/lib/spec/tool/ruby2ruby.rb +485 -0
  26. data/lib/spec/tool/test_unit_translator.rb +114 -83
  27. data/lib/spec/tool/translation_test_runner.rb +118 -0
  28. data/lib/spec/version.rb +1 -1
  29. data/test/spec/runner/context_test.rb +4 -0
  30. data/test/spec/runner/progress_bar_formatter_test.rb +1 -1
  31. data/test/spec/runner/rdoc_formatter_test.rb +1 -1
  32. data/test/spec/runner/reporter_test.rb +24 -7
  33. data/test/spec/runner/specdoc_formatter_test.rb +1 -1
  34. data/test/spec/runner/specification_test.rb +8 -0
  35. data/test/spec/tool/ruby_to_ruby_test.rb +79 -0
  36. data/test/spec/tool/test_unit_api_spec.rb +45 -31
  37. data/test/spec/tool/test_unit_api_test.rb +13 -6
  38. data/test/spec/tool/test_unit_translator_test.rb +6 -1
  39. metadata +11 -10
  40. data/bin/test2rspec +0 -35
  41. data/doc/src/tools/test2rspec.page +0 -13
  42. data/lib/spec/tool/command_line.rb +0 -39
  43. data/test/spec/tool/command_line_test.rb +0 -21
@@ -45,5 +45,5 @@ it right away.
45
45
 
46
46
  h3. 7) Test::Unit translation
47
47
 
48
- Did you invest a lot of time in writing Test::Unit tests and want to switch to RSpec? Try out the test2rspec
49
- tool, which will do most of the translation for you. (test2rspec tool is experimental)
48
+ Did you invest a lot of time in writing Test::Unit tests and want to switch to RSpec? Try out the test2spec
49
+ tool, which will do most of the translation for you. (test2spec tool is experimental)
@@ -10,7 +10,7 @@ rake.page:
10
10
  rcov.page:
11
11
  orderInfo: 13
12
12
 
13
- test2rspec.page:
13
+ test2spec.page:
14
14
  orderInfo: 14
15
15
 
16
16
  rails.page:
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: Test::Unit Migration
3
+ inMenu: true
4
+ ---
5
+ h2. Test::Unit migration
6
+
7
+ RSpec's test2spec command line tool translates existing Test::Unit classes to RSpec.
8
+
9
+ Before you can use test2spec you must gem install ParseTree and RubyInline.
10
+ RubyInline only work on systems that have a C compiler - i.e. most anything except Windows.
11
+
12
+ If you're stuck on Windows, ask a friend who has a POSIX system to translate your specs.
13
+ Once translated they can run on any Ruby platform (including Windows). After all, it's
14
+ just Ruby.
15
+
16
+ h2. The test2spec command line
17
+
18
+ <pre>
19
+ test2spec --help
20
+ {execute: ruby ../bin/test2spec --help}
21
+ </pre>
22
+
23
+ A typical invocation might look like this:
24
+
25
+ <pre>
26
+ test2spec --specdir spec test
27
+ </pre>
28
+
29
+ h2. Sample output
30
+
31
+ <notextile>
32
+ <table>
33
+ <thead>
34
+ <tr>
35
+ <td>Test::Unit</td>
36
+ <td>RSpec (translated by test2spec)</td>
37
+ </tr>
38
+ </thead>
39
+ <tbody>
40
+ <tr>
41
+ <td>
42
+ <ruby file="../test/spec/tool/test_unit_api_test.rb"/>
43
+ </td>
44
+ <td>
45
+ <ruby file="../test/spec/tool/test_unit_api_spec.rb"/>
46
+ </td>
47
+ </tr>
48
+ </tbody>
49
+ </table>
50
+ </notextile>
51
+
52
+ h2. Troubleshooting
53
+
54
+ In some cases, test2spec will not be able to translate a test class. In that case, please submit a bug report
55
+ at RSpec's bug report system along with some code so we can reproduce (and hopefully - fix) the problem.
56
+ -Or better - submit a patch.
57
+
58
+ h2. Internals
59
+
60
+ The test2spec tool is based on three other tools:
61
+
62
+ * "RubyToRuby":http://blog.zenspider.com/archives/2005/02/rubytoruby.html
63
+ * "ParseTree":http://rubyforge.org/projects/parsetree/
64
+ * "RubyInline":http://rubyforge.org/projects/rubyinline/
65
+
66
+ In fact, it's based on a modified version of "George Moschovitis' RubyToRuby enhancement":http://dark.fhtr.org/ruby2ruby.rb
67
+ of "Ryan Davis' original RubyToRuby":http://blog.zenspider.com/archives/2005/02/rubytoruby.html.
68
+
69
+ It has been modified to fix some subtle bugs that were not found by Gerorge's tests. The modified RubyToRuby
70
+ currently lives in RSpec's subversion repository.
71
+
72
+ The translation is done by TestUnitTranslator - subclass of RubyToRuby that writes out the syntax tree a little differently than
73
+ its superclass. TestUnitTranslator looks for certain Test::Unit patterns and writes out an RSpec translation instead.
@@ -177,7 +177,7 @@ context "An empty stack" do
177
177
  end
178
178
  end
179
179
  </ruby>
180
- <br>
180
+
181
181
  <pre>$ spec stack_spec.rb -f s
182
182
 
183
183
  A new stack
@@ -68,7 +68,7 @@ context "A new stack" do
68
68
  end
69
69
  end
70
70
  </ruby>
71
- <br>
71
+
72
72
  <pre>
73
73
  $ spec stack_spec.rb -f s
74
74
 
@@ -153,7 +153,7 @@ context "A new stack" do
153
153
  end
154
154
  end
155
155
  </ruby>
156
- <br>
156
+
157
157
  <pre>
158
158
  $ spec stack_spec.rb -f s
159
159
 
@@ -180,7 +180,7 @@ class Stack
180
180
  end
181
181
  end
182
182
  </ruby>
183
- <br>
183
+
184
184
  <pre>
185
185
  $ spec stack_spec.rb -f s
186
186
 
@@ -206,7 +206,7 @@ class Stack
206
206
  end
207
207
  end
208
208
  </ruby>
209
- <br>
209
+
210
210
  <pre>
211
211
  spec stack_spec.rb -f s
212
212
 
@@ -12,7 +12,7 @@ context "An empty stack" do
12
12
  end
13
13
  end
14
14
  </ruby>
15
- <br>
15
+
16
16
  <pre>
17
17
  $ spec stack_spec.rb -f s
18
18
 
@@ -38,7 +38,7 @@ context "An empty stack" do
38
38
  end
39
39
  end
40
40
  </ruby>
41
- <br>
41
+
42
42
  <pre>
43
43
  $ spec stack_spec.rb -f s
44
44
 
@@ -65,7 +65,7 @@ context "An empty stack" do
65
65
  end
66
66
  end
67
67
  </ruby>
68
- <br>
68
+
69
69
  <pre>
70
70
  $ spec stack_spec.rb -f s
71
71
 
@@ -96,7 +96,7 @@ class Stack
96
96
  end
97
97
  end
98
98
  </ruby>
99
- <br>
99
+
100
100
  <pre>
101
101
  $ spec stack_spec.rb -f s
102
102
 
@@ -126,7 +126,7 @@ context "An empty stack" do
126
126
  end
127
127
  end
128
128
  </ruby>
129
- <br>
129
+
130
130
  <pre>
131
131
  $ spec stack_spec.rb -f s
132
132
 
@@ -161,7 +161,7 @@ class Stack
161
161
  end
162
162
  end
163
163
  </ruby>
164
- <br>
164
+
165
165
  <pre>
166
166
  $ spec stack_spec.rb -f s
167
167
 
@@ -18,7 +18,7 @@ context "A stack with one item" do
18
18
  end
19
19
  end
20
20
  </ruby>
21
- <br>
21
+
22
22
  <pre>
23
23
  $ spec stack_spec.rb -f s
24
24
 
@@ -49,7 +49,7 @@ context "A stack with one item" do
49
49
  end
50
50
  end
51
51
  </ruby>
52
- <br>
52
+
53
53
  <pre>
54
54
  $ spec stack_spec.rb -f s
55
55
 
@@ -81,7 +81,7 @@ context "A stack with one item" do
81
81
  end
82
82
  end
83
83
  </ruby>
84
- <br>
84
+
85
85
  <pre>
86
86
  $ spec stack_spec.rb -f s
87
87
 
@@ -113,7 +113,7 @@ class Stack
113
113
  end
114
114
  end
115
115
  </ruby>
116
- <br>
116
+
117
117
  <pre>
118
118
  $ spec stack_spec.rb -f s
119
119
 
@@ -146,7 +146,7 @@ class Stack
146
146
  end
147
147
  end
148
148
  </ruby>
149
- <br>
149
+
150
150
  <pre>
151
151
  $ spec stack_spec.rb -f s
152
152
 
@@ -187,7 +187,7 @@ class Stack
187
187
  end
188
188
  end
189
189
  </ruby>
190
- <br>
190
+
191
191
  <pre>
192
192
  $ spec stack_spec.rb -f s
193
193
 
@@ -224,7 +224,7 @@ class Stack
224
224
  end
225
225
  end
226
226
  </ruby>
227
- <br>
227
+
228
228
  <pre>
229
229
  $ spec stack_spec.rb -f s
230
230
 
@@ -257,7 +257,7 @@ class Stack
257
257
  end
258
258
  end
259
259
  </ruby>
260
- <br>
260
+
261
261
  <pre>
262
262
  $ spec stack_spec.rb -f s
263
263
 
@@ -95,7 +95,7 @@ context "A stack with one item" do
95
95
  end
96
96
  end
97
97
  </ruby>
98
- <br>
98
+
99
99
  <pre>
100
100
  $ spec stack_spec.rb -f s
101
101
 
@@ -143,7 +143,7 @@ context "A stack with one item" do
143
143
  end
144
144
  end
145
145
  </ruby>
146
- <br>
146
+
147
147
  <pre>
148
148
  $ spec stack_spec.rb -f s
149
149
 
@@ -65,7 +65,7 @@ context "A stack with one item" do
65
65
  ...
66
66
  end
67
67
  </ruby>
68
- <br>
68
+
69
69
  <pre>
70
70
  $ spec stack_spec.rb -f s
71
71
 
@@ -17,13 +17,13 @@ module Spec
17
17
  __orig_method_missing(sym, *args, &block)
18
18
  end
19
19
 
20
- def __is_sweetened? sym
20
+ def __is_sweetened?(sym) #:nodoc:
21
21
  return true if sym.to_s =~ /^should_/
22
22
  end
23
23
  end
24
24
 
25
25
  module MessageExpectationSugar
26
- def __is_sweetened? sym
26
+ def __is_sweetened?(sym) #:nodoc:
27
27
  return true if sym.to_s =~ /^and_|^at_|^any_|^once_/
28
28
  end
29
29
  end
@@ -35,7 +35,7 @@ class Object #:nodoc:
35
35
  end
36
36
 
37
37
  class Spec::Api::Mock #:nodoc:
38
- #NOTE: this resolves a bug caused by a conflict between Sugar#method_missing and Mock#method_missing, specifically
38
+ # NOTE: this resolves a bug caused by a conflict between Sugar#method_missing and Mock#method_missing, specifically
39
39
  # when the mock is set null_object=>true. It would be nice to get rid of this.
40
40
  def should_receive(sym, &block)
41
41
  return receive(sym, &block)
@@ -22,18 +22,24 @@ module Spec
22
22
  # +name+ is the name of the context and +first+ is true if it is the
23
23
  # first context - otherwise it's false.
24
24
  #
25
+ # The next method to be invoked after this is #spec_started
26
+ def add_context(name, first)
27
+ end
28
+
29
+ # This method is invoked right before a spec is executed.
25
30
  # The next method to be invoked after this one is one of #spec_failed
26
31
  # or #spec_passed.
27
- def add_context(name, first)
32
+ def spec_started(name)
28
33
  end
29
34
 
30
- # This method is invoked whenever a spec fails, i.e. an exception occurred
35
+ # This method is invoked when a spec fails, i.e. an exception occurred
31
36
  # inside it (such as a failed should or other exception). +name+ is the name
32
- # of the specification.
33
- def spec_failed(name)
37
+ # of the specification. +counter+ is the sequence number of the failure
38
+ # (starting at 1) and +failure+ is the associated Failure object.
39
+ def spec_failed(name, counter, failure)
34
40
  end
35
41
 
36
- # This method is invoked whwnever a spec passes. +name+ is the name of the
42
+ # This method is invoked when a spec passes. +name+ is the name of the
37
43
  # specification.
38
44
  def spec_passed(name)
39
45
  end
@@ -65,7 +65,7 @@ module Spec
65
65
  exit if out == $stdout
66
66
  end
67
67
 
68
- opts.on_tail("-h", "--help", "Show this message") do
68
+ opts.on_tail("-h", "--help", "You're looking at it") do
69
69
  out.puts opts
70
70
  exit if out == $stdout
71
71
  end
@@ -5,7 +5,7 @@ module Spec
5
5
  @output << "\n" if first
6
6
  end
7
7
 
8
- def spec_failed(name, counter)
8
+ def spec_failed(name, counter, failure)
9
9
  @output << 'F'
10
10
  end
11
11
 
@@ -9,7 +9,7 @@ module Spec
9
9
  @output << "# * #{name}\n"
10
10
  end
11
11
 
12
- def spec_failed(name, counter)
12
+ def spec_failed(name, counter, failure)
13
13
  @output << "# * #{name} [#{counter} - FAILED]\n"
14
14
  end
15
15
  end
@@ -16,6 +16,11 @@ module Spec
16
16
  @context_names << name
17
17
  end
18
18
 
19
+ def spec_started(name)
20
+ @spec_names << name
21
+ @formatter.spec_started(name)
22
+ end
23
+
19
24
  def spec_finished(name, error=nil, failure_location=nil)
20
25
  if error.nil?
21
26
  spec_passed(name)
@@ -58,14 +63,12 @@ module Spec
58
63
  end
59
64
 
60
65
  def spec_passed(name)
61
- @spec_names << name
62
66
  @formatter.spec_passed(name)
63
67
  end
64
68
 
65
69
  def spec_failed(name, failure)
66
- @spec_names << name
67
70
  @failures << failure
68
- @formatter.spec_failed(name, @failures.length)
71
+ @formatter.spec_failed(name, @failures.length, failure)
69
72
  end
70
73
 
71
74
  class Failure
@@ -5,7 +5,7 @@ module Spec
5
5
  @output << "\n#{name}\n"
6
6
  end
7
7
 
8
- def spec_failed(name, counter)
8
+ def spec_failed(name, counter, failure)
9
9
  @output << "- #{name} (FAILED - #{counter})\n"
10
10
  end
11
11
 
@@ -9,6 +9,7 @@ module Spec
9
9
  end
10
10
 
11
11
  def run(reporter=nil, setup_block=nil, teardown_block=nil, dry_run=false)
12
+ reporter.spec_started(@name)
12
13
  if dry_run
13
14
  reporter.spec_finished(@name)
14
15
  else
@@ -0,0 +1,485 @@
1
+ # Taken from http://dark.fhtr.org/ruby2ruby.rb
2
+
3
+ require 'rubygems'
4
+ require 'parse_tree'
5
+ require 'support'
6
+ require 'sexp_processor'
7
+
8
+
9
+ class RubySource < String
10
+
11
+ def inspect
12
+ "\n"+to_s
13
+ end
14
+
15
+ end
16
+
17
+
18
+ class Object
19
+
20
+ def parse_tree(method_name=nil)
21
+ if method_name
22
+ m = method(method_name)
23
+ klass = m.defined_in
24
+ method_name = m.name
25
+ return ParseTree.new.parse_tree_for_method(klass, method_name)
26
+ elsif is_a?(Class)
27
+ klass = self
28
+ else
29
+ klass = self.class
30
+ end
31
+ ParseTree.new.parse_tree(klass).first
32
+ end
33
+
34
+ def source(method_name=nil)
35
+ RubySource.new RubyToRuby.new.process(parse_tree(method_name))
36
+ end
37
+
38
+ end
39
+
40
+
41
+ class Method
42
+
43
+ def defined_in
44
+ full_name = to_s.split(" ").last.chop
45
+ klass_name = full_name.split(/[\#\.]/).first
46
+ if klass_name.include?("(")
47
+ klass_name = klass_name.split("(").last.chop
48
+ end
49
+ klass = klass_name.split("::").inject(Object){|o,n| o.const_get(n)}
50
+ klass
51
+ end
52
+
53
+ def name
54
+ full_name = to_s.split(" ").last.chop
55
+ full_name.split(/[\#\.]/).last
56
+ end
57
+
58
+ end
59
+
60
+
61
+ class RubyToRuby < SexpProcessor
62
+
63
+ def self.translate(klass, method=nil)
64
+ RubySource.new(
65
+ unless method.nil? then
66
+ self.new.process(ParseTree.new.parse_tree_for_method(klass, method))
67
+ else
68
+ self.new.process(ParseTree.new.parse_tree(klass).first) # huh? why is the :class node wrapped?
69
+ end
70
+ )
71
+ end
72
+
73
+ def initialize
74
+ super
75
+ @env = Environment.new
76
+ @indent = " "
77
+ self.auto_shift_type = true
78
+ self.strict = true
79
+ self.expected = String
80
+ end
81
+
82
+ def indent(s)
83
+ s.to_s.map{|line| @indent + line}.join
84
+ end
85
+
86
+ def process_and(exp)
87
+ "(#{process exp.shift} and #{process exp.shift})"
88
+ end
89
+
90
+ def process_args(exp)
91
+ args = []
92
+
93
+ until exp.empty? do
94
+ arg = exp.shift
95
+ if arg.is_a? Array
96
+ args[-(arg.size-1)..-1] = arg[1..-1].map{|a| process a}
97
+ else
98
+ args << arg
99
+ end
100
+ end
101
+
102
+ args.empty? ? "" : "(#{args.join ', '})"
103
+ end
104
+
105
+ def process_array(exp)
106
+ code = []
107
+ until exp.empty? do
108
+ code << process(exp.shift)
109
+ end
110
+ return "[" + code.join(", ") + "]"
111
+ end
112
+
113
+ def process_attrasgn(exp)
114
+ process_call(exp)
115
+ end
116
+
117
+ def process_begin(exp)
118
+ s = "begin\n"
119
+ s << (process(exp.shift).to_s + "\n") until exp.empty?
120
+ s + "\nend"
121
+ end
122
+
123
+ def process_block(exp)
124
+ code = []
125
+ catch_block_arg = false
126
+ until exp.empty? do
127
+ if catch_block_arg
128
+ if exp.first and exp.first.first == :block_arg
129
+ code[-1] = code[-1][0..-2] + ", #{process(exp.shift)})"
130
+ end
131
+ catch_block_arg = false
132
+ else
133
+ if exp.first.first == :args
134
+ catch_block_arg = true
135
+ end
136
+ if [:ensure, :rescue].include? exp.first.first
137
+ code << process(exp.shift)
138
+ else
139
+ code << indent(process(exp.shift))
140
+ end
141
+ end
142
+ end
143
+
144
+ body = code.join("\n")
145
+ body += "\n"
146
+
147
+ return body
148
+ end
149
+
150
+ def process_block_arg(exp)
151
+ "&#{exp.shift}"
152
+ end
153
+
154
+ def process_block_pass(exp)
155
+ bname = process(exp.shift)
156
+ fcall = process(exp.shift)
157
+ if fcall[-1,1] == ')'
158
+ "#{fcall[0..-2]}, &(#{bname}))"
159
+ else
160
+ "#{fcall}(&(#{bname}))"
161
+ end
162
+ end
163
+
164
+ def process_call(exp)
165
+ receiver = process exp.shift
166
+ name = exp.shift
167
+ args_exp = exp.shift
168
+ if args_exp && args_exp.first == :array
169
+ args = "#{process(args_exp)[1..-2]}"
170
+ else
171
+ args = process args_exp
172
+ end
173
+
174
+ case name
175
+ when :<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :% then #
176
+ "(#{receiver} #{name} #{args})"
177
+ when :[] then
178
+ "#{receiver}[#{args}]"
179
+ else
180
+ "#{receiver}.#{name}#{args ? "(#{args})" : args}"
181
+ end
182
+ end
183
+
184
+ def process_case(exp)
185
+ s = "case #{process exp.shift}\n"
186
+ until exp.empty?
187
+ pt = exp.shift
188
+ if pt and pt.first == :when
189
+ s << "#{process(pt)}\n"
190
+ else
191
+ s << "else\n#{indent(process(pt))}\n"
192
+ end
193
+ end
194
+ s + "\nend"
195
+ end
196
+
197
+ def process_class(exp)
198
+ s = "class #{exp.shift} < #{exp.shift}\n"
199
+ body = ""
200
+ body << "#{process exp.shift}\n\n" until exp.empty?
201
+ s + indent(body) + "end"
202
+ end
203
+
204
+ def process_colon2(exp)
205
+ "#{process(exp.shift)}::#{exp.shift}"
206
+ end
207
+
208
+ def process_const(exp)
209
+ exp.shift.to_s
210
+ end
211
+
212
+ def process_dasgn_curr(exp)
213
+ s = exp.shift.to_s
214
+ unless exp.empty?
215
+ s += "=" + process(exp.shift)
216
+ else
217
+ if(@block_params)
218
+ s
219
+ else
220
+ ""
221
+ end
222
+ end
223
+ end
224
+
225
+ def process_defn(exp)
226
+ if exp[1].first == :cfunc
227
+ s = "# method '#{exp.shift}' defined in a C function"
228
+ exp.shift
229
+ return s
230
+ else
231
+ name = exp.shift
232
+ args = process(exp.shift)
233
+ return "def #{name}#{args}end".gsub(/\n\s*\n+/, "\n")
234
+ end
235
+ end
236
+
237
+ def process_dot2(exp)
238
+ "(#{process exp.shift}..#{process exp.shift})"
239
+ end
240
+
241
+ def process_dot3(exp)
242
+ "(#{process exp.shift}...#{process exp.shift})"
243
+ end
244
+
245
+ def process_dstr(exp)
246
+ s = exp.shift.dump[0..-2]
247
+ until exp.empty?
248
+ pt = exp.shift
249
+ if pt.first == :str
250
+ s << process(pt)[1..-2]
251
+ else
252
+ s << '#{' + process(pt) + '}'
253
+ end
254
+ end
255
+ s + '"'
256
+ end
257
+
258
+ def process_dvar(exp)
259
+ exp.shift.to_s
260
+ end
261
+
262
+ def process_ensure(exp)
263
+ process(exp.shift) + "\n" +
264
+ "ensure\n" +
265
+ indent(process(exp.shift))
266
+ end
267
+
268
+ def process_false(exp)
269
+ "false"
270
+ end
271
+
272
+ def process_fbody(exp)
273
+ process(exp.shift)
274
+ end
275
+
276
+ def process_fcall(exp)
277
+ exp_orig = exp.deep_clone
278
+ # [:fcall, :puts, [:array, [:str, "This is a weird loop"]]]
279
+ name = exp.shift.to_s
280
+ args = exp.shift
281
+ code = []
282
+ unless args.nil? then
283
+ assert_type args, :array
284
+ args.shift # :array
285
+ until args.empty? do
286
+ code << process(args.shift)
287
+ end
288
+ end
289
+ return "#{name}(#{code.join(', ')})"
290
+ end
291
+
292
+ def process_for(exp)
293
+ s = "for #{process(exp[1])} in #{process(exp[0])}\n"
294
+ 2.times{ exp.shift }
295
+ s += indent("#{process(exp.shift)}\n")
296
+ s += "end"
297
+ end
298
+
299
+ def process_gvar(exp)
300
+ exp.shift.to_s
301
+ end
302
+
303
+ def process_hash(exp)
304
+ body = []
305
+ body << "#{process(exp.shift)} => #{process(exp.shift)}" until exp.empty?
306
+ body_str = ""
307
+ body_str = "\n"+indent(body.join(",\n"))+"\n" unless body.empty?
308
+ "{" + body_str + "}"
309
+ end
310
+
311
+ def process_iasgn(exp)
312
+ "#{exp.shift} = #{process exp.shift}"
313
+ end
314
+
315
+ def cond_indent_process(pt)
316
+ (pt and pt.first == :block) ? process(pt) : indent(process(pt))
317
+ end
318
+
319
+ def process_if(exp)
320
+ s = ["if (#{process exp.shift})"]
321
+ s << "#{cond_indent_process(exp.shift)}"
322
+ s << "else\n#{cond_indent_process(exp.shift)}" until exp.empty?
323
+ s << "end"
324
+ s.join("\n")
325
+ end
326
+
327
+ def process_iter(exp)
328
+ owner = exp.shift
329
+ args = exp.shift
330
+ if !args.nil?
331
+ @block_params = true
332
+ end
333
+ processed_args = process args
334
+ block_args = processed_args.nil? ? "" : "|#{processed_args}|"
335
+
336
+ result = "#{process owner} {#{block_args}\n" +
337
+ indent("#{process exp.shift}\n") +
338
+ "}"
339
+ @block_params = false
340
+ result
341
+ end
342
+
343
+ def process_ivar(exp)
344
+ exp.shift.to_s
345
+ end
346
+
347
+ def process_lasgn(exp)
348
+ s = "#{exp.shift}"
349
+ s += " = #{process exp.shift}" unless exp.empty?
350
+ s
351
+ end
352
+
353
+ def process_lit(exp)
354
+ obj = exp.shift
355
+ if obj.is_a? Range # to get around how parsed ranges turn into lits and lose parens
356
+ "(" + obj.inspect + ")"
357
+ else
358
+ obj.inspect
359
+ end
360
+ end
361
+
362
+ def process_lvar(exp)
363
+ exp.shift.to_s
364
+ end
365
+
366
+ def process_masgn(exp)
367
+ process(exp.shift)[1..-2]
368
+ end
369
+
370
+ def process_module(exp)
371
+ s = "module #{exp.shift}\n"
372
+ body = ""
373
+ body << "#{process exp.shift}\n\n" until exp.empty?
374
+ s + indent(body) + "end"
375
+ end
376
+
377
+ def process_nil(exp)
378
+ "nil"
379
+ end
380
+
381
+ def process_not(exp)
382
+ "(not #{process exp.shift})"
383
+ end
384
+
385
+ def process_or(exp)
386
+ "(#{process exp.shift} or #{process exp.shift})"
387
+ end
388
+
389
+ def process_resbody(exp)
390
+ s = "rescue "
391
+ unless exp.empty?
392
+ if exp.first.first == :array
393
+ s << process(exp.shift)[1..-2]
394
+ end
395
+ s << "\n"
396
+ end
397
+ s << (process(exp.shift).to_s + "\n") until exp.empty?
398
+ s
399
+ end
400
+
401
+ def process_rescue(exp)
402
+ s = ""
403
+ s << (process(exp.shift).to_s + "\n") until exp.empty?
404
+ s
405
+ end
406
+
407
+ def process_retry(exp)
408
+ "retry"
409
+ end
410
+
411
+ def process_return(exp)
412
+ return "return #{process exp.shift}"
413
+ end
414
+
415
+ def process_scope(exp)
416
+ return process(exp.shift)
417
+ end
418
+
419
+ def process_self(exp)
420
+ "self"
421
+ end
422
+ def process_str(exp)
423
+ return exp.shift.dump
424
+ end
425
+
426
+ def process_super(exp)
427
+ "super(#{process(exp.shift)})"
428
+ end
429
+
430
+ def process_true(exp)
431
+ "true"
432
+ end
433
+
434
+ def process_until(exp)
435
+ cond_loop(exp, 'until')
436
+ end
437
+
438
+ def process_vcall(exp)
439
+ return exp.shift.to_s
440
+ end
441
+
442
+ def process_when(exp)
443
+ "when #{process(exp.shift).to_s[1..-2]}\n#{indent(process(exp.shift))}"
444
+ end
445
+
446
+ def process_while(exp)
447
+ cond_loop(exp, 'while')
448
+ end
449
+
450
+ def process_yield(exp)
451
+ body = process(exp.shift)[1..-2] unless exp.empty?
452
+ "yield#{body and "(#{body})"}"
453
+ end
454
+
455
+ def process_zarray(exp)
456
+ "[]"
457
+ end
458
+
459
+ def process_zsuper(exp)
460
+ "super"
461
+ end
462
+
463
+ # def process_dxstr(exp)
464
+ # puts "DXSTR:#{exp.shift}"
465
+ # end
466
+
467
+ def cond_loop(exp, name)
468
+ cond = process(exp.shift)
469
+ body = cond_indent_process(exp.shift)
470
+ head_controlled = exp.empty? ? false : exp.shift
471
+
472
+ code = []
473
+ if head_controlled then
474
+ code << "#{name} (#{cond}) do"
475
+ code << body
476
+ code << "end"
477
+ else
478
+ code << "begin"
479
+ code << body
480
+ code << "end #{name} (#{cond})"
481
+ end
482
+ code.join("\n")
483
+ end
484
+
485
+ end