Merge remote-tracking branch 'upstream/master'

Conflicts:
	lib/coffee-script/helpers.js
	test/helpers.coffee
This commit is contained in:
Jason Walton 2013-03-08 10:17:47 -05:00
commit c4f50b52d7
6 changed files with 95 additions and 39 deletions

View File

@ -165,7 +165,7 @@
}
parts = file.split('.');
parts.pop();
if (parts[parts.length - 1] === 'coffee') {
if (parts[parts.length - 1] === 'coffee' && parts.length > 1) {
parts.pop();
}
return parts.join('.');

View File

@ -1394,18 +1394,12 @@
};
Class.prototype.addBoundFunctions = function(o) {
var body, bound, func, lhs, name, rhs, _i, _len, _ref4, _ref5;
if (this.boundFuncs.length) {
o.scope.assign('_this', 'this');
_ref4 = this.boundFuncs;
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
_ref5 = _ref4[_i], name = _ref5[0], func = _ref5[1];
lhs = new Value(new Literal("this"), [new Access(name)]);
body = new Block([new Return(new Literal("" + this.ctor.name + ".prototype." + name.value + ".apply(_this, arguments)"))]);
rhs = new Code(func.params, body, 'boundfunc');
bound = new Assign(lhs, rhs);
this.ctor.body.push(bound);
}
var bvar, lhs, _i, _len, _ref4;
_ref4 = this.boundFuncs;
for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
bvar = _ref4[_i];
lhs = (new Value(new Literal("this"), [new Access(bvar)])).compile(o);
this.ctor.body.unshift(new Literal("" + lhs + " = " + (utility('bind')) + "(" + lhs + ", this)"));
}
};
@ -1442,7 +1436,7 @@
} else {
assign.variable = new Value(new Literal(name), [new Access(new Literal('prototype')), new Access(base)]);
if (func instanceof Code && func.bound) {
this.boundFuncs.push([base, func]);
this.boundFuncs.push(base);
func.bound = false;
}
}
@ -3048,6 +3042,9 @@
"extends": function() {
return "function(child, parent) { for (var key in parent) { if (" + (utility('hasProp')) + ".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }";
},
bind: function() {
return 'function(fn, me){ return function(){ return fn.apply(me, arguments); }; }';
},
indexOf: function() {
return "[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }";
},

View File

@ -120,7 +120,7 @@ exports.baseFileName = (file, stripExt = no) ->
return file unless stripExt
parts = file.split('.')
parts.pop()
parts.pop() if parts[parts.length - 1] is 'coffee'
parts.pop() if parts[parts.length - 1] is 'coffee' and parts.length > 1
parts.join('.')
# Determine if a filename represents a CoffeeScript file.

View File

@ -983,14 +983,9 @@ exports.Class = class Class extends Base
# Ensure that all functions bound to the instance are proxied in the
# constructor.
addBoundFunctions: (o) ->
if @boundFuncs.length
o.scope.assign '_this', 'this'
for [name, func] in @boundFuncs
lhs = new Value (new Literal "this"), [new Access name]
body = new Block [new Return new Literal "#{@ctor.name}.prototype.#{name.value}.apply(_this, arguments)"]
rhs = new Code func.params, body, 'boundfunc'
bound = new Assign lhs, rhs
@ctor.body.push bound
for bvar in @boundFuncs
lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
return
# Merge the properties from a top-level object as prototypal properties
@ -1020,7 +1015,7 @@ exports.Class = class Class extends Base
else
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
if func instanceof Code and func.bound
@boundFuncs.push [base, func]
@boundFuncs.push base
func.bound = no
assign
compact exprs
@ -2122,6 +2117,11 @@ UTILITIES =
function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }
"""
# Create a function bound to the current value of "this".
bind: -> '''
function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
'''
# Discover if an item is in an array.
indexOf: -> """
[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }

View File

@ -730,23 +730,52 @@ test "#2359: extending native objects that use other typed constructors requires
eq 'yes!', workingArray.method()
test "#2489: removing __bind", ->
test "#2782: non-alphanumeric-named bound functions", ->
class A
'b:c': =>
'd'
class Thing
foo: (a, b, c) ->
bar: (a, b, c) =>
thing = new Thing
eq thing.foo.length, 3
eq thing.bar.length, 3
eq (new A)['b:c'](), 'd'
test "#2773: overriding bound functions", ->
test "#2781: overriding bound functions", ->
class A
a: ->
@b()
b: =>
1
class B extends A
b: =>
2
b = (new A).b
eq b(), 1
b = (new B).b
eq b(), 2
test "#2791: bound function with destructured argument", ->
class Foo
method: => 'Foo'
method: ({a}) => 'Bar'
class Bar extends Foo
method: => 'Bar'
eq (new Foo).method({a: 'Bar'}), 'Bar'
eq (new Bar).method(), 'Bar'
test "#2796: ditto, ditto, ditto", ->
answer = null
outsideMethod = (func) ->
func.call message: 'wrong!'
class Base
constructor: ->
@message = 'right!'
outsideMethod @echo
echo: =>
answer = @message
new Base
eq answer, 'right!'

View File

@ -2,7 +2,7 @@
# -------
# pull the helpers from `CoffeeScript.helpers` into local variables
{starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
{starts, ends, compact, count, merge, extend, flatten, del, last, baseFileName} = CoffeeScript.helpers
# `starts`
@ -94,3 +94,33 @@ test "the `last` helper returns the last item of an array-like object", ->
test "the `last` helper allows one to specify an optional offset", ->
ary = [0, 1, 2, 3, 4]
eq 2, last(ary, 2)
# `baseFileName`
test "the `baseFileName` helper returns the file name to write to", ->
ext = '.js'
sourceToCompiled =
'.coffee': ext
'a.coffee': 'a' + ext
'b.coffee': 'b' + ext
'coffee.coffee': 'coffee' + ext
'.litcoffee': ext
'a.litcoffee': 'a' + ext
'b.litcoffee': 'b' + ext
'coffee.litcoffee': 'coffee' + ext
'.lit': ext
'a.lit': 'a' + ext
'b.lit': 'b' + ext
'coffee.lit': 'coffee' + ext
'.coffee.md': ext
'a.coffee.md': 'a' + ext
'b.coffee.md': 'b' + ext
'coffee.coffee.md': 'coffee' + ext
for sourceFileName, expectedFileName of sourceToCompiled
name = baseFileName sourceFileName, yes
filename = name + ext
eq filename, expectedFileName