thor 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,238 @@
1
+ # The last time the Getopt gem was modified was August 2007, so it's safe to vendor (it does everything we need)
2
+
3
+ module Getopt
4
+
5
+ REQUIRED = 0
6
+ BOOLEAN = 1
7
+ OPTIONAL = 2
8
+ INCREMENT = 3
9
+ NEGATABLE = 4
10
+ NUMERIC = 5
11
+
12
+ class Long
13
+ class Error < StandardError; end
14
+
15
+ VERSION = '1.3.6'
16
+
17
+ # Takes an array of switches. Each array consists of up to three
18
+ # elements that indicate the name and type of switch. Returns a hash
19
+ # containing each switch name, minus the '-', as a key. The value
20
+ # for each key depends on the type of switch and/or the value provided
21
+ # by the user.
22
+ #
23
+ # The long switch _must_ be provided. The short switch defaults to the
24
+ # first letter of the short switch. The default type is BOOLEAN.
25
+ #
26
+ # Example:
27
+ #
28
+ # opts = Getopt::Long.getopts(
29
+ # ["--debug"],
30
+ # ["--verbose", "-v"],
31
+ # ["--level", "-l", NUMERIC]
32
+ # )
33
+ #
34
+ # See the README file for more information.
35
+ #
36
+ def self.getopts(*switches)
37
+ if switches.empty?
38
+ raise ArgumentError, "no switches provided"
39
+ end
40
+
41
+ hash = {} # Hash returned to user
42
+ valid = [] # Tracks valid switches
43
+ types = {} # Tracks argument types
44
+ syns = {} # Tracks long and short arguments, or multiple shorts
45
+
46
+ # If a string is passed, split it and convert it to an array of arrays
47
+ if switches.first.kind_of?(String)
48
+ switches = switches.join.split
49
+ switches.map!{ |switch| switch = [switch] }
50
+ end
51
+
52
+ # Set our list of valid switches, and proper types for each switch
53
+ switches.each{ |switch|
54
+ valid.push(switch[0]) # Set valid long switches
55
+
56
+ # Set type for long switch, default to BOOLEAN.
57
+ if switch[1].kind_of?(Fixnum)
58
+ switch[2] = switch[1]
59
+ types[switch[0]] = switch[2]
60
+ switch[1] = switch[0][1..2]
61
+ else
62
+ switch[2] ||= BOOLEAN
63
+ types[switch[0]] = switch[2]
64
+ switch[1] ||= switch[0][1..2]
65
+ end
66
+
67
+ # Create synonym hash. Default to first char of long switch for
68
+ # short switch, e.g. "--verbose" creates a "-v" synonym. The same
69
+ # synonym can only be used once - first one wins.
70
+ syns[switch[0]] = switch[1] unless syns[switch[1]]
71
+ syns[switch[1]] = switch[0] unless syns[switch[1]]
72
+
73
+ switch[1].each{ |char|
74
+ types[char] = switch[2] # Set type for short switch
75
+ valid.push(char) # Set valid short switches
76
+ }
77
+
78
+ if ARGV.empty? && switch[2] == REQUIRED
79
+ raise Error, "no value provided for required argument '#{switch[0]}'"
80
+ end
81
+ }
82
+
83
+ re_long = /^(--\w+[-\w+]*)?$/
84
+ re_short = /^(-\w)$/
85
+ re_long_eq = /^(--\w+[-\w+]*)?=(.*?)$|(-\w?)=(.*?)$/
86
+ re_short_sq = /^(-\w)(\S+?)$/
87
+
88
+ ARGV.each_with_index{ |opt, index|
89
+
90
+ # Allow either -x -v or -xv style for single char args
91
+ if re_short_sq.match(opt)
92
+ chars = opt.split("")[1..-1].map{ |s| s = "-#{s}" }
93
+
94
+ chars.each_with_index{ |char, i|
95
+ unless valid.include?(char)
96
+ raise Error, "invalid switch '#{char}'"
97
+ end
98
+
99
+ # Grab the next arg if the switch takes a required arg
100
+ if types[char] == REQUIRED
101
+ # Deal with a argument squished up against switch
102
+ if chars[i+1]
103
+ arg = chars[i+1..-1].join.tr("-","")
104
+ ARGV.push(char, arg)
105
+ break
106
+ else
107
+ arg = ARGV.delete_at(index+1)
108
+ if arg.nil? || valid.include?(arg) # Minor cheat here
109
+ err = "no value provided for required argument '#{char}'"
110
+ raise Error, err
111
+ end
112
+ ARGV.push(char, arg)
113
+ end
114
+ elsif types[char] == OPTIONAL
115
+ if chars[i+1] && !valid.include?(chars[i+1])
116
+ arg = chars[i+1..-1].join.tr("-","")
117
+ ARGV.push(char, arg)
118
+ break
119
+ elsif
120
+ if ARGV[index+1] && !valid.include?(ARGV[index+1])
121
+ arg = ARGV.delete_at(index+1)
122
+ ARGV.push(char, arg)
123
+ end
124
+ else
125
+ ARGV.push(char)
126
+ end
127
+ else
128
+ ARGV.push(char)
129
+ end
130
+ }
131
+ next
132
+ end
133
+
134
+ if match = re_long.match(opt) || match = re_short.match(opt)
135
+ switch = match.captures.first
136
+ end
137
+
138
+ if match = re_long_eq.match(opt)
139
+ switch, value = match.captures.compact
140
+ ARGV.push(switch, value)
141
+ next
142
+ end
143
+
144
+ # Make sure that all the switches are valid. If 'switch' isn't
145
+ # defined at this point, it means an option was passed without
146
+ # a preceding switch, e.g. --option foo bar.
147
+ unless valid.include?(switch)
148
+ switch ||= opt
149
+ raise Error, "invalid switch '#{switch}'"
150
+ end
151
+
152
+ # Required arguments
153
+ if types[switch] == REQUIRED
154
+ nextval = ARGV[index+1]
155
+
156
+ # Make sure there's a value for mandatory arguments
157
+ if nextval.nil?
158
+ err = "no value provided for required argument '#{switch}'"
159
+ raise Error, err
160
+ end
161
+
162
+ # If there is a value, make sure it's not another switch
163
+ if valid.include?(nextval)
164
+ err = "cannot pass switch '#{nextval}' as an argument"
165
+ raise Error, err
166
+ end
167
+
168
+ # If the same option appears more than once, put the values
169
+ # in array.
170
+ if hash[switch]
171
+ hash[switch] = [hash[switch], nextval].flatten
172
+ else
173
+ hash[switch] = nextval
174
+ end
175
+ ARGV.delete_at(index+1)
176
+ end
177
+
178
+ # For boolean arguments set the switch's value to true.
179
+ if types[switch] == BOOLEAN
180
+ if hash.has_key?(switch)
181
+ raise Error, "boolean switch already set"
182
+ end
183
+ hash[switch] = true
184
+ end
185
+
186
+ # For increment arguments, set the switch's value to 0, or
187
+ # increment it by one if it already exists.
188
+ if types[switch] == INCREMENT
189
+ if hash.has_key?(switch)
190
+ hash[switch] += 1
191
+ else
192
+ hash[switch] = 1
193
+ end
194
+ end
195
+
196
+ # For optional argument, there may be an argument. If so, it
197
+ # cannot be another switch. If not, it is set to true.
198
+ if types[switch] == OPTIONAL
199
+ nextval = ARGV[index+1]
200
+ if valid.include?(nextval)
201
+ hash[switch] = true
202
+ else
203
+ hash[switch] = nextval
204
+ ARGV.delete_at(index+1)
205
+ end
206
+ end
207
+ }
208
+
209
+ # Set synonymous switches to the same value, e.g. if -t is a synonym
210
+ # for --test, and the user passes "--test", then set "-t" to the same
211
+ # value that "--test" was set to.
212
+ #
213
+ # This allows users to refer to the long or short switch and get
214
+ # the same value
215
+ hash.each{ |switch, val|
216
+ if syns.keys.include?(switch)
217
+ syns[switch].each{ |key|
218
+ hash[key] = val
219
+ }
220
+ end
221
+ }
222
+
223
+ # Get rid of leading "--" and "-" to make it easier to reference
224
+ hash.each{ |key, value|
225
+ if key[0,2] == '--'
226
+ nkey = key.sub('--', '')
227
+ else
228
+ nkey = key.sub('-', '')
229
+ end
230
+ hash.delete(key)
231
+ hash[nkey] = value
232
+ }
233
+
234
+ hash
235
+ end
236
+
237
+ end
238
+ end
@@ -0,0 +1,131 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
2
+ require "getopt"
3
+
4
+ class Thor
5
+ def self.inherited(klass)
6
+ subclass_files[File.expand_path(caller[0].split(":")[0])] << klass
7
+ subclasses << klass unless subclasses.include?(klass)
8
+ end
9
+
10
+ def self.subclass_files
11
+ @subclass_files ||= Hash.new {|h,k| h[k] = []}
12
+ end
13
+
14
+ def self.subclasses
15
+ @subclasses ||= []
16
+ end
17
+
18
+ def self.method_added(meth)
19
+ meth = meth.to_s
20
+ return if !public_instance_methods.include?(meth) || !@usage
21
+ @descriptions ||= []
22
+ @usages ||= []
23
+ @opts ||= []
24
+
25
+ @descriptions.delete(@descriptions.assoc(meth))
26
+ @descriptions << [meth, @desc]
27
+
28
+ @usages.delete(@usages.assoc(meth))
29
+ @usages << [meth, @usage]
30
+
31
+ @opts.delete(@opts.assoc(meth))
32
+ @opts << [meth, @method_options] if @method_options
33
+
34
+ @usage, @desc, @method_options = nil
35
+ end
36
+
37
+ def self.map(map)
38
+ @map ||= superclass.instance_variable_get("@map") || {}
39
+ @map.merge! map
40
+ end
41
+
42
+ def self.desc(usage, description)
43
+ @usage, @desc = usage, description
44
+ end
45
+
46
+ def self.method_options(opts)
47
+ @method_options = opts.inject({}) do |accum, (k,v)|
48
+ accum.merge("--" + k.to_s => v.to_s.upcase)
49
+ end
50
+ end
51
+
52
+ def self.help_list
53
+ return nil unless @usages
54
+ @help_list ||= begin
55
+ max_usage = @usages.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size
56
+ max_opts = @opts.empty? ? 0 : format_opts(@opts.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last).size
57
+ max_desc = @descriptions.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size
58
+ Struct.new(:klass, :usages, :opts, :descriptions, :max).new(
59
+ self, @usages, @opts, @descriptions, Struct.new(:usage, :opt, :desc).new(max_usage, max_opts, max_desc)
60
+ )
61
+ end
62
+ end
63
+
64
+ def self.format_opts(opts)
65
+ return "" if !opts
66
+ opts.map do |opt, val|
67
+ if val == true || val == "BOOLEAN"
68
+ "[#{opt}]"
69
+ elsif val == "REQUIRED"
70
+ opt + "=" + opt.gsub(/\-/, "").upcase
71
+ elsif val == "OPTIONAL"
72
+ "[" + opt + "=" + opt.gsub(/\-/, "").upcase + "]"
73
+ end
74
+ end.join(" ")
75
+ end
76
+
77
+ def self.start
78
+ meth = ARGV.shift
79
+ params = []
80
+ while !ARGV.empty?
81
+ break if ARGV.first =~ /^\-/
82
+ params << ARGV.shift
83
+ end
84
+ if defined?(@map) && @map[meth]
85
+ meth = @map[meth].to_s
86
+ end
87
+
88
+ args = ARGV.dup
89
+
90
+ if @opts.assoc(meth)
91
+ opts = @opts.assoc(meth).last.map {|opt, val| [opt, val == true ? Getopt::BOOLEAN : Getopt.const_get(val)].flatten}
92
+ options = Getopt::Long.getopts(*opts)
93
+ params << options
94
+ end
95
+
96
+ ARGV.replace args
97
+
98
+ new(meth, params).instance_variable_get("@results")
99
+ end
100
+
101
+ def initialize(op, params)
102
+ begin
103
+ op ||= "help"
104
+ @results = send(op.to_sym, *params) if public_methods.include?(op) || !methods.include?(op)
105
+ rescue ArgumentError
106
+ puts "`#{op}' was called incorrectly. Call as `#{usage(op)}'"
107
+ end
108
+ end
109
+
110
+ public :initialize
111
+
112
+ def usage(meth)
113
+ list = self.class.help_list
114
+ list.usages.assoc(meth)[1] + (list.opts.assoc(meth) ? " " + self.class.format_opts(list.opts.assoc(meth)[1]) : "")
115
+ end
116
+
117
+ map "--help" => :help
118
+
119
+ desc "help", "show this screen"
120
+ def help
121
+ list = self.class.help_list
122
+ puts "Options"
123
+ puts "-------"
124
+ list.usages.each do |meth, use|
125
+ format = "%-" + (list.max.usage + list.max.opt + 4).to_s + "s"
126
+ print format % ("#{usage(meth)}")
127
+ puts list.descriptions.assoc(meth)[1]
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,76 @@
1
+ require "thor"
2
+ require "fileutils"
3
+
4
+ class Thor
5
+ def self.package_task
6
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
7
+ desc "package", "package up the gem"
8
+ def package
9
+ FileUtils.mkdir_p(File.join(Dir.pwd, "pkg"))
10
+ Gem::Builder.new(SPEC).build
11
+ FileUtils.mv(SPEC.file_name, File.join(Dir.pwd, "pkg", SPEC.file_name))
12
+ end
13
+ RUBY
14
+ end
15
+
16
+ def self.install_task
17
+ package_task
18
+
19
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
20
+ desc "install", "install the gem"
21
+ def install
22
+ old_stderr, $stderr = $stderr.dup, File.open("/dev/null", "w")
23
+ package
24
+ $stderr = old_stderr
25
+ system %{sudo gem install pkg/#{GEM}-#{GEM_VERSION} --no-rdoc --no-ri --no-update-sources}
26
+ end
27
+ RUBY
28
+ end
29
+
30
+ def self.spec_task(file_list, opts = {})
31
+ name = opts.delete(:name) || "spec"
32
+ rcov_dir = opts.delete(:rcov_dir) || "coverage"
33
+ file_list = file_list.map {|f| %["#{f}"]}.join(" ")
34
+ verbose = opts.delete(:verbose)
35
+ opts = {:format => "specdoc", :color => true}.merge(opts)
36
+
37
+ rcov_opts = convert_task_options(opts.delete(:rcov) || {})
38
+ rcov = !rcov_opts.empty?
39
+ options = convert_task_options(opts)
40
+
41
+ if rcov
42
+ FileUtils.rm_rf(File.join(Dir.pwd, rcov_dir))
43
+ end
44
+
45
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
46
+ desc("#{name}", "spec task")
47
+ def #{name}
48
+ cmd = "ruby "
49
+ if #{rcov.inspect}
50
+ cmd << "-S rcov -o #{rcov_dir} #{rcov_opts.inspect[1...-1]} "
51
+ end
52
+ cmd << `which spec`.chomp
53
+ cmd << " -- " if #{rcov.inspect}
54
+ cmd << " "
55
+ cmd << #{file_list.inspect}
56
+ cmd << " "
57
+ cmd << #{options.inspect}
58
+ puts cmd if #{verbose.inspect}
59
+ system(cmd)
60
+ end
61
+ RUBY
62
+ end
63
+
64
+ private
65
+ def self.convert_task_options(opts)
66
+ opts.map do |key, value|
67
+ if value == true
68
+ "--#{key}"
69
+ elsif value.is_a?(Array)
70
+ value.map {|v| "--#{key} #{v.inspect}"}.join(" ")
71
+ else
72
+ "--#{key} #{value.inspect}"
73
+ end
74
+ end.join(" ")
75
+ end
76
+ end
@@ -0,0 +1,1090 @@
1
+ require 'vendor/sexp_processor'
2
+ require 'vendor/unified_ruby'
3
+
4
+ class Ruby2Ruby < SexpProcessor
5
+ include UnifiedRuby
6
+
7
+ VERSION = '1.1.8'
8
+ LINE_LENGTH = 78
9
+
10
+ ##
11
+ # Nodes that represent assignment and probably need () around them.
12
+
13
+ ASSIGN_NODES = [
14
+ :dasgn,
15
+ :flip2,
16
+ :flip3,
17
+ :lasgn,
18
+ :masgn,
19
+ :op_asgn1,
20
+ :op_asgn2,
21
+ :op_asgn_and,
22
+ :op_asgn_or,
23
+ :return,
24
+ ]
25
+
26
+ def self.translate(klass_or_str, method = nil)
27
+ self.new.process(ParseTree.translate(klass_or_str, method))
28
+ end
29
+
30
+ def initialize
31
+ super
32
+ @indent = " "
33
+ self.auto_shift_type = true
34
+ self.strict = true
35
+ self.expected = String
36
+
37
+ # self.debug[:defn] = /zsuper/
38
+ end
39
+
40
+ def process exp
41
+ exp = Sexp.from_array(exp) if Array === exp unless Sexp === exp
42
+ super exp
43
+ end
44
+
45
+ ############################################################
46
+ # Processors
47
+
48
+ def process_alias(exp)
49
+ "alias_method #{process(exp.shift)}, #{process(exp.shift)}"
50
+ end
51
+
52
+ def process_and(exp)
53
+ "(#{process exp.shift} and #{process exp.shift})"
54
+ end
55
+
56
+ def process_args(exp)
57
+ args = []
58
+
59
+ until exp.empty? do
60
+ arg = exp.shift
61
+ case arg
62
+ when Symbol then
63
+ args << arg
64
+ when Array then
65
+ case arg.first
66
+ when :block then
67
+ asgns = {}
68
+ arg[1..-1].each do |lasgn|
69
+ asgns[lasgn[1]] = process(lasgn)
70
+ end
71
+
72
+ args.each_with_index do |name, index|
73
+ args[index] = asgns[name] if asgns.has_key? name
74
+ end
75
+ when :block_arg then
76
+ args << "&#{arg.last}"
77
+ else
78
+ raise "unknown arg type #{arg.first.inspect}"
79
+ end
80
+ else
81
+ raise "unknown arg type #{arg.inspect}"
82
+ end
83
+ end
84
+
85
+ return "(#{args.join ', '})"
86
+ end
87
+
88
+ def process_arglist(exp) # custom made node
89
+ code = []
90
+ until exp.empty? do
91
+ code << process(exp.shift)
92
+ end
93
+ code.join ', '
94
+ end
95
+
96
+ def process_argscat(exp)
97
+ args = []
98
+
99
+ ary = exp.shift
100
+ ary.shift # :array
101
+ until ary.empty? do
102
+ args << process(ary.shift)
103
+ end
104
+
105
+ args << "*#{process(exp.shift)}"
106
+ args << process(exp.shift) unless exp.empty? # optional block arg
107
+
108
+ args.join ', '
109
+ end
110
+
111
+ def process_argspush(exp)
112
+ process_arglist(exp)
113
+ end
114
+
115
+ def process_array(exp)
116
+ "[#{process_arglist(exp)}]"
117
+ end
118
+
119
+ def process_attrasgn(exp)
120
+ receiver = process exp.shift
121
+ name = exp.shift
122
+ args = exp.empty? ? nil : exp.shift
123
+
124
+ case name
125
+ when :[]= then
126
+ rhs = process args.pop
127
+ args[0] = :arglist if args[0] == :array
128
+ "#{receiver}[#{process(args)}] = #{rhs}"
129
+ else
130
+ if args then
131
+ "#{receiver}.#{name.to_s[0..-2]} = #{process(args)[1..-2]}"
132
+ else
133
+ "#{receiver}.#{name.to_s[0..-2]}"
134
+ end
135
+ end
136
+ end
137
+
138
+ def process_back_ref(exp)
139
+ "$#{exp.shift}"
140
+ end
141
+
142
+ def process_begin(exp)
143
+ is_rescue = exp.first.first == :rescue rescue false
144
+ code = []
145
+ code << "begin"
146
+ until exp.empty?
147
+ src = process(exp.shift)
148
+ src = indent(src) unless src =~ /(^|\n)rescue/ # ensures no level 0 rescues
149
+ code << src
150
+ end
151
+ code << "end" unless is_rescue
152
+ return code.join("\n")
153
+ end
154
+
155
+ def process_block(exp)
156
+ result = []
157
+
158
+ exp << nil if exp.empty?
159
+ until exp.empty? do
160
+ code = exp.shift
161
+ if code.nil? or code.first == :nil then
162
+ result << "# do nothing"
163
+ else
164
+ result << process(code)
165
+ end
166
+ end
167
+
168
+ result = result.join "\n"
169
+
170
+ result = case self.context[1]
171
+ when nil, :scope, :if, :iter, :resbody, :when, :while then
172
+ result + "\n"
173
+ else
174
+ "(#{result})"
175
+ end
176
+
177
+ return result
178
+ end
179
+
180
+ def process_block_arg(exp)
181
+ "&#{exp.shift}"
182
+ end
183
+
184
+ def process_block_pass(exp)
185
+ bname = s(:block_arg, process(exp.shift)) # FIX
186
+ call = exp.shift
187
+
188
+ if Array === call.last then # HACK - I _really_ need rewrites to happen first
189
+ case call.last.first
190
+ when :splat then
191
+ call << [:array, call.pop]
192
+ when :array then
193
+ # do nothing
194
+ else
195
+ has_args = Array === call.last and call.last.first == :array
196
+ call << [:array] unless has_args
197
+ end
198
+ call.last << bname
199
+ else
200
+ call << [:array, bname]
201
+ end
202
+
203
+ process(call)
204
+ end
205
+
206
+ def process_break(exp)
207
+ val = exp.empty? ? nil : process(exp.shift)
208
+ # HACK "break" + (val ? " #{val}" : "")
209
+ if val then
210
+ "break #{val}"
211
+ else
212
+ "break"
213
+ end
214
+ end
215
+
216
+ def process_call(exp)
217
+ receiver_node_type = exp.first.nil? ? nil : exp.first.first
218
+ receiver = process exp.shift
219
+
220
+ receiver = "(#{receiver})" if
221
+ Ruby2Ruby::ASSIGN_NODES.include? receiver_node_type
222
+
223
+ name = exp.shift
224
+ args_exp = exp.shift rescue nil
225
+ if args_exp && args_exp.first == :array # FIX
226
+ args = "#{process(args_exp)[1..-2]}"
227
+ else
228
+ args = process args_exp
229
+ args = nil if args.empty?
230
+ end
231
+
232
+ case name
233
+ when :<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<, :>>, :** then
234
+ "(#{receiver} #{name} #{args})"
235
+ when :[] then
236
+ "#{receiver}[#{args}]"
237
+ when :"-@" then
238
+ "-#{receiver}"
239
+ when :"+@" then
240
+ "+#{receiver}"
241
+ else
242
+ unless receiver.nil? then
243
+ "#{receiver}.#{name}#{args ? "(#{args})" : args}"
244
+ else
245
+ "#{name}#{args ? "(#{args})" : args}"
246
+ end
247
+ end
248
+ end
249
+
250
+ def process_case(exp)
251
+ result = []
252
+ expr = process exp.shift
253
+ if expr then
254
+ result << "case #{expr}"
255
+ else
256
+ result << "case"
257
+ end
258
+ until exp.empty?
259
+ pt = exp.shift
260
+ if pt and pt.first == :when
261
+ result << "#{process(pt)}"
262
+ else
263
+ code = indent(process(pt))
264
+ code = indent("# do nothing") if code =~ /^\s*$/
265
+ result << "else\n#{code}"
266
+ end
267
+ end
268
+ result << "end"
269
+ result.join("\n")
270
+ end
271
+
272
+ def process_cdecl(exp)
273
+ "#{exp.shift} = #{process(exp.shift)}"
274
+ end
275
+
276
+ def process_class(exp)
277
+ "class #{util_module_or_class(exp, true)}"
278
+ end
279
+
280
+ def process_colon2(exp)
281
+ "#{process(exp.shift)}::#{exp.shift}"
282
+ end
283
+
284
+ def process_colon3(exp)
285
+ "::#{exp.shift}"
286
+ end
287
+
288
+ def process_const(exp)
289
+ exp.shift.to_s
290
+ end
291
+
292
+ def process_cvar(exp)
293
+ "#{exp.shift}"
294
+ end
295
+
296
+ def process_cvasgn(exp)
297
+ "#{exp.shift} = #{process(exp.shift)}"
298
+ end
299
+
300
+ def process_cvdecl(exp)
301
+ "#{exp.shift} = #{process(exp.shift)}"
302
+ end
303
+
304
+ # (a, lit1) => "a = 1"
305
+ # (a, (b, lit2)) => "a = b = 2"
306
+ # (a, (b)) => ""
307
+
308
+ def process_dasgn_curr(exp)
309
+ lhs = exp.shift.to_s
310
+ rhs = (exp.empty? ? nil : exp.shift)
311
+ if rhs.nil? then
312
+ if self.context[1] == :block then
313
+ return ''
314
+ end
315
+
316
+ return lhs
317
+ end
318
+ return "#{lhs} = #{process rhs}" unless rhs.first == :dasgn_curr
319
+
320
+ # keep recursing. ensure that the leaf node assigns to _something_
321
+ "#{lhs} = #{process rhs}"
322
+ end
323
+
324
+ def process_dasgn(exp)
325
+ if exp.size == 1 then
326
+ exp.shift.to_s
327
+ else
328
+ "#{exp.shift} = #{process(exp.shift)}"
329
+ end
330
+ end
331
+
332
+ def process_defined(exp)
333
+ "defined? #{process(exp.shift)}"
334
+ end
335
+
336
+ def process_defn(exp)
337
+ type1 = exp[1].first
338
+ type2 = exp[2].first rescue nil
339
+
340
+ if type1 == :args and [:ivar, :attrset].include? type2 then
341
+ name = exp.shift
342
+ case type2
343
+ when :ivar then
344
+ exp.clear
345
+ return "attr_reader #{name.inspect}"
346
+ when :attrset then
347
+ exp.clear
348
+ return "attr_writer :#{name.to_s[0..-2]}"
349
+ else
350
+ raise "Unknown defn type: #{exp.inspect}"
351
+ end
352
+ end
353
+
354
+ case type1
355
+ when :scope, :args then
356
+ name = exp.shift
357
+ args = process(exp.shift)
358
+ args = "" if args == "()"
359
+ body = indent(process(exp.shift))
360
+ return "def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n")
361
+ else
362
+ raise "Unknown defn type: #{type1} for #{exp.inspect}"
363
+ end
364
+ end
365
+
366
+ def process_defs(exp)
367
+ exp.unshift "#{process(exp.shift)}.#{exp.shift}"
368
+ process_defn(exp)
369
+ end
370
+
371
+ def process_dot2(exp)
372
+ "(#{process exp.shift}..#{process exp.shift})"
373
+ end
374
+
375
+ def process_dot3(exp)
376
+ "(#{process exp.shift}...#{process exp.shift})"
377
+ end
378
+
379
+ def process_dregx(exp)
380
+ "/" << util_dthing(exp, true) << "/"
381
+ end
382
+
383
+ def process_dregx_once(exp)
384
+ process_dregx(exp) + "o"
385
+ end
386
+
387
+ def process_dstr(exp)
388
+ "\"#{util_dthing(exp)}\""
389
+ end
390
+
391
+ def process_dsym(exp)
392
+ ":#{process_dstr(exp)}"
393
+ end
394
+
395
+ def process_dvar(exp)
396
+ exp.shift.to_s
397
+ end
398
+
399
+ def process_dxstr(exp)
400
+ "`#{process_dstr(exp)[1..-2]}`"
401
+ end
402
+
403
+ def process_ensure(exp)
404
+ body = process exp.shift
405
+ ens = process exp.shift
406
+ return "#{body}\nensure\n#{indent ens}"
407
+ end
408
+
409
+ def process_evstr(exp)
410
+ process exp.shift
411
+ end
412
+
413
+ def process_false(exp)
414
+ "false"
415
+ end
416
+
417
+ # TODO: remove for unified
418
+ def process_fcall(exp)
419
+ recv = exp.shift unless Symbol === exp.first # HACK conditional - some not getting rewritten?
420
+ name = exp.shift.to_s
421
+ args = exp.shift
422
+ code = []
423
+ unless args.nil? then
424
+ args[0] = :arglist if args.first == :array
425
+ code << process(args)
426
+ end
427
+ return code.empty? ? name : "#{name}(#{code.join(', ')})"
428
+ end
429
+
430
+ def process_flip2(exp)
431
+ "#{process(exp.shift)}..#{process(exp.shift)}"
432
+ end
433
+
434
+ def process_flip3(exp)
435
+ "#{process(exp.shift)}...#{process(exp.shift)}"
436
+ end
437
+
438
+ def process_for(exp)
439
+ recv = process exp.shift
440
+ iter = process exp.shift
441
+ body = exp.empty? ? nil : process(exp.shift)
442
+
443
+ result = ["for #{iter} in #{recv} do"]
444
+ result << indent(body ? body : "# do nothing")
445
+ result << "end"
446
+
447
+ result.join("\n")
448
+ end
449
+
450
+ def process_gasgn(exp)
451
+ process_iasgn(exp)
452
+ end
453
+
454
+ def process_gvar(exp)
455
+ return exp.shift.to_s
456
+ end
457
+
458
+ def process_hash(exp)
459
+ result = []
460
+ until exp.empty?
461
+ result << "#{process(exp.shift)} => #{process(exp.shift)}"
462
+ end
463
+
464
+ case self.context[1]
465
+ when :arglist, :argscat then
466
+ return "#{result.join(', ')}" # HACK - this will break w/ 2 hashes as args
467
+ else
468
+ return "{ #{result.join(', ')} }"
469
+ end
470
+ end
471
+
472
+ def process_iasgn(exp)
473
+ lhs = exp.shift
474
+ if exp.empty? then # part of an masgn
475
+ lhs.to_s
476
+ else
477
+ "#{lhs} = #{process exp.shift}"
478
+ end
479
+ end
480
+
481
+ def process_if(exp)
482
+ expand = Ruby2Ruby::ASSIGN_NODES.include? exp.first.first
483
+ c = process exp.shift
484
+ t = process exp.shift
485
+ f = process exp.shift
486
+
487
+ c = "(#{c.chomp})" if c =~ /\n/
488
+
489
+ if t then
490
+ unless expand then
491
+ if f then
492
+ r = "#{c} ? (#{t}) : (#{f})"
493
+ r = nil if r =~ /return/ # HACK - need contextual awareness or something
494
+ else
495
+ r = "#{t} if #{c}"
496
+ end
497
+ return r if r and (@indent+r).size < LINE_LENGTH and r !~ /\n/
498
+ end
499
+
500
+ r = "if #{c} then\n#{indent(t)}\n"
501
+ r << "else\n#{indent(f)}\n" if f
502
+ r << "end"
503
+
504
+ r
505
+ else
506
+ unless expand then
507
+ r = "#{f} unless #{c}"
508
+ return r if (@indent+r).size < LINE_LENGTH and r !~ /\n/
509
+ end
510
+ "unless #{c} then\n#{indent(f)}\nend"
511
+ end
512
+ end
513
+
514
+ def process_iter(exp)
515
+ iter = process exp.shift
516
+ args = exp.shift
517
+ args = (args == 0) ? '' : process(args)
518
+ body = exp.empty? ? nil : process(exp.shift)
519
+
520
+ b, e = if iter == "END" then
521
+ [ "{", "}" ]
522
+ else
523
+ [ "do", "end" ]
524
+ end
525
+
526
+ iter.sub!(/\(\)$/, '')
527
+
528
+ # REFACTOR: ugh
529
+ result = []
530
+ result << "#{iter} {"
531
+ result << " |#{args}|" if args
532
+ if body then
533
+ result << " #{body.strip} "
534
+ else
535
+ result << ' '
536
+ end
537
+ result << "}"
538
+ result = result.join
539
+ return result if result !~ /\n/ and result.size < LINE_LENGTH
540
+
541
+ result = []
542
+ result << "#{iter} #{b}"
543
+ result << " |#{args}|" if args
544
+ result << "\n"
545
+ result << indent(body.strip)
546
+ result << "\n"
547
+ result << e
548
+ result.join
549
+ end
550
+
551
+ def process_ivar(exp)
552
+ exp.shift.to_s
553
+ end
554
+
555
+ def process_lasgn(exp)
556
+ s = "#{exp.shift}"
557
+ s += " = #{process exp.shift}" unless exp.empty?
558
+ s
559
+ end
560
+
561
+ def process_lit(exp)
562
+ obj = exp.shift
563
+ case obj
564
+ when Range then
565
+ "(#{obj.inspect})"
566
+ else
567
+ obj.inspect
568
+ end
569
+ end
570
+
571
+ def process_lvar(exp)
572
+ exp.shift.to_s
573
+ end
574
+
575
+ def splat(sym)
576
+ :"*#{sym}"
577
+ end
578
+
579
+ def process_masgn(exp)
580
+ lhs = exp.shift
581
+ rhs = exp.empty? ? nil : exp.shift
582
+
583
+ unless exp.empty? then
584
+ rhs[-1] = splat(rhs[-1]) unless rhs == s(:splat)
585
+ lhs << rhs
586
+ rhs = exp.shift
587
+ end
588
+
589
+ case lhs.first
590
+ when :array then
591
+ lhs.shift
592
+ lhs = lhs.map do |l|
593
+ case l.first
594
+ when :masgn then
595
+ "(#{process(l)})"
596
+ else
597
+ process(l)
598
+ end
599
+ end
600
+ when :dasgn_curr then
601
+ lhs = [ splat(lhs.last) ]
602
+ when :splat then
603
+ lhs = [ :"*" ]
604
+ else
605
+ raise "no clue: #{lhs.inspect}"
606
+ end
607
+
608
+ if context[1] == :iter and rhs then
609
+ lhs << splat(rhs.last)
610
+ rhs = nil
611
+ end
612
+
613
+ unless rhs.nil? then
614
+ t = rhs.first
615
+ rhs = if t == :argscat then
616
+ rhs.shift
617
+ process_argscat(rhs)
618
+ else
619
+ r = process(rhs)
620
+ r = r[1..-2] if t != :to_ary
621
+ r
622
+ end
623
+ return "#{lhs.join(", ")} = #{rhs}"
624
+ else
625
+ return lhs.join(", ")
626
+ end
627
+
628
+ end
629
+
630
+ def process_match(exp)
631
+ "#{process(exp.shift)}"
632
+ end
633
+
634
+ def process_match2(exp)
635
+ lhs = process(exp.shift)
636
+ rhs = process(exp.shift)
637
+ "#{lhs} =~ #{rhs}"
638
+ end
639
+
640
+ def process_match3(exp)
641
+ rhs = process(exp.shift)
642
+ lhs = process(exp.shift)
643
+ "#{lhs} =~ #{rhs}"
644
+ end
645
+
646
+ def process_module(exp)
647
+ "module #{util_module_or_class(exp)}"
648
+ end
649
+
650
+ def process_next(exp)
651
+ val = exp.empty? ? nil : process(exp.shift)
652
+ if val then
653
+ "next #{val}"
654
+ else
655
+ "next"
656
+ end
657
+ end
658
+
659
+ def process_nil(exp)
660
+ "nil"
661
+ end
662
+
663
+ def process_not(exp)
664
+ "(not #{process exp.shift})"
665
+ end
666
+
667
+ def process_nth_ref(exp)
668
+ "$#{exp.shift}"
669
+ end
670
+
671
+ def process_op_asgn1(exp)
672
+ # [[:lvar, :b], [:array, [:lit, 1]], :"||", [:lit, 10]]
673
+ lhs = process(exp.shift)
674
+ index = process(exp.shift)
675
+ msg = exp.shift
676
+ rhs = process(exp.shift)
677
+
678
+ "#{lhs}#{index} #{msg}= #{rhs}"
679
+ end
680
+
681
+ def process_op_asgn2(exp)
682
+ # [[:lvar, :c], :var=, :"||", [:lit, 20]]
683
+ lhs = process(exp.shift)
684
+ index = exp.shift.to_s[0..-2]
685
+ msg = exp.shift
686
+
687
+ rhs = process(exp.shift)
688
+
689
+ "#{lhs}.#{index} #{msg}= #{rhs}"
690
+ end
691
+
692
+ def process_op_asgn_or(exp)
693
+ # a ||= 1
694
+ # [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
695
+ exp.shift
696
+ process(exp.shift).sub(/=/, '||=')
697
+ end
698
+
699
+ def process_op_asgn_and(exp)
700
+ # a &&= 1
701
+ # [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
702
+ exp.shift
703
+ process(exp.shift).sub(/=/, '&&=')
704
+ end
705
+
706
+ def process_or(exp)
707
+ "(#{process exp.shift} or #{process exp.shift})"
708
+ end
709
+
710
+ def process_postexe(exp)
711
+ "END"
712
+ end
713
+
714
+ def process_redo(exp)
715
+ "redo"
716
+ end
717
+
718
+ def process_resbody(exp) # TODO: rewrite this fucker
719
+ code = []
720
+
721
+ sexp = exp
722
+ until exp.empty? and (sexp.nil? or sexp.empty?)
723
+ list = sexp.shift
724
+ body = sexp.shift
725
+
726
+ var = if list and
727
+ list.size > 1 and
728
+ [:lasgn, :dasgn, :dasgn_curr].include? list.last.first then
729
+ list.pop[1]
730
+ else
731
+ nil
732
+ end
733
+
734
+ # FIX: omg this is horrid. I should be punished
735
+ var = body.delete_at(1)[1] if
736
+ [:dasgn_curr, :dasgn].include? body[1][0] unless
737
+ var or body.nil? rescue nil
738
+
739
+ if list and list.size > 1 then
740
+ list[0] = :arglist
741
+ code << "rescue #{process(list)}"
742
+ else
743
+ code << "rescue"
744
+ end
745
+
746
+ code.last << " => #{var}" if var
747
+
748
+ if body then
749
+ code << indent(process(body)).chomp
750
+ else
751
+ code << indent("# do nothing")
752
+ end
753
+
754
+ unless exp.empty? then
755
+ sexp = exp.shift
756
+ assert_type sexp, :resbody
757
+ sexp.shift
758
+ end
759
+ end
760
+
761
+ code.join("\n")
762
+ end
763
+
764
+ def process_rescue(exp)
765
+ # TODO: rewrite this
766
+ #
767
+ # a = b rescue c => [lasgn a [rescue b c]]
768
+ # begin; a = b; rescue c => [begin [rescue [lasgn a b] c]]
769
+
770
+ current = self.context[1]
771
+ case current
772
+ when :begin, :ensure, :block then
773
+ body = (exp.first.first == :resbody) ? nil : process(exp.shift)
774
+ resbody = exp.empty? ? '' : process(exp.shift)
775
+ els = exp.empty? ? nil : process(exp.shift)
776
+
777
+ code = []
778
+ code << indent(body) if body
779
+ code << resbody
780
+ if els then
781
+ code << "else"
782
+ code << indent(els)
783
+ else
784
+ unless [:block].include? current then
785
+ code << "end\n" unless current == :ensure
786
+ else
787
+ r = [body, resbody.gsub(/rescue\n\s+/, 'rescue ')].compact.join(' ')
788
+ code = [r] if (@indent+r).size < LINE_LENGTH and r !~ /\n/
789
+ end
790
+ end
791
+
792
+ code.join("\n").chomp
793
+ else # a rescue b and others
794
+ body = process exp.shift
795
+ assert_type exp.first, :resbody
796
+ resbody = exp.shift
797
+ resbody.shift # resbody
798
+ resbody.shift # nil (no types for expression form)
799
+ resbody = resbody.shift # actual code
800
+
801
+ resbody = process resbody
802
+ code = "#{body} rescue #{resbody}"
803
+ case current
804
+ when :hash then # HACK move to process_hash
805
+ "(#{code})"
806
+ else
807
+ code
808
+ end
809
+ end
810
+ end
811
+
812
+ def process_retry(exp)
813
+ "retry"
814
+ end
815
+
816
+ def process_return(exp)
817
+ # HACK return "return" + (exp.empty? ? "" : " #{process exp.shift}")
818
+
819
+ if exp.empty? then
820
+ return "return"
821
+ else
822
+ return "return #{process exp.shift}"
823
+ end
824
+ end
825
+
826
+ def process_sclass(exp)
827
+ "class << #{process(exp.shift)}\n#{indent(process(exp.shift))}\nend"
828
+ end
829
+
830
+ def process_scope(exp)
831
+ exp.empty? ? "" : process(exp.shift)
832
+ end
833
+
834
+ def process_self(exp)
835
+ "self"
836
+ end
837
+
838
+ def process_splat(exp)
839
+ if exp.empty? then
840
+ "*"
841
+ else
842
+ "*#{process(exp.shift)}"
843
+ end
844
+ end
845
+
846
+ def process_str(exp)
847
+ return exp.shift.dump
848
+ end
849
+
850
+ def process_super(exp)
851
+ args = exp.shift
852
+ args[0] = :arglist if args[0] == :array
853
+ "super(#{process(args)})"
854
+ end
855
+
856
+ def process_svalue(exp)
857
+ process(exp.shift)
858
+ end
859
+
860
+ def process_to_ary(exp)
861
+ process(exp.shift)
862
+ end
863
+
864
+ def process_true(exp)
865
+ "true"
866
+ end
867
+
868
+ def process_undef(exp)
869
+ "undef #{process(exp.shift)}"
870
+ end
871
+
872
+ def process_until(exp)
873
+ cond_loop(exp, 'until')
874
+ end
875
+
876
+ def process_valias(exp)
877
+ "alias #{exp.shift} #{exp.shift}"
878
+ end
879
+
880
+ def process_when(exp)
881
+ src = []
882
+
883
+ if self.context[1] == :array then # ugh. matz! why not an argscat?!?
884
+ val = process(exp.shift)
885
+ exp.shift # empty body
886
+ return "*#{val}"
887
+ end
888
+
889
+ until exp.empty?
890
+ cond = process(exp.shift).to_s[1..-2]
891
+ code = indent(process(exp.shift))
892
+ code = indent "# do nothing" if code =~ /\A\s*\Z/
893
+ src << "when #{cond} then\n#{code.chomp}"
894
+ end
895
+
896
+ src.join("\n")
897
+ end
898
+
899
+ def process_while(exp)
900
+ cond_loop(exp, 'while')
901
+ end
902
+
903
+ def process_xstr(exp)
904
+ "`#{process_str(exp)[1..-2]}`"
905
+ end
906
+
907
+ def process_yield(exp)
908
+ args = exp.empty? ? nil : exp.shift
909
+ if args then
910
+ args[0] = :arglist if args.first == :array
911
+ args = process(args)
912
+ end
913
+
914
+ # "yield" + (args ? "(#{args})" : "")
915
+ if args then
916
+ "yield(#{args})"
917
+ else
918
+ "yield"
919
+ end
920
+ end
921
+
922
+ def process_zarray(exp)
923
+ "[]"
924
+ end
925
+
926
+ def process_zsuper(exp)
927
+ "super"
928
+ end
929
+
930
+ def cond_loop(exp, name)
931
+ cond = process(exp.shift)
932
+ body = process(exp.shift)
933
+ head_controlled = exp.shift
934
+
935
+ body = indent(body).chomp if body
936
+
937
+ code = []
938
+ if head_controlled then
939
+ code << "#{name} #{cond} do"
940
+ code << body if body
941
+ code << "end"
942
+ else
943
+ code << "begin"
944
+ code << body if body
945
+ code << "end #{name} #{cond}"
946
+ end
947
+ code.join("\n")
948
+ end
949
+
950
+ ############################################################
951
+ # Rewriters:
952
+
953
+ def rewrite_rescue exp
954
+ exp = s(:begin, exp) if
955
+ context[1] == :block unless
956
+ context[2] == :scope and [:defn, :defs].include? context[3]
957
+ exp
958
+ end
959
+
960
+ ############################################################
961
+ # Utility Methods:
962
+
963
+ def util_dthing(exp, regx = false)
964
+ s = []
965
+ suck = true
966
+ if suck then
967
+ x = exp.shift.gsub(/"/, '\"').gsub(/\n/, '\n')
968
+ else
969
+ x = exp.shift.dump[1..-2]
970
+ end
971
+ x.gsub!(/\//, '\/') if regx
972
+
973
+ s << x
974
+ until exp.empty?
975
+ pt = exp.shift
976
+ case pt
977
+ when Sexp then
978
+ case pt.first
979
+ when :str then
980
+ if suck then
981
+ x = pt.last.gsub(/"/, '\"').gsub(/\n/, '\n')
982
+ else
983
+ x = pt.last.dump[1..-2]
984
+ end
985
+ x.gsub!(/\//, '\/') if regx
986
+ s << x
987
+ else
988
+ s << '#{' << process(pt) << '}' # do not use interpolation here
989
+ end
990
+ else
991
+ # do nothing - yet
992
+ end
993
+ end
994
+
995
+ s.join
996
+ end
997
+
998
+ def util_module_or_class(exp, is_class=false)
999
+ s = "#{exp.shift}"
1000
+
1001
+ if is_class then
1002
+ superk = process(exp.shift)
1003
+ s << " < #{superk}" if superk
1004
+ end
1005
+
1006
+ s << "\n"
1007
+
1008
+ body = []
1009
+ begin
1010
+ code = process(exp.shift).chomp
1011
+ body << code unless code.nil? or code.empty?
1012
+ end until exp.empty?
1013
+ unless body.empty? then
1014
+ body = indent(body.join("\n\n")) + "\n"
1015
+ else
1016
+ body = ""
1017
+ end
1018
+ s + body + "end"
1019
+ end
1020
+
1021
+ def indent(s)
1022
+ s.to_s.map{|line| @indent + line}.join
1023
+ end
1024
+ end
1025
+
1026
+ RubyToRuby = Ruby2Ruby # For backwards compatibilty... TODO: remove 2008-03-28
1027
+
1028
+ class Method
1029
+ def with_class_and_method_name
1030
+ if self.inspect =~ /<Method: (.*)\#(.*)>/ then
1031
+ klass = eval $1
1032
+ method = $2.intern
1033
+ raise "Couldn't determine class from #{self.inspect}" if klass.nil?
1034
+ return yield(klass, method)
1035
+ else
1036
+ raise "Can't parse signature: #{self.inspect}"
1037
+ end
1038
+ end
1039
+
1040
+ def to_sexp
1041
+ with_class_and_method_name do |klass, method|
1042
+ ParseTree.new(false).parse_tree_for_method(klass, method)
1043
+ end
1044
+ end
1045
+
1046
+ def to_ruby
1047
+ Ruby2Ruby.new.process(self.to_sexp)
1048
+ end
1049
+ end
1050
+
1051
+ class ProcStoreTmp
1052
+ @@n = 0
1053
+ def self.name
1054
+ @@n += 1
1055
+ return :"myproc#{@@n}"
1056
+ end
1057
+ end
1058
+
1059
+ class UnboundMethod
1060
+ def to_ruby
1061
+ name = ProcStoreTmp.name
1062
+ ProcStoreTmp.send(:define_method, name, self)
1063
+ m = ProcStoreTmp.new.method(name)
1064
+ result = m.to_ruby.sub(/def #{name}(?:\(([^\)]*)\))?/,
1065
+ 'proc { |\1|').sub(/end\Z/, '}')
1066
+ return result
1067
+ end
1068
+ end
1069
+
1070
+ class Proc
1071
+ def to_method
1072
+ name = ProcStoreTmp.name
1073
+ ProcStoreTmp.send(:define_method, name, self)
1074
+ ProcStoreTmp.new.method(name)
1075
+ end
1076
+
1077
+ def to_sexp
1078
+ body = self.to_method.to_sexp[2][1..-1]
1079
+ [:proc, *body]
1080
+ end
1081
+
1082
+ def to_ruby
1083
+ ruby = self.to_method.to_ruby
1084
+ ruby.sub!(/\A(def \S+)\(([^\)]*)\)/, '\1 |\2|') # move args
1085
+ ruby.sub!(/\Adef[^\n\|]+/, 'proc { ') # strip def name
1086
+ ruby.sub!(/end\Z/, '}') # strip end
1087
+ ruby.gsub!(/\s+$/, '') # trailing WS bugs me
1088
+ ruby
1089
+ end
1090
+ end