mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
merged stable
This commit is contained in:
commit
ac85fa2fc3
23 changed files with 1091 additions and 972 deletions
|
@ -1,5 +1,5 @@
|
|||
(function() {
|
||||
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, NEGATE, NO, Obj, Op, Param, Parens, Push, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, TRAILING_WHITESPACE, Throw, Try, UTILITIES, Value, While, YES, compact, del, ends, extend, flatten, last, merge, multident, starts, unfoldSoak, utility, _ref;
|
||||
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, NEGATE, NO, Obj, Op, Param, Parens, Push, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, compact, del, ends, extend, flatten, last, merge, multident, starts, unfoldSoak, utility, _ref;
|
||||
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
|
||||
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
|
||||
function ctor() { this.constructor = child; }
|
||||
|
@ -273,7 +273,6 @@
|
|||
o.scope = new Scope(null, this, null);
|
||||
o.level = LEVEL_TOP;
|
||||
code = this.compileWithDeclarations(o);
|
||||
code = code.replace(TRAILING_WHITESPACE, '');
|
||||
if (o.bare) {
|
||||
return code;
|
||||
} else {
|
||||
|
@ -2160,7 +2159,7 @@
|
|||
}
|
||||
func = new Code([], Block.wrap([expressions]));
|
||||
args = [];
|
||||
if ((mentionsArgs = expressions.contains(this.literalArgs)) || (expressions.contains(this.literalThis))) {
|
||||
if ((mentionsArgs = expressions.contains(this.literalArgs)) || expressions.contains(this.literalThis)) {
|
||||
meth = new Literal(mentionsArgs ? 'apply' : 'call');
|
||||
args = [new Literal('this')];
|
||||
if (mentionsArgs) {
|
||||
|
@ -2206,7 +2205,6 @@
|
|||
LEVEL_OP = 5;
|
||||
LEVEL_ACCESS = 6;
|
||||
TAB = ' ';
|
||||
TRAILING_WHITESPACE = /[ \t]+$/gm;
|
||||
IDENTIFIER = /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/;
|
||||
SIMPLENUM = /^[+-]?\d+$/;
|
||||
IS_STRING = /^['"]/;
|
||||
|
|
|
@ -233,7 +233,6 @@ exports.Block = class Block extends Base
|
|||
o.scope = new Scope null, this, null
|
||||
o.level = LEVEL_TOP
|
||||
code = @compileWithDeclarations o
|
||||
code = code.replace TRAILING_WHITESPACE, ''
|
||||
if o.bare then code else "(function() {\n#{code}\n}).call(this);\n"
|
||||
|
||||
# Compile the expressions body for the contents of a function, with
|
||||
|
@ -1698,8 +1697,7 @@ Closure =
|
|||
return expressions if expressions.jumps()
|
||||
func = new Code [], Block.wrap [expressions]
|
||||
args = []
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or
|
||||
( expressions.contains @literalThis)
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or expressions.contains @literalThis
|
||||
meth = new Literal if mentionsArgs then 'apply' else 'call'
|
||||
args = [new Literal 'this']
|
||||
args.push new Literal 'arguments' if mentionsArgs
|
||||
|
@ -1770,10 +1768,6 @@ LEVEL_ACCESS = 6 # ...[0]
|
|||
# Tabs are two spaces for pretty printing.
|
||||
TAB = ' '
|
||||
|
||||
# Trim out all trailing whitespace, so that the generated code plays nice
|
||||
# with Git.
|
||||
TRAILING_WHITESPACE = /[ \t]+$/gm
|
||||
|
||||
IDENTIFIER = /^[$A-Za-z_\x7f-\uffff][$\w\x7f-\uffff]*$/
|
||||
SIMPLENUM = /^[+-]?\d+$/
|
||||
|
||||
|
|
|
@ -4,30 +4,30 @@
|
|||
# * Array Literals
|
||||
# * Splats in Array Literals
|
||||
|
||||
# TODO: refactor array literal tests
|
||||
# TODO: add indexing and method invocation tests: [1][0] is 1, [].toString()
|
||||
|
||||
trailingComma = [1, 2, 3,]
|
||||
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
|
||||
test "trailing commas", ->
|
||||
trailingComma = [1, 2, 3,]
|
||||
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
|
||||
|
||||
trailingComma = [
|
||||
1, 2, 3,
|
||||
4, 5, 6
|
||||
7, 8, 9,
|
||||
]
|
||||
(sum = (sum or 0) + n) for n in trailingComma
|
||||
trailingComma = [
|
||||
1, 2, 3,
|
||||
4, 5, 6
|
||||
7, 8, 9,
|
||||
]
|
||||
(sum = (sum or 0) + n) for n in trailingComma
|
||||
|
||||
a = [((x) -> x), ((x) -> x * x)]
|
||||
ok a.length is 2
|
||||
a = [((x) -> x), ((x) -> x * x)]
|
||||
ok a.length is 2
|
||||
|
||||
# Funky indentation within non-comma-seperated arrays.
|
||||
result = [['a']
|
||||
{b: 'c'}]
|
||||
ok result[0][0] is 'a'
|
||||
ok result[1]['b'] is 'c'
|
||||
test "incorrect indentation without commas", ->
|
||||
result = [['a']
|
||||
{b: 'c'}]
|
||||
ok result[0][0] is 'a'
|
||||
ok result[1]['b'] is 'c'
|
||||
|
||||
|
||||
#### Splats in Array Literals
|
||||
# Splats in Array Literals
|
||||
|
||||
test "array splat expansions with assignments", ->
|
||||
nums = [1, 2, 3]
|
||||
|
@ -36,6 +36,19 @@ test "array splat expansions with assignments", ->
|
|||
eq 4, b
|
||||
arrayEq [0,1,2,3,4], list
|
||||
|
||||
|
||||
test "array splats with nested arrays", ->
|
||||
nonce = {}
|
||||
a = [nonce]
|
||||
list = [1, 2, a...]
|
||||
eq list[0], 1
|
||||
eq list[2], nonce
|
||||
|
||||
a = [[nonce]]
|
||||
list = [1, 2, a...]
|
||||
arrayEq list, [1, 2, [nonce]]
|
||||
|
||||
|
||||
test "mixed shorthand objects in array lists", ->
|
||||
|
||||
arr = [
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# Assignment
|
||||
# ----------
|
||||
|
||||
# TODO: organize assignment file
|
||||
|
||||
# * Assignment
|
||||
# * Compound Assignment
|
||||
# * Destructuring Assignment
|
||||
|
@ -27,7 +25,7 @@ test "compound assignments should not declare", ->
|
|||
eq Math, (-> Math or= 0)()
|
||||
|
||||
|
||||
#### Compound Assignment
|
||||
# Compound Assignment
|
||||
|
||||
test "boolean operators", ->
|
||||
nonce = {}
|
||||
|
@ -136,7 +134,7 @@ test "more compound assignment", ->
|
|||
eq c, val
|
||||
|
||||
|
||||
#### Destructuring Assignment
|
||||
# Destructuring Assignment
|
||||
|
||||
test "empty destructuring assignment", ->
|
||||
{} = [] = undefined
|
||||
|
@ -251,7 +249,7 @@ test "#1024", ->
|
|||
eq 2 * [] = 3 + 5, 16
|
||||
|
||||
|
||||
#### Existential Assignment
|
||||
# Existential Assignment
|
||||
|
||||
test "existential assignment", ->
|
||||
nonce = {}
|
||||
|
|
|
@ -3,19 +3,19 @@
|
|||
|
||||
# TODO: add method invocation tests: true.toString() is "true"
|
||||
|
||||
#764: Boolean should be indexable
|
||||
toString = Boolean::toString
|
||||
test "#764 Booleans should be indexable", ->
|
||||
toString = Boolean::toString
|
||||
|
||||
eq toString, true['toString']
|
||||
eq toString, false['toString']
|
||||
eq toString, yes['toString']
|
||||
eq toString, no['toString']
|
||||
eq toString, on['toString']
|
||||
eq toString, off['toString']
|
||||
eq toString, true['toString']
|
||||
eq toString, false['toString']
|
||||
eq toString, yes['toString']
|
||||
eq toString, no['toString']
|
||||
eq toString, on['toString']
|
||||
eq toString, off['toString']
|
||||
|
||||
eq toString, true.toString
|
||||
eq toString, false.toString
|
||||
eq toString, yes.toString
|
||||
eq toString, no.toString
|
||||
eq toString, on.toString
|
||||
eq toString, off.toString
|
||||
eq toString, true.toString
|
||||
eq toString, false.toString
|
||||
eq toString, yes.toString
|
||||
eq toString, no.toString
|
||||
eq toString, on.toString
|
||||
eq toString, off.toString
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
# Cake
|
||||
# ----
|
||||
|
||||
# TODO: add tests
|
|
@ -5,113 +5,119 @@
|
|||
# * Class Instantiation
|
||||
# * Inheritance and Super
|
||||
|
||||
# TODO: refactor class tests
|
||||
test "classes with a four-level inheritance chain", ->
|
||||
|
||||
# Test classes with a four-level inheritance chain.
|
||||
class Base
|
||||
func: (string) ->
|
||||
"zero/#{string}"
|
||||
class Base
|
||||
func: (string) ->
|
||||
"zero/#{string}"
|
||||
|
||||
@static: (string) ->
|
||||
"static/#{string}"
|
||||
@static: (string) ->
|
||||
"static/#{string}"
|
||||
|
||||
class FirstChild extends Base
|
||||
func: (string) ->
|
||||
class FirstChild extends Base
|
||||
func: (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild = class extends FirstChild
|
||||
func: (string) ->
|
||||
super('two/') + string
|
||||
|
||||
thirdCtor = ->
|
||||
@array = [1, 2, 3]
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: -> thirdCtor.call this
|
||||
|
||||
# Gratuitous comment for testing.
|
||||
func: (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
ok Base.static('word') is 'static/word'
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/').length + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is '9two/three/four'
|
||||
|
||||
ok (new ThirdChild).array.join(' ') is '1 2 3'
|
||||
|
||||
|
||||
test "constructors with inheritance and super", ->
|
||||
|
||||
identity = (f) -> f
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
||||
class SuperClass extends TopClass
|
||||
constructor: (arg) ->
|
||||
identity super 'super-' + arg
|
||||
|
||||
class SubClass extends SuperClass
|
||||
constructor: ->
|
||||
identity super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
test "Overriding the static property new doesn't clobber Function::new", ->
|
||||
|
||||
class OneClass
|
||||
@new: 'new'
|
||||
function: 'function'
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class TwoClass extends OneClass
|
||||
delete TwoClass.new
|
||||
|
||||
Function.prototype.new = -> new this arguments...
|
||||
|
||||
ok (TwoClass.new('three')).name is 'three'
|
||||
ok (new OneClass).function is 'function'
|
||||
ok OneClass.new is 'new'
|
||||
|
||||
delete Function.prototype.new
|
||||
|
||||
|
||||
test "basic classes, again, but in the manual prototype style", ->
|
||||
|
||||
Base = ->
|
||||
Base::func = (string) ->
|
||||
'zero/' + string
|
||||
Base::['func-func'] = (string) ->
|
||||
"dynamic-#{string}"
|
||||
|
||||
FirstChild = ->
|
||||
SecondChild = ->
|
||||
ThirdChild = ->
|
||||
@array = [1, 2, 3]
|
||||
this
|
||||
|
||||
ThirdChild extends SecondChild extends FirstChild extends Base
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild = class extends FirstChild
|
||||
func: (string) ->
|
||||
SecondChild::func = (string) ->
|
||||
super('two/') + string
|
||||
|
||||
thirdCtor = ->
|
||||
@array = [1, 2, 3]
|
||||
|
||||
class ThirdChild extends SecondChild
|
||||
constructor: -> thirdCtor.call this
|
||||
|
||||
# Gratuitous comment for testing.
|
||||
func: (string) ->
|
||||
ThirdChild::func = (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
ok Base.static('word') is 'static/word'
|
||||
ok result is 'zero/one/two/three/four'
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/').length + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is '9two/three/four'
|
||||
|
||||
ok (new ThirdChild).array.join(' ') is '1 2 3'
|
||||
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
|
||||
|
||||
|
||||
identity = (f) -> f
|
||||
|
||||
class TopClass
|
||||
constructor: (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
||||
class SuperClass extends TopClass
|
||||
constructor: (arg) ->
|
||||
identity super 'super-' + arg
|
||||
|
||||
class SubClass extends SuperClass
|
||||
constructor: ->
|
||||
identity super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
class OneClass
|
||||
@new: 'new'
|
||||
function: 'function'
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
class TwoClass extends OneClass
|
||||
delete TwoClass.new
|
||||
|
||||
Function.prototype.new = -> new this arguments...
|
||||
|
||||
ok (TwoClass.new('three')).name is 'three'
|
||||
ok (new OneClass).function is 'function'
|
||||
ok OneClass.new is 'new'
|
||||
|
||||
delete Function.prototype.new
|
||||
|
||||
|
||||
# And now the same tests, but written in the manual style:
|
||||
Base = ->
|
||||
Base::func = (string) ->
|
||||
'zero/' + string
|
||||
Base::['func-func'] = (string) ->
|
||||
"dynamic-#{string}"
|
||||
|
||||
FirstChild = ->
|
||||
SecondChild = ->
|
||||
ThirdChild = ->
|
||||
@array = [1, 2, 3]
|
||||
this
|
||||
|
||||
ThirdChild extends SecondChild extends FirstChild extends Base
|
||||
|
||||
FirstChild::func = (string) ->
|
||||
super('one/') + string
|
||||
|
||||
SecondChild::func = (string) ->
|
||||
super('two/') + string
|
||||
|
||||
ThirdChild::func = (string) ->
|
||||
super('three/') + string
|
||||
|
||||
result = (new ThirdChild).func 'four'
|
||||
|
||||
ok result is 'zero/one/two/three/four'
|
||||
|
||||
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
|
||||
|
||||
test "super with plain ol' functions as the original constructors", ->
|
||||
|
||||
TopClass = (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
|
@ -131,283 +137,302 @@ SubClass extends SuperClass
|
|||
ok (new SubClass).prop is 'top-super-sub'
|
||||
|
||||
|
||||
# '@' referring to the current instance, and not being coerced into a call.
|
||||
class ClassName
|
||||
amI: ->
|
||||
@ instanceof ClassName
|
||||
test "'@' referring to the current instance, and not being coerced into a call", ->
|
||||
|
||||
obj = new ClassName
|
||||
ok obj.amI()
|
||||
class ClassName
|
||||
amI: ->
|
||||
@ instanceof ClassName
|
||||
|
||||
obj = new ClassName
|
||||
ok obj.amI()
|
||||
|
||||
|
||||
# super() calls in constructors of classes that are defined as object properties.
|
||||
class Hive
|
||||
constructor: (name) -> @name = name
|
||||
test "super() calls in constructors of classes that are defined as object properties", ->
|
||||
|
||||
class Hive.Bee extends Hive
|
||||
constructor: (name) -> super
|
||||
class Hive
|
||||
constructor: (name) -> @name = name
|
||||
|
||||
maya = new Hive.Bee 'Maya'
|
||||
ok maya.name is 'Maya'
|
||||
class Hive.Bee extends Hive
|
||||
constructor: (name) -> super
|
||||
|
||||
maya = new Hive.Bee 'Maya'
|
||||
ok maya.name is 'Maya'
|
||||
|
||||
|
||||
# Class with JS-keyword properties.
|
||||
class Class
|
||||
class: 'class'
|
||||
name: -> @class
|
||||
test "classes with JS-keyword properties", ->
|
||||
|
||||
instance = new Class
|
||||
ok instance.class is 'class'
|
||||
ok instance.name() is 'class'
|
||||
class Class
|
||||
class: 'class'
|
||||
name: -> @class
|
||||
|
||||
instance = new Class
|
||||
ok instance.class is 'class'
|
||||
ok instance.name() is 'class'
|
||||
|
||||
|
||||
# Classes with methods that are pre-bound to the instance.
|
||||
# ... or statically, to the class.
|
||||
class Dog
|
||||
test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->
|
||||
|
||||
constructor: (name) ->
|
||||
@name = name
|
||||
class Dog
|
||||
constructor: (name) ->
|
||||
@name = name
|
||||
|
||||
bark: =>
|
||||
"#{@name} woofs!"
|
||||
bark: =>
|
||||
"#{@name} woofs!"
|
||||
|
||||
@static = =>
|
||||
new this('Dog')
|
||||
@static = =>
|
||||
new this('Dog')
|
||||
|
||||
spark = new Dog('Spark')
|
||||
fido = new Dog('Fido')
|
||||
fido.bark = spark.bark
|
||||
spark = new Dog('Spark')
|
||||
fido = new Dog('Fido')
|
||||
fido.bark = spark.bark
|
||||
|
||||
ok fido.bark() is 'Spark woofs!'
|
||||
ok fido.bark() is 'Spark woofs!'
|
||||
|
||||
obj = func: Dog.static
|
||||
obj = func: Dog.static
|
||||
|
||||
ok obj.func().name is 'Dog'
|
||||
ok obj.func().name is 'Dog'
|
||||
|
||||
|
||||
# Testing a bound function in a bound function.
|
||||
class Mini
|
||||
num: 10
|
||||
generate: =>
|
||||
for i in [1..3]
|
||||
=>
|
||||
@num
|
||||
test "a bound function in a bound function", ->
|
||||
|
||||
m = new Mini
|
||||
eq (func() for func in m.generate()).join(' '), '10 10 10'
|
||||
class Mini
|
||||
num: 10
|
||||
generate: =>
|
||||
for i in [1..3]
|
||||
=>
|
||||
@num
|
||||
|
||||
m = new Mini
|
||||
eq (func() for func in m.generate()).join(' '), '10 10 10'
|
||||
|
||||
|
||||
# Testing a contructor called with varargs.
|
||||
class Connection
|
||||
constructor: (one, two, three) ->
|
||||
[@one, @two, @three] = [one, two, three]
|
||||
test "contructor called with varargs", ->
|
||||
|
||||
out: ->
|
||||
"#{@one}-#{@two}-#{@three}"
|
||||
class Connection
|
||||
constructor: (one, two, three) ->
|
||||
[@one, @two, @three] = [one, two, three]
|
||||
|
||||
list = [3, 2, 1]
|
||||
conn = new Connection list...
|
||||
ok conn instanceof Connection
|
||||
ok conn.out() is '3-2-1'
|
||||
out: ->
|
||||
"#{@one}-#{@two}-#{@three}"
|
||||
|
||||
list = [3, 2, 1]
|
||||
conn = new Connection list...
|
||||
ok conn instanceof Connection
|
||||
ok conn.out() is '3-2-1'
|
||||
|
||||
|
||||
# Test calling super and passing along all arguments.
|
||||
class Parent
|
||||
method: (args...) -> @args = args
|
||||
test "calling super and passing along all arguments", ->
|
||||
|
||||
class Child extends Parent
|
||||
method: -> super
|
||||
class Parent
|
||||
method: (args...) -> @args = args
|
||||
|
||||
c = new Child
|
||||
c.method 1, 2, 3, 4
|
||||
ok c.args.join(' ') is '1 2 3 4'
|
||||
class Child extends Parent
|
||||
method: -> super
|
||||
|
||||
c = new Child
|
||||
c.method 1, 2, 3, 4
|
||||
ok c.args.join(' ') is '1 2 3 4'
|
||||
|
||||
|
||||
# Test classes wrapped in decorators.
|
||||
func = (klass) ->
|
||||
klass::prop = 'value'
|
||||
klass
|
||||
test "classes wrapped in decorators", ->
|
||||
|
||||
func class Test
|
||||
prop2: 'value2'
|
||||
func = (klass) ->
|
||||
klass::prop = 'value'
|
||||
klass
|
||||
|
||||
ok (new Test).prop is 'value'
|
||||
ok (new Test).prop2 is 'value2'
|
||||
func class Test
|
||||
prop2: 'value2'
|
||||
|
||||
ok (new Test).prop is 'value'
|
||||
ok (new Test).prop2 is 'value2'
|
||||
|
||||
|
||||
# Test anonymous classes.
|
||||
obj =
|
||||
klass: class
|
||||
method: -> 'value'
|
||||
test "anonymous classes", ->
|
||||
|
||||
instance = new obj.klass
|
||||
ok instance.method() is 'value'
|
||||
obj =
|
||||
klass: class
|
||||
method: -> 'value'
|
||||
|
||||
instance = new obj.klass
|
||||
ok instance.method() is 'value'
|
||||
|
||||
|
||||
# Implicit objects as static properties.
|
||||
class Static
|
||||
@static =
|
||||
one: 1
|
||||
two: 2
|
||||
test "Implicit objects as static properties", ->
|
||||
|
||||
ok Static.static.one is 1
|
||||
ok Static.static.two is 2
|
||||
class Static
|
||||
@static =
|
||||
one: 1
|
||||
two: 2
|
||||
|
||||
ok Static.static.one is 1
|
||||
ok Static.static.two is 2
|
||||
|
||||
|
||||
# Nothing classes.
|
||||
c = class
|
||||
ok c instanceof Function
|
||||
test "nothing classes", ->
|
||||
|
||||
c = class
|
||||
ok c instanceof Function
|
||||
|
||||
|
||||
# Classes with value'd constructors.
|
||||
counter = 0
|
||||
classMaker = ->
|
||||
counter++
|
||||
inner = counter
|
||||
->
|
||||
@value = inner
|
||||
test "classes with value'd constructors", ->
|
||||
|
||||
class One
|
||||
constructor: classMaker()
|
||||
counter = 0
|
||||
classMaker = ->
|
||||
counter++
|
||||
inner = counter
|
||||
->
|
||||
@value = inner
|
||||
|
||||
class Two
|
||||
constructor: classMaker()
|
||||
class One
|
||||
constructor: classMaker()
|
||||
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
class Two
|
||||
constructor: classMaker()
|
||||
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
ok (new One).value is 1
|
||||
ok (new Two).value is 2
|
||||
|
||||
|
||||
# Exectuable class bodies.
|
||||
class A
|
||||
if true
|
||||
b: 'b'
|
||||
else
|
||||
c: 'c'
|
||||
test "exectuable class bodies", ->
|
||||
|
||||
a = new A
|
||||
class A
|
||||
if true
|
||||
b: 'b'
|
||||
else
|
||||
c: 'c'
|
||||
|
||||
eq a.b, 'b'
|
||||
eq a.c, undefined
|
||||
a = new A
|
||||
|
||||
eq a.b, 'b'
|
||||
eq a.c, undefined
|
||||
|
||||
|
||||
# Light metaprogramming.
|
||||
class Base
|
||||
@attr: (name) ->
|
||||
@::[name] = (val) ->
|
||||
if arguments.length > 0
|
||||
@["_#{name}"] = val
|
||||
else
|
||||
@["_#{name}"]
|
||||
test "mild metaprogramming", ->
|
||||
|
||||
class Robot extends Base
|
||||
@attr 'power'
|
||||
@attr 'speed'
|
||||
class Base
|
||||
@attr: (name) ->
|
||||
@::[name] = (val) ->
|
||||
if arguments.length > 0
|
||||
@["_#{name}"] = val
|
||||
else
|
||||
@["_#{name}"]
|
||||
|
||||
robby = new Robot
|
||||
class Robot extends Base
|
||||
@attr 'power'
|
||||
@attr 'speed'
|
||||
|
||||
ok robby.power() is undefined
|
||||
robby = new Robot
|
||||
|
||||
robby.power 11
|
||||
robby.speed Infinity
|
||||
ok robby.power() is undefined
|
||||
|
||||
eq robby.power(), 11
|
||||
eq robby.speed(), Infinity
|
||||
robby.power 11
|
||||
robby.speed Infinity
|
||||
|
||||
eq robby.power(), 11
|
||||
eq robby.speed(), Infinity
|
||||
|
||||
|
||||
# Namespaced classes do not reserve their function name in outside scope.
|
||||
one = {}
|
||||
two = {}
|
||||
test "namespaced classes do not reserve their function name in outside scope", ->
|
||||
|
||||
class one.Klass
|
||||
@label = "one"
|
||||
one = {}
|
||||
two = {}
|
||||
|
||||
class two.Klass
|
||||
@label = "two"
|
||||
class one.Klass
|
||||
@label = "one"
|
||||
|
||||
eq typeof Klass, 'undefined'
|
||||
eq one.Klass.label, 'one'
|
||||
eq two.Klass.label, 'two'
|
||||
class two.Klass
|
||||
@label = "two"
|
||||
|
||||
eq typeof Klass, 'undefined'
|
||||
eq one.Klass.label, 'one'
|
||||
eq two.Klass.label, 'two'
|
||||
|
||||
|
||||
# Nested classes.
|
||||
class Outer
|
||||
constructor: ->
|
||||
@label = 'outer'
|
||||
test "nested classes", ->
|
||||
|
||||
class @Inner
|
||||
class Outer
|
||||
constructor: ->
|
||||
@label = 'inner'
|
||||
@label = 'outer'
|
||||
|
||||
eq (new Outer).label, 'outer'
|
||||
eq (new Outer.Inner).label, 'inner'
|
||||
class @Inner
|
||||
constructor: ->
|
||||
@label = 'inner'
|
||||
|
||||
eq (new Outer).label, 'outer'
|
||||
eq (new Outer.Inner).label, 'inner'
|
||||
|
||||
|
||||
# Variables in constructor bodies are correctly scoped.
|
||||
class A
|
||||
x = 1
|
||||
constructor: ->
|
||||
x = 10
|
||||
y = 20
|
||||
y = 2
|
||||
captured: ->
|
||||
{x, y}
|
||||
test "variables in constructor bodies are correctly scoped", ->
|
||||
|
||||
a = new A
|
||||
eq a.captured().x, 10
|
||||
eq a.captured().y, 2
|
||||
class A
|
||||
x = 1
|
||||
constructor: ->
|
||||
x = 10
|
||||
y = 20
|
||||
y = 2
|
||||
captured: ->
|
||||
{x, y}
|
||||
|
||||
a = new A
|
||||
eq a.captured().x, 10
|
||||
eq a.captured().y, 2
|
||||
|
||||
|
||||
# Issue #924: Static methods in nested classes.
|
||||
class A
|
||||
@B: class
|
||||
@c = -> 5
|
||||
test "Issue #924: Static methods in nested classes", ->
|
||||
|
||||
eq A.B.c(), 5
|
||||
class A
|
||||
@B: class
|
||||
@c = -> 5
|
||||
|
||||
eq A.B.c(), 5
|
||||
|
||||
|
||||
# `class extends this` ...
|
||||
class A
|
||||
func: -> 'A'
|
||||
test "`class extends this`", ->
|
||||
|
||||
B = null
|
||||
makeClass = ->
|
||||
B = class extends this
|
||||
func: -> super + ' B'
|
||||
class A
|
||||
func: -> 'A'
|
||||
|
||||
makeClass.call A
|
||||
B = null
|
||||
makeClass = ->
|
||||
B = class extends this
|
||||
func: -> super + ' B'
|
||||
|
||||
eq (new B()).func(), 'A B'
|
||||
makeClass.call A
|
||||
|
||||
eq (new B()).func(), 'A B'
|
||||
|
||||
|
||||
test "ensure that constructors invoked with splats return a new object", ->
|
||||
|
||||
args = [1, 2, 3]
|
||||
Type = (@args) ->
|
||||
type = new Type args
|
||||
|
||||
ok type and type instanceof Type
|
||||
ok type.args and type.args instanceof Array
|
||||
ok v is args[i] for v, i in type.args
|
||||
|
||||
Type1 = (@a, @b, @c) ->
|
||||
type1 = new Type1 args...
|
||||
|
||||
ok type1 instanceof Type1
|
||||
eq type1.constructor, Type1
|
||||
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
|
||||
|
||||
# Ensure that constructors invoked with splats cache the function.
|
||||
called = 0
|
||||
get = -> if called++ then false else class Type
|
||||
new get() args...
|
||||
|
||||
test "`new` shouldn't add extra parens", ->
|
||||
|
||||
ok new Date().constructor is Date
|
||||
|
||||
|
||||
# Ensure that constructors invoked with splats return a new object.
|
||||
args = [1, 2, 3]
|
||||
Type = (@args) ->
|
||||
type = new Type args
|
||||
test "`new` works against bare function", ->
|
||||
|
||||
ok type and type instanceof Type
|
||||
ok type.args and type.args instanceof Array
|
||||
ok v is args[i] for v, i in type.args
|
||||
|
||||
Type1 = (@a, @b, @c) ->
|
||||
type1 = new Type1 args...
|
||||
|
||||
ok type1 instanceof Type1
|
||||
eq type1.constructor, Type1
|
||||
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
|
||||
|
||||
# Ensure that constructors invoked with splats cache the function.
|
||||
called = 0
|
||||
get = -> if called++ then false else class Type
|
||||
new get() args...
|
||||
|
||||
# `new` shouldn't add extra parens
|
||||
ok new Date().constructor is Date
|
||||
|
||||
# `new` works against bare function
|
||||
eq Date, new ->
|
||||
eq this, new => this
|
||||
Date
|
||||
eq Date, new ->
|
||||
eq this, new => this
|
||||
Date
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
# Command
|
||||
# -------
|
||||
|
||||
# TODO: add tests
|
|
@ -110,7 +110,7 @@ test "spaced comments with conditional statements", ->
|
|||
eq nonce, result
|
||||
|
||||
|
||||
#### Block Comments
|
||||
# Block Comments
|
||||
|
||||
###
|
||||
This is a here-comment.
|
||||
|
|
|
@ -1,47 +1,43 @@
|
|||
# Compilation
|
||||
# -----------
|
||||
|
||||
# TODO: refactor compilation tests
|
||||
|
||||
# helper to assert that a string should fail compilation
|
||||
cantCompile = (code) ->
|
||||
throws -> CoffeeScript.compile code
|
||||
|
||||
|
||||
# Ensure that carriage returns don't break compilation on Windows.
|
||||
doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on
|
||||
test "ensure that carriage returns don't break compilation on Windows", ->
|
||||
doesNotThrow -> CoffeeScript.compile 'one\r\ntwo', bare: on
|
||||
|
||||
# `globals: on` removes `var`s
|
||||
eq -1, CoffeeScript.compile('x = y', bare: on, globals: on).indexOf 'var'
|
||||
test "--bare and globals:on", ->
|
||||
eq -1, CoffeeScript.compile('x = y', bare: on, globals: on).indexOf 'var'
|
||||
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test'
|
||||
|
||||
ok 'passed' is CoffeeScript.eval '"passed"', bare: on, filename: 'test'
|
||||
|
||||
# multiple generated references
|
||||
(->
|
||||
test "multiple generated references", ->
|
||||
a = {b: []}
|
||||
a.b[true] = -> this == a.b
|
||||
c = 0
|
||||
d = []
|
||||
ok a.b[0<++c<2] d...
|
||||
)()
|
||||
|
||||
# Splat on a line by itself is invalid.
|
||||
cantCompile "x 'a'\n...\n"
|
||||
test "splat on a line by itself is invalid", ->
|
||||
cantCompile "x 'a'\n...\n"
|
||||
|
||||
#750
|
||||
cantCompile 'f(->'
|
||||
test "Issue 750", ->
|
||||
|
||||
cantCompile 'a = (break)'
|
||||
cantCompile 'f(->'
|
||||
|
||||
cantCompile 'a = (return 5 for item in list)'
|
||||
cantCompile 'a = (break)'
|
||||
|
||||
cantCompile 'a = (return 5 while condition)'
|
||||
cantCompile 'a = (return 5 for item in list)'
|
||||
|
||||
cantCompile 'a = for x in y\n return 5'
|
||||
cantCompile 'a = (return 5 while condition)'
|
||||
|
||||
# Issue #986: Unicode identifiers.
|
||||
λ = 5
|
||||
eq λ, 5
|
||||
cantCompile 'a = for x in y\n return 5'
|
||||
|
||||
test "Issue #986: Unicode identifiers", ->
|
||||
λ = 5
|
||||
eq λ, 5
|
||||
|
||||
test "don't accidentally stringify keywords", ->
|
||||
ok (-> this == 'this')() is false
|
||||
|
@ -57,4 +53,4 @@ test "#1026", ->
|
|||
'''
|
||||
|
||||
test "#1050", ->
|
||||
cantCompile "### */ ###"
|
||||
cantCompile "### */ ###"
|
||||
|
|
|
@ -9,323 +9,357 @@
|
|||
|
||||
# TODO: refactor comprehension tests
|
||||
|
||||
# Basic array comprehensions.
|
||||
nums = (n * n for n in [1, 2, 3] when n & 1)
|
||||
results = (n * 2 for n in nums)
|
||||
test "Basic array comprehensions.", ->
|
||||
|
||||
ok results.join(',') is '2,18'
|
||||
nums = (n * n for n in [1, 2, 3] when n & 1)
|
||||
results = (n * 2 for n in nums)
|
||||
|
||||
ok results.join(',') is '2,18'
|
||||
|
||||
|
||||
# Basic object comprehensions.
|
||||
obj = {one: 1, two: 2, three: 3}
|
||||
names = (prop + '!' for prop of obj)
|
||||
odds = (prop + '!' for prop, value of obj when value & 1)
|
||||
test "Basic object comprehensions.", ->
|
||||
|
||||
ok names.join(' ') is "one! two! three!"
|
||||
ok odds.join(' ') is "one! three!"
|
||||
obj = {one: 1, two: 2, three: 3}
|
||||
names = (prop + '!' for prop of obj)
|
||||
odds = (prop + '!' for prop, value of obj when value & 1)
|
||||
|
||||
ok names.join(' ') is "one! two! three!"
|
||||
ok odds.join(' ') is "one! three!"
|
||||
|
||||
|
||||
# Basic range comprehensions.
|
||||
nums = (i * 3 for i in [1..3])
|
||||
test "Basic range comprehensions.", ->
|
||||
|
||||
negs = (x for x in [-20..-5*2])
|
||||
negs = negs[0..2]
|
||||
nums = (i * 3 for i in [1..3])
|
||||
|
||||
result = nums.concat(negs).join(', ')
|
||||
negs = (x for x in [-20..-5*2])
|
||||
negs = negs[0..2]
|
||||
|
||||
ok result is '3, 6, 9, -20, -19, -18'
|
||||
result = nums.concat(negs).join(', ')
|
||||
|
||||
ok result is '3, 6, 9, -20, -19, -18'
|
||||
|
||||
|
||||
# With range comprehensions, you can loop in steps.
|
||||
results = (x for x in [0...15] by 5)
|
||||
ok results.join(' ') is '0 5 10'
|
||||
test "With range comprehensions, you can loop in steps.", ->
|
||||
|
||||
results = (x for x in [0..100] by 10)
|
||||
ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
|
||||
results = (x for x in [0...15] by 5)
|
||||
ok results.join(' ') is '0 5 10'
|
||||
|
||||
results = (x for x in [0..100] by 10)
|
||||
ok results.join(' ') is '0 10 20 30 40 50 60 70 80 90 100'
|
||||
|
||||
|
||||
# And can loop downwards, with a negative step.
|
||||
results = (x for x in [5..1])
|
||||
test "And can loop downwards, with a negative step.", ->
|
||||
|
||||
ok results.join(' ') is '5 4 3 2 1'
|
||||
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
|
||||
results = (x for x in [5..1])
|
||||
|
||||
results = (x for x in [10..1])
|
||||
ok results.join(' ') is [10..1].join(' ')
|
||||
ok results.join(' ') is '5 4 3 2 1'
|
||||
ok results.join(' ') is [(10-5)..(-2+3)].join(' ')
|
||||
|
||||
results = (x for x in [10...0] by -2)
|
||||
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
|
||||
results = (x for x in [10..1])
|
||||
ok results.join(' ') is [10..1].join(' ')
|
||||
|
||||
results = (x for x in [10...0] by -2)
|
||||
ok results.join(' ') is [10, 8, 6, 4, 2].join(' ')
|
||||
|
||||
|
||||
# Range comprehension gymnastics.
|
||||
eq "#{i for i in [5..1]}", '5,4,3,2,1'
|
||||
eq "#{i for i in [5..-5] by -5}", '5,0,-5'
|
||||
test "Range comprehension gymnastics.", ->
|
||||
|
||||
a = 6
|
||||
b = 0
|
||||
c = -2
|
||||
eq "#{i for i in [5..1]}", '5,4,3,2,1'
|
||||
eq "#{i for i in [5..-5] by -5}", '5,0,-5'
|
||||
|
||||
eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
|
||||
eq "#{i for i in [a..b] by c}", '6,4,2,0'
|
||||
a = 6
|
||||
b = 0
|
||||
c = -2
|
||||
|
||||
eq "#{i for i in [a..b]}", '6,5,4,3,2,1,0'
|
||||
eq "#{i for i in [a..b] by c}", '6,4,2,0'
|
||||
|
||||
|
||||
# Multiline array comprehension with filter.
|
||||
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
|
||||
num *= -1
|
||||
num -= 2
|
||||
num * -1
|
||||
eq evens + '', '4,6,8'
|
||||
test "Multiline array comprehension with filter.", ->
|
||||
|
||||
evens = for num in [1, 2, 3, 4, 5, 6] when not (num & 1)
|
||||
num *= -1
|
||||
num -= 2
|
||||
num * -1
|
||||
eq evens + '', '4,6,8'
|
||||
|
||||
|
||||
# The in operator still works, standalone.
|
||||
ok 2 of evens
|
||||
test "The in operator still works, standalone.", ->
|
||||
|
||||
# all isn't reserved.
|
||||
all = 1
|
||||
ok 2 of evens
|
||||
|
||||
|
||||
# Ensure that the closure wrapper preserves local variables.
|
||||
obj = {}
|
||||
test "all isn't reserved.", ->
|
||||
|
||||
for method in ['one', 'two', 'three'] then do (method) ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
ok obj.one() is "I'm one"
|
||||
ok obj.two() is "I'm two"
|
||||
ok obj.three() is "I'm three"
|
||||
all = 1
|
||||
|
||||
|
||||
# Index values at the end of a loop.
|
||||
i = 0
|
||||
for i in [1..3]
|
||||
-> 'func'
|
||||
break if false
|
||||
ok i is 4
|
||||
test "Ensure that the closure wrapper preserves local variables.", ->
|
||||
|
||||
obj = {}
|
||||
|
||||
for method in ['one', 'two', 'three'] then do (method) ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
ok obj.one() is "I'm one"
|
||||
ok obj.two() is "I'm two"
|
||||
ok obj.three() is "I'm three"
|
||||
|
||||
|
||||
# Ensure that local variables are closed over for range comprehensions.
|
||||
funcs = for i in [1..3]
|
||||
do (i) ->
|
||||
-> -i
|
||||
test "Index values at the end of a loop.", ->
|
||||
|
||||
eq (func() for func in funcs).join(' '), '-1 -2 -3'
|
||||
ok i is 4
|
||||
i = 0
|
||||
for i in [1..3]
|
||||
-> 'func'
|
||||
break if false
|
||||
ok i is 4
|
||||
|
||||
|
||||
# Even when referenced in the filter.
|
||||
list = ['one', 'two', 'three']
|
||||
test "Ensure that local variables are closed over for range comprehensions.", ->
|
||||
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
do (num, i) ->
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
ok methods[0]() is 'one 0'
|
||||
ok methods[1]() is 'three 2'
|
||||
|
||||
|
||||
# Even a convoluted one.
|
||||
funcs = []
|
||||
|
||||
for i in [1..3]
|
||||
do (i) ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
|
||||
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
|
||||
|
||||
funcs = []
|
||||
|
||||
results = for i in [1..3]
|
||||
do (i) ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
|
||||
ok results.join(', ') is '3 , 3 6 , 3 6 9'
|
||||
|
||||
|
||||
# Naked ranges are expanded into arrays.
|
||||
array = [0..10]
|
||||
ok(num % 2 is 0 for num in array by 2)
|
||||
|
||||
|
||||
# Nested shared scopes.
|
||||
foo = ->
|
||||
for i in [0..7]
|
||||
funcs = for i in [1..3]
|
||||
do (i) ->
|
||||
for j in [0..7]
|
||||
do (j) ->
|
||||
-> i + j
|
||||
-> -i
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
eq (func() for func in funcs).join(' '), '-1 -2 -3'
|
||||
ok i is 4
|
||||
|
||||
|
||||
# Scoped loop pattern matching.
|
||||
a = [[0], [1]]
|
||||
funcs = []
|
||||
test "Even when referenced in the filter.", ->
|
||||
|
||||
for [v] in a
|
||||
do (v) ->
|
||||
funcs.push -> v
|
||||
list = ['one', 'two', 'three']
|
||||
|
||||
eq funcs[0](), 0
|
||||
eq funcs[1](), 1
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
do (num, i) ->
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
ok methods[0]() is 'one 0'
|
||||
ok methods[1]() is 'three 2'
|
||||
|
||||
|
||||
# Nested comprehensions.
|
||||
multiLiner =
|
||||
for x in [3..5]
|
||||
for y in [3..5]
|
||||
[x, y]
|
||||
test "Even a convoluted one.", ->
|
||||
|
||||
singleLiner =
|
||||
(([x, y] for y in [3..5]) for x in [3..5])
|
||||
funcs = []
|
||||
|
||||
ok multiLiner.length is singleLiner.length
|
||||
ok 5 is multiLiner[2][2][1]
|
||||
ok 5 is singleLiner[2][2][1]
|
||||
for i in [1..3]
|
||||
do (i) ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
|
||||
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
|
||||
|
||||
funcs = []
|
||||
|
||||
results = for i in [1..3]
|
||||
do (i) ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
|
||||
ok results.join(', ') is '3 , 3 6 , 3 6 9'
|
||||
|
||||
|
||||
# Comprehensions within parentheses.
|
||||
result = null
|
||||
store = (obj) -> result = obj
|
||||
store (x * 2 for x in [3, 2, 1])
|
||||
test "Naked ranges are expanded into arrays.", ->
|
||||
|
||||
ok result.join(' ') is '6 4 2'
|
||||
array = [0..10]
|
||||
ok(num % 2 is 0 for num in array by 2)
|
||||
|
||||
|
||||
# Closure-wrapped comprehensions that refer to the "arguments" object.
|
||||
expr = ->
|
||||
result = (item * item for item in arguments)
|
||||
test "Nested shared scopes.", ->
|
||||
|
||||
ok expr(2, 4, 8).join(' ') is '4 16 64'
|
||||
foo = ->
|
||||
for i in [0..7]
|
||||
do (i) ->
|
||||
for j in [0..7]
|
||||
do (j) ->
|
||||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
||||
# Fast object comprehensions over all properties, including prototypal ones.
|
||||
class Cat
|
||||
constructor: -> @name = 'Whiskers'
|
||||
breed: 'tabby'
|
||||
hair: 'cream'
|
||||
test "Scoped loop pattern matching.", ->
|
||||
|
||||
whiskers = new Cat
|
||||
own = (value for own key, value of whiskers)
|
||||
all = (value for key, value of whiskers)
|
||||
a = [[0], [1]]
|
||||
funcs = []
|
||||
|
||||
ok own.join(' ') is 'Whiskers'
|
||||
ok all.sort().join(' ') is 'Whiskers cream tabby'
|
||||
for [v] in a
|
||||
do (v) ->
|
||||
funcs.push -> v
|
||||
|
||||
eq funcs[0](), 0
|
||||
eq funcs[1](), 1
|
||||
|
||||
|
||||
# Optimized range comprehensions.
|
||||
exxes = ('x' for [0...10])
|
||||
ok exxes.join(' ') is 'x x x x x x x x x x'
|
||||
test "Nested comprehensions.", ->
|
||||
|
||||
multiLiner =
|
||||
for x in [3..5]
|
||||
for y in [3..5]
|
||||
[x, y]
|
||||
|
||||
singleLiner =
|
||||
(([x, y] for y in [3..5]) for x in [3..5])
|
||||
|
||||
ok multiLiner.length is singleLiner.length
|
||||
ok 5 is multiLiner[2][2][1]
|
||||
ok 5 is singleLiner[2][2][1]
|
||||
|
||||
|
||||
# Comprehensions safely redeclare parameters if they're not present in closest
|
||||
# scope.
|
||||
rule = (x) -> x
|
||||
test "Comprehensions within parentheses.", ->
|
||||
|
||||
learn = ->
|
||||
rule for rule in [1, 2, 3]
|
||||
result = null
|
||||
store = (obj) -> result = obj
|
||||
store (x * 2 for x in [3, 2, 1])
|
||||
|
||||
ok learn().join(' ') is '1 2 3'
|
||||
|
||||
ok rule(101) is 101
|
||||
|
||||
f = -> [-> ok no, 'should cache source']
|
||||
ok yes for k of [f] = f()
|
||||
ok result.join(' ') is '6 4 2'
|
||||
|
||||
|
||||
# Lenient on pure statements not trying to reach out of the closure
|
||||
val = for i in [1]
|
||||
for j in [] then break
|
||||
i
|
||||
ok val[0] is i
|
||||
test "Closure-wrapped comprehensions that refer to the 'arguments' object.", ->
|
||||
|
||||
expr = ->
|
||||
result = (item * item for item in arguments)
|
||||
|
||||
ok expr(2, 4, 8).join(' ') is '4 16 64'
|
||||
|
||||
|
||||
# Comprehensions only wrap their last line in a closure, allowing other lines
|
||||
# to have pure expressions in them.
|
||||
func = -> for i in [1]
|
||||
break if i is 2
|
||||
j for j in [1]
|
||||
test "Fast object comprehensions over all properties, including prototypal ones.", ->
|
||||
|
||||
ok func()[0][0] is 1
|
||||
class Cat
|
||||
constructor: -> @name = 'Whiskers'
|
||||
breed: 'tabby'
|
||||
hair: 'cream'
|
||||
|
||||
i = 6
|
||||
odds = while i--
|
||||
continue unless i & 1
|
||||
i
|
||||
whiskers = new Cat
|
||||
own = (value for own key, value of whiskers)
|
||||
all = (value for key, value of whiskers)
|
||||
|
||||
ok odds.join(', ') is '5, 3, 1'
|
||||
ok own.join(' ') is 'Whiskers'
|
||||
ok all.sort().join(' ') is 'Whiskers cream tabby'
|
||||
|
||||
|
||||
# Issue #897: Ensure that plucked function variables aren't leaked.
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
test "Optimized range comprehensions.", ->
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
exxes = ('x' for [0...10])
|
||||
ok exxes.join(' ') is 'x x x x x x x x x x'
|
||||
|
||||
|
||||
# Issue #905. Soaks as the for loop subject.
|
||||
a = {b: {c: [1, 2, 3]}}
|
||||
for d in a.b?.c
|
||||
e = d
|
||||
test "Comprehensions safely redeclare parameters if they're not present in closest scope.", ->
|
||||
|
||||
eq e, 3
|
||||
rule = (x) -> x
|
||||
|
||||
learn = ->
|
||||
rule for rule in [1, 2, 3]
|
||||
|
||||
ok learn().join(' ') is '1 2 3'
|
||||
|
||||
ok rule(101) is 101
|
||||
|
||||
f = -> [-> ok no, 'should cache source']
|
||||
ok yes for k of [f] = f()
|
||||
|
||||
|
||||
# Issue #948. Capturing loop variables.
|
||||
funcs = []
|
||||
list = ->
|
||||
[1, 2, 3]
|
||||
test "Lenient on pure statements not trying to reach out of the closure", ->
|
||||
|
||||
for y in list()
|
||||
do (y) ->
|
||||
z = y
|
||||
funcs.push -> "y is #{y} and z is #{z}"
|
||||
|
||||
eq funcs[1](), "y is 2 and z is 2"
|
||||
val = for i in [1]
|
||||
for j in [] then break
|
||||
i
|
||||
ok val[0] is i
|
||||
|
||||
|
||||
# Cancel the comprehension if there's a jump inside the loop.
|
||||
result = try
|
||||
for i in [0...10]
|
||||
continue if i < 5
|
||||
i
|
||||
test "Comprehensions only wrap their last line in a closure, allowing other lines
|
||||
to have pure expressions in them.", ->
|
||||
|
||||
eq result, 10
|
||||
func = -> for i in [1]
|
||||
break if i is 2
|
||||
j for j in [1]
|
||||
|
||||
ok func()[0][0] is 1
|
||||
|
||||
i = 6
|
||||
odds = while i--
|
||||
continue unless i & 1
|
||||
i
|
||||
|
||||
ok odds.join(', ') is '5, 3, 1'
|
||||
|
||||
|
||||
# Comprehensions over break.
|
||||
arrayEq (break for [1..10]), []
|
||||
test "Issue #897: Ensure that plucked function variables aren't leaked.", ->
|
||||
|
||||
# Comprehensions over continue.
|
||||
arrayEq (break for [1..10]), []
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
|
||||
|
||||
# Comprehensions over function literals.
|
||||
a = 0
|
||||
for f in [-> a = 1]
|
||||
do (f) ->
|
||||
do f
|
||||
test "Issue #905. Soaks as the for loop subject.", ->
|
||||
|
||||
eq a, 1
|
||||
a = {b: {c: [1, 2, 3]}}
|
||||
for d in a.b?.c
|
||||
e = d
|
||||
|
||||
eq e, 3
|
||||
|
||||
|
||||
# Comprehensions that mention arguments.
|
||||
list = [arguments: 10]
|
||||
args = for f in list
|
||||
do (f) ->
|
||||
f.arguments
|
||||
eq args[0], 10
|
||||
test "Issue #948. Capturing loop variables.", ->
|
||||
|
||||
funcs = []
|
||||
list = ->
|
||||
[1, 2, 3]
|
||||
|
||||
for y in list()
|
||||
do (y) ->
|
||||
z = y
|
||||
funcs.push -> "y is #{y} and z is #{z}"
|
||||
|
||||
eq funcs[1](), "y is 2 and z is 2"
|
||||
|
||||
|
||||
test "Cancel the comprehension if there's a jump inside the loop.", ->
|
||||
|
||||
result = try
|
||||
for i in [0...10]
|
||||
continue if i < 5
|
||||
i
|
||||
|
||||
eq result, 10
|
||||
|
||||
|
||||
test "Comprehensions over break.", ->
|
||||
|
||||
arrayEq (break for [1..10]), []
|
||||
|
||||
|
||||
test "Comprehensions over continue.", ->
|
||||
|
||||
arrayEq (continue for [1..10]), []
|
||||
|
||||
|
||||
test "Comprehensions over function literals.", ->
|
||||
|
||||
a = 0
|
||||
for f in [-> a = 1]
|
||||
do (f) ->
|
||||
do f
|
||||
|
||||
eq a, 1
|
||||
|
||||
|
||||
test "Comprehensions that mention arguments.", ->
|
||||
|
||||
list = [arguments: 10]
|
||||
args = for f in list
|
||||
do (f) ->
|
||||
f.arguments
|
||||
eq args[0], 10
|
||||
|
||||
|
||||
test "expression conversion under explicit returns", ->
|
||||
|
@ -341,8 +375,6 @@ test "expression conversion under explicit returns", ->
|
|||
arrayEq [nonce,nonce,nonce], fn()
|
||||
|
||||
|
||||
#### Implicit Destructuring Assignment
|
||||
|
||||
test "implicit destructuring assignment in object of objects", ->
|
||||
a={}; b={}; c={}
|
||||
obj = {
|
||||
|
@ -353,6 +385,7 @@ test "implicit destructuring assignment in object of objects", ->
|
|||
result = ([y,z] for y, { d: z } of obj)
|
||||
arrayEq [['a',a],['b',b],['c',c]], result
|
||||
|
||||
|
||||
test "implicit destructuring assignment in array of objects", ->
|
||||
a={}; b={}; c={}; d={}; e={}; f={}
|
||||
arr = [
|
||||
|
@ -363,6 +396,7 @@ test "implicit destructuring assignment in array of objects", ->
|
|||
result = ([y,z] for { a: y, b: { c: z } } in arr)
|
||||
arrayEq [[a,b],[c,d],[e,f]], result
|
||||
|
||||
|
||||
test "implicit destructuring assignment in array of arrays", ->
|
||||
a={}; b={}; c={}; d={}; e={}; f={}
|
||||
arr = [[a, [b]], [c, [d]], [e, [f]]]
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
|
||||
#### Conditionals
|
||||
# Conditionals
|
||||
|
||||
test "basic conditionals", ->
|
||||
if false
|
||||
|
@ -198,38 +198,38 @@ test "#748: trailing reserved identifiers", ->
|
|||
eq nonce, result
|
||||
|
||||
|
||||
#### For / While / Until / Loop
|
||||
test "basic `while` loops", ->
|
||||
|
||||
# TODO: refactor while tests
|
||||
i = 5
|
||||
list = while i -= 1
|
||||
i * 2
|
||||
ok list.join(' ') is "8 6 4 2"
|
||||
|
||||
# While
|
||||
i = 5
|
||||
list = (i * 3 while i -= 1)
|
||||
ok list.join(' ') is "12 9 6 3"
|
||||
|
||||
i = 5
|
||||
list = while i -= 1
|
||||
i * 2
|
||||
ok list.join(' ') is "8 6 4 2"
|
||||
i = 5
|
||||
func = (num) -> i -= num
|
||||
assert = -> ok i < 5 > 0
|
||||
results = while func 1
|
||||
assert()
|
||||
i
|
||||
ok results.join(' ') is '4 3 2 1'
|
||||
|
||||
i = 5
|
||||
list = (i * 3 while i -= 1)
|
||||
ok list.join(' ') is "12 9 6 3"
|
||||
i = 10
|
||||
results = while i -= 1 when i % 2 is 0
|
||||
i * 2
|
||||
ok results.join(' ') is '16 12 8 4'
|
||||
|
||||
i = 5
|
||||
func = (num) -> i -= num
|
||||
assert = -> ok i < 5 > 0
|
||||
results = while func 1
|
||||
assert()
|
||||
i
|
||||
ok results.join(' ') is '4 3 2 1'
|
||||
|
||||
i = 10
|
||||
results = while i -= 1 when i % 2 is 0
|
||||
i * 2
|
||||
ok results.join(' ') is '16 12 8 4'
|
||||
test "Issue 759: `if` within `while` condition", ->
|
||||
|
||||
2 while if 1 then 0
|
||||
|
||||
#759: `if` within `while` condition
|
||||
2 while if 1 then 0
|
||||
|
||||
test "assignment inside the condition of a `while` loop", ->
|
||||
|
||||
nonce = {}
|
||||
count = 1
|
||||
a = nonce while count--
|
||||
|
@ -239,47 +239,45 @@ test "assignment inside the condition of a `while` loop", ->
|
|||
b = nonce
|
||||
eq nonce, b
|
||||
|
||||
# While over break.
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
break
|
||||
arrayEq result, []
|
||||
|
||||
# While over continue.
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
continue
|
||||
arrayEq result, []
|
||||
test "While over break.", ->
|
||||
|
||||
# Until
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
break
|
||||
arrayEq result, []
|
||||
|
||||
# TODO: refactor until tests
|
||||
# TODO: add until tests
|
||||
|
||||
value = false
|
||||
i = 0
|
||||
results = until value
|
||||
value = true if i is 5
|
||||
i++
|
||||
ok i is 6
|
||||
test "While over continue.", ->
|
||||
|
||||
# Loop
|
||||
i = 0
|
||||
result = while i < 10
|
||||
i++
|
||||
continue
|
||||
arrayEq result, []
|
||||
|
||||
# TODO: refactor loop tests
|
||||
# TODO: add loop tests
|
||||
|
||||
i = 5
|
||||
list = []
|
||||
loop
|
||||
i -= 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
ok list.join(' ') is '8 6 4 2'
|
||||
test "Basic `until`", ->
|
||||
|
||||
value = false
|
||||
i = 0
|
||||
results = until value
|
||||
value = true if i is 5
|
||||
i++
|
||||
ok i is 6
|
||||
|
||||
|
||||
test "Basic `loop`", ->
|
||||
|
||||
i = 5
|
||||
list = []
|
||||
loop
|
||||
i -= 1
|
||||
break if i is 0
|
||||
list.push i * 2
|
||||
ok list.join(' ') is '8 6 4 2'
|
||||
|
||||
# TODO: refactor for tests
|
||||
# TODO: add for tests
|
||||
|
||||
test "break at the top level", ->
|
||||
for i in [1,2,3]
|
||||
|
@ -289,7 +287,7 @@ test "break at the top level", ->
|
|||
eq 2, result
|
||||
|
||||
test "break *not* at the top level", ->
|
||||
someFunc = () ->
|
||||
someFunc = ->
|
||||
i = 0
|
||||
while ++i < 3
|
||||
result = i
|
||||
|
@ -298,121 +296,125 @@ test "break *not* at the top level", ->
|
|||
eq 2, someFunc()
|
||||
|
||||
|
||||
#### Switch
|
||||
test "basic `switch`", ->
|
||||
|
||||
# TODO: refactor switch tests
|
||||
|
||||
num = 10
|
||||
result = switch num
|
||||
when 5 then false
|
||||
when 'a'
|
||||
true
|
||||
true
|
||||
false
|
||||
when 10 then true
|
||||
|
||||
|
||||
# Mid-switch comment with whitespace
|
||||
# and multi line
|
||||
when 11 then false
|
||||
else false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
func = (num) ->
|
||||
switch num
|
||||
when 2, 4, 6
|
||||
num = 10
|
||||
result = switch num
|
||||
when 5 then false
|
||||
when 'a'
|
||||
true
|
||||
true
|
||||
when 1, 3, 5
|
||||
false
|
||||
|
||||
ok func(2)
|
||||
ok func(6)
|
||||
ok !func(3)
|
||||
eq func(8), undefined
|
||||
when 10 then true
|
||||
|
||||
|
||||
# Ensure that trailing switch elses don't get rewritten.
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
# Mid-switch comment with whitespace
|
||||
# and multi line
|
||||
when 11 then false
|
||||
else false
|
||||
|
||||
ok result
|
||||
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
when "other thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
ok result
|
||||
|
||||
|
||||
# Should be able to handle switches sans-condition.
|
||||
result = switch
|
||||
when null then 0
|
||||
when !1 then 1
|
||||
when '' not of {''} then 2
|
||||
when [] not instanceof Array then 3
|
||||
when true is false then 4
|
||||
when 'x' < 'y' > 'z' then 5
|
||||
when 'a' in ['b', 'c'] then 6
|
||||
when 'd' in (['e', 'f']) then 7
|
||||
else ok
|
||||
func = (num) ->
|
||||
switch num
|
||||
when 2, 4, 6
|
||||
true
|
||||
when 1, 3, 5
|
||||
false
|
||||
|
||||
eq result, ok
|
||||
ok func(2)
|
||||
ok func(6)
|
||||
ok !func(3)
|
||||
eq func(8), undefined
|
||||
|
||||
|
||||
# Should be able to use "@properties" within the switch clause.
|
||||
obj = {
|
||||
num: 101
|
||||
func: ->
|
||||
switch @num
|
||||
when 101 then '101!'
|
||||
else 'other'
|
||||
}
|
||||
test "Ensure that trailing switch elses don't get rewritten.", ->
|
||||
|
||||
ok obj.func() is '101!'
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
result = false
|
||||
switch "word"
|
||||
when "one thing"
|
||||
doSomething()
|
||||
when "other thing"
|
||||
doSomething()
|
||||
else
|
||||
result = true unless false
|
||||
|
||||
ok result
|
||||
|
||||
|
||||
# Should be able to use "@properties" within the switch cases.
|
||||
obj = {
|
||||
num: 101
|
||||
func: (yesOrNo) ->
|
||||
result = switch yesOrNo
|
||||
when yes then @num
|
||||
else 'other'
|
||||
result
|
||||
}
|
||||
test "Should be able to handle switches sans-condition.", ->
|
||||
|
||||
ok obj.func(yes) is 101
|
||||
result = switch
|
||||
when null then 0
|
||||
when !1 then 1
|
||||
when '' not of {''} then 2
|
||||
when [] not instanceof Array then 3
|
||||
when true is false then 4
|
||||
when 'x' < 'y' > 'z' then 5
|
||||
when 'a' in ['b', 'c'] then 6
|
||||
when 'd' in (['e', 'f']) then 7
|
||||
else ok
|
||||
|
||||
eq result, ok
|
||||
|
||||
|
||||
# Switch with break as the return value of a loop.
|
||||
i = 10
|
||||
results = while i > 0
|
||||
i--
|
||||
switch i % 2
|
||||
when 1 then i
|
||||
when 0 then break
|
||||
test "Should be able to use `@properties` within the switch clause.", ->
|
||||
|
||||
eq results.join(', '), '9, , 7, , 5, , 3, , 1, '
|
||||
obj = {
|
||||
num: 101
|
||||
func: ->
|
||||
switch @num
|
||||
when 101 then '101!'
|
||||
else 'other'
|
||||
}
|
||||
|
||||
ok obj.func() is '101!'
|
||||
|
||||
|
||||
# Issue #997. Switch doesn't fallthrough.
|
||||
val = 1
|
||||
switch true
|
||||
when true
|
||||
if false
|
||||
return 5
|
||||
else
|
||||
val = 2
|
||||
test "Should be able to use `@properties` within the switch cases.", ->
|
||||
|
||||
eq val, 1
|
||||
obj = {
|
||||
num: 101
|
||||
func: (yesOrNo) ->
|
||||
result = switch yesOrNo
|
||||
when yes then @num
|
||||
else 'other'
|
||||
result
|
||||
}
|
||||
|
||||
ok obj.func(yes) is 101
|
||||
|
||||
|
||||
test "Switch with break as the return value of a loop.", ->
|
||||
|
||||
i = 10
|
||||
results = while i > 0
|
||||
i--
|
||||
switch i % 2
|
||||
when 1 then i
|
||||
when 0 then break
|
||||
|
||||
eq results.join(', '), '9, , 7, , 5, , 3, , 1, '
|
||||
|
||||
|
||||
test "Issue #997. Switch doesn't fallthrough.", ->
|
||||
|
||||
val = 1
|
||||
switch true
|
||||
when true
|
||||
if false
|
||||
return 5
|
||||
else
|
||||
val = 2
|
||||
|
||||
eq val, 1
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
nonce = {}
|
||||
|
||||
|
||||
#### Throw
|
||||
# Throw
|
||||
|
||||
test "basic exception throwing", ->
|
||||
throws (-> throw 'error'), 'error'
|
||||
|
||||
|
||||
#### Empty Try/Catch/Finally
|
||||
# Empty Try/Catch/Finally
|
||||
|
||||
test "try can exist alone", ->
|
||||
try
|
||||
|
@ -43,7 +43,7 @@ test "single-line try/catch/finally with empty try, empty catch, empty finally",
|
|||
try catch err then finally
|
||||
|
||||
|
||||
#### Try/Catch/Finally as an Expression
|
||||
# Try/Catch/Finally as an Expression
|
||||
|
||||
test "return the result of try when no exception is thrown", ->
|
||||
result = try
|
||||
|
@ -81,7 +81,7 @@ test "optional catch", ->
|
|||
eq nonce, fn()
|
||||
|
||||
|
||||
#### Try/Catch/Finally Interaction With Other Constructs
|
||||
# Try/Catch/Finally Interaction With Other Constructs
|
||||
|
||||
test "try/catch with empty catch as last statement in a function body", ->
|
||||
fn = ->
|
||||
|
|
|
@ -21,7 +21,7 @@ test "multiple semicolon-separated statements in parentheticals", ->
|
|||
eq nonce, (1; 2; nonce)
|
||||
eq nonce, (-> return (1; 2; nonce))()
|
||||
|
||||
#### Line Continuation
|
||||
# Line Continuation
|
||||
|
||||
# Property Access
|
||||
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
# * Explicit Returns
|
||||
|
||||
# shared identity function
|
||||
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
|
||||
id = (_) -> if arguments.length is 1 then _ else [arguments...]
|
||||
|
||||
|
||||
test "basic argument passing", ->
|
||||
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
|
@ -18,7 +20,9 @@ test "basic argument passing", ->
|
|||
eq a, (id a)
|
||||
eq c, (id a, b, c)[2]
|
||||
|
||||
|
||||
test "passing arguments on separate lines", ->
|
||||
|
||||
a = {}
|
||||
b = {}
|
||||
c = {}
|
||||
|
@ -37,7 +41,9 @@ test "passing arguments on separate lines", ->
|
|||
eq b,
|
||||
(id b)
|
||||
|
||||
|
||||
test "optional parens can be used in a nested fashion", ->
|
||||
|
||||
call = (func) -> func()
|
||||
add = (a,b) -> a + b
|
||||
result = call ->
|
||||
|
@ -45,7 +51,9 @@ test "optional parens can be used in a nested fashion", ->
|
|||
add 5, 5
|
||||
ok result is 10
|
||||
|
||||
|
||||
test "hanging commas and semicolons in argument list", ->
|
||||
|
||||
fn = () -> arguments.length
|
||||
eq 2, fn(0,1,)
|
||||
eq 3, fn 0, 1,
|
||||
|
@ -58,24 +66,32 @@ test "hanging commas and semicolons in argument list", ->
|
|||
throws -> CoffeeScript.compile "fn(,0)"
|
||||
throws -> CoffeeScript.compile "fn(;0)"
|
||||
|
||||
func = ->
|
||||
return if true
|
||||
eq undefined, func()
|
||||
|
||||
result = ("hello".slice) 3
|
||||
ok result is 'lo'
|
||||
test "function invocation", ->
|
||||
|
||||
# And even with strange things like this:
|
||||
funcs = [((x) -> x), ((x) -> x * x)]
|
||||
result = funcs[1] 5
|
||||
ok result is 25
|
||||
func = ->
|
||||
return if true
|
||||
eq undefined, func()
|
||||
|
||||
# More fun with optional parens.
|
||||
fn = (arg) -> arg
|
||||
ok fn(fn {prop: 101}).prop is 101
|
||||
result = ("hello".slice) 3
|
||||
ok result is 'lo'
|
||||
|
||||
|
||||
test "And even with strange things like this:", ->
|
||||
|
||||
funcs = [((x) -> x), ((x) -> x * x)]
|
||||
result = funcs[1] 5
|
||||
ok result is 25
|
||||
|
||||
|
||||
test "More fun with optional parens.", ->
|
||||
|
||||
fn = (arg) -> arg
|
||||
ok fn(fn {prop: 101}).prop is 101
|
||||
|
||||
okFunc = (f) -> ok(f())
|
||||
okFunc -> true
|
||||
|
||||
okFunc = (f) -> ok(f())
|
||||
okFunc -> true
|
||||
|
||||
test "chained function calls", ->
|
||||
nonce = {}
|
||||
|
@ -84,31 +100,39 @@ test "chained function calls", ->
|
|||
eq nonce, identityWrap(identityWrap(nonce))()()
|
||||
eq nonce, (identityWrap identityWrap nonce)()()
|
||||
|
||||
# Multi-blocks with optional parens.
|
||||
result = fn( ->
|
||||
fn ->
|
||||
"Wrapped"
|
||||
)
|
||||
ok result()() is 'Wrapped'
|
||||
|
||||
# method calls
|
||||
fnId = (fn) -> -> fn.apply this, arguments
|
||||
math = {
|
||||
add: (a, b) -> a + b
|
||||
anonymousAdd: (a, b) -> a + b
|
||||
fastAdd: fnId (a, b) -> a + b
|
||||
}
|
||||
ok math.add(5, 5) is 10
|
||||
ok math.anonymousAdd(10, 10) is 20
|
||||
ok math.fastAdd(20, 20) is 40
|
||||
test "Multi-blocks with optional parens.", ->
|
||||
|
||||
fn = (arg) -> arg
|
||||
result = fn( ->
|
||||
fn ->
|
||||
"Wrapped"
|
||||
)
|
||||
ok result()() is 'Wrapped'
|
||||
|
||||
|
||||
test "method calls", ->
|
||||
|
||||
fnId = (fn) -> -> fn.apply this, arguments
|
||||
math = {
|
||||
add: (a, b) -> a + b
|
||||
anonymousAdd: (a, b) -> a + b
|
||||
fastAdd: fnId (a, b) -> a + b
|
||||
}
|
||||
ok math.add(5, 5) is 10
|
||||
ok math.anonymousAdd(10, 10) is 20
|
||||
ok math.fastAdd(20, 20) is 40
|
||||
|
||||
|
||||
test "Ensure that functions can have a trailing comma in their argument list", ->
|
||||
|
||||
mult = (x, mids..., y) ->
|
||||
x *= n for n in mids
|
||||
x *= y
|
||||
ok mult(1, 2,) is 2
|
||||
ok mult(1, 2, 3,) is 6
|
||||
ok mult(10, (i for i in [1..6])...) is 7200
|
||||
|
||||
# Ensure that functions can have a trailing comma in their argument list
|
||||
mult = (x, mids..., y) ->
|
||||
x *= n for n in mids
|
||||
x *= y
|
||||
ok mult(1, 2,) is 2
|
||||
ok mult(1, 2, 3,) is 6
|
||||
ok mult(10, (i for i in [1..6])...) is 7200
|
||||
|
||||
test "`@` and `this` should both be able to invoke a method", ->
|
||||
nonce = {}
|
||||
|
@ -118,133 +142,167 @@ test "`@` and `this` should both be able to invoke a method", ->
|
|||
fn.withAt()
|
||||
fn.withThis()
|
||||
|
||||
# Trying an implicit object call with a trailing function.
|
||||
a = null
|
||||
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
|
||||
meth 'apple', b: 1, a: 13, ->
|
||||
'orange'
|
||||
ok a is '13 apple orange'
|
||||
|
||||
# Ensure that empty functions don't return mistaken values.
|
||||
obj =
|
||||
func: (@param, @rest...) ->
|
||||
ok obj.func(101, 102, 103, 104) is undefined
|
||||
ok obj.param is 101
|
||||
ok obj.rest.join(' ') is '102 103 104'
|
||||
test "Trying an implicit object call with a trailing function.", ->
|
||||
|
||||
# Passing multiple functions without paren-wrapping is legal, and should compile.
|
||||
sum = (one, two) -> one() + two()
|
||||
result = sum ->
|
||||
7 + 9
|
||||
, ->
|
||||
1 + 3
|
||||
ok result is 20
|
||||
a = null
|
||||
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
|
||||
meth 'apple', b: 1, a: 13, ->
|
||||
'orange'
|
||||
ok a is '13 apple orange'
|
||||
|
||||
# Implicit call with a trailing if statement as a param.
|
||||
func = -> arguments[1]
|
||||
result = func 'one', if false then 100 else 13
|
||||
ok result is 13
|
||||
|
||||
# Test more function passing:
|
||||
result = sum( ->
|
||||
1 + 2
|
||||
, ->
|
||||
2 + 1
|
||||
)
|
||||
ok result is 6
|
||||
test "Ensure that empty functions don't return mistaken values.", ->
|
||||
|
||||
sum = (a, b) -> a + b
|
||||
result = sum(1
|
||||
, 2)
|
||||
ok result is 3
|
||||
obj =
|
||||
func: (@param, @rest...) ->
|
||||
ok obj.func(101, 102, 103, 104) is undefined
|
||||
ok obj.param is 101
|
||||
ok obj.rest.join(' ') is '102 103 104'
|
||||
|
||||
# Chained blocks, with proper indentation levels:
|
||||
counter =
|
||||
results: []
|
||||
tick: (func) ->
|
||||
@results.push func()
|
||||
this
|
||||
counter
|
||||
.tick ->
|
||||
3
|
||||
.tick ->
|
||||
2
|
||||
.tick ->
|
||||
1
|
||||
arrayEq [3,2,1], counter.results
|
||||
|
||||
# This is a crazy one.
|
||||
x = (obj, func) -> func obj
|
||||
ident = (x) -> x
|
||||
result = x {one: ident 1}, (obj) ->
|
||||
inner = ident(obj)
|
||||
ident inner
|
||||
ok result.one is 1
|
||||
test "Passing multiple functions without paren-wrapping is legal, and should compile.", ->
|
||||
|
||||
# More paren compilation tests:
|
||||
reverse = (obj) -> obj.reverse()
|
||||
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
|
||||
sum = (one, two) -> one() + two()
|
||||
result = sum ->
|
||||
7 + 9
|
||||
, ->
|
||||
1 + 3
|
||||
ok result is 20
|
||||
|
||||
# Test for inline functions with parentheses and implicit calls.
|
||||
combine = (func, num) -> func() * num
|
||||
result = combine (-> 1 + 2), 3
|
||||
ok result is 9
|
||||
|
||||
# Test for calls/parens/multiline-chains.
|
||||
f = (x) -> x
|
||||
result = (f 1).toString()
|
||||
.length
|
||||
ok result is 1
|
||||
test "Implicit call with a trailing if statement as a param.", ->
|
||||
|
||||
# Test implicit calls in functions in parens:
|
||||
result = ((val) ->
|
||||
[].push val
|
||||
val
|
||||
)(10)
|
||||
ok result is 10
|
||||
func = -> arguments[1]
|
||||
result = func 'one', if false then 100 else 13
|
||||
ok result is 13
|
||||
|
||||
# Ensure that chained calls with indented implicit object literals below are
|
||||
# alright.
|
||||
result = null
|
||||
obj =
|
||||
method: (val) -> this
|
||||
second: (hash) -> result = hash.three
|
||||
obj
|
||||
.method(
|
||||
101
|
||||
).second(
|
||||
one:
|
||||
two: 2
|
||||
three: 3
|
||||
|
||||
test "Test more function passing:", ->
|
||||
|
||||
sum = (one, two) -> one() + two()
|
||||
|
||||
result = sum( ->
|
||||
1 + 2
|
||||
, ->
|
||||
2 + 1
|
||||
)
|
||||
eq result, 3
|
||||
ok result is 6
|
||||
|
||||
# Test newline-supressed call chains with nested functions.
|
||||
obj =
|
||||
call: -> this
|
||||
func = ->
|
||||
sum = (a, b) -> a + b
|
||||
result = sum(1
|
||||
, 2)
|
||||
ok result is 3
|
||||
|
||||
|
||||
test "Chained blocks, with proper indentation levels:", ->
|
||||
|
||||
counter =
|
||||
results: []
|
||||
tick: (func) ->
|
||||
@results.push func()
|
||||
this
|
||||
counter
|
||||
.tick ->
|
||||
3
|
||||
.tick ->
|
||||
2
|
||||
.tick ->
|
||||
1
|
||||
arrayEq [3,2,1], counter.results
|
||||
|
||||
|
||||
test "This is a crazy one.", ->
|
||||
|
||||
x = (obj, func) -> func obj
|
||||
ident = (x) -> x
|
||||
result = x {one: ident 1}, (obj) ->
|
||||
inner = ident(obj)
|
||||
ident inner
|
||||
ok result.one is 1
|
||||
|
||||
|
||||
test "More paren compilation tests:", ->
|
||||
|
||||
reverse = (obj) -> obj.reverse()
|
||||
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
|
||||
|
||||
|
||||
test "Test for inline functions with parentheses and implicit calls.", ->
|
||||
|
||||
combine = (func, num) -> func() * num
|
||||
result = combine (-> 1 + 2), 3
|
||||
ok result is 9
|
||||
|
||||
|
||||
test "Test for calls/parens/multiline-chains.", ->
|
||||
|
||||
f = (x) -> x
|
||||
result = (f 1).toString()
|
||||
.length
|
||||
ok result is 1
|
||||
|
||||
|
||||
test "Test implicit calls in functions in parens:", ->
|
||||
|
||||
result = ((val) ->
|
||||
[].push val
|
||||
val
|
||||
)(10)
|
||||
ok result is 10
|
||||
|
||||
|
||||
test "Ensure that chained calls with indented implicit object literals below are alright.", ->
|
||||
|
||||
result = null
|
||||
obj =
|
||||
method: (val) -> this
|
||||
second: (hash) -> result = hash.three
|
||||
obj
|
||||
.call ->
|
||||
one two
|
||||
.call ->
|
||||
three four
|
||||
101
|
||||
eq func(), 101
|
||||
.method(
|
||||
101
|
||||
).second(
|
||||
one:
|
||||
two: 2
|
||||
three: 3
|
||||
)
|
||||
eq result, 3
|
||||
|
||||
# Implicit objects with number arguments.
|
||||
func = (x, y) -> y
|
||||
obj =
|
||||
prop: func "a", 1
|
||||
ok obj.prop is 1
|
||||
|
||||
# Non-spaced unary and binary operators should cause a function call.
|
||||
func = (val) -> val + 1
|
||||
ok (func +5) is 6
|
||||
ok (func -5) is -4
|
||||
test "Test newline-supressed call chains with nested functions.", ->
|
||||
|
||||
# Prefix unary assignment operators are allowed in parenless calls.
|
||||
val = 5
|
||||
ok (func --val) is 5
|
||||
obj =
|
||||
call: -> this
|
||||
func = ->
|
||||
obj
|
||||
.call ->
|
||||
one two
|
||||
.call ->
|
||||
three four
|
||||
101
|
||||
eq func(), 101
|
||||
|
||||
|
||||
test "Implicit objects with number arguments.", ->
|
||||
|
||||
func = (x, y) -> y
|
||||
obj =
|
||||
prop: func "a", 1
|
||||
ok obj.prop is 1
|
||||
|
||||
|
||||
test "Non-spaced unary and binary operators should cause a function call.", ->
|
||||
|
||||
func = (val) -> val + 1
|
||||
ok (func +5) is 6
|
||||
ok (func -5) is -4
|
||||
|
||||
|
||||
test "Prefix unary assignment operators are allowed in parenless calls.", ->
|
||||
|
||||
func = (val) -> val + 1
|
||||
val = 5
|
||||
ok (func --val) is 5
|
||||
|
||||
test "#855: execution context for `func arr...` should be `null`", ->
|
||||
contextTest = -> eq @, global
|
||||
|
@ -262,13 +320,14 @@ test "#904: Destructuring function arguments with same-named variables in scope"
|
|||
eq nonce, a
|
||||
eq nonce, b
|
||||
|
||||
obj =
|
||||
index: 0
|
||||
0: {method: -> this is obj[0]}
|
||||
ok obj[obj.index++].method([]...), 'should cache base value'
|
||||
|
||||
test "caching base value", ->
|
||||
|
||||
obj =
|
||||
index: 0
|
||||
0: {method: -> this is obj[0]}
|
||||
ok obj[obj.index++].method([]...)
|
||||
|
||||
#### Splats in Function Invocations
|
||||
|
||||
test "passing splats to functions", ->
|
||||
arrayEq [0..4], id id [0..4]...
|
||||
|
@ -280,33 +339,40 @@ test "passing splats to functions", ->
|
|||
arrayEq [2..6], others
|
||||
eq 7, last
|
||||
|
||||
#894: Splatting against constructor-chained functions.
|
||||
x = null
|
||||
class Foo
|
||||
bar: (y) -> x = y
|
||||
new Foo().bar([101]...)
|
||||
eq x, 101
|
||||
|
||||
# Functions with splats being called with too few arguments.
|
||||
pen = null
|
||||
method = (first, variable..., penultimate, ultimate) ->
|
||||
pen = penultimate
|
||||
method 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
ok pen is 8
|
||||
method 1, 2, 3
|
||||
ok pen is 2
|
||||
method 1, 2
|
||||
ok pen is 2
|
||||
test "Issue 894: Splatting against constructor-chained functions.", ->
|
||||
|
||||
x = null
|
||||
class Foo
|
||||
bar: (y) -> x = y
|
||||
new Foo().bar([101]...)
|
||||
eq x, 101
|
||||
|
||||
|
||||
test "Functions with splats being called with too few arguments.", ->
|
||||
|
||||
pen = null
|
||||
method = (first, variable..., penultimate, ultimate) ->
|
||||
pen = penultimate
|
||||
method 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
ok pen is 8
|
||||
method 1, 2, 3
|
||||
ok pen is 2
|
||||
method 1, 2
|
||||
ok pen is 2
|
||||
|
||||
|
||||
test "splats with super() within classes.", ->
|
||||
|
||||
class Parent
|
||||
meth: (args...) ->
|
||||
args
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums = [3, 2, 1]
|
||||
super nums...
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
# splats with super() within classes.
|
||||
class Parent
|
||||
meth: (args...) ->
|
||||
args
|
||||
class Child extends Parent
|
||||
meth: ->
|
||||
nums = [3, 2, 1]
|
||||
super nums...
|
||||
ok (new Child).meth().join(' ') is '3 2 1'
|
||||
|
||||
test "#1011: passing a splat to a method of a number", ->
|
||||
eq '1011', 11.toString [2]...
|
||||
|
@ -315,12 +381,13 @@ test "#1011: passing a splat to a method of a number", ->
|
|||
eq '1011', (131.0).toString [5]...
|
||||
|
||||
|
||||
#### Implicit Return
|
||||
test "implicit return", ->
|
||||
|
||||
eq ok, new ->
|
||||
ok
|
||||
### Should `return` implicitly ###
|
||||
### even with trailing comments. ###
|
||||
|
||||
eq ok, new ->
|
||||
ok
|
||||
### Should `return` implicitly ###
|
||||
### even with trailing comments. ###
|
||||
|
||||
test "implicit returns with multiple branches", ->
|
||||
nonce = {}
|
||||
|
@ -332,6 +399,7 @@ test "implicit returns with multiple branches", ->
|
|||
nonce
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
test "implicit returns with switches", ->
|
||||
nonce = {}
|
||||
fn = ->
|
||||
|
@ -340,6 +408,7 @@ test "implicit returns with switches", ->
|
|||
else return undefined
|
||||
eq nonce, fn()
|
||||
|
||||
|
||||
test "preserve context when generating closure wrappers for expression conversions", ->
|
||||
nonce = {}
|
||||
obj =
|
||||
|
@ -355,9 +424,7 @@ test "preserve context when generating closure wrappers for expression conversio
|
|||
eq nonce, obj.property
|
||||
|
||||
|
||||
#### Explicit Returns
|
||||
|
||||
test "don't wrap \"pure\" statements in a closure", ->
|
||||
test "don't wrap 'pure' statements in a closure", ->
|
||||
nonce = {}
|
||||
items = [0, 1, 2, 3, nonce, 4, 5]
|
||||
fn = (items) ->
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
# * Parameter Destructuring
|
||||
# * Default Parameters
|
||||
|
||||
#### Function Definition
|
||||
# Function Definition
|
||||
|
||||
x = 1
|
||||
y = {}
|
||||
|
@ -46,7 +46,7 @@ del = -> 5
|
|||
ok del() is 5
|
||||
|
||||
|
||||
#### Bound Function Definition
|
||||
# Bound Function Definition
|
||||
|
||||
obj =
|
||||
bound: ->
|
||||
|
@ -64,7 +64,7 @@ ok obj isnt obj.unbound()
|
|||
eq obj, obj.nested()
|
||||
|
||||
|
||||
#### Parameter List Features
|
||||
# Parameter List Features
|
||||
|
||||
test "splats", ->
|
||||
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{starts, ends, compact, count, merge, extend, flatten, del, last} = CoffeeScript.helpers
|
||||
|
||||
|
||||
#### `starts`
|
||||
# `starts`
|
||||
|
||||
test "the `starts` helper tests if a string starts with another string", ->
|
||||
ok starts('01234', '012')
|
||||
|
@ -16,7 +16,7 @@ test "the `starts` helper can take an optional offset", ->
|
|||
ok not starts('01234', '01', 1)
|
||||
|
||||
|
||||
#### `ends`
|
||||
# `ends`
|
||||
|
||||
test "the `ends` helper tests if a string ends with another string", ->
|
||||
ok ends('01234', '234')
|
||||
|
@ -27,7 +27,7 @@ test "the `ends` helper can take an optional offset", ->
|
|||
ok not ends('01234', '234', 6)
|
||||
|
||||
|
||||
#### `compact`
|
||||
# `compact`
|
||||
|
||||
test "the `compact` helper removes falsey values from an array, preserves truthy ones", ->
|
||||
allValues = [1, 0, false, obj={}, [], '', ' ', -1, null, undefined, true]
|
||||
|
@ -35,7 +35,7 @@ test "the `compact` helper removes falsey values from an array, preserves truthy
|
|||
arrayEq truthyValues, compact(allValues)
|
||||
|
||||
|
||||
#### `count`
|
||||
# `count`
|
||||
|
||||
test "the `count` helper counts the number of occurances of a string in another string", ->
|
||||
eq 1/0, count('abc', '')
|
||||
|
@ -46,7 +46,7 @@ test "the `count` helper counts the number of occurances of a string in another
|
|||
eq 2, count('abcdabcd','abc')
|
||||
|
||||
|
||||
#### `merge`
|
||||
# `merge`
|
||||
|
||||
test "the `merge` helper makes a new object with all properties of the objects given as its arguments", ->
|
||||
ary = [0, 1, 2, 3, 4]
|
||||
|
@ -58,7 +58,7 @@ test "the `merge` helper makes a new object with all properties of the objects g
|
|||
eq val, merged[key]
|
||||
|
||||
|
||||
#### `extend`
|
||||
# `extend`
|
||||
|
||||
test "the `extend` helper performs a shallow copy", ->
|
||||
ary = [0, 1, 2, 3]
|
||||
|
@ -69,7 +69,7 @@ test "the `extend` helper performs a shallow copy", ->
|
|||
eq 2, obj[2]
|
||||
|
||||
|
||||
#### `flatten`
|
||||
# `flatten`
|
||||
|
||||
test "the `flatten` helper flattens an array", ->
|
||||
success = yes
|
||||
|
@ -77,7 +77,7 @@ test "the `flatten` helper flattens an array", ->
|
|||
ok success
|
||||
|
||||
|
||||
#### `del`
|
||||
# `del`
|
||||
|
||||
test "the `del` helper deletes a property from an object and returns the deleted value", ->
|
||||
obj = [0, 1, 2]
|
||||
|
@ -85,7 +85,7 @@ test "the `del` helper deletes a property from an object and returns the deleted
|
|||
ok 1 not of obj
|
||||
|
||||
|
||||
#### `last`
|
||||
# `last`
|
||||
|
||||
test "the `last` helper returns the last item of an array-like object", ->
|
||||
ary = [0, 1, 2, 3, 4]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# * String Interpolation
|
||||
# * Regular Expression Interpolation
|
||||
|
||||
#### String Interpolation
|
||||
# String Interpolation
|
||||
|
||||
# TODO: refactor string interpolation tests
|
||||
|
||||
|
@ -109,7 +109,7 @@ eq 'multiline nested "interpolations" work', """multiline #{
|
|||
} work"""
|
||||
|
||||
|
||||
#### Regular Expression Interpolation
|
||||
# Regular Expression Interpolation
|
||||
|
||||
# TODO: improve heregex interpolation tests
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
# * Non-Integer Literals
|
||||
|
||||
|
||||
#### Decimal Integer Literals
|
||||
# Decimal Integer Literals
|
||||
|
||||
test "call methods directly on numbers", ->
|
||||
eq 4, 4.valueOf()
|
||||
|
@ -23,7 +23,7 @@ eq Number::toString, 42['toString']
|
|||
eq Number::toString, 42.toString
|
||||
|
||||
|
||||
#### Non-Integer Literals
|
||||
# Non-Integer Literals
|
||||
|
||||
# Decimal number literals.
|
||||
value = .25 + .75
|
||||
|
|
|
@ -59,7 +59,7 @@ test "use `::` operator on keywords `this` and `@`", ->
|
|||
eq nonce, obj.withThis()
|
||||
|
||||
|
||||
#### Existential Operator (Binary)
|
||||
# Existential Operator (Binary)
|
||||
|
||||
test "binary existential operator", ->
|
||||
nonce = {}
|
||||
|
@ -91,7 +91,7 @@ test "binary existential operator with negative number", ->
|
|||
eq -1, a
|
||||
|
||||
|
||||
#### Existential Operator (Unary)
|
||||
# Existential Operator (Unary)
|
||||
|
||||
test "postfix existential operator", ->
|
||||
ok (if nonexistent? then false else true)
|
||||
|
@ -114,7 +114,7 @@ test "postfix existential operator on expressions", ->
|
|||
eq true, (1 or 0)?, true
|
||||
|
||||
|
||||
#### `is`,`isnt`,`==`,`!=`
|
||||
# `is`,`isnt`,`==`,`!=`
|
||||
|
||||
test "`==` and `is` should be interchangeable", ->
|
||||
a = b = 1
|
||||
|
@ -130,7 +130,7 @@ test "`!=` and `isnt` should be interchangeable", ->
|
|||
ok a isnt b
|
||||
|
||||
|
||||
#### [not] in/of
|
||||
# [not] in/of
|
||||
|
||||
# - `in` should check if an array contains a value using `indexOf`
|
||||
# - `of` should check if a property is defined on an object using `in`
|
||||
|
@ -185,7 +185,7 @@ test "#768: `in` should preserve evaluation order", ->
|
|||
eq 3, share
|
||||
|
||||
|
||||
#### Chained Comparison
|
||||
# Chained Comparison
|
||||
|
||||
test "chainable operators", ->
|
||||
ok 100 > 10 > 1 > 0 > -1
|
||||
|
|
|
@ -35,7 +35,7 @@ test "#584: slashes are allowed unescaped in character classes", ->
|
|||
ok /^a\/[/]b$/.test 'a//b'
|
||||
|
||||
|
||||
#### Heregexe(n|s)
|
||||
# Heregexe(n|s)
|
||||
|
||||
test "a heregex will ignore whitespace and comments", ->
|
||||
eq /^I'm\x20+[a]\s+Heregex?\/\/\//gim + '', ///
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# shared array
|
||||
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
#### Slicing
|
||||
# Slicing
|
||||
|
||||
test "basic slicing", ->
|
||||
arrayEq [7, 8, 9] , shared[7..9]
|
||||
|
@ -53,7 +53,7 @@ test "string slicing", ->
|
|||
ok str[-5..] is "vwxyz"
|
||||
|
||||
|
||||
#### Splicing
|
||||
# Splicing
|
||||
|
||||
test "basic splicing", ->
|
||||
ary = [0..9]
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# * Soaked Function Invocation
|
||||
|
||||
|
||||
#### Soaked Property Access
|
||||
# Soaked Property Access
|
||||
|
||||
test "soaked property access", ->
|
||||
nonce = {}
|
||||
|
@ -73,7 +73,7 @@ test "operations on soaked properties", ->
|
|||
eq yes, delete a?.b.c
|
||||
|
||||
|
||||
#### Soaked Method Invocation
|
||||
# Soaked Method Invocation
|
||||
|
||||
test "soaked method invocation", ->
|
||||
nonce = {}
|
||||
|
@ -96,7 +96,7 @@ test "#733", ->
|
|||
eq a.b?.c?([2, 3]...), 2
|
||||
|
||||
|
||||
#### Soaked Function Invocation
|
||||
# Soaked Function Invocation
|
||||
|
||||
test "soaked function invocation", ->
|
||||
nonce = {}
|
||||
|
|
Loading…
Reference in a new issue