lib/ruby2js/converter/class2.rb in ruby2js-3.5.3 vs lib/ruby2js/converter/class2.rb in ruby2js-3.6.0

- old
+ new

@@ -7,30 +7,36 @@ # (...) # NOTE: this is the es2015 version of class handle :class2 do |name, inheritance, *body| + body.compact! + while body.length == 1 and body.first.type == :begin + body = body.first.children + end + + proxied = body.find do |node| + node.type == :def and node.children.first == :method_missing + end + if name.type == :const and name.children.first == nil put 'class ' parse name + put '$' if proxied else parse name + put '$' if proxied put ' = class' end if inheritance put ' extends ' parse inheritance end put " {" - body.compact! - while body.length == 1 and body.first.type == :begin - body = body.first.children - end - begin class_name, @class_name = @class_name, name class_parent, @class_parent = @class_parent, inheritance @rbstack.push({}) constructor = [] @@ -62,25 +68,25 @@ ast.children.each do |child| walk[child] if child.is_a? Parser::AST::Node end - if ast.type == :send and ast.children.first == nil - if ast.children[1] == :attr_accessor - ast.children[2..-1].each_with_index do |child_sym, index2| - ivars << :"@#{child_sym.children.first}" - end - elsif ast.children[1] == :attr_reader - ast.children[2..-1].each_with_index do |child_sym, index2| - ivars << :"@#{child_sym.children.first}" - end - elsif ast.children[1] == :attr_writer - ast.children[2..-1].each_with_index do |child_sym, index2| - ivars << :"@#{child_sym.children.first}" - end - end - end + if ast.type == :send and ast.children.first == nil + if ast.children[1] == :attr_accessor + ast.children[2..-1].each_with_index do |child_sym, index2| + ivars << :"@#{child_sym.children.first}" + end + elsif ast.children[1] == :attr_reader + ast.children[2..-1].each_with_index do |child_sym, index2| + ivars << :"@#{child_sym.children.first}" + end + elsif ast.children[1] == :attr_writer + ast.children[2..-1].each_with_index do |child_sym, index2| + ivars << :"@#{child_sym.children.first}" + end + end + end end walk[@ast] # process leading initializers in constructor @@ -295,9 +301,46 @@ parse m.updated(:send, [@class_name, *m.children[1..-1]]) end else parse m, :statement end + end + + if proxied + put @sep + + rename = name.updated(nil, [name.children.first, name.children.last.to_s + '$']) + + if proxied.children[1].children.length == 1 + # special case: if method_missing only has on argument, call it + # directly (i.e., don't pass arguments). This enables + # method_missing to return instance attributes (getters) as well + # as bound functions (methods). + forward = s(:send, s(:lvar, :obj), :method_missing, s(:lvar, :prop)) + else + # normal case: return a function which, when called, will call + # method_missing with method name and arguments. + forward = s(:block, s(:send, nil, :proc), s(:args, s(:restarg, :args)), + s(:send, s(:lvar, :obj), :method_missing, s(:lvar, :prop), + s(:splat, s(:lvar, :args)))) + end + + proxy = s(:return, s(:send, s(:const, nil, :Proxy), :new, + s(:send, rename, :new, s(:splat, s(:lvar, :args))), + s(:hash, s(:pair, s(:sym, :get), s(:block, s(:send, nil, :proc), + s(:args, s(:arg, :obj), s(:arg, :prop)), + s(:if, s(:in?, s(:lvar, :prop), s(:lvar, :obj)), + s(:return, s(:send, s(:lvar, :obj), :[], s(:lvar, :prop))), + s(:return, forward)))))) + ) + + if name.children.first == nil + proxy = s(:def, name.children.last, s(:args, s(:restarg, :args)), proxy) + else + proxy = s(:defs, *name.children, s(:args, s(:restarg, :args)), proxy) + end + + parse proxy end ensure @class_name = class_name @class_parent = class_parent