One line coffeescript "return if" iterating an array - coffeescript

This is my code (not working)
return monitor if (monitor.uuid is $scope.selectedMonitor) for monitor in $scope.monitors
I want to return monitor if the if is true and I'm trying to do in one single line. Is it possibile?

You could use the when keyword:
getSelectedMonitor = ->
return monitor for monitor in $scope.monitors when monitor.uuid is $scope.selectedMonitor
This generates the following JS:
var getSelectedMonitor = function() {
var monitor, _i, _len, _ref;
_ref = $scope.monitors;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
monitor = _ref[_i];
if (monitor.uuid === $scope.selectedMonitor) {
return monitor;
}
}
};

Related

Google Spreadsheet - How to avoid sending email duplicates?

I am having an issue with a script. I used the following script from Google Developers Website in order to do a simple merge mail. See https://developers.google.com/apps-script/articles/mail_merge
I modified a bit the script so to prevent email duplicates. However, even if the script seems to work as it marks 'EMAIL_SENT' in each row every time an email is sent. It does not pay attention if the mail as already been marked and still send the mail.
I believe there is an error at line 16 "var emailSent = rowData[6];"
I would really appreciate if someone could help me. Whoever you are thanks in advance.
Here is the modified script :
var EMAIL_SENT = "EMAIL_SENT";
function sendEmails() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dataSheet = ss.getSheets()[0];
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 7);
var templateSheet = ss.getSheets()[1];
var emailTemplate = templateSheet.getRange("A2").getValue();
var objects = getRowsData(dataSheet, dataRange);
for (var i = 0; i < objects.length; ++i) {
var Resume = DriveApp.getFilesByName('Resume.pdf') var Portfolio = DriveApp.getFilesByName('Portfolio.pdf') var rowData = objects[i];
var emailText = fillInTemplateFromObject(emailTemplate, rowData);
var emailSubject = "Architectural Internship";
var emailSent = rowData[6];
if (emailSent != EMAIL_SENT) {
MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText, {
attachments: [Resume.next(), Portfolio.next()]
});
dataSheet.getRange(2 + i, 7).setValue(EMAIL_SENT);
SpreadsheetApp.flush();
}
}
}
function fillInTemplateFromObject(template, data) {
var email = template;
var templateVars = template.match(/\${\"[^\"]+\"}/g);
for (var i = 0; i < templateVars.length; ++i) {
var variableData = data[normalizeHeader(templateVars[i])];
email = email.replace(templateVars[i], variableData || "");
}
return email;
}
function getRowsData(sheet, range, columnHeadersRowIndex) {
columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() - 1;
var numColumns = range.getEndColumn() - range.getColumn() + 1;
var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
var headers = headersRange.getValues()[0];
return getObjects(range.getValues(), normalizeHeaders(headers));
}
function getObjects(data, keys) {
var objects = [];
for (var i = 0; i < data.length; ++i) {
var object = {};
var hasData = false;
for (var j = 0; j < data[i].length; ++j) {
var cellData = data[i][j];
if (isCellEmpty(cellData)) {
continue;
}
object[keys[j]] = cellData;
hasData = true;
}
if (hasData) {
objects.push(object);
}
}
return objects;
}
function normalizeHeaders(headers) {
var keys = [];
for (var i = 0; i < headers.length; ++i) {
var key = normalizeHeader(headers[i]);
if (key.length > 0) {
keys.push(key);
}
}
return keys;
}
function normalizeHeader(header) {
var key = "";
var upperCase = false;
for (var i = 0; i < header.length; ++i) {
var letter = header[i];
if (letter == " " && key.length > 0) {
upperCase = true;
continue;
}
if (!isAlnum(letter)) {
continue;
}
if (key.length == 0 && isDigit(letter)) {
continue;
}
if (upperCase) {
upperCase = false;
key += letter.toUpperCase();
} else {
key += letter.toLowerCase();
}
}
return key;
}
// Returns true if the cell where cellData was read from is empty. // Arguments: // - cellData: string function isCellEmpty(cellData) {
return typeof(cellData) == "string" && cellData == "";
}
// Returns true if the character char is alphabetical, false otherwise. function isAlnum(char) { return char >= 'A' && char <= 'Z' || char >= 'a' && char <= 'z' || isDigit(char); }
// Returns true if the character char is a digit, false otherwise. function isDigit(char) { return char >= '0' && char <= '9'; }
Your code is really hard to read and the functions that return 2 or more objects make it even harder...you are using variable names that are also a bit confusing.... but that is probably a personal pov :-)
Anyway, I think I've found the issue: when you write var rowData = objects[i];
This "object" is actually the result of the getRowData function but if you look at this function, you'll see that it returns 2 objects, the first one being itself the result of another function (getObjects) ...
You are checking the value is the 6th element of the array which is actually an object and compare it to a string. The equality will never be true.
I didn't go further in the analyse since I found it really confusing ( as I already said) but at least you have a first element to check .
I would suggest you rewrite this code in a more simple way and use more appropriate variable names to help you while debugging.
I would recommend logging both values before executing to make sure they are the same. I would also guess that the email_sent and EMAIL_SENT are different data types. Can also try forcing the value to string for comparison.
To clarify:
logger.Log(emailSent);
logger.Log(EMAIL_SENT);
if (emailSent.toString() != EMAIL_SENT.toString())
{...
Error is in this line of code -
var dataRange = sheet.getRange(startRow, 1, numRows, 2)
It's considering only 2 columns in the range. Changed 2 to 3 and it worked fine.

For loop not waiting for winjs promise completion

For loop not waiting for winjs promise completion
for (var j = 0; j < magazineResult[0].data.length; j++) {
downRequest[0].data[j].COVER_PAGE_THUMB = parentUrl + eval(JSON.stringify(downRequest[0].data[j].COVER_PAGE_THUMB));
// Create a new download operation.
downloadFile(eval(magazineResult[0].data[j].COVER_PAGE_THUMB),eval(JSON.stringify(magazineResult[0].data[j].COVER_PAGE_THUMB)));
var url = downRequest[0].data[j].COVER_PAGE_THUMB;
var imgPath = downRequest[0].data[j].ISSUE_ID;
var imgExtension = url.substring(url.lastIndexOf('.') + 1);
var fileName = imgPath + "." + imgExtension;
var promise = Windows.Storage.ApplicationData.current.localFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting);
// Assign the completion handler function.
promise.done(function (newFile) {
MagazineDownLoad.downloadFile(url, fileName, j, newFile);
});
}
If you're trying to get MagazineDownLoad.downloadFile to operate asynchronously then you'll have to modify it's definition:
// in MagazineDownload
function downloadFile(url, filename, j, newfile){
return new WinJS.Promise(function (complete, error, progress) {
var returnValue;
//do the stuff that you do and assign something to returnValue
complete(returnValue);
});
}
Then you can use it asynchronously:
for (var j = 0; j < magazineResult[0].data.length; j++) {
downRequest[0].data[j].COVER_PAGE_THUMB = parentUrl + eval(JSON.stringify(downRequest[0].data[j].COVER_PAGE_THUMB));
// Create a new download operation.
downloadFile(eval(magazineResult[0].data[j].COVER_PAGE_THUMB),eval(JSON.stringify(magazineResult[0].data[j].COVER_PAGE_THUMB)));
var url = downRequest[0].data[j].COVER_PAGE_THUMB;
var imgPath = downRequest[0].data[j].ISSUE_ID;
var imgExtension = url.substring(url.lastIndexOf('.') + 1);
var fileName = imgPath + "." + imgExtension;
var promise = Windows.Storage.ApplicationData.current.localFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting);
// Assign the completion handler function.
promise.done(function (newFile) {
MagazineDownLoad.downloadFile(url, fileName, j, newFile).done(function(result){
//do some more stuff with the result
});
});
}
The WinJS.Promise() runs asynchronously and your for-loop runs in sync. What you are experiencing is expected. If you want to queue your actions you should not perform a loop, but rather queue a new action when your done() is called. Something like this:
var index = 0, data = magazineResult[0].data;
function queueDownload() {
// Duplicate all needed logic here from your question
var promise = Windows.Storage.ApplicationData.current.localFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting);
// Assign the completion handler function.
promise.done(function (newFile) {
MagazineDownLoad.downloadFile(url, fileName, j, newFile);
if (index < data.length) {
queueDownload(++index);
}
});
}
queueDownload(index);

