From a88d63378cd8120097e51bbc3abf3fc90c450f87 Mon Sep 17 00:00:00 2001 From: Kevin Stumpf Date: Thu, 15 Oct 2015 17:42:37 -0700 Subject: [PATCH] v1.0.0 --- README.md | 63 ++++++++++++++++++++++- index.js | 1 + lib/momentDurationFormatFrequency.js | 63 +++++++++++++++++++++++ package.json | 33 ++++++++++++ test/momentDurationFormatFrequencySpec.js | 50 ++++++++++++++++++ 5 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 index.js create mode 100644 lib/momentDurationFormatFrequency.js create mode 100644 package.json create mode 100644 test/momentDurationFormatFrequencySpec.js diff --git a/README.md b/README.md index d9e6fc0..9b83ce9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,61 @@ -# frequency-formatter -Formats time interval to human readable string +# Moment Duration Format Frequency + +**Format plugin for the Moment Duration object.** + +This is a plugin to the Moment.js JavaScript date library to add frequency formatting to Moment Durations. + + +--- + +## Installation + +**Node.js** + +`npm install moment-duration-format-frequency` + + +## Usage + +### Module + +To use this plugin as a module, use the `require` function: +``` +require("moment-duration-format-frequency"); +``` + +The plugin does not export anything, so there is no need to assign the require output to a variable. + +The plugin depends on moment.js. + + +### Basics + +The duration format method can format moment durations as human readable frequencies: + +``` +moment.duration(1.5, 'weeks').formatAsFrequency('weeks'); +// "every 1-2 weeks" + +moment.duration(0.23, 'weeks').formatAsFrequency('weeks'); +// "4-5 times per week" + +moment.duration(3, 'weeks').formatAsFrequency('weeks'); +// "every 3 weeks" + +moment.duration(0.25, 'weeks').formatAsFrequency('weeks'); +// "4 times per week" + +moment.duration(3, 'years').formatAsFrequency('years'); +// "every 3 years" +``` + +### Customization + +Individual strings can be customized: + +``` +moment.duration.fn.formatAsFrequency.defaults.everyString = 'alle'; + +moment.duration(3, 'years').formatAsFrequency('years'); +// "alle 3 years" +``` \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..dcf4dca --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/frequencyFormatter'); \ No newline at end of file diff --git a/lib/momentDurationFormatFrequency.js b/lib/momentDurationFormatFrequency.js new file mode 100644 index 0000000..f387bb5 --- /dev/null +++ b/lib/momentDurationFormatFrequency.js @@ -0,0 +1,63 @@ +/* jshint node: true */ + +'use strict'; + +var moment = require('moment'); +var util = require('util'); +var _ = require('lodash'); +var isNaturalNumber = require('is-natural-number'); + +(function(moment) { + var roundNumber = function(number) { + return parseFloat(number.toFixed(2)); + }; + + var isApproximatelyNaturalNumber = function(number) { + return isNaturalNumber(roundNumber(number)); + }; + + moment.duration.fn.formatAsFrequency = function(unit, options) { + options = options || {}; + _.defaults(options, this.formatAsFrequency.defaults); + + var unitDuration = moment.duration(1, unit); + var isValidUnit = unitDuration.asMilliseconds() > 0; + if (!isValidUnit) { + throw new Error(util.format('%s is not a valid moment unit', unit)); + } + + var intervalInMs = this.asMilliseconds(); + var unitDurationInMs = unitDuration.asMilliseconds(); + + var unitSingular = moment.normalizeUnits(unit); + var unitPlural = unitSingular + 's'; + + if (intervalInMs === unitDurationInMs) { + return util.format('%s %s', options.everyString, unitSingular); + } + + if (intervalInMs < unitDurationInMs) { + var numberOfIntervalsPerUnit = unitDurationInMs / intervalInMs; + if (isApproximatelyNaturalNumber(numberOfIntervalsPerUnit)) { + return util.format('%d %s %s %s', roundNumber(numberOfIntervalsPerUnit), options.timesString, options.perString, unitSingular); + } + + return util.format('%d%s%d %s %s %s', Math.floor(numberOfIntervalsPerUnit), options.separatorString, Math.ceil(numberOfIntervalsPerUnit), options.timesString, options.perString, unitSingular); + } + + var numberOfUnitsPerInterval = intervalInMs / unitDuration; + if (isApproximatelyNaturalNumber(numberOfUnitsPerInterval)) { + return util.format('%s %d %s', options.everyString, roundNumber(numberOfUnitsPerInterval), unitPlural); + } + + return util.format('%s %d%s%d %s', options.everyString, Math.floor(numberOfUnitsPerInterval), options.separatorString, Math.ceil(numberOfUnitsPerInterval), unitPlural); + + }; + + moment.duration.fn.formatAsFrequency.defaults = { + everyString: 'every', + perString: 'per', + timesString: 'times', + separatorString: '-' + }; +})(moment); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..ef6c60d --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "moment-duration-format-frequency", + "version": "1.0.0", + "description": "Formats time interval to human readable string", + "main": "index.js", + "scripts": { + "test": "mocha test" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/DispatcherInc/moment-duration-format-frequency.git" + }, + "keywords": [ + "frequency", + "format", + "interval", + "string" + ], + "author": "Kevin Stumpf", + "license": "ISC", + "bugs": { + "url": "https://github.com/DispatcherInc/moment-duration-format-frequency/issues" + }, + "homepage": "https://github.com/DispatcherInc/moment-duration-format-frequency#readme", + "devDependencies": { + "chai": "^3.3.0" + }, + "dependencies": { + "is-natural-number": "^2.0.0", + "lodash": "^3.10.1", + "moment": ">=1.4.0" + } +} diff --git a/test/momentDurationFormatFrequencySpec.js b/test/momentDurationFormatFrequencySpec.js new file mode 100644 index 0000000..3b0f95a --- /dev/null +++ b/test/momentDurationFormatFrequencySpec.js @@ -0,0 +1,50 @@ +/* jshint node: true */ + +'use strict'; + +var chai = require('chai'); +var expect = chai.expect; +var moment = require('moment'); + +require('./../lib/momentDurationFormatFrequency'); + +describe('moment-duration-format-frequency', function() { + it('should work with frequencies greater than 1 per unit', function() { + var everyOneAndAHalfWeeks = moment.duration(1.5, 'weeks'); + + expect(everyOneAndAHalfWeeks.formatAsFrequency('weeks')).to.eql('every 1-2 weeks'); + }); + + it('should work with frequencies less than 1 per unit', function() { + var fourToFiveTimesPerWeek = moment.duration(0.23, 'weeks'); + + expect(fourToFiveTimesPerWeek.formatAsFrequency('weeks')).to.eql('4-5 times per week'); + }); + + it('should work with frequencies of 1 per unit', function() { + var everyThreeWeeks = moment.duration(3, 'weeks'); + + expect(everyThreeWeeks.formatAsFrequency('weeks')).to.eql('every 3 weeks'); + }); + + it('should work with frequencies whose inverse is a natural number', function() { + var fourTimesPerWeek = moment.duration(0.25, 'weeks'); + + expect(fourTimesPerWeek.formatAsFrequency('weeks')).to.eql('4 times per week'); + }); + + it('should work with years unit as well', function() { + var everyThreeYears = moment.duration(3, 'years'); + + expect(everyThreeYears.formatAsFrequency('years')).to.eql('every 3 years'); + }); + + describe('defaults', function() { + it('everyString should be overwritable', function() { + moment.duration.fn.formatAsFrequency.defaults.everyString = 'alle'; + + var everyThreeYears = moment.duration(3, 'years'); + expect(everyThreeYears.formatAsFrequency('years')).to.eql('alle 3 years'); + }); + }); +}); \ No newline at end of file