thor 0.9.2

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.
@@ -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