How to do a very simple for loop

I want to accomplish this in coffeescript:
for (i = 0, i < count, i++) {
doSomething();
} // count is a number
But it is always handled as an array.
Is there way to prevent this? I have tried a while loop, but it didn´t work out for me.
Thanks!
First of all, you want to implement this:
for(i = 0; i < count; i++) { ... }
in CoffeeScript, not for(i = 0, ...).
There's an example of this sort of thing right in the documentation:
countdown = (num for num in [10..1])
and the JavaScript version:
var countdown, num;
countdown = (function() {
var _i, _results;
_results = [];
for (num = _i = 10; _i >= 1; num = --_i) {
_results.push(num);
}
return _results;
})();
So you just want to use this:
for i in [1..count]
doSomething()
or
doSomething() for i in [1..count]
Note the the range starts at 1 so that [1..count] gives you count iterations.

Extending Javascript objects with CoffeeScript

I want to add the ability to extend javascript objects by adding a method to the prototype.
The method will receive one or more other objects and will add all of the key/values to this.
This is what I came up with:
Object::extend = (objects...) ->
#[key] = value for key, value of object for object in objects
or this:
Object::extend = (objects...) ->
for object in objects
for key, value of object
#[key] = value
Both work as expected, and compile into the same javascript code:
var __slice = [].slice;
Object.prototype.extend = function() {
var key, object, objects, value, _i, _len, _results;
objects = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
_results = [];
for (_i = 0, _len = objects.length; _i < _len; _i++) {
object = objects[_i];
_results.push((function() {
var _results1;
_results1 = [];
for (key in object) {
value = object[key];
_results1.push(this[key] = value);
}
return _results1;
}).call(this));
}
return _results;
};
What I'm not too happy about is the whole results thing that is created per for loop which is completely redundant for my purpose.
Is there a way to get a code more like:
Object.prototype.extend = function() {
var key, object, objects, value, _i, _len;
objects = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
for (_i = 0, _len = objects.length; _i < _len; _i++) {
object = objects[_i];
(function() {
for (key in object) {
value = object[key];
this[key] = value;
}
}).call(this);
}
};
Thanks.
Edit
I'm aware that I can simply embed javascript code, but looking for a coffeescript solution.
You can try adding an explicit return:
Object::extend = (objects...) ->
for object in objects
for key, value of object
#[key] = value
return
That produces this:
var __slice = [].slice;
Object.prototype.extend = function() {
var key, object, objects, value, _i, _len;
objects = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
for (_i = 0, _len = objects.length; _i < _len; _i++) {
object = objects[_i];
for (key in object) {
value = object[key];
this[key] = value;
}
}
};
Every CoffeeScript function returns the value of the last expression in the function, CoffeeScript loops are also expressions. That means that CoffeeScript has to build all that _results stuff to produce a return value for your function since you had an implicit return applying to the outer loop. If you remove that implicit return by adding an explicit "return nothing" then the CS→JS compiler seems to be smart enough to not do all that extra _results work.

I'm trying to re-write this in CoffeeScript. Coming unstuck

function getElementsByClassName(className)
{
// get all elements in the document
if (document.all)
{
var allElements = document.all;
}
else
{
var allElements = document.getElementsByTagName("*");
}
var foundElements = [];
for (var i = 0, ii = allElements.length; i < ii; i++)
{
if (allElements[i].className == className)
{
foundElements[foundElements.length] = allElements[i];
}
}
return foundElements;
}
var listItems = document.getElementsByClassName("quirky");
for (var i = 0, ii = listItems.length; i < ii; i++)
{
alert(listItems[i].nodeName);
}
getElementsByClassName = (className) ->
# get all elements in the document
if document.all
allElements = document.all
else
allElements = document.getElementsByTagName "*"
el for el in allElements when el.className == className
# NOTE: getElementsByClassName was never assigned as a member
# of document. So this call will likely fail, unless you are
# using a latest-version browser.
listItems = document.getElementsByClassName "quirky"
for i in listItems
alert i.nodeName