Skip to content

Commit

Permalink
Auto-magically pass blocks in zsuper calls (super with no args)
Browse files Browse the repository at this point in the history
  • Loading branch information
adambeynon committed Aug 2, 2013
1 parent ec91c4c commit 775d2c6
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 6 deletions.
7 changes: 5 additions & 2 deletions corelib/opal/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@
};

// Super dispatcher
Opal.dispatch_super = function(obj, jsid, args, defs) {
Opal.dispatch_super = function(obj, jsid, args, iter, defs) {
var dispatcher;

if (defs) {
Expand All @@ -310,7 +310,10 @@
dispatcher = obj._isClass ? obj._klass : obj._klass._super._proto;
}

return dispatcher['$' + jsid].apply(obj, args);
dispatcher = dispatcher['$' + jsid];
dispatcher._p = iter;

return dispatcher.apply(obj, args);
};

// return helper
Expand Down
10 changes: 6 additions & 4 deletions lib/opal/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,7 @@ def js_def(recvr, mid, args, stmts, line, end_line, sexp)
scope_name = @scope.identity

if @scope.uses_block?
@scope.add_temp "$iter = #{scope_name}._p"
@scope.add_temp yielder
blk = fragment(("\n%s%s = %s._p || nil, %s._p = null;\n%s" %
[@indent, yielder, scope_name, scope_name, @indent]), sexp)
Expand Down Expand Up @@ -2100,23 +2101,24 @@ def process_zsuper(exp, level)

def js_super args, sexp
if @scope.def_in_class?
@scope.uses_block!
mid = @scope.mid.to_s
sid = "super_#{unique_temp}"

@scope.uses_super = sid


[fragment("#{sid}.apply(#{current_self}, ", sexp), args, fragment(")", sexp)]
[fragment("(#{sid}._p = $iter, #{sid}.apply(#{current_self}, ", sexp), args, fragment("))", sexp)]

elsif @scope.type == :def
@scope.uses_block!
@scope.identify!
cls_name = @scope.parent.name || "#{current_self}._klass._proto"
jsid = mid_to_jsid @scope.mid.to_s

if @scope.defs
[f("$opal.dispatch_super(this, #{@scope.mid.to_s.inspect},", sexp), args, f(", #{cls_name})", sexp)]
[f("$opal.dispatch_super(this, #{@scope.mid.to_s.inspect},", sexp), args, f(", $iter, #{cls_name})", sexp)]
else
[fragment("$opal.dispatch_super(#{current_self}, #{@scope.mid.to_s.inspect}, ", sexp), args, fragment(")", sexp)]
[fragment("$opal.dispatch_super(#{current_self}, #{@scope.mid.to_s.inspect}, ", sexp), args, fragment(", $iter)", sexp)]
end

elsif @scope.type == :iter
Expand Down
35 changes: 35 additions & 0 deletions spec/opal/language/super_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ class SingletonMethodSuperSpec
def meth
"bar"
end

def passing_block(*args, &block)
[args, block_given?]
end

def self.pass_block(&block)
block_given?
end

class A < SingletonMethodSuperSpec
def passing_block(*a)
super
end

def self.pass_block
super
end
end
end

# FIXME: we cant make a better test case than this??? For some reason, a single test cannot be deduced
Expand All @@ -17,4 +35,21 @@ def meth
def obj.meth; "foo " + super; end
obj.meth.should == "foo bar"
end

describe "with no arguments or parens" do
before do
@obj = SingletonMethodSuperSpec::A.new
@kls = SingletonMethodSuperSpec::A
end

it "passes the block to super" do
@obj.passing_block(1, 2, 3).should == [[1, 2, 3], false]
@obj.passing_block(1, 2, 3) { }.should == [[1, 2, 3], true]
end

it "passes the block to super on singleton methods" do
@kls.pass_block.should be_false
@kls.pass_block { }.should be_true
end
end
end

0 comments on commit 775d2c6

Please sign in to comment.