Skip to content

Instantly share code, notes, and snippets.

@tyleraadams
Last active August 29, 2015 14:05
Show Gist options
  • Save tyleraadams/40ad94ae7e29c7b0437d to your computer and use it in GitHub Desktop.
Save tyleraadams/40ad94ae7e29c7b0437d to your computer and use it in GitHub Desktop.
/*LEARN YOU THE NODE.JS FOR MUCH WIN!
─────────────────────────────────────
BABY STEPS
Exercise 2 of 13
Write a program that accepts one or more numbers as command-line arguments and prints the sum of those numbers to the console (stdout).
-------------------------------------------------------------------------------
## HINTS
You can access command-line arguments via the global process object. The process object has an argv property which is an array containing the complete command-line. i.e. process.argv.
To get started, write a program that simply contains:
console.log(process.argv)
Run it with node program.js and some numbers as arguments. e.g:
$ node program.js 1 2 3
In which case the output would be an array looking something like:
[ 'node', '/path/to/your/program.js', '1', '2', '3' ]
You'll need to think about how to loop through the number arguments so you can output just their sum. The first element of the process.argv array is always 'node', and the second element is always the path to your program.js file, so you need to start at the 3rd element (index 2), adding each item to the total until you reach the end of the array.
Also be aware that all elements of process.argv are strings and you may need to coerce them into numbers. You can do this by prefixing the property with + or passing it to Number(). e.g. +process.argv[2] or Number(process.argv[2]).
learnyounode will be supplying arguments to your program when you run learnyounode verify program.js so you don't need to supply them yourself. To test your program without verifying it, you can invoke it with learnyounode run program.js. When you use run, you are invoking the test environment that learnyounode sets up for each exercise.
*/
// console.log(process.argv);
var array = process.argv;
var sum = 0;
for(var i=2; i<array.length; i++) {
sum += Number(array[i]);
}
console.log(sum);
/*HTTP CLIENT
Exercise 7 of 13
Write a program that performs an HTTP GET request to a URL provided to you as the first command-line argument. Write the String contents of each "data" event from the response to a new line on the console (stdout).
-------------------------------------------------------------------------------
## HINTS
For this exercise you will need to use the http core module.
Documentation on the http module can be found by pointing your browser here:
file:///usr/local/lib/node_modules/learnyounode/node_apidoc/http.html
The http.get() method is a shortcut for simple GET requests, use it to simplify your solution. The first argument to http.get() can be the URL you want to GET, provide a callback as the second argument.
Unlike other callback functions, this one has the signature:
function callback (response) { ... }
Where the response object is a Node Stream object. You can treat Node Streams as objects that emit events, the three events that are of most interest are: "data", "error" and "end". You listen to an event like so:
response.on("data", function (data) { ... })
The "data" is emitted when a chunk of data is available and can be processed. The size of the chunk depends upon the underlying data source.
The response object / Stream that you get from http.get() also has a setEncoding() method. If you call this method with "utf8", the "data" events will emit Strings rather than the standard Node Buffer objects which you have to explicitly convert to Strings.*/
var http = require('http');
var inputUrl = process.argv[2];
http.get(inputUrl, function(response) {
response.setEncoding('utf8');
response.on('error', console.error);
response.on('data', console.log);
});
/*HTTP COLLECT
Exercise 8 of 13
Write a program that performs an HTTP GET request to a URL provided to you as the first command-line argument. Collect all data from the server (not just the first "data" event) and then write two lines to the console (stdout).
The first line you write should just be an integer representing the number of characters received from the server and the second line should contain the complete String of characters sent by the server.
-------------------------------------------------------------------------------
## HINTS
There are two approaches you can take to this problem:
1) Collect data across multiple "data" events and append the results together prior to printing the output. Use the "end" event to determine when the stream is finished and you can write the output.
2) Use a third-party package to abstract the difficulties involved in collecting an entire stream of data. Two different packages provide a useful API for solving this problem (there are likely more!): bl (Buffer List) and concat-stream; take your pick!
[http://npm.im/bl](http://npm.im/bl)
[http://npm.im/concat-stream](http://npm.im/concat-stream)
To install a Node package, use the Node Package Manager npm. Simply type:
$ npm install bl
And it will download and install the latest version of the package into a subdirectory named node_modules. Any package in this subdirectory under your main program file can be loaded with the require syntax without being prefixed by './':
var bl = require('bl')
Node will first look in the core modules and then in the node_modules directory where the package is located.
If you don't have an Internet connection, simply make a node_modules directory and copy the entire directory for the package you want to use from inside the learnyounode installation directory:
file:///usr/local/lib/node_modules/learnyounode/node_modules/bl
file:///usr/local/lib/node_modules/learnyounode/node_modules/concat-stream
Both bl and concat-stream can have a stream piped in to them and they will collect the data for you. Once the stream has ended, a callback will be fired with the data:
response.pipe(bl(function (err, data) { ... }))
// or
response.pipe(concatStream(function (data) { ... }))
Note that you will probably need to data.toString() to convert from a Buffer.
Documentation for both of these modules has been installed along with learnyounode on your system and you can read them by pointing your browser here:
file:///usr/local/lib/node_modules/learnyounode/docs/bl.html
file:///usr/local/lib/node_modules/learnyounode/docs/concat-stream.html */
var http = require('http');
var inputUrl = process.argv[2];
http.get(inputUrl, function(response){
response.on('error', console.error);
response.setEncoding('utf8');
var dataArr = [];
response.on('data', function(data){
dataArr.push(data);
})
response.on('end', function(){
var result = dataArr.join('')
console.log(result.length);
console.log(result);
})
});
// var http = require('http')
// var bl = require('bl')
// http.get(process.argv[2], function (response) {
// response.pipe(bl(function (err, data) {
// if (err)
// return console.error(err)
// data = data.toString()
// console.log(data.length)
// console.log(data)
// }))
// })
var fs = require('fs');
var buffer = fs.readFileSync(process.argv[2]);
console.log(buffer.toString().split("\n").length-1)
fs = require('fs');
fs.readFile(process.argv[2], 'utf8', function(err, data) {
if(err) throw err;
var text = data;
var lines = text.split("\n").length - 1;
console.log(lines);
});
// JUGGLING ASYNC
// Exercise 9 of 13
// This problem is the same as the previous problem (HTTP COLLECT) in that you need to use http.get(). However, this time you will be provided with three URLs as the first three command-line arguments.
// You must collect the complete content provided to you by each of the URLs and print it to the console (stdout). You don't need to print out the length, just the data as a String; one line per URL. The catch is that you must print them out in the same order as the URLs are provided to you as command-line arguments.
// -------------------------------------------------------------------------------
// ## HINTS
// Don't expect these three servers to play nicely! They are not going to give you complete responses in the order you hope, so you can't naively just print the output as you get it because they will be out of order.
// You will need to queue the results and keep track of how many of the URLs have returned their entire contents. Only once you have them all, you can print the data to the console.
// Counting callbacks is one of the fundamental ways of managing async in Node. Rather than doing it yourself, you may find it more convenient to rely on a third-party library such as [async](http://npm.im/async) or [after](http://npm.im/after). But for this exercise, try and do it without any external helper library.
var http = require('http');
var urls = process.argv.slice(2, process.argv.length);
var countDown = urls.length;
var requestResults = [];
urls.map(function(currentUrl, index, array){
var mapping = { index: ''}
http.get(currentUrl,function(response){
response.setEncoding('utf8');
response.on('error', console.error);
var str = '';
response.on('data', function(data){
str += data
});
response.on('end', function(){
requestResults[index] = str
countDown--;
if(countDown === 0){
requestResults.map(function(result){
console.log(result);
});
}
});
});
});
// official nodeschool solution
// var http = require('http')
// var bl = require('bl')
// var results = []
// var count = 0
// function printResults () {
// for (var i = 0; i < 3; i++)
// console.log(results[i])
// }
// function httpGet (index) {
// http.get(process.argv[2 + index], function (response) {
// response.pipe(bl(function (err, data) {
// if (err)
// return console.error(err)
// results[index] = data.toString()
// count++
// if (count == 3) // yay! we are the last one!
// printResults()
// }))
// })
// }
// for (var i = 0; i < 3; i++)
// httpGet(i)
var modular = require('./modular')
var input = process.argv;
var pathTo = input[2];
var filter = input[3];
//read directory
modular(pathTo,filter, function(err, list){
if(err) console.log( "Err - ROAR" + err );
for(var i=0; i<list.length; i++){
console.log(list[i]);
}
});
/*LEARN YOU THE NODE.JS FOR MUCH WIN!
─────────────────────────────────────
MAKE IT MODULAR
Exercise 6 of 13
This problem is the same as the previous but introduces the concept of modules. You will need to create two files to solve this.
Create a program that prints a list of files in a given directory, filtered by the extension of the files. The first argument is the directory name and the second argument is the extension filter. Print the list of files (one file per line) to the console. You must use asynchronous I/O.
You must write a module file to do most of the work. The module must export a single function that takes three arguments: the directory name, the filename extension string and a callback function, in that order. The filename extension argument must be the same as was passed to your program. i.e. don't turn it in to a RegExp or prefix with "." or do anything else but pass it to your module where you can do what you need to make your filter work.
The callback function must be called using the idiomatic node(err, data) convention. This convention stipulates that unless there's an error, the first argument passed to the callback will be null, and the second will be your data. In this case the data will be your filtered list of files, as an Array. If you receive an error, e.g. from your call to fs.readdir(), the callback must be called with the error, and only the error, as the first argument.
You must not print directly to the console from your module file, only from your original program.
In the case of an error bubbling up to your original program file, simply check for it and print an informative message to the console.
These four things is the contract that your module must follow.
* Export a single function that takes exactly the arguments described.
* Call the callback exactly once with an error or some data as described.
* Don't change anything else, like global variables or stdout.
* Handle all the errors that may occur and pass them to the callback.
The benifit of having a contract is that your module can be used by anyone who expects this contract. So your module could be used by anyone else who does learnyounode, or the verifier, and just work.
-------------------------------------------------------------------------------
## HINTS
Create a new module by creating a new file that just contains your directory reading and filtering function. To define a single function export you assign your function to the module.exports object, overwriting what is already there:
module.exports = function (args) { ... }
Or you can use a named function and assign the name.
To use your new module in your original program file, use the require() call in the same way that you require('fs') to load the fs module. The only difference is that for local modules must be prefixed with './'. So, if your file is named mymodule.js then:
var mymodule = require('./mymodule.js')
The '.js' is optional here and you will often see it omitted.
You now have the module.exports object in your module assigned to the mymodule variable. Since you are exporting a single function, mymodule is a function you can call!
Also keep in mind that it is idiomatic to check for errors and do early-returns within callback functions:
function bar (callback) {
foo(function (err, data) {
if (err)
return callback(err) // early return
// ... no error, continue doing cool things with `data`
// all went well, call callback with `null` for the error argument
callback(null, data)
})
}
-------------------------------------------------------------------------------
» To print these instructions again, run: learnyounode print
» To execute your program in a test environment, run: learnyounode run program.js
» To verify your program, run: learnyounode verify program.js
» For help run: learnyounode help */
var fs = require('fs');
var path = require('path');
module.exports = function(dirName, extension, callback) {
extension = "." + extension;
fs.readdir(dirName, function(err, list){
if(err) return callback(err);
var data = [];
for(var i=0; i<list.length; i++){
if(path.extname(list[i]) === extension ){
data.push(list[i]);
}
}
// data = list.filter(function (file) {
// return path.extname(file) === '.' + filterStr
// }); proposed solution ^
callback(null, data)
});
}
/* TIME SERVER
Exercise 10 of 13
Write a TCP time server!
Your server should listen to TCP connections on the port provided by the first argument to your program. For each connection you must write the current date & 24 hour time in the format:
"YYYY-MM-DD hh:mm"
'Sun Aug 31 2014 15:34:52 GMT-0400 (EDT)'
followed by a newline character. Month, day, hour and minute must be zero-filled to 2 integers. For example:
"2013-07-06 17:42"
-------------------------------------------------------------------------------
## HINTS
For this exercise we'll be creating a raw TCP server. There's no HTTP involved here so we need to use the net module from Node core which has all the basic networking functions.
The net module has a method named net.createServer() that takes a callback function. Unlike most callbacks in Node, the callback used by createServer() is called more than once. Every connection received by your server triggers another call to the callback. The callback function has the signature:
function callback (socket) { ... }
net.createServer() also returns an instance of your server. You must call server.listen(portNumber) to start listening on a particular port.
A typical Node TCP server looks like this:
var net = require('net')
var server = net.createServer(function (socket) {
// socket handling logic
})
server.listen(8000)
Remember to use the port number supplied to you as the first command-line argument.
The socket object contains a lot of meta-data regarding the connection, but it is also a Node duplex Stream, in that it can be both read from, and written to. For this exercise we only need to write data and then close the socket.
Use socket.write(data) to write data to the socket and socket.end() to close the socket. Alternatively, the .end() method also takes a data object so you can simplify to just: socket.end(data).
Documentation on the net module can be found by pointing your browser here:
file:///usr/local/lib/node_modules/learnyounode/node_apidoc/net.html
To create the date, you'll need to create a custom format from a new Date() object. The methods that will be useful are:
date.getFullYear()
date.getMonth() // starts at 0
date.getDate() // returns the day of month
date.getHours()
date.getMinutes()
Or, if you want to be adventurous, use the strftime package from npm. The strftime(fmt, date) function takes date formats just like the unix date command. You can read more about strftime at: [https://github.com/samsonjs/strftime](https://github.com/samsonjs/strftime) */
var net = require('net');
var server = net.createServer(function(socket) {
var date = new Date();
console.log(date)
var year = date.getFullYear();
var month = date.getMonth() + 1;
if(month<10){
month = "0" + month
}
console.log(month)
var day = date.getDate()
var hours = date.getHours()
var minutes = date.getMinutes()
//"YYYY-MM-DD hh:mm"
var data = year + "-" + month + "-" + day + " " + hours + ":" + minutes + "\n"
socket.end(data)
});
server.listen(process.argv[2]);
// official solution
// var net = require('net')
// function zeroFill(i) {
// return (i < 10 ? '0' : '') + i
// }
// function now () {
// var d = new Date()
// return d.getFullYear() + '-'
// + zeroFill(d.getMonth() + 1) + '-'
// + zeroFill(d.getDate()) + ' '
// + zeroFill(d.getHours()) + ':'
// + zeroFill(d.getMinutes())
// }
// var server = net.createServer(function (socket) {
// socket.end(now() + '\n')
// })
// server.listen(Number(process.argv[2]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment