How to use setTimeout() in Coffeescript - coffeescript

I can't seem to use setTimeout() to call one of my own functions. I can use setTimeout to call alert(), but not a function that I've written myself. Here's the simplest code that reproduces the problem:
I have the following coffeeScript
setTimeout(run, 1000)
run = () ->
console.log("run was called!")
Which generates the following Javascript
// Generated by CoffeeScript 1.6.3
(function() {
var run;
setTimeout(run, 1000);
run = function() {
return console.log("run was called!");
};
}).call(this);
Nothing is printed to the console.

run = () ->
console.log("run was called!")
setTimeout(run, 1000)
You are relying on javascript function hoisting for functions declared with the syntax function run(){}, but coffeescript declares them as variables: var run = function(){}, so you have to define the function before you reference it, otherwise it's still undefined when you pass it to setTimeout.

Anonymous Option:
Peter is exactly right. But you can also use setTimeout without declaring a variable:
setTimeout ->
console.log 'run was called!'
, 1000
Yields:
(function() {
setTimeout(function() {
return console.log("run was called!")
}, 1e3)
}).call(this);

Related

I found this example of a function that accepts a callback but it's not working?

This code is similar to our previous mean() function, except in the
following if block where we check to see if a callback has been
provided. If it has, then the callback is applied to each value
before being added to the total; otherwise, the total is calculated
using just the values from the array given as the first argument
mean([2,5,7,11,4]); // this should just calculate the mean << 5.8
mean([2,5,7,11,4],x => 2*x); << 11.6
function mean(array ,callback) {
if (callback) {
array.map( callback );
}
const total = array.reduce((a, b) => a + b);
return total/array.length;
}
console.log(mean([2,5,7,11,4,5],x => 2*x));
function mean(array,callback) {
if (callback) {
array = array.map( callback ); // <--- note changes here
}
const total = array.reduce((a, b) => a + b);
return total/array.length;
}
console.log(mean([2,5,7,11,4])); //5.8 fine
console.log(mean([2,5,7,11,4],x => 2*x)) // 11.6
You weren't off by much. Check out the exact definition of Array.prototype.map() The return value from that function is a new array with each element being the result of the callback function.
I will say, your question got me to review Array.prototype.map() and passing callback functions. Thanks!
Almost forgot.. See how simple my code is formatted? That makes it easy for someone to see what's going on quickly. Recommend you do the same when posting questions here in the future.

With function in Coffee Script

Is the following code possible to coffee script?
With pex
.simpleObject = {}
.explicitFunction = ()->
alert "Hello world!"
.CONSTANTPI = 3.16
Endwith
Please disregard contents inside with. I am just referring how to do that in coffee script? instead of repeatedly typing the word pex.
As JavaScript's with statement should not be used, it's better to implement it with nested function and this accessor:
_with = (object, block) -> block.call object
_with pex, ->
#simpleObject = {}
#explicitFunction = ()->
alert "Hello world!"
#CONSTANTPI = 3.16
you could write a little helper function, since your goal seems to be assigning properties to an object, this one should suffice:
addprops = (obj, addthis) ->
for own key,value of addthis
obj[key] = value
pex = {}
addprops pex,
simpleObject: {}
explicitFunction: ()->
alert "Hello world!"
CONSTANTPI: 3.16
console.log pex
###
OUTPUT:
{ simpleObject: {},
explicitFunction: [Function],
CONSTANTPI: 3.16 }
###
You also could have a look at one of the several mixin libraries out there.

MongoDB eval() with arguments

I'm getting a strange result when trying to use eval with the args argument. The following works fine:
> db.eval(function(coll) {
var res = db[coll].find({});
return(res.count());
}, ['KenColl'])
1438
But when I pass a second argument, I always get empty results, even if I don't use it:
> db.eval(function(coll, query) {
var res = db[coll].find({});
return(res.count());
}, ['KenColl', {}])
0
Am I misunderstanding something about eval and args? I'm running version 2.4.3 of both mongod and the MongoDB shell.
For db.eval you shouldn't pass the arguments as an array, just pass them into the function.
The following example should work:
db.eval(function(coll, query) {
var res = db[coll].find(query);
return(res.count());
}, 'KenColl', {})
p.s. your first example only works because in javascript db['KenColl'] === db[['KenColl']]

