/test/classes.coffee

http://github.com/jashkenas/coffee-script · CoffeeScript · 1948 lines · 1446 code · 407 blank · 95 comment · 19 complexity · 25665dc5f64f2605be840e485297332d MD5 · raw file

  1. # Classes
  2. # -------
  3. # * Class Definition
  4. # * Class Instantiation
  5. # * Inheritance and Super
  6. # * ES2015+ Class Interoperability
  7. test "classes with a four-level inheritance chain", ->
  8. class Base
  9. func: (string) ->
  10. "zero/#{string}"
  11. @static: (string) ->
  12. "static/#{string}"
  13. class FirstChild extends Base
  14. func: (string) ->
  15. super('one/') + string
  16. SecondChild = class extends FirstChild
  17. func: (string) ->
  18. super('two/') + string
  19. thirdCtor = ->
  20. @array = [1, 2, 3]
  21. class ThirdChild extends SecondChild
  22. constructor: ->
  23. super()
  24. thirdCtor.call this
  25. # Gratuitous comment for testing.
  26. func: (string) ->
  27. super('three/') + string
  28. result = (new ThirdChild).func 'four'
  29. ok result is 'zero/one/two/three/four'
  30. ok Base.static('word') is 'static/word'
  31. ok (new ThirdChild).array.join(' ') is '1 2 3'
  32. test "constructors with inheritance and super", ->
  33. identity = (f) -> f
  34. class TopClass
  35. constructor: (arg) ->
  36. @prop = 'top-' + arg
  37. class SuperClass extends TopClass
  38. constructor: (arg) ->
  39. identity super 'super-' + arg
  40. class SubClass extends SuperClass
  41. constructor: ->
  42. identity super 'sub'
  43. ok (new SubClass).prop is 'top-super-sub'
  44. test "'super' with accessors", ->
  45. class Base
  46. m: -> 4
  47. n: -> 5
  48. o: -> 6
  49. name = 'o'
  50. class A extends Base
  51. m: -> super()
  52. n: -> super.n()
  53. "#{name}": -> super()
  54. p: -> super[name]()
  55. a = new A
  56. eq 4, a.m()
  57. eq 5, a.n()
  58. eq 6, a.o()
  59. eq 6, a.p()
  60. test "soaked 'super' invocation", ->
  61. class Base
  62. method: -> 2
  63. class A extends Base
  64. method: -> super?()
  65. noMethod: -> super?()
  66. a = new A
  67. eq 2, a.method()
  68. eq undefined, a.noMethod()
  69. name = 'noMethod'
  70. class B extends Base
  71. "#{'method'}": -> super?()
  72. "#{'noMethod'}": -> super?() ? super['method']()
  73. b = new B
  74. eq 2, b.method()
  75. eq 2, b.noMethod()
  76. test "'@' referring to the current instance, and not being coerced into a call", ->
  77. class ClassName
  78. amI: ->
  79. @ instanceof ClassName
  80. obj = new ClassName
  81. ok obj.amI()
  82. test "super() calls in constructors of classes that are defined as object properties", ->
  83. class Hive
  84. constructor: (name) -> @name = name
  85. class Hive.Bee extends Hive
  86. constructor: (name) -> super name
  87. maya = new Hive.Bee 'Maya'
  88. ok maya.name is 'Maya'
  89. test "classes with JS-keyword properties", ->
  90. class Class
  91. class: 'class'
  92. name: -> @class
  93. instance = new Class
  94. ok instance.class is 'class'
  95. ok instance.name() is 'class'
  96. test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->
  97. class Dog
  98. constructor: (name) ->
  99. @name = name
  100. bark: =>
  101. "#{@name} woofs!"
  102. @static = =>
  103. new this('Dog')
  104. spark = new Dog('Spark')
  105. fido = new Dog('Fido')
  106. fido.bark = spark.bark
  107. ok fido.bark() is 'Spark woofs!'
  108. obj = func: Dog.static
  109. ok obj.func().name is 'Dog'
  110. test "a bound function in a bound function", ->
  111. class Mini
  112. num: 10
  113. generate: =>
  114. for i in [1..3]
  115. =>
  116. @num
  117. m = new Mini
  118. eq (func() for func in m.generate()).join(' '), '10 10 10'
  119. test "contructor called with varargs", ->
  120. class Connection
  121. constructor: (one, two, three) ->
  122. [@one, @two, @three] = [one, two, three]
  123. out: ->
  124. "#{@one}-#{@two}-#{@three}"
  125. list = [3, 2, 1]
  126. conn = new Connection list...
  127. ok conn instanceof Connection
  128. ok conn.out() is '3-2-1'
  129. test "calling super and passing along all arguments", ->
  130. class Parent
  131. method: (args...) -> @args = args
  132. class Child extends Parent
  133. method: -> super arguments...
  134. c = new Child
  135. c.method 1, 2, 3, 4
  136. ok c.args.join(' ') is '1 2 3 4'
  137. test "classes wrapped in decorators", ->
  138. func = (klass) ->
  139. klass::prop = 'value'
  140. klass
  141. func class Test
  142. prop2: 'value2'
  143. ok (new Test).prop is 'value'
  144. ok (new Test).prop2 is 'value2'
  145. test "anonymous classes", ->
  146. obj =
  147. klass: class
  148. method: -> 'value'
  149. instance = new obj.klass
  150. ok instance.method() is 'value'
  151. test "Implicit objects as static properties", ->
  152. class Static
  153. @static =
  154. one: 1
  155. two: 2
  156. ok Static.static.one is 1
  157. ok Static.static.two is 2
  158. test "nothing classes", ->
  159. c = class
  160. ok c instanceof Function
  161. test "classes with static-level implicit objects", ->
  162. class A
  163. @static = one: 1
  164. two: 2
  165. class B
  166. @static = one: 1,
  167. two: 2
  168. eq A.static.one, 1
  169. eq A.static.two, undefined
  170. eq (new A).two, 2
  171. eq B.static.one, 1
  172. eq B.static.two, 2
  173. eq (new B).two, undefined
  174. test "classes with value'd constructors", ->
  175. counter = 0
  176. classMaker = ->
  177. inner = ++counter
  178. ->
  179. @value = inner
  180. @
  181. class One
  182. constructor: classMaker()
  183. class Two
  184. constructor: classMaker()
  185. eq (new One).value, 1
  186. eq (new Two).value, 2
  187. eq (new One).value, 1
  188. eq (new Two).value, 2
  189. test "executable class bodies", ->
  190. class A
  191. if true
  192. b: 'b'
  193. else
  194. c: 'c'
  195. a = new A
  196. eq a.b, 'b'
  197. eq a.c, undefined
  198. test "#2502: parenthesizing inner object values", ->
  199. class A
  200. category: (type: 'string')
  201. sections: (type: 'number', default: 0)
  202. eq (new A).category.type, 'string'
  203. eq (new A).sections.default, 0
  204. test "conditional prototype property assignment", ->
  205. debug = false
  206. class Person
  207. if debug
  208. age: -> 10
  209. else
  210. age: -> 20
  211. eq (new Person).age(), 20
  212. test "mild metaprogramming", ->
  213. class Base
  214. @attr: (name) ->
  215. @::[name] = (val) ->
  216. if arguments.length > 0
  217. @["_#{name}"] = val
  218. else
  219. @["_#{name}"]
  220. class Robot extends Base
  221. @attr 'power'
  222. @attr 'speed'
  223. robby = new Robot
  224. ok robby.power() is undefined
  225. robby.power 11
  226. robby.speed Infinity
  227. eq robby.power(), 11
  228. eq robby.speed(), Infinity
  229. test "namespaced classes do not reserve their function name in outside scope", ->
  230. one = {}
  231. two = {}
  232. class one.Klass
  233. @label = "one"
  234. class two.Klass
  235. @label = "two"
  236. eq typeof Klass, 'undefined'
  237. eq one.Klass.label, 'one'
  238. eq two.Klass.label, 'two'
  239. test "nested classes", ->
  240. class Outer
  241. constructor: ->
  242. @label = 'outer'
  243. class @Inner
  244. constructor: ->
  245. @label = 'inner'
  246. eq (new Outer).label, 'outer'
  247. eq (new Outer.Inner).label, 'inner'
  248. test "variables in constructor bodies are correctly scoped", ->
  249. class A
  250. x = 1
  251. constructor: ->
  252. x = 10
  253. y = 20
  254. y = 2
  255. captured: ->
  256. {x, y}
  257. a = new A
  258. eq a.captured().x, 10
  259. eq a.captured().y, 2
  260. test "Issue #924: Static methods in nested classes", ->
  261. class A
  262. @B: class
  263. @c = -> 5
  264. eq A.B.c(), 5
  265. test "`class extends this`", ->
  266. class A
  267. func: -> 'A'
  268. B = null
  269. makeClass = ->
  270. B = class extends this
  271. func: -> super() + ' B'
  272. makeClass.call A
  273. eq (new B()).func(), 'A B'
  274. test "ensure that constructors invoked with splats return a new object", ->
  275. args = [1, 2, 3]
  276. Type = (@args) ->
  277. type = new Type args
  278. ok type and type instanceof Type
  279. ok type.args and type.args instanceof Array
  280. ok v is args[i] for v, i in type.args
  281. Type1 = (@a, @b, @c) ->
  282. type1 = new Type1 args...
  283. ok type1 instanceof Type1
  284. eq type1.constructor, Type1
  285. ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
  286. # Ensure that constructors invoked with splats cache the function.
  287. called = 0
  288. get = -> if called++ then false else class Type
  289. new (get()) args...
  290. test "`new` shouldn't add extra parens", ->
  291. ok new Date().constructor is Date
  292. test "`new` works against bare function", ->
  293. eq Date, new ->
  294. Date
  295. test "`new` works against statement", ->
  296. class A
  297. (new try A) instanceof A
  298. test "#1182: a subclass should be able to set its constructor to an external function", ->
  299. ctor = ->
  300. @val = 1
  301. return
  302. class A
  303. class B extends A
  304. constructor: ctor
  305. eq (new B).val, 1
  306. test "#1182: external constructors continued", ->
  307. ctor = ->
  308. class A
  309. class B extends A
  310. method: ->
  311. constructor: ctor
  312. ok B::method
  313. test "#1313: misplaced __extends", ->
  314. nonce = {}
  315. class A
  316. class B extends A
  317. prop: nonce
  318. constructor: -> super()
  319. eq nonce, B::prop
  320. test "#1182: execution order needs to be considered as well", ->
  321. counter = 0
  322. makeFn = (n) -> eq n, ++counter; ->
  323. class B extends (makeFn 1)
  324. @B: makeFn 2
  325. constructor: makeFn 3
  326. test "#1182: external constructors with bound functions", ->
  327. fn = ->
  328. {one: 1}
  329. this
  330. class B
  331. class A
  332. constructor: fn
  333. method: => this instanceof A
  334. ok (new A).method.call(new B)
  335. test "#1372: bound class methods with reserved names", ->
  336. class C
  337. delete: =>
  338. ok C::delete
  339. test "#1380: `super` with reserved names", ->
  340. class C
  341. do: -> super()
  342. ok C::do
  343. class B
  344. 0: -> super()
  345. ok B::[0]
  346. test "#1464: bound class methods should keep context", ->
  347. nonce = {}
  348. nonce2 = {}
  349. class C
  350. constructor: (@id) ->
  351. @boundStaticColon: => new this(nonce)
  352. @boundStaticEqual= => new this(nonce2)
  353. eq nonce, C.boundStaticColon().id
  354. eq nonce2, C.boundStaticEqual().id
  355. test "#1009: classes with reserved words as determined names", -> (->
  356. eq 'function', typeof (class @for)
  357. ok not /\beval\b/.test (class @eval).toString()
  358. ok not /\barguments\b/.test (class @arguments).toString()
  359. ).call {}
  360. test "#1482: classes can extend expressions", ->
  361. id = (x) -> x
  362. nonce = {}
  363. class A then nonce: nonce
  364. class B extends id A
  365. eq nonce, (new B).nonce
  366. test "#1598: super works for static methods too", ->
  367. class Parent
  368. method: ->
  369. 'NO'
  370. @method: ->
  371. 'yes'
  372. class Child extends Parent
  373. @method: ->
  374. 'pass? ' + super()
  375. eq Child.method(), 'pass? yes'
  376. test "#1842: Regression with bound functions within bound class methods", ->
  377. class Store
  378. @bound: =>
  379. do =>
  380. eq this, Store
  381. Store.bound()
  382. # And a fancier case:
  383. class Store
  384. eq this, Store
  385. @bound: =>
  386. do =>
  387. eq this, Store
  388. @unbound: ->
  389. eq this, Store
  390. instance: =>
  391. ok this instanceof Store
  392. Store.bound()
  393. Store.unbound()
  394. (new Store).instance()
  395. test "#1876: Class @A extends A", ->
  396. class A
  397. class @A extends A
  398. ok (new @A) instanceof A
  399. test "#1813: Passing class definitions as expressions", ->
  400. ident = (x) -> x
  401. result = ident class A then x = 1
  402. eq result, A
  403. result = ident class B extends A
  404. x = 1
  405. eq result, B
  406. test "#1966: external constructors should produce their return value", ->
  407. ctor = -> {}
  408. class A then constructor: ctor
  409. ok (new A) not instanceof A
  410. test "#1980: regression with an inherited class with static function members", ->
  411. class A
  412. class B extends A
  413. @static: => 'value'
  414. eq B.static(), 'value'
  415. test "#1534: class then 'use strict'", ->
  416. # [14.1 Directive Prologues and the Use Strict Directive](http://es5.github.com/#x14.1)
  417. nonce = {}
  418. error = 'do -> ok this'
  419. strictTest = "do ->'use strict';#{error}"
  420. return unless (try CoffeeScript.run strictTest, bare: yes catch e then nonce) is nonce
  421. throws -> CoffeeScript.run "class then 'use strict';#{error}", bare: yes
  422. doesNotThrow -> CoffeeScript.run "class then #{error}", bare: yes
  423. doesNotThrow -> CoffeeScript.run "class then #{error};'use strict'", bare: yes
  424. # comments are ignored in the Directive Prologue
  425. comments = ["""
  426. class
  427. ### comment ###
  428. 'use strict'
  429. #{error}""",
  430. """
  431. class
  432. ### comment 1 ###
  433. ### comment 2 ###
  434. 'use strict'
  435. #{error}""",
  436. """
  437. class
  438. ### comment 1 ###
  439. ### comment 2 ###
  440. 'use strict'
  441. #{error}
  442. ### comment 3 ###"""
  443. ]
  444. throws (-> CoffeeScript.run comment, bare: yes) for comment in comments
  445. # [ES5 §14.1](http://es5.github.com/#x14.1) allows for other directives
  446. directives = ["""
  447. class
  448. 'directive 1'
  449. 'use strict'
  450. #{error}""",
  451. """
  452. class
  453. 'use strict'
  454. 'directive 2'
  455. #{error}""",
  456. """
  457. class
  458. ### comment 1 ###
  459. 'directive 1'
  460. 'use strict'
  461. #{error}""",
  462. """
  463. class
  464. ### comment 1 ###
  465. 'directive 1'
  466. ### comment 2 ###
  467. 'use strict'
  468. #{error}"""
  469. ]
  470. throws (-> CoffeeScript.run directive, bare: yes) for directive in directives
  471. test "#2052: classes should work in strict mode", ->
  472. try
  473. do ->
  474. 'use strict'
  475. class A
  476. catch e
  477. ok no
  478. test "directives in class with extends ", ->
  479. strictTest = """
  480. class extends Object
  481. ### comment ###
  482. 'use strict'
  483. do -> eq this, undefined
  484. """
  485. CoffeeScript.run strictTest, bare: yes
  486. test "#2630: class bodies can't reference arguments", ->
  487. throwsCompileError 'class Test then arguments'
  488. # #4320: Don't be too eager when checking, though.
  489. class Test
  490. arguments: 5
  491. eq 5, Test::arguments
  492. test "#2319: fn class n extends o.p [INDENT] x = 123", ->
  493. first = ->
  494. base = onebase: ->
  495. first class OneKeeper extends base.onebase
  496. one = 1
  497. one: -> one
  498. eq new OneKeeper().one(), 1
  499. test "#2599: other typed constructors should be inherited", ->
  500. class Base
  501. constructor: -> return {}
  502. class Derived extends Base
  503. ok (new Derived) not instanceof Derived
  504. ok (new Derived) not instanceof Base
  505. ok (new Base) not instanceof Base
  506. test "extending native objects works with and without defining a constructor", ->
  507. class MyArray extends Array
  508. method: -> 'yes!'
  509. myArray = new MyArray
  510. ok myArray instanceof MyArray
  511. ok 'yes!', myArray.method()
  512. class OverrideArray extends Array
  513. constructor: -> super()
  514. method: -> 'yes!'
  515. overrideArray = new OverrideArray
  516. ok overrideArray instanceof OverrideArray
  517. eq 'yes!', overrideArray.method()
  518. test "#2782: non-alphanumeric-named bound functions", ->
  519. class A
  520. 'b:c': =>
  521. 'd'
  522. eq (new A)['b:c'](), 'd'
  523. test "#2781: overriding bound functions", ->
  524. class A
  525. a: ->
  526. @b()
  527. b: =>
  528. 1
  529. class B extends A
  530. b: =>
  531. 2
  532. b = (new A).b
  533. eq b(), 1
  534. b = (new B).b
  535. eq b(), 2
  536. test "#2791: bound function with destructured argument", ->
  537. class Foo
  538. method: ({a}) => 'Bar'
  539. eq (new Foo).method({a: 'Bar'}), 'Bar'
  540. test "#2796: ditto, ditto, ditto", ->
  541. answer = null
  542. outsideMethod = (func) ->
  543. func.call message: 'wrong!'
  544. class Base
  545. constructor: ->
  546. @message = 'right!'
  547. outsideMethod @echo
  548. echo: =>
  549. answer = @message
  550. new Base
  551. eq answer, 'right!'
  552. test "#3063: Class bodies cannot contain pure statements", ->
  553. throwsCompileError """
  554. class extends S
  555. return if S.f
  556. @f: => this
  557. """
  558. test "#2949: super in static method with reserved name", ->
  559. class Foo
  560. @static: -> 'baz'
  561. class Bar extends Foo
  562. @static: -> super()
  563. eq Bar.static(), 'baz'
  564. test "#3232: super in static methods (not object-assigned)", ->
  565. class Foo
  566. @baz = -> true
  567. @qux = -> true
  568. class Bar extends Foo
  569. @baz = -> super()
  570. Bar.qux = -> super()
  571. ok Bar.baz()
  572. ok Bar.qux()
  573. test "#1392 calling `super` in methods defined on namespaced classes", ->
  574. class Base
  575. m: -> 5
  576. n: -> 4
  577. namespace =
  578. A: ->
  579. B: ->
  580. class namespace.A extends Base
  581. m: -> super()
  582. eq 5, (new namespace.A).m()
  583. namespace.B::m = namespace.A::m
  584. namespace.A::m = null
  585. eq 5, (new namespace.B).m()
  586. class C
  587. @a: class extends Base
  588. m: -> super()
  589. eq 5, (new C.a).m()
  590. test "#4436 immediately instantiated named class", ->
  591. ok new class Foo
  592. test "dynamic method names", ->
  593. class A
  594. "#{name = 'm'}": -> 1
  595. eq 1, new A().m()
  596. class B extends A
  597. "#{name = 'm'}": -> super()
  598. eq 1, new B().m()
  599. getName = -> 'm'
  600. class C
  601. "#{name = getName()}": -> 1
  602. eq 1, new C().m()
  603. test "dynamic method names and super", ->
  604. class Base
  605. @m: -> 6
  606. m: -> 5
  607. m2: -> 4.5
  608. n: -> 4
  609. name = -> count++; 'n'
  610. count = 0
  611. m = 'm'
  612. class A extends Base
  613. "#{m}": -> super()
  614. "#{name()}": -> super()
  615. m = 'n'
  616. eq 5, (new A).m()
  617. eq 4, (new A).n()
  618. eq 1, count
  619. m = 'm'
  620. m2 = 'm2'
  621. count = 0
  622. class B extends Base
  623. @[name()] = -> super()
  624. "#{m}": -> super()
  625. "#{m2}": -> super()
  626. b = new B
  627. m = m2 = 'n'
  628. eq 6, B.m()
  629. eq 5, b.m()
  630. eq 4.5, b.m2()
  631. eq 1, count
  632. class C extends B
  633. m: -> super()
  634. eq 5, (new C).m()
  635. # ES2015+ class interoperability
  636. # Based on https://github.com/balupton/es6-javascript-class-interop
  637. # Helper functions to generate true ES classes to extend:
  638. getBasicClass = ->
  639. ```
  640. class BasicClass {
  641. constructor (greeting) {
  642. this.greeting = greeting || 'hi'
  643. }
  644. }
  645. ```
  646. BasicClass
  647. getExtendedClass = (BaseClass) ->
  648. ```
  649. class ExtendedClass extends BaseClass {
  650. constructor (greeting, name) {
  651. super(greeting || 'hello')
  652. this.name = name
  653. }
  654. }
  655. ```
  656. ExtendedClass
  657. test "can instantiate a basic ES class", ->
  658. BasicClass = getBasicClass()
  659. i = new BasicClass 'howdy!'
  660. eq i.greeting, 'howdy!'
  661. test "can instantiate an extended ES class", ->
  662. BasicClass = getBasicClass()
  663. ExtendedClass = getExtendedClass BasicClass
  664. i = new ExtendedClass 'yo', 'buddy'
  665. eq i.greeting, 'yo'
  666. eq i.name, 'buddy'
  667. test "can extend a basic ES class", ->
  668. BasicClass = getBasicClass()
  669. class ExtendedClass extends BasicClass
  670. constructor: (@name) ->
  671. super()
  672. i = new ExtendedClass 'dude'
  673. eq i.name, 'dude'
  674. test "can extend an extended ES class", ->
  675. BasicClass = getBasicClass()
  676. ExtendedClass = getExtendedClass BasicClass
  677. class ExtendedExtendedClass extends ExtendedClass
  678. constructor: (@value) ->
  679. super()
  680. getDoubledValue: ->
  681. @value * 2
  682. i = new ExtendedExtendedClass 7
  683. eq i.getDoubledValue(), 14
  684. test "CoffeeScript class can be extended in ES", ->
  685. class CoffeeClass
  686. constructor: (@favoriteDrink = 'latte', @size = 'grande') ->
  687. getDrinkOrder: ->
  688. "#{@size} #{@favoriteDrink}"
  689. ```
  690. class ECMAScriptClass extends CoffeeClass {
  691. constructor (favoriteDrink) {
  692. super(favoriteDrink);
  693. this.favoriteDrink = this.favoriteDrink + ' with a dash of semicolons';
  694. }
  695. }
  696. ```
  697. e = new ECMAScriptClass 'coffee'
  698. eq e.getDrinkOrder(), 'grande coffee with a dash of semicolons'
  699. test "extended CoffeeScript class can be extended in ES", ->
  700. class CoffeeClass
  701. constructor: (@favoriteDrink = 'latte') ->
  702. class CoffeeClassWithDrinkOrder extends CoffeeClass
  703. constructor: (@favoriteDrink, @size = 'grande') ->
  704. super()
  705. getDrinkOrder: ->
  706. "#{@size} #{@favoriteDrink}"
  707. ```
  708. class ECMAScriptClass extends CoffeeClassWithDrinkOrder {
  709. constructor (favoriteDrink) {
  710. super(favoriteDrink);
  711. this.favoriteDrink = this.favoriteDrink + ' with a dash of semicolons';
  712. }
  713. }
  714. ```
  715. e = new ECMAScriptClass 'coffee'
  716. eq e.getDrinkOrder(), 'grande coffee with a dash of semicolons'
  717. test "`this` access after `super` in extended classes", ->
  718. class Base
  719. class Test extends Base
  720. constructor: (param, @param) ->
  721. eq param, nonce
  722. result = { super: super(), @param, @method }
  723. eq result.super, this
  724. eq result.param, @param
  725. eq result.method, @method
  726. ok result.method isnt Test::method
  727. method: =>
  728. nonce = {}
  729. new Test nonce, {}
  730. test "`@`-params and bound methods with multiple `super` paths (blocks)", ->
  731. nonce = {}
  732. class Base
  733. constructor: (@name) ->
  734. class Test extends Base
  735. constructor: (param, @param) ->
  736. if param
  737. super 'param'
  738. eq @name, 'param'
  739. else
  740. super 'not param'
  741. eq @name, 'not param'
  742. eq @param, nonce
  743. ok @method isnt Test::method
  744. method: =>
  745. new Test true, nonce
  746. new Test false, nonce
  747. test "`@`-params and bound methods with multiple `super` paths (expressions)", ->
  748. nonce = {}
  749. class Base
  750. constructor: (@name) ->
  751. class Test extends Base
  752. constructor: (param, @param) ->
  753. # Contrived example: force each path into an expression with inline assertions
  754. if param
  755. result = (
  756. eq (super 'param'), @;
  757. eq @name, 'param';
  758. eq @param, nonce;
  759. ok @method isnt Test::method
  760. )
  761. else
  762. result = (
  763. eq (super 'not param'), @;
  764. eq @name, 'not param';
  765. eq @param, nonce;
  766. ok @method isnt Test::method
  767. )
  768. method: =>
  769. new Test true, nonce
  770. new Test false, nonce
  771. test "constructor super in arrow functions", ->
  772. class Test extends (class)
  773. constructor: (@param) ->
  774. do => super()
  775. eq @param, nonce
  776. new Test nonce = {}
  777. # TODO Some of these tests use CoffeeScript.compile and CoffeeScript.run when they could use
  778. # regular test mechanics.
  779. # TODO Some of these tests might be better placed in `test/error_messages.coffee`.
  780. # TODO Some of these tests are duplicates.
  781. # Ensure that we always throw if we experience more than one super()
  782. # call in a constructor. This ends up being a runtime error.
  783. # Should be caught at compile time.
  784. test "multiple super calls", ->
  785. throwsA = """
  786. class A
  787. constructor: (@drink) ->
  788. make: -> "Making a #{@drink}"
  789. class MultiSuper extends A
  790. constructor: (drink) ->
  791. super(drink)
  792. super(drink)
  793. @newDrink = drink
  794. new MultiSuper('Late').make()
  795. """
  796. throws -> CoffeeScript.run throwsA, bare: yes
  797. # Basic test to ensure we can pass @params in a constuctor and
  798. # inheritance works correctly
  799. test "@ params", ->
  800. class A
  801. constructor: (@drink, @shots, @flavor) ->
  802. make: -> "Making a #{@flavor} #{@drink} with #{@shots} shot(s)"
  803. a = new A('Machiato', 2, 'chocolate')
  804. eq a.make(), "Making a chocolate Machiato with 2 shot(s)"
  805. class B extends A
  806. b = new B('Machiato', 2, 'chocolate')
  807. eq b.make(), "Making a chocolate Machiato with 2 shot(s)"
  808. # Ensure we can accept @params with default parameters in a constructor
  809. test "@ params with defaults in a constructor", ->
  810. class A
  811. # Multiple @ params with defaults
  812. constructor: (@drink = 'Americano', @shots = '1', @flavor = 'caramel') ->
  813. make: -> "Making a #{@flavor} #{@drink} with #{@shots} shot(s)"
  814. a = new A()
  815. eq a.make(), "Making a caramel Americano with 1 shot(s)"
  816. # Ensure we can handle default constructors with class params
  817. test "@ params with class params", ->
  818. class Beverage
  819. drink: 'Americano'
  820. shots: '1'
  821. flavor: 'caramel'
  822. class A
  823. # Class creation as a default param with `this`
  824. constructor: (@drink = new Beverage()) ->
  825. a = new A()
  826. eq a.drink.drink, 'Americano'
  827. beverage = new Beverage
  828. class B
  829. # class costruction with a default external param
  830. constructor: (@drink = beverage) ->
  831. b = new B()
  832. eq b.drink.drink, 'Americano'
  833. class C
  834. # Default constructor with anonymous empty class
  835. constructor: (@meta = class) ->
  836. c = new C()
  837. ok c.meta instanceof Function
  838. test "@ params without super, including errors", ->
  839. classA = """
  840. class A
  841. constructor: (@drink) ->
  842. make: -> "Making a #{@drink}"
  843. a = new A('Machiato')
  844. """
  845. throwsB = """
  846. class B extends A
  847. #implied super
  848. constructor: (@drink) ->
  849. b = new B('Machiato')
  850. """
  851. throwsCompileError classA + throwsB, bare: yes
  852. test "@ params super race condition", ->
  853. classA = """
  854. class A
  855. constructor: (@drink) ->
  856. make: -> "Making a #{@drink}"
  857. """
  858. throwsB = """
  859. class B extends A
  860. constructor: (@params) ->
  861. b = new B('Machiato')
  862. """
  863. throwsCompileError classA + throwsB, bare: yes
  864. # Race condition with @ and super
  865. throwsC = """
  866. class C extends A
  867. constructor: (@params) ->
  868. super(@params)
  869. c = new C('Machiato')
  870. """
  871. throwsCompileError classA + throwsC, bare: yes
  872. test "@ with super call", ->
  873. class D
  874. make: -> "Making a #{@drink}"
  875. class E extends D
  876. constructor: (@drink) ->
  877. super()
  878. e = new E('Machiato')
  879. eq e.make(), "Making a Machiato"
  880. test "@ with splats and super call", ->
  881. class A
  882. make: -> "Making a #{@drink}"
  883. class B extends A
  884. constructor: (@drink...) ->
  885. super()
  886. B = new B('Machiato')
  887. eq B.make(), "Making a Machiato"
  888. test "super and external constructors", ->
  889. # external constructor with @ param is allowed
  890. ctorA = (@drink) ->
  891. class A
  892. constructor: ctorA
  893. make: -> "Making a #{@drink}"
  894. a = new A('Machiato')
  895. eq a.make(), "Making a Machiato"
  896. # External constructor with super
  897. throwsC = """
  898. class B
  899. constructor: (@drink) ->
  900. make: -> "Making a #{@drink}"
  901. ctorC = (drink) ->
  902. super(drink)
  903. class C extends B
  904. constructor: ctorC
  905. c = new C('Machiato')
  906. """
  907. throwsCompileError throwsC, bare: yes
  908. test "bound functions without super", ->
  909. # Bound function with @
  910. # Throw on compile, since bound
  911. # constructors are illegal
  912. throwsA = """
  913. class A
  914. constructor: (drink) =>
  915. @drink = drink
  916. """
  917. throwsCompileError throwsA, bare: yes
  918. test "super in a bound function in a constructor", ->
  919. throwsB = """
  920. class A
  921. class B extends A
  922. constructor: do => super
  923. """
  924. throwsCompileError throwsB, bare: yes
  925. test "super in a bound function", ->
  926. class A
  927. constructor: (@drink) ->
  928. make: -> "Making a #{@drink}"
  929. class B extends A
  930. make: (@flavor) =>
  931. super() + " with #{@flavor}"
  932. b = new B('Machiato')
  933. eq b.make('vanilla'), "Making a Machiato with vanilla"
  934. # super in a bound function in a bound function
  935. class C extends A
  936. make: (@flavor) =>
  937. func = () =>
  938. super() + " with #{@flavor}"
  939. func()
  940. c = new C('Machiato')
  941. eq c.make('vanilla'), "Making a Machiato with vanilla"
  942. # bound function in a constructor
  943. class D extends A
  944. constructor: (drink) ->
  945. super(drink)
  946. x = =>
  947. eq @drink, "Machiato"
  948. x()
  949. d = new D('Machiato')
  950. eq d.make(), "Making a Machiato"
  951. # duplicate
  952. test "super in a try/catch", ->
  953. classA = """
  954. class A
  955. constructor: (param) ->
  956. throw "" unless param
  957. """
  958. throwsB = """
  959. class B extends A
  960. constructor: ->
  961. try
  962. super()
  963. """
  964. throwsC = """
  965. ctor = ->
  966. try
  967. super()
  968. class C extends A
  969. constructor: ctor
  970. """
  971. throws -> CoffeeScript.run classA + throwsB, bare: yes
  972. throws -> CoffeeScript.run classA + throwsC, bare: yes
  973. test "mixed ES6 and CS6 classes with a four-level inheritance chain", ->
  974. # Extended test
  975. # ES2015+ class interoperability
  976. ```
  977. class Base {
  978. constructor (greeting) {
  979. this.greeting = greeting || 'hi';
  980. }
  981. func (string) {
  982. return 'zero/' + string;
  983. }
  984. static staticFunc (string) {
  985. return 'static/' + string;
  986. }
  987. }
  988. ```
  989. class FirstChild extends Base
  990. func: (string) ->
  991. super('one/') + string
  992. ```
  993. class SecondChild extends FirstChild {
  994. func (string) {
  995. return super.func('two/' + string);
  996. }
  997. }
  998. ```
  999. thirdCtor = ->
  1000. @array = [1, 2, 3]
  1001. class ThirdChild extends SecondChild
  1002. constructor: ->
  1003. super()
  1004. thirdCtor.call this
  1005. func: (string) ->
  1006. super('three/') + string
  1007. result = (new ThirdChild).func 'four'
  1008. ok result is 'zero/one/two/three/four'
  1009. ok Base.staticFunc('word') is 'static/word'
  1010. # exercise extends in a nested class
  1011. test "nested classes with super", ->
  1012. class Outer
  1013. constructor: ->
  1014. @label = 'outer'
  1015. class @Inner
  1016. constructor: ->
  1017. @label = 'inner'
  1018. class @ExtendedInner extends @Inner
  1019. constructor: ->
  1020. tmp = super()
  1021. @label = tmp.label + ' extended'
  1022. @extender: () =>
  1023. class ExtendedSelf extends @
  1024. constructor: ->
  1025. tmp = super()
  1026. @label = tmp.label + ' from this'
  1027. new ExtendedSelf
  1028. eq (new Outer).label, 'outer'
  1029. eq (new Outer.Inner).label, 'inner'
  1030. eq (new Outer.ExtendedInner).label, 'inner extended'
  1031. eq (Outer.extender()).label, 'outer from this'
  1032. test "Static methods generate 'static' keywords", ->
  1033. compile = """
  1034. class CheckStatic
  1035. constructor: (@drink) ->
  1036. @className: -> 'CheckStatic'
  1037. c = new CheckStatic('Machiato')
  1038. """
  1039. result = CoffeeScript.compile compile, bare: yes
  1040. ok result.match(' static ')
  1041. test "Static methods in nested classes", ->
  1042. class Outer
  1043. @name: -> 'Outer'
  1044. class @Inner
  1045. @name: -> 'Inner'
  1046. eq Outer.name(), 'Outer'
  1047. eq Outer.Inner.name(), 'Inner'
  1048. test "mixed constructors with inheritance and ES6 super", ->
  1049. identity = (f) -> f
  1050. class TopClass
  1051. constructor: (arg) ->
  1052. @prop = 'top-' + arg
  1053. ```
  1054. class SuperClass extends TopClass {
  1055. constructor (arg) {
  1056. identity(super('super-' + arg));
  1057. }
  1058. }
  1059. ```
  1060. class SubClass extends SuperClass
  1061. constructor: ->
  1062. identity super 'sub'
  1063. ok (new SubClass).prop is 'top-super-sub'
  1064. test "ES6 static class methods can be overriden", ->
  1065. class A
  1066. @name: -> 'A'
  1067. class B extends A
  1068. @name: -> 'B'
  1069. eq A.name(), 'A'
  1070. eq B.name(), 'B'
  1071. # If creating static by direct assignment rather than ES6 static keyword
  1072. test "ES6 Static methods should set `this` to undefined // ES6 ", ->
  1073. class A
  1074. @test: ->
  1075. eq this, undefined
  1076. # Ensure that our object prototypes work with ES6
  1077. test "ES6 prototypes can be overriden", ->
  1078. class A
  1079. className: 'classA'
  1080. ```
  1081. class B {
  1082. test () {return "B";};
  1083. }
  1084. ```
  1085. b = new B
  1086. a = new A
  1087. eq a.className, 'classA'
  1088. eq b.test(), 'B'
  1089. Object.setPrototypeOf(b, a)
  1090. eq b.className, 'classA'
  1091. # This shouldn't throw,
  1092. # as we only change inheritance not object construction
  1093. # This may be an issue with ES, rather than CS construction?
  1094. #eq b.test(), 'B'
  1095. class D extends B
  1096. B::test = () -> 'D'
  1097. eq (new D).test(), 'D'
  1098. # TODO: implement this error check
  1099. # test "ES6 conformance to extending non-classes", ->
  1100. # A = (@title) ->
  1101. # 'Title: ' + @
  1102. # class B extends A
  1103. # b = new B('caffeinated')
  1104. # eq b.title, 'caffeinated'
  1105. # # Check inheritance chain
  1106. # A::getTitle = () -> @title
  1107. # eq b.getTitle(), 'caffeinated'
  1108. # throwsC = """
  1109. # C = {title: 'invalid'}
  1110. # class D extends {}
  1111. # """
  1112. # # This should catch on compile and message should be "class can only extend classes and functions."
  1113. # throws -> CoffeeScript.run throwsC, bare: yes
  1114. # TODO: Evaluate future compliance with "strict mode";
  1115. # test "Class function environment should be in `strict mode`, ie as if 'use strict' was in use", ->
  1116. # class A
  1117. # # this might be a meaningless test, since these are likely to be runtime errors and different
  1118. # # for every browser. Thoughts?
  1119. # constructor: () ->
  1120. # # Ivalid: prop reassignment
  1121. # @state = {prop: [1], prop: {a: 'a'}}
  1122. # # eval reassignment
  1123. # @badEval = eval;
  1124. # # Should throw, but doesn't
  1125. # a = new A
  1126. test "only one method named constructor allowed", ->
  1127. throwsA = """
  1128. class A
  1129. constructor: (@first) ->
  1130. constructor: (@last) ->
  1131. """
  1132. throwsCompileError throwsA, bare: yes
  1133. test "If the constructor of a child class does not call super,it should return an object.", ->
  1134. nonce = {}
  1135. class A
  1136. class B extends A
  1137. constructor: ->
  1138. return nonce
  1139. eq nonce, new B
  1140. test "super can only exist in extended classes", ->
  1141. throwsA = """
  1142. class A
  1143. constructor: (@name) ->
  1144. super()
  1145. """
  1146. throwsCompileError throwsA, bare: yes
  1147. # --- CS1 classes compatability breaks ---
  1148. test "CS6 Class extends a CS1 compiled class", ->
  1149. ```
  1150. // Generated by CoffeeScript 1.11.1
  1151. var BaseCS1, ExtendedCS1,
  1152. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  1153. hasProp = {}.hasOwnProperty;
  1154. BaseCS1 = (function() {
  1155. function BaseCS1(drink) {
  1156. this.drink = drink;
  1157. }
  1158. BaseCS1.prototype.make = function() {
  1159. return "making a " + this.drink;
  1160. };
  1161. BaseCS1.className = function() {
  1162. return 'BaseCS1';
  1163. };
  1164. return BaseCS1;
  1165. })();
  1166. ExtendedCS1 = (function(superClass) {
  1167. extend(ExtendedCS1, superClass);
  1168. function ExtendedCS1(flavor) {
  1169. this.flavor = flavor;
  1170. ExtendedCS1.__super__.constructor.call(this, 'cafe ole');
  1171. }
  1172. ExtendedCS1.prototype.make = function() {
  1173. return "making a " + this.drink + " with " + this.flavor;
  1174. };
  1175. ExtendedCS1.className = function() {
  1176. return 'ExtendedCS1';
  1177. };
  1178. return ExtendedCS1;
  1179. })(BaseCS1);
  1180. ```
  1181. class B extends BaseCS1
  1182. eq B.className(), 'BaseCS1'
  1183. b = new B('machiato')
  1184. eq b.make(), "making a machiato"
  1185. test "CS6 Class extends an extended CS1 compiled class", ->
  1186. ```
  1187. // Generated by CoffeeScript 1.11.1
  1188. var BaseCS1, ExtendedCS1,
  1189. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  1190. hasProp = {}.hasOwnProperty;
  1191. BaseCS1 = (function() {
  1192. function BaseCS1(drink) {
  1193. this.drink = drink;
  1194. }
  1195. BaseCS1.prototype.make = function() {
  1196. return "making a " + this.drink;
  1197. };
  1198. BaseCS1.className = function() {
  1199. return 'BaseCS1';
  1200. };
  1201. return BaseCS1;
  1202. })();
  1203. ExtendedCS1 = (function(superClass) {
  1204. extend(ExtendedCS1, superClass);
  1205. function ExtendedCS1(flavor) {
  1206. this.flavor = flavor;
  1207. ExtendedCS1.__super__.constructor.call(this, 'cafe ole');
  1208. }
  1209. ExtendedCS1.prototype.make = function() {
  1210. return "making a " + this.drink + " with " + this.flavor;
  1211. };
  1212. ExtendedCS1.className = function() {
  1213. return 'ExtendedCS1';
  1214. };
  1215. return ExtendedCS1;
  1216. })(BaseCS1);
  1217. ```
  1218. class B extends ExtendedCS1
  1219. eq B.className(), 'ExtendedCS1'
  1220. b = new B('vanilla')
  1221. eq b.make(), "making a cafe ole with vanilla"
  1222. test "CS6 Class extends a CS1 compiled class with super()", ->
  1223. ```
  1224. // Generated by CoffeeScript 1.11.1
  1225. var BaseCS1, ExtendedCS1,
  1226. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  1227. hasProp = {}.hasOwnProperty;
  1228. BaseCS1 = (function() {
  1229. function BaseCS1(drink) {
  1230. this.drink = drink;
  1231. }
  1232. BaseCS1.prototype.make = function() {
  1233. return "making a " + this.drink;
  1234. };
  1235. BaseCS1.className = function() {
  1236. return 'BaseCS1';
  1237. };
  1238. return BaseCS1;
  1239. })();
  1240. ExtendedCS1 = (function(superClass) {
  1241. extend(ExtendedCS1, superClass);
  1242. function ExtendedCS1(flavor) {
  1243. this.flavor = flavor;
  1244. ExtendedCS1.__super__.constructor.call(this, 'cafe ole');
  1245. }
  1246. ExtendedCS1.prototype.make = function() {
  1247. return "making a " + this.drink + " with " + this.flavor;
  1248. };
  1249. ExtendedCS1.className = function() {
  1250. return 'ExtendedCS1';
  1251. };
  1252. return ExtendedCS1;
  1253. })(BaseCS1);
  1254. ```
  1255. class B extends ExtendedCS1
  1256. constructor: (@shots) ->
  1257. super('caramel')
  1258. make: () ->
  1259. super() + " and #{@shots} shots of espresso"
  1260. eq B.className(), 'ExtendedCS1'
  1261. b = new B('three')
  1262. eq b.make(), "making a cafe ole with caramel and three shots of espresso"
  1263. test 'Bound method called normally before binding is ok', ->
  1264. class Base
  1265. constructor: ->
  1266. @setProp()
  1267. eq @derivedBound(), 3
  1268. class Derived extends Base
  1269. setProp: ->
  1270. @prop = 3
  1271. derivedBound: =>
  1272. @prop
  1273. d = new Derived
  1274. test 'Bound method called as callback after super() is ok', ->
  1275. class Base
  1276. class Derived extends Base
  1277. constructor: (@prop = 3) ->
  1278. super()
  1279. f = @derivedBound
  1280. eq f(), 3
  1281. derivedBound: =>
  1282. @prop
  1283. d = new Derived
  1284. {derivedBound} = d
  1285. eq derivedBound(), 3
  1286. test 'Bound method of base class called as callback is ok', ->
  1287. class Base
  1288. constructor: (@prop = 3) ->
  1289. f = @baseBound
  1290. eq f(), 3
  1291. baseBound: =>
  1292. @prop
  1293. b = new Base
  1294. {baseBound} = b
  1295. eq baseBound(), 3
  1296. test 'Bound method of prop-named class called as callback is ok', ->
  1297. Hive = {}
  1298. class Hive.Bee
  1299. constructor: (@prop = 3) ->
  1300. f = @baseBound
  1301. eq f(), 3
  1302. baseBound: =>
  1303. @prop
  1304. b = new Hive.Bee
  1305. {baseBound} = b
  1306. eq baseBound(), 3
  1307. test 'Bound method of class with expression base class called as callback is ok', ->
  1308. calledB = no
  1309. B = ->
  1310. throw new Error if calledB
  1311. calledB = yes
  1312. class
  1313. class A extends B()
  1314. constructor: (@prop = 3) ->
  1315. super()
  1316. f = @derivedBound
  1317. eq f(), 3
  1318. derivedBound: =>
  1319. @prop
  1320. b = new A
  1321. {derivedBound} = b
  1322. eq derivedBound(), 3
  1323. test 'Bound method of class with expression class name called as callback is ok', ->
  1324. calledF = no
  1325. obj = {}
  1326. B = class
  1327. f = ->
  1328. throw new Error if calledF
  1329. calledF = yes
  1330. obj
  1331. class f().A extends B
  1332. constructor: (@prop = 3) ->
  1333. super()
  1334. g = @derivedBound
  1335. eq g(), 3
  1336. derivedBound: =>
  1337. @prop
  1338. a = new obj.A
  1339. {derivedBound} = a
  1340. eq derivedBound(), 3
  1341. test 'Bound method of anonymous child class called as callback is ok', ->
  1342. f = ->
  1343. B = class
  1344. class extends B
  1345. constructor: (@prop = 3) ->
  1346. super()
  1347. g = @derivedBound
  1348. eq g(), 3
  1349. derivedBound: =>
  1350. @prop
  1351. a = new (f())
  1352. {derivedBound} = a
  1353. eq derivedBound(), 3
  1354. test 'Bound method of immediately instantiated class with expression base class called as callback is ok', ->
  1355. calledF = no
  1356. obj = {}
  1357. B = class
  1358. f = ->
  1359. throw new Error if calledF
  1360. calledF = yes
  1361. obj
  1362. a = new class f().A extends B
  1363. constructor: (@prop = 3) ->
  1364. super()
  1365. g = @derivedBound
  1366. eq g(), 3
  1367. derivedBound: =>
  1368. @prop
  1369. {derivedBound} = a
  1370. eq derivedBound(), 3
  1371. test "#4591: super.x.y, super['x'].y", ->
  1372. class A
  1373. x:
  1374. y: 1
  1375. z: -> 2
  1376. class B extends A
  1377. constructor: ->
  1378. super()
  1379. @w = super.x.y
  1380. @v = super['x'].y
  1381. @u = super.x['y']
  1382. @t = super.x.z()
  1383. @s = super['x'].z()
  1384. @r = super.x['z']()
  1385. b = new B
  1386. eq 1, b.w
  1387. eq 1, b.v
  1388. eq 1, b.u
  1389. eq 2, b.t
  1390. eq 2, b.s
  1391. eq 2, b.r
  1392. test "#4464: backticked expressions in class body", ->
  1393. class A
  1394. `get x() { return 42; }`
  1395. class B
  1396. `get x() { return 42; }`
  1397. constructor: ->
  1398. @y = 84
  1399. a = new A
  1400. eq 42, a.x
  1401. b = new B
  1402. eq 42, b.x
  1403. eq 84, b.y
  1404. test "#4724: backticked expression in a class body with hoisted member", ->
  1405. class A
  1406. `get x() { return 42; }`
  1407. hoisted: 84
  1408. a = new A
  1409. eq 42, a.x
  1410. eq 84, a.hoisted
  1411. test "#4822: nested anonymous classes use non-conflicting variable names", ->
  1412. Class = class
  1413. @a: class
  1414. @b: 1
  1415. eq Class.a.b, 1
  1416. test "#4827: executable class body wrappers have correct context", ->
  1417. test = ->
  1418. class @A
  1419. class @B extends @A
  1420. @property = 1
  1421. o = {}
  1422. test.call o
  1423. ok typeof o.A is typeof o.B is 'function'
  1424. test "#4868: Incorrect ‘Can’t call super with @params’ error", ->
  1425. class A
  1426. constructor: (@func = ->) ->
  1427. @x = 1
  1428. @func()
  1429. class B extends A
  1430. constructor: ->
  1431. super -> @x = 2
  1432. a = new A
  1433. b = new B
  1434. eq 1, a.x
  1435. eq 2, b.x
  1436. class C
  1437. constructor: (@c = class) -> @c
  1438. class D extends C
  1439. constructor: ->
  1440. super class then constructor: (@a) -> @a = 3
  1441. d = new (new D).c
  1442. eq 3, d.a
  1443. test "#4609: Support new.target", ->
  1444. class A
  1445. constructor: ->
  1446. @calledAs = new.target.name
  1447. class B extends A
  1448. b = new B
  1449. eq b.calledAs, 'B'
  1450. newTarget = null
  1451. Foo = ->
  1452. newTarget = !!new.target
  1453. Foo()
  1454. eq newTarget, no
  1455. newTarget = null
  1456. new Foo()
  1457. eq newTarget, yes
  1458. test "#5085: Bug: @ reference to class not maintained in do block", ->
  1459. thisFoo = 'initial foo'
  1460. thisBar = 'initial bar'
  1461. fn = (o) -> o.bar()
  1462. class A
  1463. @foo = 'foo assigned in class'
  1464. do => thisFoo = @foo
  1465. fn bar: => thisBar = @foo
  1466. eq thisFoo, 'foo assigned in class'
  1467. eq thisBar, 'foo assigned in class'
  1468. test "#5204: Computed class property", ->
  1469. foo = 'bar'
  1470. class A
  1471. [foo]: 'baz'
  1472. a = new A()
  1473. eq a.bar, 'baz'
  1474. eq A::bar, 'baz'
  1475. test "#5204: Static computed class property", ->
  1476. foo = 'bar'
  1477. qux = 'quux'
  1478. class A
  1479. @[foo]: 'baz'
  1480. @[qux]: -> 3
  1481. eq A.bar, 'baz'
  1482. eq A.quux(), 3