UNPKG

weathernaut

Version:

CLI tool for querying the Weather Underground API

330 lines (288 loc) 12.9 kB
// Generated by CoffeeScript 1.7.1 (function() { var WeathernautDefaultFormatter, WeathernautStore, async, fs, handleError, path, request, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; require('colors'); request = require('request'); fs = require('fs'); path = require('path'); async = require('async'); handleError = function(func, err) { console.error("Error in " + func + ": " + (err.toString().red)); return process.exit(1); }; WeathernautStore = (function() { WeathernautStore.prototype.apiKey = null; WeathernautStore.prototype.cacheFile = null; WeathernautStore.prototype.cache = null; WeathernautStore.prototype.maxCacheAgeInMsec = null; function WeathernautStore(apiKey) { this.apiKey = apiKey; this.getDataFor = __bind(this.getDataFor, this); this.updateCacheFor = __bind(this.updateCacheFor, this); this.writeMemoryCacheToDisk = __bind(this.writeMemoryCacheToDisk, this); this.doAPIRequest = __bind(this.doAPIRequest, this); this.cachedDataIsValidFor = __bind(this.cachedDataIsValidFor, this); this.cachedDataIsNotStaleFor = __bind(this.cachedDataIsNotStaleFor, this); this.cachedDataExistsFor = __bind(this.cachedDataExistsFor, this); this.readCacheFile = __bind(this.readCacheFile, this); this.cacheFile = path.join(process.env.HOME, '.weathernaut-cache'); this.maxCacheAgeInMsec = 1000 * 60 * 60 * 12; this.cache = this.readCacheFile(); } WeathernautStore.prototype.readCacheFile = function() { var err; if (!fs.existsSync(this.cacheFile)) { fs.writeFileSync(this.cacheFile, JSON.stringify({})); } try { return JSON.parse(fs.readFileSync(this.cacheFile).toString()); } catch (_error) { err = _error; return {}; } }; WeathernautStore.prototype.cachedDataExistsFor = function(service, zipcode) { var _ref, _ref1; return ((_ref = this.cache) != null ? (_ref1 = _ref[service]) != null ? _ref1[zipcode] : void 0 : void 0) != null; }; WeathernautStore.prototype.cachedDataIsNotStaleFor = function(service, zipcode) { var _ref, _ref1, _ref2; return (new Date().getTime() - ((_ref = this.cache) != null ? (_ref1 = _ref[service]) != null ? (_ref2 = _ref1[zipcode]) != null ? _ref2.retrievedOn : void 0 : void 0 : void 0)) < this.maxCacheAgeInMsec; }; WeathernautStore.prototype.cachedDataIsValidFor = function(service, zipcode) { return this.cachedDataExistsFor(service, zipcode) && this.cachedDataIsNotStaleFor(service, zipcode); }; WeathernautStore.prototype.doAPIRequest = function(service, zipcode, callback) { var url; url = "http://api.wunderground.com/api/" + this.apiKey + "/" + service + "/q/" + zipcode + ".json"; return request(url, (function(_this) { return function(err, response, body) { var responseObj, _ref, _ref1; if (err != null) { handleError('doAPIRequest', err); } if ((response != null ? response.statusCode : void 0) !== 200) { handleError('doAPIRequest', "http status code was " + (response != null ? (_ref = response.statusCode) != null ? _ref.toString().yellow : void 0 : void 0)); } try { responseObj = JSON.parse(body != null ? typeof body.toString === "function" ? body.toString() : void 0 : void 0); if ((responseObj != null ? (_ref1 = responseObj.response) != null ? _ref1.error : void 0 : void 0) != null) { throw new Error(responseObj.response.error.type); } responseObj.retrievedOn = new Date().getTime(); delete responseObj.response; return callback(null, responseObj); } catch (_error) { err = _error; return callback(err); } }; })(this)); }; WeathernautStore.prototype.writeMemoryCacheToDisk = function(callback) { var err; try { fs.writeFileSync(this.cacheFile, JSON.stringify(this.cache)); return callback(); } catch (_error) { err = _error; handleError('writeMemoryCacheToDisk', err); return callback(err); } }; WeathernautStore.prototype.updateCacheFor = function(service, zipcode, callback) { return this.doAPIRequest(service, zipcode, (function(_this) { return function(err, dataForZip) { var _base; if (err != null) { return callback(err); } if ((_base = _this.cache)[service] == null) { _base[service] = {}; } _this.cache[service][zipcode] = dataForZip; return _this.writeMemoryCacheToDisk(function(err) { if (err) { handleError('updateCacheFor', err); } return callback(); }); }; })(this)); }; WeathernautStore.prototype.getDataFor = function(service, zipcode, callback) { if (this.cachedDataIsValidFor(service, zipcode)) { return callback(null, this.cache[service][zipcode]); } else { return this.updateCacheFor(service, zipcode, (function(_this) { return function(err) { if (err) { handleError('getDataFor', err); } return callback(err, _this.cache[service][zipcode]); }; })(this)); } }; return WeathernautStore; })(); WeathernautDefaultFormatter = (function() { function WeathernautDefaultFormatter() { this.formatForecastDay = __bind(this.formatForecastDay, this); this.formatForecastHeader = __bind(this.formatForecastHeader, this); this.printForecastData = __bind(this.printForecastData, this); this.formatAstronomicalLine = __bind(this.formatAstronomicalLine, this); this.formatAstronomicalHeader = __bind(this.formatAstronomicalHeader, this); this.printAstronomicalData = __bind(this.printAstronomicalData, this); } WeathernautDefaultFormatter.prototype.printAstronomicalData = function(zip, data) { var err, formattedLines, header, line, lines, moon_phase, percentIlluminated, sunrise, sunset, _ref, _ref1, _ref2, _ref3; try { moon_phase = data.moon_phase; percentIlluminated = moon_phase.percentIlluminated, sunrise = moon_phase.sunrise, sunset = moon_phase.sunset; lines = [ { label: 'moon: ', data: "" + (percentIlluminated != null ? typeof percentIlluminated.toString === "function" ? percentIlluminated.toString() : void 0 : void 0) + "% full" }, { label: 'sunrise: ', data: "" + (sunrise != null ? (_ref = sunrise.hour) != null ? typeof _ref.toString === "function" ? _ref.toString() : void 0 : void 0 : void 0) + ":" + (sunrise != null ? (_ref1 = sunrise.minute) != null ? typeof _ref1.toString === "function" ? _ref1.toString() : void 0 : void 0 : void 0) }, { label: 'sunset: ', data: "" + (sunset != null ? (_ref2 = sunset.hour) != null ? typeof _ref2.toString === "function" ? _ref2.toString() : void 0 : void 0 : void 0) + ":" + (sunset != null ? (_ref3 = sunset.minute) != null ? _ref3.toString() : void 0 : void 0) } ]; header = this.formatAstronomicalHeader(zip); formattedLines = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = lines.length; _i < _len; _i++) { line = lines[_i]; _results.push(this.formatAstronomicalLine(line)); } return _results; }).call(this); console.log(header); return console.log(formattedLines.join('\n')); } catch (_error) { err = _error; return handleError('WeathernautDefaultFormatter::printAstronomicalData', err); } }; WeathernautDefaultFormatter.prototype.formatAstronomicalHeader = function(zipcode) { return '***'.white.bold + (" astronomy for " + zipcode + " ").red.bold + '***'.white.bold; }; WeathernautDefaultFormatter.prototype.formatAstronomicalLine = function(line) { return ' --> '.white.bold + line.label.toString().red + ' ' + line.data.toString().white; }; WeathernautDefaultFormatter.prototype.printForecastData = function(zip, data, maxDays) { var day, err, formattedDays, header, highs, lows, spacesBetweenDays; if (maxDays == null) { maxDays = 10; } try { header = this.formatForecastHeader(zip, maxDays); formattedDays = (function() { var _i, _len, _ref, _results; _ref = data.forecast.simpleforecast.forecastday.splice(0, maxDays); _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { day = _ref[_i]; _results.push(this.formatForecastDay(day)); } return _results; }).call(this); spacesBetweenDays = 4; spacesBetweenDays = Array(spacesBetweenDays + 1).join(' '); highs = ((function() { var _i, _len, _results; _results = []; for (_i = 0, _len = formattedDays.length; _i < _len; _i++) { day = formattedDays[_i]; _results.push(day.high); } return _results; })()).join(spacesBetweenDays); lows = ((function() { var _i, _len, _results; _results = []; for (_i = 0, _len = formattedDays.length; _i < _len; _i++) { day = formattedDays[_i]; _results.push(day.low); } return _results; })()).join(spacesBetweenDays); return console.log([header, highs, lows].join('\n')); } catch (_error) { err = _error; return handleError('WeathernautDefaultFormatter::printForecastData', err); } }; WeathernautDefaultFormatter.prototype.formatForecastHeader = function(zip, maxDays) { return '***'.white.bold + (" " + maxDays + "-day forecast for " + zip + " ").red.bold + '***'.white.bold; }; WeathernautDefaultFormatter.prototype.formatForecastDay = function(day) { var dateNum, dateNumColored, dateNumInner, dateWeekday, high, length, low, padding; low = day.low.fahrenheit.toString(); high = day.high.fahrenheit.toString(); dateNumInner = "" + day.date.month + "/" + day.date.day; dateNum = "(" + dateNumInner + ") "; dateNumColored = "(" + dateNumInner.cyan + ") "; dateWeekday = "" + day.date.weekday_short + ": "; length = [dateWeekday.length, ("(" + dateNumInner + ") ").length]; padding = [0, 0]; padding[0] = length[0] < length[1] ? length[1] - length[0] : 0; padding[1] = length[0] > length[1] ? length[0] - length[1] : 0; padding[0] = Array(padding[0] + 1).join(' '); padding[1] = Array(padding[1] + 1).join(' '); return { high: "" + dateWeekday + padding[0] + high.red + "F", low: "" + dateNumColored + padding[1] + low.blue.bold + "F" }; }; return WeathernautDefaultFormatter; })(); exports.Weathernaut = (function() { Weathernaut.prototype.apiKey = null; Weathernaut.prototype.store = null; Weathernaut.prototype.formatter = null; function Weathernaut(apiKey) { this.apiKey = apiKey; this.printForecastDataFor = __bind(this.printForecastDataFor, this); this.printAstronomicalDataFor = __bind(this.printAstronomicalDataFor, this); this.store = new WeathernautStore(this.apiKey); this.formatter = new WeathernautDefaultFormatter(); } Weathernaut.VALID_SERVICES = { astronomy: 'astronomy', forecast: 'forecast10day' }; Weathernaut.validServices = function() { return Object.keys(Weathernaut.VALID_SERVICES); }; Weathernaut.prototype.printAstronomicalDataFor = function(zipcode) { return this.store.getDataFor(Weathernaut.VALID_SERVICES.astronomy, zipcode, (function(_this) { return function(err, data) { if (err != null) { return handleError('Weathernaut::printAstronomicalDataFor', err); } else { return _this.formatter.printAstronomicalData(zipcode, data); } }; })(this)); }; Weathernaut.prototype.printForecastDataFor = function(zipcode, maxDays) { return this.store.getDataFor(Weathernaut.VALID_SERVICES.forecast, zipcode, (function(_this) { return function(err, data) { if (err != null) { return handleError('Weathernaut::printForecastDataFor', err); } else { return _this.formatter.printForecastData(zipcode, data, maxDays); } }; })(this)); }; return Weathernaut; })(); }).call(this);