FB.api() object type as a variable

I have written the code below:
function processLWO(lwo,type)
{
FB.api('me/'+lwo,
'post',
{shoe :'<%=sItemURL%>',object :'<%=sItemURL%>'},
function (response)
{
//code
}
);
}
My problem is with the following line of code:
//Code that works - Code A
shoe :'<%=sItemURL%>',object :'<%=sItemURL%>'
//Code I want to use - Code B
type.toString():'<%=sItemURL%>'
Code A works but I want to implement Code B because it is more flexible however Code B returns a Javascript error stating the original function that lead to this function is undefined. I understand type.toString() should be a Facebook object (for example, shoe or object) but if type.toString() is processed and returns a value then it would be evaluated as a valid object type.
Any suggestions how to solve this? Code A is just so lazy/stupid....
var params = {};
params[type] = <%=sItemURL%>'
FB.api('/me/' + lwo, 'POST', params, ...

How do I declare a variable in a specific scope in coffeescript?

I'm trying to write a jasmine test in coffeescript that uses a beforeEach block. This runs into a problem with coffeescript's variable scoping. Here's what I'd like to write:
describe 'PhoneDetailCtrl', () ->
beforeEach () ->
scope = angular.scope()
$browser = scope.$service('$browser')
it 'should fetch phone detail', () ->
scope.params = {phoneId:'xyz'}
$browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'})
ctrl = scope.$new(PhoneDetailCtrl)
expect(ctrl.phone).toEqualData({})
$browser.xhr.flush()
expect(ctrl.phone).toEqualData({name:'phone xyz'})
This doesn't work, though, because the scope and $browser will get declared with var in the innermost scope. That is, once in the beforeEach and then again in the it block. I can force the variables to be declared in the right scope by initializing them, but this seems very strange:
describe 'PhoneDetailCtrl', () ->
$browser = {}
scope = {}
beforeEach () ->
scope = angular.scope()
$browser = scope.$service('$browser')
it 'should fetch phone detail', () ->
scope.params = {phoneId:'xyz'}
...
This works, but the javascript it compiles to is actually
describe('PhoneListCtrl', function() {
var $browser, ctrl, scope;
$browser = {};
ctrl = {};
scope = {};
where all I need is the line var $browser, ctrl, scope;. Can I write this more concisely in coffeescript?
You are doing it the right way.
This is described in the CoffeeScript documentation. I wouldn't worry about the JS that it creates. Yes, it is a bit messy if you were to write it yourself, but this is one of the things that you have to live with when you use a re-writer like CoffeeScript.
You do, however, have a couple of options which are pretty nice.
You can put the variables in the current context if you wish (which happens to be your jasmine.Spec object for the curious, so it is a relatively safe and appropriate place to be putting variables... just don't overwrite existing vars in the context.):
describe 'PhoneDetailCtrl', () ->
beforeEach () ->
#scope = angular.scope()
#$browser = #scope.$service('$browser')
it 'should fetch phone detail', () ->
#scope.params = {phoneId:'xyz'}
#... etc
You can also setup your own variable in which to store things
describe 'PhoneDetailCtrl', () ->
setup = {}
beforeEach () ->
setup.scope = angular.scope()
setup.$browser = setup.scope.$service('$browser')
it 'should fetch phone detail', () ->
setup.scope.params = {phoneId:'xyz'}
#... etc
Your test could be written like the following:
describe "MyGame", ->
mygame = null
beforeEach inject (_MyGame_) ->
mygame = _MyGame_
it "should have two players", ->
expect(mygame.opponents.length).toEqual 2
Much cleaner syntax - without the need to make things global.