mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
76c076db55
The following is now allowed: o = a: 1 b: 2 "#{'c'}": 3 "#{'d'}": 4 e: 5 "#{'f'}": 6 g: 7 It compiles to: o = ( obj = { a: 1, b: 2 }, obj["" + 'c'] = 3, obj["" + 'd'] = 4, obj.e = 5, obj["" + 'f'] = 6, obj.g = 7, obj ); - Closes #3039. Empty interpolations in object keys are now _supposed_ to be allowed. - Closes #1131. No need to improve error messages for attempted key interpolation anymore. - Implementing this required fixing the following bug: `("" + a): 1` used to error out on the colon, saying "unexpected colon". But really, it is the attempted object key that is unexpected. Now the error is on the opening parenthesis instead. - However, the above fix broke some error message tests for regexes. The easiest way to fix this was to make a seemingly unrelated change: The error messages for unexpected identifiers, numbers, strings and regexes now say for example 'unexpected string' instead of 'unexpected """some #{really long} string"""'. In other words, the tag _name_ is used instead of the tag _value_. This was way easier to implement, and is more helpful to the user. Using the tag value is good for operators, reserved words and the like, but not for tokens which can contain any text. For example, 'unexpected identifier' is better than 'unexpected expected' (if a variable called 'expected' was used erraneously). - While writing tests for the above point I found a few minor bugs with string locations which have been fixed.
896 lines
16 KiB
CoffeeScript
896 lines
16 KiB
CoffeeScript
# Classes
|
|
# -------
|
|
|
|
# * Class Definition
|
|
# * Class Instantiation
|
|
# * Inheritance and Super
|
|
|
|
test "classes with a four-level inheritance chain", ->
|
|
|
|
class Base
|
|
func: (string) ->
|
|
"zero/#{string}"
|
|
|
|
@static: (string) ->
|
|
"static/#{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::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' prototypes", ->
|
|
|
|
TopClass = ->
|
|
TopClass::func = (arg) ->
|
|
'top-' + arg
|
|
|
|
SuperClass = ->
|
|
SuperClass extends TopClass
|
|
SuperClass::func = (arg) ->
|
|
super 'super-' + arg
|
|
|
|
SubClass = ->
|
|
SubClass extends SuperClass
|
|
SubClass::func = ->
|
|
super 'sub'
|
|
|
|
eq (new SubClass).func(), 'top-super-sub'
|
|
|
|
|
|
test "'@' referring to the current instance, and not being coerced into a call", ->
|
|
|
|
class ClassName
|
|
amI: ->
|
|
@ instanceof ClassName
|
|
|
|
obj = new ClassName
|
|
ok obj.amI()
|
|
|
|
|
|
test "super() calls in constructors of classes that are defined as object properties", ->
|
|
|
|
class Hive
|
|
constructor: (name) -> @name = name
|
|
|
|
class Hive.Bee extends Hive
|
|
constructor: (name) -> super
|
|
|
|
maya = new Hive.Bee 'Maya'
|
|
ok maya.name is 'Maya'
|
|
|
|
|
|
test "classes with JS-keyword properties", ->
|
|
|
|
class Class
|
|
class: 'class'
|
|
name: -> @class
|
|
|
|
instance = new Class
|
|
ok instance.class is 'class'
|
|
ok instance.name() is 'class'
|
|
|
|
|
|
test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->
|
|
|
|
class Dog
|
|
constructor: (name) ->
|
|
@name = name
|
|
|
|
bark: =>
|
|
"#{@name} woofs!"
|
|
|
|
@static = =>
|
|
new this('Dog')
|
|
|
|
spark = new Dog('Spark')
|
|
fido = new Dog('Fido')
|
|
fido.bark = spark.bark
|
|
|
|
ok fido.bark() is 'Spark woofs!'
|
|
|
|
obj = func: Dog.static
|
|
|
|
ok obj.func().name is 'Dog'
|
|
|
|
|
|
test "a bound function in a bound function", ->
|
|
|
|
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'
|
|
|
|
|
|
test "contructor called with varargs", ->
|
|
|
|
class Connection
|
|
constructor: (one, two, three) ->
|
|
[@one, @two, @three] = [one, two, three]
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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'
|
|
|
|
instance = new obj.klass
|
|
ok instance.method() is 'value'
|
|
|
|
|
|
test "Implicit objects as static properties", ->
|
|
|
|
class Static
|
|
@static =
|
|
one: 1
|
|
two: 2
|
|
|
|
ok Static.static.one is 1
|
|
ok Static.static.two is 2
|
|
|
|
|
|
test "nothing classes", ->
|
|
|
|
c = class
|
|
ok c instanceof Function
|
|
|
|
|
|
test "classes with static-level implicit objects", ->
|
|
|
|
class A
|
|
@static = one: 1
|
|
two: 2
|
|
|
|
class B
|
|
@static = one: 1,
|
|
two: 2
|
|
|
|
eq A.static.one, 1
|
|
eq A.static.two, undefined
|
|
eq (new A).two, 2
|
|
|
|
eq B.static.one, 1
|
|
eq B.static.two, 2
|
|
eq (new B).two, undefined
|
|
|
|
|
|
test "classes with value'd constructors", ->
|
|
|
|
counter = 0
|
|
classMaker = ->
|
|
inner = ++counter
|
|
->
|
|
@value = inner
|
|
|
|
class One
|
|
constructor: classMaker()
|
|
|
|
class Two
|
|
constructor: classMaker()
|
|
|
|
eq (new One).value, 1
|
|
eq (new Two).value, 2
|
|
eq (new One).value, 1
|
|
eq (new Two).value, 2
|
|
|
|
|
|
test "executable class bodies", ->
|
|
|
|
class A
|
|
if true
|
|
b: 'b'
|
|
else
|
|
c: 'c'
|
|
|
|
a = new A
|
|
|
|
eq a.b, 'b'
|
|
eq a.c, undefined
|
|
|
|
|
|
test "#2502: parenthesizing inner object values", ->
|
|
|
|
class A
|
|
category: (type: 'string')
|
|
sections: (type: 'number', default: 0)
|
|
|
|
eq (new A).category.type, 'string'
|
|
|
|
eq (new A).sections.default, 0
|
|
|
|
|
|
test "conditional prototype property assignment", ->
|
|
debug = false
|
|
|
|
class Person
|
|
if debug
|
|
age: -> 10
|
|
else
|
|
age: -> 20
|
|
|
|
eq (new Person).age(), 20
|
|
|
|
|
|
test "mild metaprogramming", ->
|
|
|
|
class Base
|
|
@attr: (name) ->
|
|
@::[name] = (val) ->
|
|
if arguments.length > 0
|
|
@["_#{name}"] = val
|
|
else
|
|
@["_#{name}"]
|
|
|
|
class Robot extends Base
|
|
@attr 'power'
|
|
@attr 'speed'
|
|
|
|
robby = new Robot
|
|
|
|
ok robby.power() is undefined
|
|
|
|
robby.power 11
|
|
robby.speed Infinity
|
|
|
|
eq robby.power(), 11
|
|
eq robby.speed(), Infinity
|
|
|
|
|
|
test "namespaced classes do not reserve their function name in outside scope", ->
|
|
|
|
one = {}
|
|
two = {}
|
|
|
|
class one.Klass
|
|
@label = "one"
|
|
|
|
class two.Klass
|
|
@label = "two"
|
|
|
|
eq typeof Klass, 'undefined'
|
|
eq one.Klass.label, 'one'
|
|
eq two.Klass.label, 'two'
|
|
|
|
|
|
test "nested classes", ->
|
|
|
|
class Outer
|
|
constructor: ->
|
|
@label = 'outer'
|
|
|
|
class @Inner
|
|
constructor: ->
|
|
@label = 'inner'
|
|
|
|
eq (new Outer).label, 'outer'
|
|
eq (new Outer.Inner).label, 'inner'
|
|
|
|
|
|
test "variables in constructor bodies are correctly scoped", ->
|
|
|
|
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
|
|
|
|
|
|
test "Issue #924: Static methods in nested classes", ->
|
|
|
|
class A
|
|
@B: class
|
|
@c = -> 5
|
|
|
|
eq A.B.c(), 5
|
|
|
|
|
|
test "`class extends this`", ->
|
|
|
|
class A
|
|
func: -> 'A'
|
|
|
|
B = null
|
|
makeClass = ->
|
|
B = class extends this
|
|
func: -> super + ' 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
|
|
|
|
|
|
test "`new` works against bare function", ->
|
|
|
|
eq Date, new ->
|
|
eq this, new => this
|
|
Date
|
|
|
|
|
|
test "#1182: a subclass should be able to set its constructor to an external function", ->
|
|
ctor = ->
|
|
@val = 1
|
|
class A
|
|
class B extends A
|
|
constructor: ctor
|
|
eq (new B).val, 1
|
|
|
|
test "#1182: external constructors continued", ->
|
|
ctor = ->
|
|
class A
|
|
class B extends A
|
|
method: ->
|
|
constructor: ctor
|
|
ok B::method
|
|
|
|
test "#1313: misplaced __extends", ->
|
|
nonce = {}
|
|
class A
|
|
class B extends A
|
|
prop: nonce
|
|
constructor: ->
|
|
eq nonce, B::prop
|
|
|
|
test "#1182: execution order needs to be considered as well", ->
|
|
counter = 0
|
|
makeFn = (n) -> eq n, ++counter; ->
|
|
class B extends (makeFn 1)
|
|
@B: makeFn 2
|
|
constructor: makeFn 3
|
|
|
|
test "#1182: external constructors with bound functions", ->
|
|
fn = ->
|
|
{one: 1}
|
|
this
|
|
class B
|
|
class A
|
|
constructor: fn
|
|
method: => this instanceof A
|
|
ok (new A).method.call(new B)
|
|
|
|
test "#1372: bound class methods with reserved names", ->
|
|
class C
|
|
delete: =>
|
|
ok C::delete
|
|
|
|
test "#1380: `super` with reserved names", ->
|
|
class C
|
|
do: -> super
|
|
ok C::do
|
|
|
|
class B
|
|
0: -> super
|
|
ok B::[0]
|
|
|
|
test "#1464: bound class methods should keep context", ->
|
|
nonce = {}
|
|
nonce2 = {}
|
|
class C
|
|
constructor: (@id) ->
|
|
@boundStaticColon: => new this(nonce)
|
|
@boundStaticEqual= => new this(nonce2)
|
|
eq nonce, C.boundStaticColon().id
|
|
eq nonce2, C.boundStaticEqual().id
|
|
|
|
test "#1009: classes with reserved words as determined names", -> (->
|
|
eq 'function', typeof (class @for)
|
|
ok not /\beval\b/.test (class @eval).toString()
|
|
ok not /\barguments\b/.test (class @arguments).toString()
|
|
).call {}
|
|
|
|
test "#1482: classes can extend expressions", ->
|
|
id = (x) -> x
|
|
nonce = {}
|
|
class A then nonce: nonce
|
|
class B extends id A
|
|
eq nonce, (new B).nonce
|
|
|
|
test "#1598: super works for static methods too", ->
|
|
|
|
class Parent
|
|
method: ->
|
|
'NO'
|
|
@method: ->
|
|
'yes'
|
|
|
|
class Child extends Parent
|
|
@method: ->
|
|
'pass? ' + super
|
|
|
|
eq Child.method(), 'pass? yes'
|
|
|
|
test "#1842: Regression with bound functions within bound class methods", ->
|
|
|
|
class Store
|
|
@bound: =>
|
|
do =>
|
|
eq this, Store
|
|
|
|
Store.bound()
|
|
|
|
# And a fancier case:
|
|
|
|
class Store
|
|
|
|
eq this, Store
|
|
|
|
@bound: =>
|
|
do =>
|
|
eq this, Store
|
|
|
|
@unbound: ->
|
|
eq this, Store
|
|
|
|
instance: =>
|
|
ok this instanceof Store
|
|
|
|
Store.bound()
|
|
Store.unbound()
|
|
(new Store).instance()
|
|
|
|
test "#1876: Class @A extends A", ->
|
|
class A
|
|
class @A extends A
|
|
|
|
ok (new @A) instanceof A
|
|
|
|
test "#1813: Passing class definitions as expressions", ->
|
|
ident = (x) -> x
|
|
|
|
result = ident class A then x = 1
|
|
|
|
eq result, A
|
|
|
|
result = ident class B extends A
|
|
x = 1
|
|
|
|
eq result, B
|
|
|
|
test "#1966: external constructors should produce their return value", ->
|
|
ctor = -> {}
|
|
class A then constructor: ctor
|
|
ok (new A) not instanceof A
|
|
|
|
test "#1980: regression with an inherited class with static function members", ->
|
|
|
|
class A
|
|
|
|
class B extends A
|
|
@static: => 'value'
|
|
|
|
eq B.static(), 'value'
|
|
|
|
test "#1534: class then 'use strict'", ->
|
|
# [14.1 Directive Prologues and the Use Strict Directive](http://es5.github.com/#x14.1)
|
|
nonce = {}
|
|
error = 'do -> ok this'
|
|
strictTest = "do ->'use strict';#{error}"
|
|
return unless (try CoffeeScript.run strictTest, bare: yes catch e then nonce) is nonce
|
|
|
|
throws -> CoffeeScript.run "class then 'use strict';#{error}", bare: yes
|
|
doesNotThrow -> CoffeeScript.run "class then #{error}", bare: yes
|
|
doesNotThrow -> CoffeeScript.run "class then #{error};'use strict'", bare: yes
|
|
|
|
# comments are ignored in the Directive Prologue
|
|
comments = ["""
|
|
class
|
|
### comment ###
|
|
'use strict'
|
|
#{error}""",
|
|
"""
|
|
class
|
|
### comment 1 ###
|
|
### comment 2 ###
|
|
'use strict'
|
|
#{error}""",
|
|
"""
|
|
class
|
|
### comment 1 ###
|
|
### comment 2 ###
|
|
'use strict'
|
|
#{error}
|
|
### comment 3 ###"""
|
|
]
|
|
throws (-> CoffeeScript.run comment, bare: yes) for comment in comments
|
|
|
|
# [ES5 §14.1](http://es5.github.com/#x14.1) allows for other directives
|
|
directives = ["""
|
|
class
|
|
'directive 1'
|
|
'use strict'
|
|
#{error}""",
|
|
"""
|
|
class
|
|
'use strict'
|
|
'directive 2'
|
|
#{error}""",
|
|
"""
|
|
class
|
|
### comment 1 ###
|
|
'directive 1'
|
|
'use strict'
|
|
#{error}""",
|
|
"""
|
|
class
|
|
### comment 1 ###
|
|
'directive 1'
|
|
### comment 2 ###
|
|
'use strict'
|
|
#{error}"""
|
|
]
|
|
throws (-> CoffeeScript.run directive, bare: yes) for directive in directives
|
|
|
|
test "#2052: classes should work in strict mode", ->
|
|
try
|
|
do ->
|
|
'use strict'
|
|
class A
|
|
catch e
|
|
ok no
|
|
|
|
test "directives in class with extends ", ->
|
|
strictTest = """
|
|
class extends Object
|
|
### comment ###
|
|
'use strict'
|
|
do -> eq this, undefined
|
|
"""
|
|
CoffeeScript.run strictTest, bare: yes
|
|
|
|
test "#2630: class bodies can't reference arguments", ->
|
|
throws ->
|
|
CoffeeScript.compile('class Test then arguments')
|
|
|
|
test "#2319: fn class n extends o.p [INDENT] x = 123", ->
|
|
first = ->
|
|
|
|
base = onebase: ->
|
|
|
|
first class OneKeeper extends base.onebase
|
|
one = 1
|
|
one: -> one
|
|
|
|
eq new OneKeeper().one(), 1
|
|
|
|
|
|
test "#2599: other typed constructors should be inherited", ->
|
|
class Base
|
|
constructor: -> return {}
|
|
|
|
class Derived extends Base
|
|
|
|
ok (new Derived) not instanceof Derived
|
|
ok (new Derived) not instanceof Base
|
|
ok (new Base) not instanceof Base
|
|
|
|
test "#2359: extending native objects that use other typed constructors requires defining a constructor", ->
|
|
class BrokenArray extends Array
|
|
method: -> 'no one will call me'
|
|
|
|
brokenArray = new BrokenArray
|
|
ok brokenArray not instanceof BrokenArray
|
|
ok typeof brokenArray.method is 'undefined'
|
|
|
|
class WorkingArray extends Array
|
|
constructor: -> super
|
|
method: -> 'yes!'
|
|
|
|
workingArray = new WorkingArray
|
|
ok workingArray instanceof WorkingArray
|
|
eq 'yes!', workingArray.method()
|
|
|
|
|
|
test "#2782: non-alphanumeric-named bound functions", ->
|
|
class A
|
|
'b:c': =>
|
|
'd'
|
|
|
|
eq (new A)['b:c'](), 'd'
|
|
|
|
|
|
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: ({a}) => 'Bar'
|
|
|
|
eq (new Foo).method({a: 'Bar'}), '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!'
|
|
|
|
test "#3063: Class bodies cannot contain pure statements", ->
|
|
throws -> CoffeeScript.compile """
|
|
class extends S
|
|
return if S.f
|
|
@f: => this
|
|
"""
|
|
|
|
test "#2949: super in static method with reserved name", ->
|
|
class Foo
|
|
@static: -> 'baz'
|
|
|
|
class Bar extends Foo
|
|
@static: -> super
|
|
|
|
eq Bar.static(), 'baz'
|
|
|
|
test "#3232: super in static methods (not object-assigned)", ->
|
|
class Foo
|
|
@baz = -> true
|
|
@qux = -> true
|
|
|
|
class Bar extends Foo
|
|
@baz = -> super
|
|
Bar.qux = -> super
|
|
|
|
ok Bar.baz()
|
|
ok Bar.qux()
|
|
|
|
test "#1392 calling `super` in methods defined on namespaced classes", ->
|
|
class Base
|
|
m: -> 5
|
|
n: -> 4
|
|
namespace =
|
|
A: ->
|
|
B: ->
|
|
namespace.A extends Base
|
|
|
|
namespace.A::m = -> super
|
|
eq 5, (new namespace.A).m()
|
|
namespace.B::m = namespace.A::m
|
|
namespace.A::m = null
|
|
eq 5, (new namespace.B).m()
|
|
|
|
count = 0
|
|
getNamespace = -> count++; namespace
|
|
getNamespace().A::n = -> super
|
|
eq 4, (new namespace.A).n()
|
|
eq 1, count
|
|
|
|
class C
|
|
@a: ->
|
|
@a extends Base
|
|
@a::m = -> super
|
|
eq 5, (new C.a).m()
|
|
|
|
test "dynamic method names and super", ->
|
|
class Base
|
|
@m: -> 6
|
|
m: -> 5
|
|
m2: -> 4.5
|
|
n: -> 4
|
|
A = ->
|
|
A extends Base
|
|
|
|
m = 'm'
|
|
A::[m] = -> super
|
|
m = 'n'
|
|
eq 5, (new A).m()
|
|
|
|
name = -> count++; 'n'
|
|
|
|
count = 0
|
|
A::[name()] = -> super
|
|
eq 4, (new A).n()
|
|
eq 1, count
|
|
|
|
m = 'm'
|
|
m2 = 'm2'
|
|
count = 0
|
|
class B extends Base
|
|
@[name()] = -> super
|
|
@::[m] = -> super
|
|
"#{m2}": -> super
|
|
b = new B
|
|
m = m2 = 'n'
|
|
eq 6, B.m()
|
|
eq 5, b.m()
|
|
eq 4.5, b.m2()
|
|
eq 1, count
|
|
|
|
class C extends B
|
|
m: -> super
|
|
eq 5, (new C).m()
|