lib/ruby2ruby.rb in ruby2ruby-2.4.2 vs lib/ruby2ruby.rb in ruby2ruby-2.4.3

- old
+ new

@@ -1,9 +1,9 @@ #!/usr/bin/env ruby -w -require 'rubygems' -require 'sexp_processor' +require "rubygems" +require "sexp_processor" # :stopdoc: # REFACTOR: stolen from ruby_parser class Regexp unless defined? ENC_NONE then @@ -13,33 +13,33 @@ ENC_UTF8 = /x/u.options end unless defined? CODES then CODES = { - EXTENDED => 'x', - IGNORECASE => 'i', - MULTILINE => 'm', - ENC_NONE => 'n', - ENC_EUC => 'e', - ENC_SJIS => 's', - ENC_UTF8 => 'u', + EXTENDED => "x", + IGNORECASE => "i", + MULTILINE => "m", + ENC_NONE => "n", + ENC_EUC => "e", + ENC_SJIS => "s", + ENC_UTF8 => "u", } end end # :startdoc: ## # Generate ruby code from a sexp. class Ruby2Ruby < SexpProcessor - VERSION = "2.4.2" # :nodoc: + VERSION = "2.4.3" # :nodoc: # cutoff for one-liners LINE_LENGTH = 78 # binary operation messages - BINARY = [:<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<, :>>, :**, :'!=', :^, :|, :&] + BINARY = [:<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<, :>>, :**, :"!=", :^, :|, :&] ## # Nodes that represent assignment and probably need () around them. # # TODO: this should be replaced with full precedence support :/ @@ -74,11 +74,11 @@ :false, :lit, :lvar, :nil, :str, - :true + :true, ] def initialize # :nodoc: super @indent = " " @@ -116,10 +116,12 @@ end def process_args exp # :nodoc: _, *args = exp + shadow = [] + args = args.map { |arg| case arg when Symbol then arg when Sexp then @@ -129,19 +131,28 @@ when :masgn then process(arg) when :kwarg then _, k, v = arg "#{k}: #{process v}" + when :shadow then + shadow << arg[1] + next else raise "unknown arg type #{arg.first.inspect}" end + when nil then + "" else raise "unknown arg type #{arg.inspect}" end - } + }.compact - "(#{args.join ', '})" + args = args.join(", ").strip + shadow = shadow.join(", ").strip + shadow = "; #{shadow}" unless shadow.empty? + + "(%s%s)" % [args, shadow] end def process_array exp # :nodoc: "[#{process_arglist exp}]" end @@ -178,11 +189,11 @@ def process_begin exp # :nodoc: _, *rest = exp code = rest.map { |sexp| src = process sexp - src = indent src unless src =~ /(^|\n)(rescue|ensure)/ # ensure no level 0 rescues + src = indent src unless src =~ /(^|\n)(rescue|ensure)/ # ensure no level 0 rescues src } code.unshift "begin" code.push "end" @@ -236,22 +247,22 @@ # exp.push(*exp.pop[1..-1]) if exp.size == 1 && exp.first.first == :arglist @calls.push name in_context :arglist do - max = args.size-1 + max = args.size - 1 args = args.map.with_index { |arg, i| arg_type = arg.sexp_type is_empty_hash = arg == s(:hash) arg = process arg next if arg.empty? strip_hash = (arg_type == :hash and not BINARY.include? name and not is_empty_hash and - (i == max or args[i+1].sexp_type == :splat)) + (i == max or args[i + 1].sexp_type == :splat)) wrap_arg = Ruby2Ruby::ASSIGN_NODES.include? arg_type arg = arg[2..-3] if strip_hash arg = "(#{arg})" if wrap_arg @@ -260,32 +271,32 @@ end case name when *BINARY then if safe_call - "#{receiver}&.#{name}(#{args.join(', ')})" + "#{receiver}&.#{name}(#{args.join(", ")})" elsif args.length > 1 - "#{receiver}.#{name}(#{args.join(', ')})" + "#{receiver}.#{name}(#{args.join(", ")})" else - "(#{receiver} #{name} #{args.join(', ')})" + "(#{receiver} #{name} #{args.join(", ")})" end when :[] then receiver ||= "self" - "#{receiver}[#{args.join(', ')}]" + "#{receiver}[#{args.join(", ")}]" when :[]= then receiver ||= "self" rhs = args.pop - "#{receiver}[#{args.join(', ')}] = #{rhs}" + "#{receiver}[#{args.join(", ")}] = #{rhs}" when :"!" then "(not #{receiver})" when :"-@" then "-#{receiver}" when :"+@" then "+#{receiver}" else args = nil if args.empty? - args = "(#{args.join(', ')})" if args + args = "(#{args.join(", ")})" if args receiver = "#{receiver}." if receiver and not safe_call receiver = "#{receiver}&." if receiver and safe_call "#{receiver}#{name}#{args}" end @@ -302,15 +313,15 @@ result = [] expr = process expr - if expr then - result << "case #{expr}" - else - result << "case" - end + result << if expr then + "case #{expr}" + else + "case" + end result.concat rest.map { |pt| if pt and pt.sexp_type == :when "#{process pt}" else @@ -414,11 +425,11 @@ body = body.join("\n") body = body.lines.to_a[1..-2].join("\n") if simple && body =~ /^\Abegin/ && body =~ /^end\z/ body = indent(body) unless simple && body =~ /(^|\n)rescue/ - return "#{comm}def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n") + "#{comm}def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n") end def process_defs exp # :nodoc: _, lhs, name, args, *body = exp var = [:self, :cvar, :dvar, :ivar, :gvar, :lvar].include? lhs.sexp_type @@ -473,14 +484,14 @@ body = process body ens = nil if ens == s(:nil) ens = process(ens) || "# do nothing" ens = "begin\n#{ens}\nend\n" if ens =~ /(^|\n)rescue/ - body.sub!(/\n\s*end\z/, '') + body.sub!(/\n\s*end\z/, "") body = indent(body) unless body =~ /(^|\n)rescue/ - return "#{body}\nensure\n#{indent ens}" + "#{body}\nensure\n#{indent ens}" end def process_evstr exp # :nodoc: _, x = exp @@ -528,12 +539,10 @@ end def process_hash(exp) # :nodoc: _, *pairs = exp - result = [] - result = pairs.each_slice(2).map { |k, v| if k.sexp_type == :kwsplat then "%s" % process(k) else t = v.sexp_type @@ -544,11 +553,11 @@ "%s => %s" % [lhs, rhs] end } - return result.empty? ? "{}" : "{ #{result.join(', ')} }" + result.empty? ? "{}" : "{ #{result.join(", ")} }" end def process_iasgn(exp) # :nodoc: _, lhs, rhs = exp @@ -575,67 +584,89 @@ r = "#{c} ? (#{t}) : (#{f})" r = nil if r =~ /return/ # HACK - need contextual awareness or something else r = "#{t} if #{c}" end - return r if r and (@indent+r).size < LINE_LENGTH and r !~ /\n/ + return r if r and (@indent + r).size < LINE_LENGTH and r !~ /\n/ end r = "if #{c} then\n#{indent(t)}\n" r << "else\n#{indent(f)}\n" if f r << "end" r elsif f unless expand then r = "#{f} unless #{c}" - return r if (@indent+r).size < LINE_LENGTH and r !~ /\n/ + return r if (@indent + r).size < LINE_LENGTH and r !~ /\n/ end "unless #{c} then\n#{indent(f)}\nend" else # empty if statement, just do it in case of side effects from condition - "if #{c} then\n#{indent '# do nothing'}\nend" + "if #{c} then\n#{indent "# do nothing"}\nend" end end + def process_lambda exp # :nodoc: + "->" + end + def process_iter(exp) # :nodoc: _, iter, args, body = exp + is_lambda = iter.sexp_type == :lambda + iter = process iter body = process body if body - args = case args - when 0 then + args = case + when args == 0 then "" + when is_lambda then + " (#{process(args)[1..-2]})" else " |#{process(args)[1..-2]}|" end b, e = if iter == "END" then - [ "{", "}" ] + %w[ { } ] else - [ "do", "end" ] + %w[ do end ] end - iter.sub!(/\(\)$/, '') + iter.sub!(/\(\)$/, "") # REFACTOR: ugh result = [] - result << "#{iter} {" - result << args - if body then - result << " #{body.strip} " + if is_lambda then + result << iter + result << args + result << " {" else - result << ' ' + result << "#{iter} {" + result << args end + result << if body then + " #{body.strip} " + else + " " + end result << "}" result = result.join return result if result !~ /\n/ and result.size < LINE_LENGTH result = [] - result << "#{iter} #{b}" - result << args + + if is_lambda then + result << iter + result << args + result << " #{b}" + else + result << "#{iter} #{b}" + result << args + end + result << "\n" if body then result << indent(body.strip) result << "\n" end @@ -675,47 +706,32 @@ _, name = exp name.to_s end def process_masgn(exp) # :nodoc: - _, (type, *), * = exp # ugly, but STRICT_SEXP=1+ requires this + # s(:masgn, s(:array, s(:lasgn, :var), ...), s(:to_ary, <val>, ...)) + # s(:iter, <call>, s(:args, s(:masgn, :a, :b)), <body>) + parenthesize = true - if type == :array then - _, lhs, rhs = exp + result = exp.sexp_body.map { |sexp| + case sexp + when Sexp then + if sexp.sexp_type == :array then + parenthesize = context.grep(:masgn).size > 1 + res = process sexp - case exp.length - when 3 then # a, b = c, d - lhs = lhs.sexp_body.map { |e| - process e - } - - rhs = case rhs && rhs.sexp_type - when :array then # a, b = [c, d] - process(rhs)[1..-2] - else # a, b = c - process rhs - end - "%s = %s" % [lhs.join(", "), rhs] - when 2 then # a, (b, c) = ... - "(%s)" % [process(lhs)[1..-2]] - else - raise "unknown masgn length: %p" % [exp] - end - else # a { |(b, c)| ... } - lhs = exp.sexp_body.map { |e| - case e - when Symbol then - e - when Sexp then - process e + res[1..-2] else - raise "unknown masgn type: %p" % [e] + process sexp end - } - - "(%s)" % [lhs.join(", ")] - end + when Symbol then + sexp + else + raise "unknown masgn: #{sexp.inspect}" + end + } + parenthesize ? "(#{result.join ", "})" : result.join(" = ") end def process_match exp # :nodoc: _, rhs = exp @@ -809,18 +825,18 @@ def process_op_asgn_and(exp) # :nodoc: # a &&= 1 # [[:lvar, :a], [:lasgn, :a, [:lit, 1]]] _, _lhs, rhs = exp - process(rhs).sub(/\=/, '&&=') + process(rhs).sub(/\=/, "&&=") end def process_op_asgn_or(exp) # :nodoc: # a ||= 1 # [[:lvar, :a], [:lasgn, :a, [:lit, 1]]] _, _lhs, rhs = exp - process(rhs).sub(/\=/, '||=') + process(rhs).sub(/\=/, "||=") end def process_or(exp) # :nodoc: _, lhs, rhs = exp @@ -854,14 +870,13 @@ "rescue#{args}\n#{indent body.join("\n")}" end def process_rescue exp # :nodoc: _, *rest = exp - exp = nil body = process rest.shift unless rest.first.sexp_type == :resbody - els = process rest.pop unless rest.last && rest.last.sexp_type == :resbody + els = process rest.pop unless rest.last && rest.last.sexp_type == :resbody body ||= "# do nothing" # TODO: I don't like this using method_missing, but I need to ensure tests simple = rest.size == 1 && rest.first.size <= 3 && @@ -876,11 +891,11 @@ } if els then "#{indent body}\n#{resbodies.join("\n")}\nelse\n#{indent els}" elsif simple then - resbody = resbodies.first.sub(/\n\s*/, ' ') + resbody = resbodies.first.sub(/\n\s*/, " ") "#{body} #{resbody}" else "#{indent body}\n#{resbodies.join("\n")}" end end @@ -909,11 +924,11 @@ rhs = rest.pop args = rest.pop # should be nil raise "dunno what to do: #{args.inspect}" if args - name = name.to_s.sub(/=$/, '') + name = name.to_s.sub(/=$/, "") if rhs && rhs != s(:arglist) then "#{receiver}&.#{name} = #{process rhs}" else raise "dunno what to do: #{rhs.inspect}" @@ -1002,11 +1017,11 @@ "undef #{process name}" end def process_until(exp) # :nodoc: - cond_loop(exp, 'until') + cond_loop(exp, "until") end def process_valias exp # :nodoc: _, lhs, rhs = exp @@ -1046,11 +1061,11 @@ args = args.map { |arg| process arg } unless args.empty? then - "yield(#{args.join(', ')})" + "yield(#{args.join(", ")})" else "yield" end end @@ -1207,11 +1222,11 @@ ## # Wrap appropriate expressions in matching parens. def parenthesize exp - case self.context[1] + case context[1] when nil, :defn, :defs, :class, :sclass, :if, :iter, :resbody, :when, :while then exp else "(#{exp})" end @@ -1241,32 +1256,27 @@ # first item in sexp is a string literal str = dthing_escape(type, str) rest = rest.map { |pt| - case pt - when Sexp then # TODO: what the fuck? why?? - case pt.sexp_type - when :str then - dthing_escape(type, pt.last) - when :evstr then - '#{%s}' % [process(pt)] - else - raise "unknown type: #{pt.inspect}" - end + case pt.sexp_type + when :str then + dthing_escape(type, pt.last) + when :evstr then + '#{%s}' % [process(pt)] else - raise "unhandled value in d-thing: #{pt.inspect}" + raise "unknown type: #{pt.inspect}" end } [str, rest].join end ## # Utility method to generate ether a module or class. - def util_module_or_class(exp, is_class=false) + def util_module_or_class exp, is_class = false result = [] _, name, *body = exp superk = body.shift if is_class @@ -1283,14 +1293,14 @@ body = body.map { |sexp| process(sexp).chomp } - unless body.empty? then - body = indent(body.join("\n\n")) + "\n" - else - body = "" - end + body = unless body.empty? then + indent(body.join("\n\n")) + "\n" + else + "" + end result << body result << "end" result.join