pax_global_header00006660000000000000000000000064125752035750014525gustar00rootroot0000000000000052 comment=4add1b491840c17c80cd0ca8145505d663955861 normalize-range-0.1.2/000077500000000000000000000000001257520357500146175ustar00rootroot00000000000000normalize-range-0.1.2/.editorconfig000066400000000000000000000002741257520357500172770ustar00rootroot00000000000000root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.md] trim_trailing_whitespace = false normalize-range-0.1.2/.gitattributes000066400000000000000000000000141257520357500175050ustar00rootroot00000000000000* text=auto normalize-range-0.1.2/.gitignore000066400000000000000000000001051257520357500166030ustar00rootroot00000000000000*.log /coverage/ /node_modules/ /.idea/ /sandbox.* /sandbox/ /build/ normalize-range-0.1.2/.jscsrc000066400000000000000000000003601257520357500161060ustar00rootroot00000000000000{ "preset" : "google", "fileExtensions": [".js"], "validateQuoteMarks" : { "mark": "'", "escape": true }, "excludeFiles" : ["node_modules/**", "test/**", "coverage/**", "dist/**", "build/**", "sandbox.js", "sandbox/**"] } normalize-range-0.1.2/.jshintrc000066400000000000000000000002641257520357500164460ustar00rootroot00000000000000{ "node": true, "esnext": true, "bitwise": true, "curly": true, "immed": true, "newcap": true, "noarg": true, "undef": true, "unused": "vars", "strict": true } normalize-range-0.1.2/.travis.yml000066400000000000000000000003741257520357500167340ustar00rootroot00000000000000sudo: false language: node_js node_js: - 'iojs' - '0.12' - '0.10' after_script: - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js - cat ./coverage/lcov.info | ./node_modules/codeclimate-test-reporter/bin/codeclimate.js normalize-range-0.1.2/index.js000066400000000000000000000026561257520357500162750ustar00rootroot00000000000000'use strict'; module.exports = { wrap: wrapRange, limit: limitRange, validate: validateRange, test: testRange, curry: curry, name: name }; function wrapRange(min, max, value) { var maxLessMin = max - min; return ((value - min) % maxLessMin + maxLessMin) % maxLessMin + min; } function limitRange(min, max, value) { return Math.max(min, Math.min(max, value)); } function validateRange(min, max, value, minExclusive, maxExclusive) { if (!testRange(min, max, value, minExclusive, maxExclusive)) { throw new Error(value + ' is outside of range [' + min + ',' + max + ')'); } return value; } function testRange(min, max, value, minExclusive, maxExclusive) { return !( value < min || value > max || (maxExclusive && (value === max)) || (minExclusive && (value === min)) ); } function name(min, max, minExcl, maxExcl) { return (minExcl ? '(' : '[') + min + ',' + max + (maxExcl ? ')' : ']'); } function curry(min, max, minExclusive, maxExclusive) { var boundNameFn = name.bind(null, min, max, minExclusive, maxExclusive); return { wrap: wrapRange.bind(null, min, max), limit: limitRange.bind(null, min, max), validate: function(value) { return validateRange(min, max, value, minExclusive, maxExclusive); }, test: function(value) { return testRange(min, max, value, minExclusive, maxExclusive); }, toString: boundNameFn, name: boundNameFn }; } normalize-range-0.1.2/license000066400000000000000000000021401257520357500161610ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) James Talmage (github.com/jamestalmage) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. normalize-range-0.1.2/package.json000066400000000000000000000022401257520357500171030ustar00rootroot00000000000000{ "name": "normalize-range", "version": "0.1.2", "description": "Utility for normalizing a numeric range, with a wrapping function useful for polar coordinates", "license": "MIT", "repository": "jamestalmage/normalize-range", "author": { "name": "James Talmage", "email": "james@talmage.io", "url": "github.com/jamestalmage" }, "engines": { "node": ">=0.10.0" }, "scripts": { "test": "npm run cover && npm run lint && npm run style", "cover": "istanbul cover ./node_modules/.bin/_mocha", "lint": "jshint --reporter=node_modules/jshint-stylish *.js test/*.js", "debug": "mocha", "watch": "mocha -w", "style": "jscs *.js ./**/*.js && jscs ./test/** --config=./test/.jscsrc" }, "files": [ "index.js" ], "keywords": [ "range", "normalize", "utility", "angle", "degrees", "polar" ], "dependencies": {}, "devDependencies": { "almost-equal": "^1.0.0", "codeclimate-test-reporter": "^0.1.0", "coveralls": "^2.11.2", "istanbul": "^0.3.17", "jscs": "^2.1.1", "jshint": "^2.8.0", "jshint-stylish": "^2.0.1", "mocha": "^2.2.5", "stringify-pi": "0.0.3" } } normalize-range-0.1.2/readme.md000066400000000000000000000076551257520357500164130ustar00rootroot00000000000000# normalize-range Utility for normalizing a numeric range, with a wrapping function useful for polar coordinates. [![Build Status](https://travis-ci.org/jamestalmage/normalize-range.svg?branch=master)](https://travis-ci.org/jamestalmage/normalize-range) [![Coverage Status](https://coveralls.io/repos/jamestalmage/normalize-range/badge.svg?branch=master&service=github)](https://coveralls.io/github/jamestalmage/normalize-range?branch=master) [![Code Climate](https://codeclimate.com/github/jamestalmage/normalize-range/badges/gpa.svg)](https://codeclimate.com/github/jamestalmage/normalize-range) [![Dependency Status](https://david-dm.org/jamestalmage/normalize-range.svg)](https://david-dm.org/jamestalmage/normalize-range) [![devDependency Status](https://david-dm.org/jamestalmage/normalize-range/dev-status.svg)](https://david-dm.org/jamestalmage/normalize-range#info=devDependencies) [![NPM](https://nodei.co/npm/normalize-range.png)](https://nodei.co/npm/normalize-range/) ## Usage ```js var nr = require('normalize-range'); nr.wrap(0, 360, 400); //=> 40 nr.wrap(0, 360, -90); //=> 270 nr.limit(0, 100, 500); //=> 100 nr.limit(0, 100, -20); //=> 0 // There is a convenient currying function var wrapAngle = nr.curry(0, 360).wrap; var limitTo10 = nr.curry(0, 10).limit; wrapAngle(-30); //=> 330 ``` ## API ### wrap(min, max, value) Normalizes a values that "wraps around". For example, in a polar coordinate system, 270˚ can also be represented as -90˚. For wrapping purposes we assume `max` is functionally equivalent to `min`, and that `wrap(max + 1) === wrap(min + 1)`. Wrap always assumes that `min` is *inclusive*, and `max` is *exclusive*. In other words, if `value === max` the function will wrap it, and return `min`, but `min` will not be wrapped. ```js nr.wrap(0, 360, 0) === 0; nr.wrap(0, 360, 360) === 0; nr.wrap(0, 360, 361) === 1; nr.wrap(0, 360, -1) === 359; ``` You are not restricted to whole numbers, and ranges can be negative. ```js var π = Math.PI; var radianRange = nr.curry(-π, π); redianRange.wrap(0) === 0; nr.wrap(π) === -π; nr.wrap(4 * π / 3) === -2 * π / 3; ``` ### limit(min, max, value) Normalize the value by bringing it within the range. If `value` is greater than `max`, `max` will be returned. If `value` is less than `min`, `min` will be returned. Otherwise, `value` is returned unaltered. Both ends of this range are *inclusive*. ### test(min, max, value, [minExclusive], [maxExclusive]) Returns `true` if `value` is within the range, `false` otherwise. It defaults to `inclusive` on both ends of the range, but that can be changed by setting `minExclusive` and/or `maxExclusive` to a truthy value. ### validate(min, max, value, [minExclusive], [maxExclusive]) Returns `value` or throws an error if `value` is outside the specified range. ### name(min, max, value, [minExclusive], [maxExclusive]) Returns a string representing this range in [range notation](https://en.wikipedia.org/wiki/Interval_(mathematics)#Classification_of_intervals). ### curry(min, max, [minExclusive], [maxExclusive]) Convenience method for currying all method arguments except `value`. ```js var angle = require('normalize-range').curry(-180, 180, false, true); angle.wrap(270) //=> -90 angle.limit(200) //=> 180 angle.test(0) //=> true angle.validate(300) //=> throws an Error angle.toString() // or angle.name() //=> "[-180,180)" ``` #### min *Required* Type: `number` The minimum value (inclusive) of the range. #### max *Required* Type: `number` The maximum value (exclusive) of the range. #### value *Required* Type: `number` The value to be normalized. #### returns Type: `number` The normalized value. ## Building and Releasing - `npm test`: tests, linting, coverage and style checks. - `npm run watch`: autotest mode for active development. - `npm run debug`: run tests without coverage (istanbul can obscure line #'s) Release via `cut-release` tool. ## License MIT © [James Talmage](http://github.com/jamestalmage) normalize-range-0.1.2/test/000077500000000000000000000000001257520357500155765ustar00rootroot00000000000000normalize-range-0.1.2/test/.jscsrc000066400000000000000000000002301257520357500170610ustar00rootroot00000000000000{ "preset" : "google", "fileExtensions": [".js"], "validateQuoteMarks" : { "mark": "'", "escape": true }, "maximumLineLength" : 120 } normalize-range-0.1.2/test/.jshintrc000066400000000000000000000000611257520357500174200ustar00rootroot00000000000000{ "extends": "../.jshintrc", "mocha": true } normalize-range-0.1.2/test/test.js000066400000000000000000000113201257520357500171100ustar00rootroot00000000000000'use strict'; var assert = require('assert'); var ranges = require('../'); var namePi = require('stringify-pi'); var almostEqual = require('almost-equal'); var π = Math.PI; function close(a, b) { return almostEqual(a, b, almostEqual.DBL_EPSILON, almostEqual.DBL_EPSILON); } function names(type, min, max, value, expected, minExcl, maxExcl) { var lb = minExcl ? '(' : '['; var rb = maxExcl ? ')' : ']'; var rangeName = type + ': ' + lb + namePi(min) + ',' + namePi(max) + rb; var testName = rangeName + ' ' + namePi(value) + ' === ' + namePi(expected); return { range: rangeName, test: testName }; } function _test(type, min, max, value, expected, minExcl, maxExcl) { var n = names(type, min, max, value, expected, minExcl, maxExcl); it(n.test, function() { var result = ranges[type](min, max, value, minExcl, maxExcl); if (!close(result, expected)) { assert.strictEqual( result, expected, n.range ); } }); } describe('wrap ', function() { function test(min, max, value, expected) { return _test('wrap', min, max, value, expected, false, true); } var angleWrap = ranges.curry(0, 360).wrap; function angle(value, expected) { test(0, 360, value, expected); var message = 'angleWrap(' + value + ') === ' + expected; it(message, function() { assert.strictEqual( angleWrap(value), expected, message ); }); } function angle2(value, expected) { test(-180, 180, value, expected); } angle(-270, 90); angle(-20, 340); angle(0, 0); angle(20, 20); angle(100, 100); angle(352.5, 352.5); angle(360, 0); angle(400, 40); angle(720, 0); angle2(-200, 160); angle2(-181, 179); angle2(-180, -180); angle2(-20, -20); angle2(0, 0); angle2(0, 0); test(-π, π, -π, -π); test(-π, π, 0, 0); test(-π, π, 2 * π, 0); test(-π, π, 2 * π / 3, 2 * π / 3); test(-π, π, 4 * π / 3, -2 * π / 3); }); describe('limit', function() { var test = _test.bind(null, 'limit'); test(0, 10, -1, 0); test(0, 10, 0, 0); test(0, 10, 5, 5); test(0, 10, 10, 10); test(0, 10, 11, 10); }); describe('test', function() { function isOk(min, max, value, minExcl, maxExcl, ok) { var n = names('test', min, max, value, ok ? 'ok' : 'notOk', minExcl, maxExcl); it(n.test, function() { assert.strictEqual( !!ok, ranges.test(min, max, value, minExcl, maxExcl), n.test ); }); } function ok(min, max, value, minExcl, maxExcl) { isOk(min, max, value, minExcl, maxExcl, true); } function notOk(min, max, value, minExcl, maxExcl) { isOk(min, max, value, minExcl, maxExcl, false); } notOk(0, 10, -1); notOk(0, 10, 0, true); ok(0, 10, 0); ok(0, 10, 9); ok(0, 10, 10); notOk(0, 10, 10, false, true); notOk(0, 10, 11); it('curried', function() { var c = ranges.curry(0, 10, false, true).test; assert.strictEqual(c(0), true); assert.strictEqual(c(10), false); assert.strictEqual(c(8), true); assert.strictEqual(c(11), false); }); }); describe('validate', function() { function isOk(min, max, value, minExcl, maxExcl, ok) { var n = names('test', min, max, value, ok ? 'ok' : 'notOk', minExcl, maxExcl); it(n.test, function() { if (ok) { assert.strictEqual( ranges.validate(min, max, value, minExcl, maxExcl), value, n.test ); } else { assert.throws(function() { ranges.validate(min, max, value, minExcl, maxExcl); }, null, n.test); } }); } function ok(min, max, value, minExcl, maxExcl) { isOk(min, max, value, minExcl, maxExcl, true); } function notOk(min, max, value, minExcl, maxExcl) { isOk(min, max, value, minExcl, maxExcl, false); } notOk(0, 10, -1); notOk(0, 10, 0, true); ok(0, 10, 0); ok(0, 10, 9); ok(0, 10, 10); notOk(0, 10, 10, false, true); notOk(0, 10, 11); it('curried', function() { var c = ranges.curry(0, 10, true, false).validate; assert.throws(function() { c(0); }); assert.strictEqual(c(10), 10); assert.strictEqual(c(8), 8); assert.throws(function() { c(11); }); }); }); describe('name', function() { function test(expected, varargs) { var args = Array.prototype.slice.call(arguments, 1); it(expected, function() { assert.strictEqual( ranges.name.apply(ranges, args), expected ); }); } test('[0,10]', 0, 10); test('[6,7]', 6, 7); test('(-10,7]', -10, 7, true); test('[-50,13)', -50, 13, false, true); test('(-1,1)', -1, 1, true, true); it('toString() on curried objs', function() { assert.strictEqual( '' + ranges.curry(1, 3, true), '(1,3]' ); }); });