Why do I get an error running the code shown below ? (It's used in one of the homework's in the Stanford 'Startup engineering' course on Coursera: https://class.coursera.org/startup-001/quiz/attempt?quiz_id=149)
The course ran in june-sept 2013, so there may have been updates to node or csv that have broken the script, perhaps? The homework is not about fixing the script, so this question is not a 'cheat', and the course is not currently running anyway..
So, the environment is: Ubuntu 14.04 (kernel 3-13-0-29-generic), node v0.11.13, npm v1.4.9
And I have npm install
'd csv, accounting util and restler in the home directory, and the script is there too.
This has me completely stumped.... :-(
error message:
[ubuntu@ip-xxx-xxx-xxx-xxx:~]$node market-research.js
Invoked at command line.
Wrote market-research.csv
Symbol Name Market Cap Previous Close Price P/E Ratio Shares EPS Earnings
/home/ubuntu/market-research.js:47
csv()
^
TypeError: object is not a function
at csv2console (/home/ubuntu/market-research.js:47:5)
at Request.response2console (/home/ubuntu/market-research.js:65:13)
at Request.EventEmitter.emit (events.js:110:17)
at Request.mixin._fireSuccess (/home/ubuntu/node_modules/restler/lib/restler.js:226:10)
at /home/ubuntu/node_modules/restler/lib/restler.js:158:20
at IncomingMessage.parsers.auto (/home/ubuntu/node_modules/restler/lib/restler.js:394:7)
at Request.mixin._encode (/home/ubuntu/node_modules/restler/lib/restler.js:195:29)
at /home/ubuntu/node_modules/restler/lib/restler.js:154:16
at Request.mixin._decode (/home/ubuntu/node_modules/restler/lib/restler.js:170:7)
at IncomingMessage.<anonymous> (/home/ubuntu/node_modules/restler/lib/restler.js:147:14)
[ubuntu@ip-xxx-xxx-xxx-xxx:~]$
code:
#!/usr/bin/env node
/*
Use the Yahoo Finance CSV API to do some basic market research calculations.
- Background: http://greenido.wordpress.com/2009/12/22/yahoo-finance-hidden-api/
- Example URL: http://finance.yahoo.com/d/quotes.csv?s=GOOG+FB+AAPL&f=snj1pr
s: Symbol
n: Name
j1: Market Capitalization (in billions)
p: Price-per-share (at previous close)
r: Price to Earnings Ratio
Further references.
- https://github.com/danwrong/restler
- https://github.com/wdavidw/node-csv
- http://josscrowcroft.github.io/accounting.js
- http://stackoverflow.com/questions/4981891/node-js-equivalent-of-pythons-if-name-main
- http://nodejs.org/docs/latest/api/util.html#util_util_format_format
*/
var util = require('util');
var fs = require('fs');
var rest = require('restler');
var csv = require('csv');
var accounting = require('accounting');
var CSVFILE_DEFAULT = "market-research.csv";
var SYMBOLS_DEFAULT = ["GOOG", "FB", "AAPL", "YHOO", "MSFT", "LNKD", "CRM"];
var COLUMNS_DEFAULT = 'snj1pr'; // http://greenido.wordpress.com/2009/12/22/yahoo-finance-hidden-api
var HEADERS_DEFAULT = ["Symbol", "Name", "Market Cap", "Previous Close Price",
"P/E Ratio", "Shares", "EPS", "Earnings"];
var financeurl = function(symbols, columns) {
return util.format(
'http://finance.yahoo.com/d/quotes.csv?s=%s&f=%s',
symbols.join('+'),
columns);
};
var marketCapFloat = function(marketCapString) {
return parseFloat(marketCapString.split('B')[0]) * 1e9;
};
var csv2console = function(csvfile, headers) {
console.log(headers.join("\t"));
csv()
.from.path(csvfile)
.on('record', function(row, index) {
var shares = Math.round(marketCapFloat(row[2])/row[3], 0);
var eps = (row[3]/row[4]).toFixed(3);
var earnings = accounting.formatMoney(eps * shares);
outrow = row.concat([shares, eps, earnings]);
console.log(outrow.join("\t"));
});
};
var buildfn = function(csvfile, headers) {
var response2console = function(result, response) {
if (result instanceof Error) {
console.error('Error: ' + util.format(response.message));
} else {
console.error("Wrote %s", csvfile);
fs.writeFileSync(csvfile, result);
csv2console(csvfile, headers);
}
};
return response2console;
};
var marketResearch = function(symbols, columns, csvfile, headers) {
symbols = symbols || SYMBOLS_DEFAULT;
columns = columns || COLUMNS_DEFAULT;
csvfile = csvfile || CSVFILE_DEFAULT;
headers = headers || HEADERS_DEFAULT;
var apiurl = financeurl(symbols, columns);
var response2console = buildfn(csvfile, headers);
rest.get(apiurl).on('complete', response2console);
};
if(require.main == module) {
console.error('Invoked at command line.');
var symbols = process.argv;
if(symbols.length > 2) {
symbols = symbols.slice(2, symbols.length);
} else {
symbols = undefined;
};
marketResearch(symbols);
} else {
console.error('Invoked via library call');
}
exports.marketResearch = marketResearch;
contents of market-research.csv created by the script:
"GOOG","Google Inc.",386.6B,569.20,29.49
"FB","Facebook, Inc.",194.5B,73.855,78.49
"AAPL","Apple Inc.",613.8B,102.25,16.49
"YHOO","Yahoo! Inc.",38.302B,38.31,33.11
"MSFT","Microsoft Corpora",374.3B,44.88,17.06
"LNKD","LinkedIn Corporat",27.747B,223.26,N/A
"CRM","Salesforce.com In",36.577B,58.29,N/A
The TypeError: "x" is not a function can be fixed using the following suggestions: Paying attention to detail in code and minimizing typos. Importing the correct and relevant script libraries used in code. Making sure the called property of an object is actually a function.
The TypeError object represents an error when an operation could not be performed, typically (but not exclusively) when a value is not of the expected type. A TypeError may be thrown when: an operand or argument passed to a function is incompatible with the type expected by that operator or function; or.
Within the Node framework a TypeError indicates that a passed argument is not of the appropriate type. This method is used liberally throughout the built-in Node API modules, and should also be used within your own custom code to perform type checking at the top of of your functions and methods.
The throw statement throws a user-defined exception. Execution of the current function will stop (the statements after throw won't be executed), and control will be passed to the first catch block in the call stack.
Quantas 94 Heavy, thanks for the hint.
12 months ago, node-csv was at version 0.2, but it is now at 0.4 and the API has changed.
I've now written the csv-console function as follows:
// part of file market-script.js
// edited by Jeff Moye (Moyesoft)
// no attribution in the original file
var csv2console = function(csvfile, headers) {
console.log(headers.join("\t"));
var parser = csv.parse(); //create the parser
parser.on('readable', function(){ //the 'record' event no longer exists
// so instead we write a handler for the
// 'readable' event
while(record = parser.read()){ // and read() each record in a loop
var shares = Math.round(marketCapFloat(record[2])/record[3], 0);
var eps = (record[3]/record[4]).toFixed(3);
var earnings = accounting.formatMoney(eps * shares);
outrow = record.concat([shares, eps, earnings]);
console.log(outrow.join("\t"));
}
});
parser.on('error', function(err){ // we may as well have an error handler
console.log(err.message);
});
fs.createReadStream(csvfile).pipe(parser); //open file as a stream and pipe it to the parser
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With