UNPKG

11.8 kBtext/coffeescriptView Raw
1suite 'Function Invocation', ->
2
3# * Function Invocation
4# * Splats in Function Invocations
5# * Implicit Returns
6# * Explicit Returns
7 id = (_) -> if arguments.length is 1 then _ else [].slice.call arguments
8
9 test "basic argument passing", ->
10 a = {}
11 b = {}
12 c = {}
13 eq 1, (id 1)
14 eq 2, (id 1, 2)[1]
15 eq a, (id a)
16 eq c, (id a, b, c)[2]
17
18 #test "passing arguments on separate lines", ->
19 # a = {}
20 # b = {}
21 # c = {}
22 # ok(id(
23 # a
24 # b
25 # c
26 # )[1] is b)
27 # eq(0, id(
28 # 0
29 # 10
30 # )[0])
31 # eq(a,id(
32 # a
33 # ))
34 # eq b,
35 # (id b)
36
37 test "optional parens can be used in a nested fashion", ->
38 call = (func) -> func()
39 add = (a,b) -> a + b
40 result = call ->
41 inner = call ->
42 add 5, 5
43 ok result is 10
44
45 test "hanging commas and semicolons in argument list", ->
46 fn = -> arguments.length
47 eq 2, fn(0,1,)
48 eq 3, fn 0, 1,
49 2
50 eq 2, fn(0, 1; 2)
51
52 test "function invocation", ->
53 func = ->
54 return if true
55 eq undefined, func()
56 result = ("hello".slice) 3
57 ok result is 'lo'
58
59 test "And even with strange things like this:", ->
60 funcs = [((x) -> x), ((x) -> x * x)]
61 result = funcs[1] 5
62 eq 25, result
63
64 test "More fun with optional parens.", ->
65 fn = (arg) -> arg
66 eq 101, fn(fn {prop: 101}).prop
67 okFunc = (f) -> ok(f())
68 okFunc -> true
69
70 test "chained function calls", ->
71 nonce = {}
72 identityWrap = (x) ->
73 -> x
74 eq nonce, identityWrap(identityWrap(nonce))()()
75 eq nonce, (identityWrap identityWrap nonce)()()
76
77 #test "Multi-blocks with optional parens.", ->
78 # fn = (arg) -> arg
79 # result = fn( ->
80 # fn ->
81 # "Wrapped"
82 # )
83 # ok result()() is 'Wrapped'
84
85 test "method calls", ->
86 fnId = (fn) -> -> fn.apply this, arguments
87 obj = {}
88 obj.add = (a, b) -> a + b
89 obj.anonymousAdd = (a, b) -> a + b
90 obj.fastAdd = fnId (a, b) -> a + b
91 eq 10, obj.add(5, 5)
92 eq 20, obj.anonymousAdd 10, 10
93 eq 40, obj.fastAdd (20), 20
94
95 #test "Ensure that functions can have a trailing comma in their argument list", ->
96 # mult = (x, mids..., y) ->
97 # x *= n for n in mids
98 # x *= y
99 # ok mult(1, 2,) is 2
100 # ok mult(1, 2, 3,) is 6
101 # ok mult(10, (i for i in [1..6])...) is 7200
102
103 test "`@` and `this` should both be able to invoke a function", ->
104 nonce = {}
105 fn = (arg) -> eq nonce, arg
106 fn.withAt = -> @ nonce
107 fn.withThis = -> this nonce
108 fn.withAt()
109 fn.withThis()
110
111 test "Trying an implicit object call with a trailing function.", ->
112 a = null
113 meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
114 meth 'apple', b: 1, a: 13, ->
115 'orange'
116 ok a is '13 apple orange'
117
118 #test "Ensure that empty functions don't return mistaken values.", ->
119 # obj = {func: (@param, @rest...) ->}
120 # ok obj.func(101, 102, 103, 104) is undefined
121 # ok obj.param is 101
122 # ok obj.rest.join(' ') is '102 103 104'
123
124 #test "Passing multiple functions without paren-wrapping is legal, and should compile.", ->
125 # sum = (one, two) -> one() + two()
126 # eq 20, sum ->
127 # 7 + 9
128 # , ->
129 # 1 + 3
130 # eq 16, sum -> 5 + 7, -> 2 + 3
131 # eq 6, sum( ->
132 # 1 + 2
133 # , ->
134 # 2 + 1
135 # )
136
137 test "Implicit call with a trailing if statement as a param.", ->
138 func = -> arguments[1]
139 result = func 'one', if false then 100 else 13
140 ok result is 13
141
142 #test "Test more function passing:", ->
143 # sum = (one, two) -> one() + two()
144 #
145 # result = sum( ->
146 # 1 + 2
147 # , ->
148 # 2 + 1
149 # )
150 # ok result is 6
151 #
152 # sum = (a, b) -> a + b
153 # result = sum(1
154 # , 2)
155 # ok result is 3
156
157 #test "Chained blocks, with proper indentation levels:", ->
158 # counter =
159 # results: []
160 # tick: (func) ->
161 # @results.push func()
162 # this
163 # counter
164 # .tick ->
165 # 3
166 # .tick ->
167 # 2
168 # .tick ->
169 # 1
170 # arrayEq [3,2,1], counter.results
171
172 test "TODO: find out what this test case is testing and rename it", ->
173 x = (obj, func) -> func obj
174 ident = (x) -> x
175 result = x {one: ident 1}, (obj) ->
176 inner = ident(obj)
177 ident inner
178 ok result.one is 1
179
180 test "More paren compilation tests:", ->
181 reverse = (obj) -> obj.reverse()
182 ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
183
184 test "Test for inline functions with parentheses and implicit calls.", ->
185 combine = (func, num) -> func() * num
186 result = combine (-> 1 + 2), 3
187 ok result is 9
188
189 #test "Test for calls/parens/multiline-chains.", ->
190 # f = (x) -> x
191 # result = (f 1).toString()
192 # .length
193 # ok result is 1
194
195 test "Test implicit calls in functions in parens:", ->
196 result = ((val) ->
197 [].push val
198 val
199 )(10)
200 ok result is 10
201
202 #test "Ensure that chained calls with indented implicit object literals below are alright.", ->
203 # result = null
204 # obj =
205 # method: (val) -> this
206 # second: (hash) -> result = hash.three
207 # obj
208 # .method(
209 # 101
210 # ).second(
211 # one:
212 # two: 2
213 # three: 3
214 # )
215 # eq result, 3
216
217 #test "Test newline-supressed call chains with nested functions.", ->
218 # obj =
219 # call: -> this
220 # func = ->
221 # obj
222 # .call ->
223 # one two
224 # .call ->
225 # three four
226 # 101
227 # eq func(), 101
228
229 #test "Implicit objects with number arguments.", ->
230 # func = (x, y) -> y
231 # obj =
232 # prop: func "a", 1
233 # ok obj.prop is 1
234
235 test "Non-spaced unary and binary operators should cause a function call.", ->
236 func = (val) -> val + 1
237 ok (func +5) is 6
238 ok (func -5) is -4
239
240 test "Prefix unary assignment operators are allowed in parenless calls.", ->
241 func = (val) -> val + 1
242 val = 5
243 ok (func --val) is 5
244
245 test "jashkenas/coffee-script#855: execution context for `func arr...` should be `null`", ->
246 contextTest = -> eq @, if window? then window else global
247 array = []
248 contextTest array
249 contextTest.apply null, array
250 contextTest array...
251
252 #test "jashkenas/coffee-script#904: Destructuring function arguments with same-named variables in scope", ->
253 # a = b = nonce = {}
254 # fn = ([a,b]) -> {a:a,b:b}
255 # result = fn([c={},d={}])
256 # eq c, result.a
257 # eq d, result.b
258 # eq nonce, a
259 # eq nonce, b
260
261 #test "Simple Destructuring function arguments with same-named variables in scope", ->
262 # x = 1
263 # f = ([x]) -> x
264 # eq f([2]), 2
265 # eq x, 1
266
267 test "caching base value", ->
268 obj = {index: 0, 0: {method: -> this is obj[0]}}
269 ok obj[obj.index++].method([]...)
270
271 test "passing splats to functions", ->
272 arrayEq [0..4], id id [0..4]...
273 fn = (a, b, c..., d) -> [a, b, c, d]
274 range = [0..3]
275 [first, second, others, last] = fn range..., 4, [5...8]...
276 eq 0, first
277 eq 1, second
278 arrayEq [2..6], others
279 eq 7, last
280
281 test "splat variables are local to the function", ->
282 outer = "x"
283 clobber = (avar, outer...) -> outer
284 clobber "foo", "bar"
285 eq "x", outer
286
287 test "Issue 894: Splatting against constructor-chained functions.", ->
288 x = null
289 class Foo
290 bar: (y) -> x = y
291 new Foo().bar([101]...)
292 eq x, 101
293
294 test "Functions with splats being called with too few arguments.", ->
295 method = (first, variable..., penultimate, ultimate) ->
296 penultimate
297 eq 8, method 1, 2, 3, 4, 5, 6, 7, 8, 9
298 eq 2, method 1, 2, 3
299 eq 2, method 1, 2
300
301 #test "splats with super() within classes.", ->
302 # class Parent
303 # meth: (args...) ->
304 # args
305 # class Child extends Parent
306 # meth: ->
307 # nums = [3, 2, 1]
308 # super nums...
309 # ok (new Child).meth().join(' ') is '3 2 1'
310
311 test "jashkenas/coffee-script#1011: passing a splat to a method of a number", ->
312 eq '1011', 11.toString [2]...
313 eq '1011', (31).toString [3]...
314 eq '1011', 69.0.toString [4]...
315 eq '1011', (131.0).toString [5]...
316
317 test "splats and the `new` operator: functions that return `null` should construct their instance", ->
318 args = []
319 child = new (constructor = -> null) args...
320 ok child instanceof constructor
321
322 test "splats and the `new` operator: functions that return functions should construct their return value", ->
323 args = []
324 fn = ->
325 child = new (constructor = -> fn) args...
326 ok child not instanceof constructor
327 eq fn, child
328
329 test "implicit return", ->
330 eq ok, new ->
331 ok
332 ### Should `return` implicitly ###
333 ### even with trailing comments. ###
334 eq ok, new ->
335 ok
336 # Should `return` implicitly
337 # even with trailing comments.
338
339 test "implicit returns with multiple branches", ->
340 nonce = {}
341 fn = ->
342 if not nonce
343 null
344 else
345 nonce
346 eq nonce, fn()
347
348 test "implicit returns with switches", ->
349 nonce = {}
350 fn = ->
351 switch nonce
352 when nonce then nonce
353 else return undefined
354 eq nonce, fn()
355
356 test "preserve context when generating closure wrappers for expression conversions", ->
357 nonce = {}
358 obj = {property: nonce, method: ->
359 this.result = if false
360 10
361 else
362 "a"
363 "b"
364 this.property
365 }
366 eq nonce, obj.method()
367 eq nonce, obj.property
368
369 #test "don't wrap 'pure' statements in a closure", ->
370 # nonce = {}
371 # items = [0, 1, 2, 3, nonce, 4, 5]
372 # fn = (items) ->
373 # for item in items
374 # return item if item is nonce
375 # eq nonce, fn items
376
377 test "usage of `new` is careful about where the invocation parens end up", ->
378 #eq 'object', typeof new try Array
379 eq 'object', typeof new do -> ->
380
381 test "implicit call against control structures", ->
382 result = null
383 save = (obj) -> result = obj
384
385 save switch id false
386 when true
387 'true'
388 when false
389 'false'
390 eq result, 'false'
391
392 save if id false
393 'false'
394 else
395 'true'
396 eq result, 'true'
397
398 save unless id false
399 'true'
400 else
401 'false'
402 eq result, 'true'
403
404 save try
405 doesnt exist
406 catch error
407 'caught'
408 eq result, 'caught'
409
410 save try doesnt(exist) catch error then 'caught2'
411 eq result, 'caught2'
412
413 test "jashkenas/coffee-script#1420: things like `(fn() ->)`; there are no words for this one", ->
414 fn = -> (f) -> f()
415 nonce = {}
416 eq nonce, (fn() -> nonce)
417
418 test "jashkenas/coffee-script#1416: don't omit one 'new' when compiling 'new new'", ->
419 nonce = {}
420 obj = new new -> -> {prop: nonce}
421 eq obj.prop, nonce
422
423 test "jashkenas/coffee-script#1416: don't omit one 'new' when compiling 'new new fn()()'", ->
424 nonce = {}
425 argNonceA = {}
426 argNonceB = {}
427 fn = (a) -> (b) -> {a, b, prop: nonce}
428 obj = new new fn(argNonceA)(argNonceB)
429 eq obj.prop, nonce
430 eq obj.a, argNonceA
431 eq obj.b, argNonceB
432
433 test "jashkenas/coffee-script#1840: accessing the `prototype` after function invocation should compile", ->
434 nonce = {}
435 obj = {prototype: {id: nonce}}
436 dotAccess = -> obj.prototype
437 protoAccess = -> obj
438 eq dotAccess().id, nonce
439 eq protoAccess()::id, nonce
440
441 test "jashkenas/coffee-script#960: improved 'do'", ->
442
443 do (nonExistent = 'one') ->
444 eq nonExistent, 'one'
445
446 overridden = 1
447 do (overridden = 2) ->
448 eq overridden, 2
449
450 two = 2
451 do (one = 1, two, three = 3) ->
452 eq one, 1
453 eq two, 2
454 eq three, 3
455
456 ret = do func = (two) ->
457 eq two, 2
458 func
459 eq ret, func
460
461 test "soaked function application", ->
462 nonce = {}
463 eq undefined, f?(0, 1)
464 eq undefined, f? 0, 1
465 eq undefined, f?
466 a: 0
467 eq undefined, f? 0,
468 a: 1
469 f = -> nonce
470 eq nonce, f?(0, 1)
471 eq nonce, f? 0, 1
472 eq nonce, f?
473 a: 0
474 eq nonce, f? 0,
475 a: 1