rspec 0.5.7 → 0.5.8

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