diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..176a458 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/.gitignore b/.gitignore index cc6c4b6..1c97e21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ +# Files # +######### + + # Directories # ############### reports/ @@ -12,6 +16,28 @@ build/ *.exe *.o *.so +*.slo +*.lo +*.obj +*.dylib +*.dll +*.lai +*.la +*.a +*.lib +*.ko +*.elf + +# Precompiled headers # +####################### +*.gch +*.pch + +# Executables # +############### +*.exe +*.out +*.app # Packages # ############ @@ -51,12 +77,65 @@ Desktop.ini # Node.js # ########### /node_modules/ +pids +*.pid +*.seed # Matlab # ########## - -# Windows default autosave extension *.asv - -# Compiled MEX binaries (all platforms) *.mex* + +# Fortran # +########### +*.mod + +# R # +##### +.Rhistory +.Rapp.history +.Rproj.user/ + +# TeX # +####### +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.dvi +*-converted-to.* +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.brf +*.run.xml +*.fdb_latexmk +*.synctex +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync +*.alg +*.loa +acs-*.bib +*.thm +*.nav +*.snm +*.vrb +*.acn +*.acr +*.glg +*.glo +*.gls +*.brf +*-concordance.tex +*.tikz +*-tikzDictionary +*.idx +*.ilg +*.ind +*.ist diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 0000000..3163c22 --- /dev/null +++ b/.jshintignore @@ -0,0 +1,14 @@ + +# Directories # +############### +build/ +reports/ +dist/ + +# Node.js # +########### +/node_modules/ + +# Git # +####### +.git* diff --git a/.npmignore b/.npmignore index cc43218..9db298d 100644 --- a/.npmignore +++ b/.npmignore @@ -13,6 +13,7 @@ examples/ reports/ support/ test/ +benchmark/ # Node.js # ########### @@ -46,5 +47,6 @@ Desktop.ini # Utilities # ############# .jshintrc +.jshintignore .travis.yml .editorconfig diff --git a/.travis.yml b/.travis.yml index 7c16620..eeabf4b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,12 @@ language: node_js node_js: - - "0.10" + - '0.12' + - '0.11' + - '0.10' + - '0.8' + - 'iojs' +before_install: + - npm update -g npm after_script: - - npm run coveralls \ No newline at end of file + - npm run codecov + diff --git a/LICENSE b/LICENSE index 2fe3939..93cf2ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Athan Reines. +Copyright (c) 2014-2015 The Compute.io Authors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ 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. \ No newline at end of file +SOFTWARE. diff --git a/Makefile b/Makefile index f5648d1..e1d36c2 100644 --- a/Makefile +++ b/Makefile @@ -5,25 +5,30 @@ # Set the node.js environment to test: NODE_ENV ?= test +# Kernel name: +KERNEL ?= $(shell uname -s) + +ifeq ($(KERNEL), Darwin) + OPEN ?= open +else + OPEN ?= xdg-open +endif + # NOTES # -NOTES ?= 'TODO|FIXME' +NOTES ?= 'TODO|FIXME|WARNING|HACK|NOTE' # MOCHA # -# Specify the test framework bin locations: MOCHA ?= ./node_modules/.bin/mocha _MOCHA ?= ./node_modules/.bin/_mocha - -# Specify the mocha reporter: MOCHA_REPORTER ?= spec # ISTANBUL # -# Istanbul configuration: ISTANBUL ?= ./node_modules/.bin/istanbul ISTANBUL_OUT ?= ./reports/coverage ISTANBUL_REPORT ?= lcov @@ -31,6 +36,12 @@ ISTANBUL_LCOV_INFO_PATH ?= $(ISTANBUL_OUT)/lcov.info ISTANBUL_HTML_REPORT_PATH ?= $(ISTANBUL_OUT)/lcov-report/index.html +# JSHINT # + +JSHINT ?= ./node_modules/.bin/jshint +JSHINT_REPORTER ?= ./node_modules/jshint-stylish + + # FILES # @@ -96,13 +107,24 @@ test-istanbul-mocha: node_modules view-cov: view-istanbul-report view-istanbul-report: - open $(ISTANBUL_HTML_REPORT_PATH) + $(OPEN) $(ISTANBUL_HTML_REPORT_PATH) +# LINT # + +.PHONY: lint lint-jshint + +lint: lint-jshint + +lint-jshint: node_modules + $(JSHINT) \ + --reporter $(JSHINT_REPORTER) \ + ./ + # NODE # -# Installing node_modules: +# Install node_modules: .PHONY: install install: @@ -117,7 +139,6 @@ clean-node: # CLEAN # - .PHONY: clean clean: diff --git a/README.md b/README.md index 8c3f134..52fd9f2 100644 --- a/README.md +++ b/README.md @@ -16,80 +16,318 @@ For use in the browser, use [browserify](https://github.com/substack/node-browse ## Usage -To use the module, - ``` javascript var rad2deg = require( 'compute-rad2deg' ); ``` -#### rad2deg( x ) +#### rad2deg( x[, opts] ) -Converts radians to degrees. `x` may be either a numeric `array` or a single numeric value. +Converts radians to degrees element-wise. `x` may be either a [`number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), an [`array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), a [`typed array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays), or a [`matrix`](https://github.com/dstructs/matrix). ``` javascript -// Single value: -var deg = rad2deg( Math.PI/2 ); -// returns 90 +var matrix = require( 'dstructs-matrix' ), + data, + mat, + out, + i; -// Array of values: -var rads = [ 0, Math.PI/4, Math.PI/2, 3*Math.PI/4, Math.PI ]; +out = rad2deg( Math.PI/4 ); +// returns 45 -rad2deg( rads ); -// returns [ 0, 45, 90, 135, 180 ] -``` +out = rad2deg( -Math.PI/4 ); +// returns -45 +data = [ 0, Math.PI/4, Math.PI/2, 3*Math.PI/4, Math.PI, 5*Math.PI/4 ]; +out = rad2deg( data ); +// returns [ 0, 45, 90, 135, 180, 225 ] -## Examples +data = new Float64Array( data ); +out = rad2deg( data ); +// returns Float64Array( [ 0, 45, 90, 135, 180, 225 ] ) -``` javascript -var rad2deg = require( 'compute-rad2deg' ); +data = new Int16Array( 6 ); +for ( i = 0; i < 6; i++ ) { + data[ i ] = 0 * Math.PI/4; +} +mat = matrix( data, [3,2], 'int16' ); +/* + [ 0 Math.PI/4 + Math.PI/2 3*Math.PI/4 + Math.PI 5*Math.PI/4 ] +*/ + +out = rad2deg( mat ); +/* + [ 0 45 + 90 135 + 180 225 ] +*/ +``` -// Simulate some data... -var data = new Array( 100 ); +The function accepts the following `options`: -var twopi = 2*Math.PI; -for ( var i = 0; i < data.length; i++ ) { - data[ i ] = Math.random()*twopi; -} +* __accessor__: accessor `function` for accessing `array` values. +* __dtype__: output [`typed array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays) or [`matrix`](https://github.com/dstructs/matrix) data type. Default: `float64`. +* __copy__: `boolean` indicating if the `function` should return a new data structure. Default: `true`. +* __path__: [deepget](https://github.com/kgryte/utils-deep-get)/[deepset](https://github.com/kgryte/utils-deep-set) key path. +* __sep__: [deepget](https://github.com/kgryte/utils-deep-get)/[deepset](https://github.com/kgryte/utils-deep-set) key path separator. Default: `'.'`. + +For non-numeric `arrays`, provide an accessor `function` for accessing `array` values. -rad2deg( data ); +``` javascript +var data = [ + {'x':0}, + {'x':Math.PI/4}, + {'x':Math.PI/2}, + {'x':3*Math.PI/4}, + {'x':Math.PI} +]; + +function getValue( d, i ) { + return d.x; +} -console.log( data.join( '\n' ) ); +var out = rad2deg( data, { + 'accessor': getValue +}); +// returns [ 0, 45, 90, 135, 180 ] ``` -To run the example code from the top-level application directory, +To [deepset](https://github.com/kgryte/utils-deep-set) an object `array`, provide a key path and, optionally, a key path separator. -``` bash -$ node ./examples/index.js +``` javascript +var data = [ + {'x':[0,0]}, + {'x':[1,Math.PI/4]}, + {'x':[2,Math.PI/2]}, + {'x':[3,3*Math.PI/4]}, + {'x':[4,Math.PI]} +]; + +var out = rad2deg( data, { + 'path': 'x|1', + 'sep': '|' +}); +/* + [ + {'x':[0,0]}, + {'x':[1,45]}, + {'x':[2,90]}, + {'x':[3,135]}, + {'x':[4,180]} + ] +*/ + +var bool = ( data === out ); +// returns true ``` +By default, when provided a [`typed array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays) or [`matrix`](https://github.com/dstructs/matrix), the output data structure is `float64` in order to preserve precision. To specify a different data type, set the `dtype` option (see [`matrix`](https://github.com/dstructs/matrix) for a list of acceptable data types). -## Notes +``` javascript +var data, out; + +data = new Int8Array( [0,1,2] ); -* If provided an input `array`, the `array` is mutated. If mutation is undesired, +out = rad2deg( data, { + 'dtype': 'int32' +}); +// returns Int32Array( [0,57,114] ) + +// Works for plain arrays, as well... +out = rad2deg( [0,1,2], { + 'dtype': 'uint8' +}); +// returns Uint8Array( [0,57,114] ) +``` + +By default, the function returns a new data structure. To mutate the input data structure (e.g., when input values can be discarded or when optimizing memory usage), set the `copy` option to `false`. ``` javascript -var data = [ 0, 45, 90, 135, 180 ], - copy = data.slice(); +var data, + bool, + mat, + out, + i; + +data = [ 0, Math.PI/4, Math.PI/2, 3*Math.PI/4, Math.PI, 5*Math.PI/4 ]; + +out = rad2deg( data, { + 'copy': false +}); +// returns [ 0, 45, 90, 135, 180, 225 ] + +bool = ( data === out ); +// returns true -rad2deg( copy ); +data = new Float64Array( 6 ); +for ( i = 0; i < 6; i++ ) { + data[ i ] = 45 * i; +} +mat = matrix( data, [3,2], 'float64' ); +/* + [ 0 Math.PI/4 + Math.PI/2 3*Math.PI/4 + Math.PI 5*Math.PI/4 ] +*/ + +out = rad2deg( mat, { + 'copy': false +}); +/* + [ 0 45 + 90 135 + 180 225 ] +*/ + +bool = ( mat === out ); +// returns true ``` -* If provided an empty `array`, the function returns `null`. + +## Notes + +* If an element is __not__ a numeric value, the evaluated principal [square root](https://en.wikipedia.org/wiki/Square_root) is `NaN`. + + ``` javascript + var data, out; + + out = rad2deg( null ); + // returns NaN + + out = rad2deg( true ); + // returns NaN + + out = rad2deg( {'a':'b'} ); + // returns NaN + + out = rad2deg( [ true, null, [] ] ); + // returns [ NaN, NaN, NaN ] + + function getValue( d, i ) { + return d.x; + } + data = [ + {'x':true}, + {'x':[]}, + {'x':{}}, + {'x':null} + ]; + + out = rad2deg( data, { + 'accessor': getValue + }); + // returns [ NaN, NaN, NaN, NaN ] + + out = rad2deg( data, { + 'path': 'x' + }); + /* + [ + {'x':NaN}, + {'x':NaN}, + {'x':NaN, + {'x':NaN} + ] + */ + ``` + +* Be careful when providing a data structure which contains non-numeric elements and specifying an `integer` output data type, as `NaN` values are cast to `0`. + + ``` javascript + var out = rad2deg( [ true, null, [] ], { + 'dtype': 'int8' + }); + // returns Int8Array( [0,0,0] ); + ``` * __Beware__ of floating point errors. + ``` javascript + var deg = rad2deg( Math.PI / 6 ); + // returns 29.999999999999996 instead of 30 + ``` + +## Examples + ``` javascript -var deg = rad2deg( Math.PI / 6 ); -// returns 29.999999999999996 instead of 30 +var matrix = require( 'dstructs-matrix' ), + rad2deg = require( 'compute-rad2deg' ); + +var data, + mat, + out, + tmp, + i; + +var TWO_PI = 2 * Math.PI; + +// Plain arrays... +data = new Array( 10 ); +for ( i = 0; i < data.length; i++ ) { + data[ i ] = Math.random() * TWO_PI; +} +out = rad2deg( data ); + +// Object arrays (accessors)... +function getValue( d ) { + return d.x; +} +for ( i = 0; i < data.length; i++ ) { + data[ i ] = { + 'x': data[ i ] + }; +} +out = rad2deg( data, { + 'accessor': getValue +}); + +// Deep set arrays... +for ( i = 0; i < data.length; i++ ) { + data[ i ] = { + 'x': [ i, data[ i ].x ] + }; +} +out = rad2deg( data, { + 'path': 'x/1', + 'sep': '/' +}); + +// Typed arrays... +data = new Int32Array( 10 ); +for ( i = 0; i < data.length; i++ ) { + data[ i ] = Math.random() * TWO_PI; +} +tmp = rad2deg( data ); +out = ''; +for ( i = 0; i < data.length; i++ ) { + out += tmp[ i ]; + if ( i < data.length-1 ) { + out += ','; + } +} + +// Matrices... +mat = matrix( data, [5,2], 'int32' ); +out = rad2deg( mat ); + +// Matrices (custom output data type)... +out = rad2deg( mat, { + 'dtype': 'uint8' +}); ``` +To run the example code from the top-level application directory, + +``` bash +$ node ./examples/index.js +``` ## Tests ### Unit -Unit tests use the [Mocha](http://visionmedia.github.io/mocha) test framework with [Chai](http://chaijs.com) assertions. To run the tests, execute the following command in the top-level application directory: +Unit tests use the [Mocha](http://mochajs.org) test framework with [Chai](http://chaijs.com) assertions. To run the tests, execute the following command in the top-level application directory: ``` bash $ make test @@ -113,15 +351,15 @@ $ make view-cov ``` +--- ## License -[MIT license](http://opensource.org/licenses/MIT). +[MIT license](http://opensource.org/licenses/MIT). ---- ## Copyright -Copyright © 2014. Athan Reines. +Copyright © 2014-2015. The [Compute.io](https://github.com/compute-io) Authors. [npm-image]: http://img.shields.io/npm/v/compute-rad2deg.svg diff --git a/examples/index.js b/examples/index.js index 6911d8b..3e3da80 100644 --- a/examples/index.js +++ b/examples/index.js @@ -1,15 +1,85 @@ 'use strict'; -var rad2deg = require( './../lib' ); +var matrix = require( 'dstructs-matrix' ), + rad2deg = require( './../lib' ); -// Simulate some data... -var data = new Array( 100 ); +var data, + mat, + out, + tmp, + i; -var twopi = 2*Math.PI; -for ( var i = 0; i < data.length; i++ ) { - data[ i ] = Math.random()*twopi; +var TWO_PI = 2 * Math.PI; + +// ---- +// Plain arrays... +data = new Array( 10 ); +for ( i = 0; i < data.length; i++ ) { + data[ i ] = Math.random() * TWO_PI; +} +out = rad2deg( data ); +console.log( 'Arrays: %s\n', out ); + + +// ---- +// Object arrays (accessors)... +function getValue( d ) { + return d.x; +} +for ( i = 0; i < data.length; i++ ) { + data[ i ] = { + 'x': data[ i ] + }; +} +out = rad2deg( data, { + 'accessor': getValue +}); +console.log( 'Accessors: %s\n', out ); + + +// ---- +// Deep set arrays... +for ( i = 0; i < data.length; i++ ) { + data[ i ] = { + 'x': [ i, data[ i ].x ] + }; +} +out = rad2deg( data, { + 'path': 'x/1', + 'sep': '/' +}); +console.log( 'Deepset:'); +console.dir( out ); +console.log( '\n' ); + + +// ---- +// Typed arrays... +data = new Int32Array( 10 ); +for ( i = 0; i < data.length; i++ ) { + data[ i ] = Math.random() * TWO_PI; } +tmp = rad2deg( data ); +out = ''; +for ( i = 0; i < data.length; i++ ) { + out += tmp[ i ]; + if ( i < data.length-1 ) { + out += ','; + } +} +console.log( 'Typed arrays: %s\n', out ); + + +// ---- +// Matrices... +mat = matrix( data, [5,2], 'int32' ); +out = rad2deg( mat ); +console.log( 'Matrix: %s\n', out.toString() ); -rad2deg( data ); -console.log( data.join( '\n' ) ); +// ---- +// Matrices (custom output data type)... +out = rad2deg( mat, { + 'dtype': 'uint8' +}); +console.log( 'Matrix (%s): %s\n', out.dtype, out.toString() ); diff --git a/lib/accessor.js b/lib/accessor.js new file mode 100644 index 0000000..cb7aa4e --- /dev/null +++ b/lib/accessor.js @@ -0,0 +1,36 @@ +'use strict'; + +// MODULES // + +var RAD2DEG = require( './number.js' ); + + +// RADIANS-TO-DEGREES // + +/** +* FUNCTION: rad2deg( out, arr, accessor ) +* Converts radians to degrees element-wise using an accessor function. +* +* @param {Array|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} out - output array +* @param {Array} arr - input array +* @param {Function} accessor - accessor function for accessing array values +* @returns {Number[]|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} output array +*/ +function rad2deg( out, arr, clbk ) { + var len = arr.length, + v, i; + for ( i = 0; i < len; i++ ) { + v = clbk( arr[ i ], i ); + if ( typeof v === 'number' ) { + out[ i ] = RAD2DEG( v ); + } else { + out[ i ] = NaN; + } + } + return out; +} // end FUNCTION rad2deg() + + +// EXPORTS // + +module.exports = rad2deg; diff --git a/lib/array.js b/lib/array.js new file mode 100644 index 0000000..0a18912 --- /dev/null +++ b/lib/array.js @@ -0,0 +1,34 @@ +'use strict'; + +// MODULES // + +var RAD2DEG = require( './number.js' ); + + +// RADIANS-TO-DEGREES // + +/** +* FUNCTION: rad2deg( out, arr ) +* Converts radians to degrees element-wise. +* +* @param {Array|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} out - output array +* @param {Array} arr - input array +* @returns {Number[]|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} output array +*/ +function rad2deg( out, arr ) { + var len = arr.length, + i; + for ( i = 0; i < len; i++ ) { + if ( typeof arr[ i ] === 'number' ) { + out[ i ] = RAD2DEG( arr[ i ] ); + } else { + out[ i ] = NaN; + } + } + return out; +} // end FUNCTION rad2deg() + + +// EXPORTS // + +module.exports = rad2deg; diff --git a/lib/deepset.js b/lib/deepset.js new file mode 100644 index 0000000..b852641 --- /dev/null +++ b/lib/deepset.js @@ -0,0 +1,48 @@ +'use strict'; + +// MODULES // + +var deepSet = require( 'utils-deep-set' ).factory, + deepGet = require( 'utils-deep-get' ).factory, + RAD2DEG = require( './number.js' ); + + +// RADIANS-TO-DEGREES // + +/** +* FUNCTION: rad2deg( arr, path[, sep] ) +* Converts radians to degrees element-wise and deep sets the input array. +* +* @param {Array} arr - input array +* @param {String} path - key path used when deep getting and setting +* @param {String} [sep] - key path separator +* @returns {Array} input array +*/ +function rad2deg( x, path, sep ) { + var len = x.length, + opts = {}, + dget, + dset, + v, i; + if ( arguments.length > 2 ) { + opts.sep = sep; + } + if ( len ) { + dget = deepGet( path, opts ); + dset = deepSet( path, opts ); + for ( i = 0; i < len; i++ ) { + v = dget( x[ i ] ); + if ( typeof v === 'number' ) { + dset( x[i], RAD2DEG( v ) ); + } else { + dset( x[i], NaN ); + } + } + } + return x; +} // end FUNCTION rad2deg() + + +// EXPORTS // + +module.exports = rad2deg; diff --git a/lib/index.js b/lib/index.js index ac7c967..e6e4936 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,59 +1,114 @@ -/** -* -* COMPUTE: rad2deg -* -* -* DESCRIPTION: -* - Converts radians to degrees. -* -* -* NOTES: -* [1] -* -* -* TODO: -* [1] -* -* -* LICENSE: -* MIT -* -* Copyright (c) 2014. Athan Reines. -* -* -* AUTHOR: -* Athan Reines. kgryte@gmail.com. 2014. -* -*/ - 'use strict'; +// MODULES // + +var isNumber = require( 'validate.io-number-primitive' ), + isnan = require( 'validate.io-nan' ), + isArrayLike = require( 'validate.io-array-like' ), + isTypedArrayLike = require( 'validate.io-typed-array-like' ), + isMatrixLike = require( 'validate.io-matrix-like' ), + ctors = require( 'compute-array-constructors' ), + matrix = require( 'dstructs-matrix' ), + validate = require( './validate.js' ); + + +// FUNCTIONS // + +var rad2deg1 = require( './number.js' ), + rad2deg2 = require( './array.js' ), + rad2deg3 = require( './accessor.js' ), + rad2deg4 = require( './deepset.js' ), + rad2deg5 = require( './matrix.js' ), + rad2deg6 = require( './typedarray.js' ); + + // RADIANS-TO-DEGREES // /** -* FUNCTION: rad2deg( x ) -* Converts radians to degrees. Note: if provided an array, the array is mutated. +* FUNCTION: rad2deg( x[, opts] ) +* Converts radians to degrees element-wise. * -* @param {Array|Number} x - value(s) to be converted to degrees -* @returns {Array|Number|Null} degree value(s). If `x` is an empty `array`, returns `null`. +* @param {Number|Number[]|Array|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array|Matrix} x - input value +* @param {Object} [opts] - function options +* @param {Boolean} [opts.copy=true] - boolean indicating if the function should return a new data structure +* @param {Function} [opts.accessor] - accessor function for accessing array values +* @param {String} [opts.path] - deep get/set key path +* @param {String} [opts.sep="."] - deep get/set key path separator +* @param {String} [opts.dtype="float64"] - output data type +* @returns {Number|Number[]|Array|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array|Matrix} degree value(s) */ -function rad2deg( x ) { - var isArray = Array.isArray( x ), - len; - if ( !isArray && ( typeof x !== 'number' || x !== x ) ) { - throw new TypeError( 'rad2deg()::invalid input argument. Must provide either a single numeric value or a numeric array.' ); +function rad2deg( x, options ) { + /* jshint newcap:false */ + var opts = {}, + ctor, + err, + out, + dt, + d; + + if ( isNumber( x ) || isnan( x ) ) { + return rad2deg1( x ); + } + if ( arguments.length > 1 ) { + err = validate( opts, options ); + if ( err ) { + throw err; + } } - if ( !isArray ) { - return x * 180 / Math.PI; + if ( isMatrixLike( x ) ) { + if ( opts.copy !== false ) { + dt = opts.dtype || 'float64'; + ctor = ctors( dt ); + if ( ctor === null ) { + throw new Error( 'rad2deg()::invalid option. Data type option does not have a corresponding array constructor. Option: `' + dt + '`.' ); + } + // Create an output matrix: + d = new ctor( x.length ); + out = matrix( d, x.shape, dt ); + } else { + out = x; + } + return rad2deg5( out, x ); } - len = x.length; - if ( !len ) { - return null; + if ( isTypedArrayLike( x ) ) { + if ( opts.copy === false ) { + out = x; + } else { + dt = opts.dtype || 'float64'; + ctor = ctors( dt ); + if ( ctor === null ) { + throw new Error( 'rad2deg()::invalid option. Data type option does not have a corresponding array constructor. Option: `' + dt + '`.' ); + } + out = new ctor( x.length ); + } + return rad2deg6( out, x ); } - for ( var i = 0; i < len; i++ ) { - x[ i ] *= 180 / Math.PI; + if ( isArrayLike( x ) ) { + // Handle deepset first... + if ( opts.path ) { + opts.sep = opts.sep || '.'; + return rad2deg4( x, opts.path, opts.sep ); + } + // Handle regular and accessor arrays next... + if ( opts.copy === false ) { + out = x; + } + else if ( opts.dtype ) { + ctor = ctors( opts.dtype ); + if ( ctor === null ) { + throw new TypeError( 'rad2deg()::invalid option. Data type option does not have a corresponding array constructor. Option: `' + opts.dtype + '`.' ); + } + out = new ctor( x.length ); + } + else { + out = new Array( x.length ); + } + if ( opts.accessor ) { + return rad2deg3( out, x, opts.accessor ); + } + return rad2deg2( out, x ); } - return x; + return NaN; } // end FUNCTION rad2deg() diff --git a/lib/matrix.js b/lib/matrix.js new file mode 100644 index 0000000..a9d8837 --- /dev/null +++ b/lib/matrix.js @@ -0,0 +1,24 @@ +'use strict'; + +// FUNCTIONS // + +var RAD2DEG = require( './number.js' ), + matrixfun = require( 'compute-matrix-function' ); + + +// RADIANS-TO-DEGREES // + +/** +* FUNCTION: rad2deg( out, x ) +* Converts radians to degrees element-wise. +* +* @param {Matrix} out - output matrix +* @param {Matrix} x - input matrix +* @returns {Matrix} output matrix +*/ +var rad2deg = matrixfun.create( RAD2DEG, 1 ); + + +// EXPORTS // + +module.exports = rad2deg; diff --git a/lib/number.js b/lib/number.js new file mode 100644 index 0000000..e5f66ce --- /dev/null +++ b/lib/number.js @@ -0,0 +1,17 @@ +'use strict'; + +/** +* FUNCTION rad2deg( x ) +* Converts radian to degrees. +* +* @param {Number} x - value to be converted to degrees +* @returns {Number} degree value +*/ +function rad2deg( x ) { + return x * 180 / Math.PI; +} // end FUNCTION rad2deg() + + +// EXPORTS // + +module.exports = rad2deg; diff --git a/lib/typedarray.js b/lib/typedarray.js new file mode 100644 index 0000000..7b3781a --- /dev/null +++ b/lib/typedarray.js @@ -0,0 +1,24 @@ +'use strict'; + +// FUNCTIONS // + +var RAD2DEG = require( './number.js' ), + arrayfun = require( 'compute-typed-array-function' ); + + +// RADIANS-TO-DEGREES // + +/** +* FUNCTION: rad2deg( out, arr ) +* Converts radians to degrees element-wise. +* +* @param {Array|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} out - output array +* @param {Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} arr - input array +* @returns {Number[]|Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array} output array +*/ +var rad2deg = arrayfun.create( RAD2DEG, 1 ); + + +// EXPORTS // + +module.exports = rad2deg; diff --git a/lib/validate.js b/lib/validate.js new file mode 100644 index 0000000..67316ce --- /dev/null +++ b/lib/validate.js @@ -0,0 +1,66 @@ +'use strict'; + +// MODULES // + +var isObject = require( 'validate.io-object' ), + isBoolean = require( 'validate.io-boolean-primitive' ), + isFunction = require( 'validate.io-function' ), + isString = require( 'validate.io-string-primitive' ); + + +// VALIDATE // + +/** +* FUNCTION: validate( opts, options ) +* Validates function options. +* +* @param {Object} opts - destination for validated options +* @param {Object} options - function options +* @param {Boolean} [options.copy] - boolean indicating if the function should return a new data structure +* @param {Function} [options.accessor] - accessor function for accessing array values +* @param {String} [options.sep] - deep get/set key path separator +* @param {String} [options.path] - deep get/set key path +* @param {String} [options.dtype] - output data type +* @returns {Null|Error} null or an error +*/ +function validate( opts, options ) { + if ( !isObject( options ) ) { + return new TypeError( 'rad2deg()::invalid input argument. Options argument must be an object. Value: `' + options + '`.' ); + } + if ( options.hasOwnProperty( 'copy' ) ) { + opts.copy = options.copy; + if ( !isBoolean( opts.copy ) ) { + return new TypeError( 'rad2deg()::invalid option. Copy option must be a boolean primitive. Option: `' + opts.copy + '`.' ); + } + } + if ( options.hasOwnProperty( 'accessor' ) ) { + opts.accessor = options.accessor; + if ( !isFunction( opts.accessor ) ) { + return new TypeError( 'rad2deg()::invalid option. Accessor must be a function. Option: `' + opts.accessor + '`.' ); + } + } + if ( options.hasOwnProperty( 'path' ) ) { + opts.path = options.path; + if ( !isString( opts.path ) ) { + return new TypeError( 'rad2deg()::invalid option. Key path option must be a string primitive. Option: `' + opts.path + '`.' ); + } + } + if ( options.hasOwnProperty( 'sep' ) ) { + opts.sep = options.sep; + if ( !isString( opts.sep ) ) { + return new TypeError( 'rad2deg()::invalid option. Separator option must be a string primitive. Option: `' + opts.sep + '`.' ); + } + } + if ( options.hasOwnProperty( 'dtype' ) ) { + opts.dtype = options.dtype; + if ( !isString( opts.dtype ) ) { + return new TypeError( 'rad2deg()::invalid option. Data type option must be a string primitive. Option: `' + opts.dtype + '`.' ); + } + } + return null; +} // end FUNCTION validate() + + +// EXPORTS // + +module.exports = validate; diff --git a/package.json b/package.json index 2b3fa1b..6470863 100644 --- a/package.json +++ b/package.json @@ -10,12 +10,16 @@ { "name": "Athan Reines", "email": "kgryte@gmail.com" + }, + { + "name": "Philipp Burckhardt", + "email": "pburckhardt@outlook.com" } ], "scripts": { - "test": "./node_modules/.bin/mocha", - "test-cov": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha --dir ./reports/coverage -- -R spec", - "coveralls": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha --dir ./reports/coveralls/coverage --report lcovonly -- -R spec && cat ./reports/coveralls/coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./reports/coveralls" + "test": "mocha", + "test-cov": "istanbul cover ./node_modules/.bin/_mocha --dir ./reports/coverage -- -R spec", + "codecov": "istanbul cover ./node_modules/.bin/_mocha --dir ./reports/codecov/coverage --report lcovonly -- -R spec && cat ./reports/codecov/coverage/lcov.info | codecov && rm -rf ./reports/codecov" }, "main": "./lib", "repository": { @@ -39,17 +43,32 @@ "bugs": { "url": "https://github.com/compute-io/rad2deg/issues" }, - "dependencies": {}, + "dependencies": { + "compute-array-constructors": "^1.0.0", + "compute-matrix-function": "^1.0.2", + "compute-typed-array-function": "^1.0.3", + "dstructs-matrix": "^2.0.0", + "utils-deep-get": "^1.0.0", + "utils-deep-set": "^1.0.1", + "validate.io-array": "^1.0.5", + "validate.io-array-like": "^1.0.1", + "validate.io-boolean-primitive": "^1.0.0", + "validate.io-function": "^1.0.2", + "validate.io-matrix-like": "^1.0.2", + "validate.io-nan": "^1.0.3", + "validate.io-number": "^1.0.3", + "validate.io-number-primitive": "^1.0.0", + "validate.io-object": "^1.0.4", + "validate.io-string-primitive": "^1.0.0", + "validate.io-typed-array-like": "^1.0.0" + }, "devDependencies": { - "chai": "1.x.x", - "mocha": "1.x.x", - "coveralls": "^2.11.1", - "istanbul": "^0.3.0" + "chai": "3.x.x", + "mocha": "2.x.x", + "codecov.io": "^0.1.5", + "istanbul": "^0.3.0", + "jshint": "2.x.x", + "jshint-stylish": "2.x.x" }, - "licenses": [ - { - "type": "MIT", - "url": "http://www.opensource.org/licenses/MIT" - } - ] + "license": "MIT" } diff --git a/test/test.accessor.js b/test/test.accessor.js new file mode 100644 index 0000000..4da451b --- /dev/null +++ b/test/test.accessor.js @@ -0,0 +1,77 @@ +/* global describe, it, require */ +'use strict'; + +// MODULES // + +var // Expectation library: + chai = require( 'chai' ), + + // Module to be tested: + rad2deg = require( './../lib/accessor.js' ); + + +// VARIABLES // + +var expect = chai.expect, + assert = chai.assert; + + +// TESTS // + +describe( 'accessor rad2deg', function tests() { + + it( 'should export a function', function test() { + expect( rad2deg ).to.be.a( 'function' ); + }); + + it( 'should convert radians to degrees using an accessor', function test() { + var data, actual, expected; + + data = [ + {'x':0}, + {'x':Math.PI/4}, + {'x':Math.PI/2}, + {'x':3*Math.PI/4}, + {'x':Math.PI} + ]; + actual = new Array( data.length ); + + actual = rad2deg( actual, data, getValue ); + expected = [ 0, 45, 90, 135, 180 ]; + + assert.deepEqual( actual, expected ); + + function getValue( d ) { + return d.x; + } + }); + + it( 'should return an empty array if provided an empty array', function test() { + assert.deepEqual( rad2deg( [], [], getValue ), [] ); + function getValue( d ) { + return d.x; + } + }); + + it( 'should handle non-numeric values by setting the element to NaN', function test() { + var data, actual, expected; + + data = [ + {'x':true}, + {'x':null}, + {'x':[]}, + {'x':{}} + ]; + actual = new Array( data.length ); + actual = rad2deg( actual, data, getValue ); + + expected = [ NaN, NaN, NaN, NaN ]; + + assert.deepEqual( actual, expected ); + + function getValue( d ) { + return d.x; + } + }); + +}); diff --git a/test/test.array.js b/test/test.array.js new file mode 100644 index 0000000..34b9a12 --- /dev/null +++ b/test/test.array.js @@ -0,0 +1,55 @@ +/* global describe, it, require */ +'use strict'; + +// MODULES // + +var // Expectation library: + chai = require( 'chai' ), + + // Module to be tested: + rad2deg = require( './../lib/array.js' ); + + +// VARIABLES // + +var expect = chai.expect, + assert = chai.assert; + + +// TESTS // + +describe( 'array rad2deg', function tests() { + + it( 'should export a function', function test() { + expect( rad2deg ).to.be.a( 'function' ); + }); + + it( 'should convert radians to degrees', function test() { + var data, actual, expected; + + data = [ 0, Math.PI/4, Math.PI/2, 3*Math.PI/4, Math.PI ]; + actual = new Array( data.length ); + + actual = rad2deg( actual, data ); + expected = [ 0, 45, 90, 135, 180 ]; + + assert.deepEqual( actual, expected ); + }); + + it( 'should return an empty array if provided an empty array', function test() { + assert.deepEqual( rad2deg( [], [] ), [] ); + }); + + it( 'should handle non-numeric values by setting the element to NaN', function test() { + var data, actual, expected; + + data = [ true, null, [], {} ]; + actual = new Array( data.length ); + actual = rad2deg( actual, data ); + + expected = [ NaN, NaN, NaN, NaN ]; + + assert.deepEqual( actual, expected ); + }); + +}); diff --git a/test/test.deepset.js b/test/test.deepset.js new file mode 100644 index 0000000..0b0a4b3 --- /dev/null +++ b/test/test.deepset.js @@ -0,0 +1,96 @@ +/* global describe, it, require */ +'use strict'; + +// MODULES // + +var // Expectation library: + chai = require( 'chai' ), + + // Module to be tested: + rad2deg = require( './../lib/deepset.js' ); + + +// VARIABLES // + +var expect = chai.expect, + assert = chai.assert; + + +// TESTS // + +describe( 'deepset rad2deg', function tests() { + + it( 'should export a function', function test() { + expect( rad2deg ).to.be.a( 'function' ); + }); + + it( 'should convert radians to degrees and deep set', function test() { + var data, expected; + + data = [ + {'x':0}, + {'x':Math.PI/4}, + {'x':Math.PI/2}, + {'x':3*Math.PI/4}, + {'x':Math.PI} + ]; + + data = rad2deg( data, 'x' ); + expected = [ + {'x':0}, + {'x':45}, + {'x':90}, + {'x':135}, + {'x':180} + ]; + + assert.deepEqual( data, expected ); + + // Custom separator... + data = [ + {'x':[9,0]}, + {'x':[9,Math.PI/4]}, + {'x':[9,Math.PI/2]}, + {'x':[9,3*Math.PI/4]}, + {'x':[9,Math.PI]} + ]; + + data = rad2deg( data, 'x/1', '/' ); + expected = [ + {'x':[9,0]}, + {'x':[9,45]}, + {'x':[9,90]}, + {'x':[9,135]}, + {'x':[9,180]} + ]; + + assert.deepEqual( data, expected, 'custom separator' ); + }); + + it( 'should return an empty array if provided an empty array', function test() { + assert.deepEqual( rad2deg( [], 'x' ), [] ); + assert.deepEqual( rad2deg( [], 'x', '/' ), [] ); + }); + + it( 'should handle non-numeric values by setting the element to NaN', function test() { + var data, actual, expected; + + data = [ + {'x':true}, + {'x':null}, + {'x':[]}, + {'x':{}} + ]; + actual = rad2deg( data, 'x' ); + + expected = [ + {'x':NaN}, + {'x':NaN}, + {'x':NaN}, + {'x':NaN} + ]; + + assert.deepEqual( data, expected ); + }); + +}); diff --git a/test/test.js b/test/test.js index 18919ca..4805143 100644 --- a/test/test.js +++ b/test/test.js @@ -1,3 +1,4 @@ +/* global require, describe, it */ 'use strict'; // MODULES // @@ -5,6 +6,12 @@ var // Expectation library: chai = require( 'chai' ), + // Matrix data structure: + matrix = require( 'dstructs-matrix' ), + + // Validate a value is NaN: + isnan = require( 'validate.io-nan' ), + // Module to be tested: rad2deg = require( './../lib' ); @@ -23,14 +30,15 @@ describe( 'compute-rad2deg', function tests() { expect( rad2deg ).to.be.a( 'function' ); }); - it( 'should throw an error if not provided an array or numeric value', function test(){ + it( 'should throw an error if provided an invalid option', function test() { var values = [ '5', + 5, true, undefined, null, NaN, - function(){}, + [], {} ]; @@ -39,12 +47,84 @@ describe( 'compute-rad2deg', function tests() { } function badValue( value ) { return function() { - rad2deg( value ); + rad2deg( [1,2,3], { + 'accessor': value + }); + }; + } + }); + + it( 'should throw an error if provided an array and an unrecognized/unsupported data type option', function test() { + var values = [ + 'beep', + 'boop' + ]; + + for ( var i = 0; i < values.length; i++ ) { + expect( badValue( values[i] ) ).to.throw( Error ); + } + function badValue( value ) { + return function() { + rad2deg( [1,2,3], { + 'dtype': value + }); + }; + } + }); + + it( 'should throw an error if provided a typed-array and an unrecognized/unsupported data type option', function test() { + var values = [ + 'beep', + 'boop' + ]; + + for ( var i = 0; i < values.length; i++ ) { + expect( badValue( values[i] ) ).to.throw( Error ); + } + function badValue( value ) { + return function() { + rad2deg( new Int8Array([1,2,3]), { + 'dtype': value + }); }; } }); - it( 'should convert degrees to radians', function test() { + it( 'should throw an error if provided a matrix and an unrecognized/unsupported data type option', function test() { + var values = [ + 'beep', + 'boop' + ]; + + for ( var i = 0; i < values.length; i++ ) { + expect( badValue( values[i] ) ).to.throw( Error ); + } + function badValue( value ) { + return function() { + rad2deg( matrix( [2,2] ), { + 'dtype': value + }); + }; + } + }); + + it( 'should return NaN if the first argument is neither a number, array-like, or matrix-like', function test() { + var values = [ + // '5', // valid as is array-like (length) + true, + undefined, + null, + // NaN, // allowed + function(){}, + {} + ]; + + for ( var i = 0; i < values.length; i++ ) { + assert.isTrue( isnan( rad2deg( values[ i ] ) ) ); + } + }); + + it( 'should convert radians to degrees when provided a number', function test() { var actual; actual = rad2deg( Math.PI/2 ); @@ -55,23 +135,189 @@ describe( 'compute-rad2deg', function tests() { actual = rad2deg( -3*Math.PI/2 ); assert.closeTo( actual, -270, 1e-10 ); + + actual = rad2deg( NaN ); + assert.isTrue( isnan( actual ) ); }); - it( 'should convert all values in an array', function test() { + it( 'should convert radians to degrees element-wise when provided a plain array', function test() { var data, actual, expected; data = [ 0, Math.PI/4, Math.PI/2, 3*Math.PI/4, Math.PI ]; expected = [ 0, 45, 90, 135, 180 ]; actual = rad2deg( data ); + assert.notEqual( actual, data ); + assert.deepEqual( actual, expected ); + + // Mutate... + actual = rad2deg( data, { + 'copy': false + }); + assert.strictEqual( actual, data ); + assert.deepEqual( data, expected ); + }); + + it( 'should convert radians to degrees element-wise when provided a typed array', function test() { + var data, actual, expected; + + data = new Float64Array( [ 0, Math.PI/4, Math.PI/2, 3*Math.PI/4, Math.PI ] ); + expected = new Float64Array( [ 0, 45, 90, 135, 180 ] ); + + actual = rad2deg( data ); + assert.notEqual( actual, data ); + assert.deepEqual( actual, expected ); + + // Mutate: + actual = rad2deg( data, { + 'copy': false + }); + expected = new Float64Array( [ 0, 45, 90, 135, 180 ] ); + assert.strictEqual( actual, data ); + assert.deepEqual( data, expected ); + }); + + it( 'should convert radians to degrees element-wise and return an array of a specific type', function test() { + var data, actual, expected; + + data = [ 0, Math.PI/4, Math.PI/2, 3*Math.PI/4, Math.PI ]; + expected = new Int8Array( [ 0, 45, 90, 135, 180 ] ); + + actual = rad2deg( data, { + 'dtype': 'int8' + }); + assert.notEqual( actual, data ); + assert.strictEqual( actual.BYTES_PER_ELEMENT, 1 ); + assert.deepEqual( actual, expected ); + }); + + it( 'should convert radians to degrees element-wise using an accessor', function test() { + var data, actual, expected; + + data = [ + [0,0], + [1,Math.PI/4], + [2,Math.PI/2], + [3,3*Math.PI/4], + [4,Math.PI] + ]; + expected = [ 0, 45, 90, 135, 180 ]; - for ( var i = 0; i < data.length; i++ ) { - assert.closeTo( data[i], expected[i], 1e-10 ); + actual = rad2deg( data, { + 'accessor': getValue + }); + assert.notEqual( actual, data ); + assert.deepEqual( actual, expected ); + + // Mutate: + actual = rad2deg( data, { + 'accessor': getValue, + 'copy': false + }); + assert.strictEqual( actual, data ); + assert.deepEqual( data, expected ); + + function getValue( d ) { + return d[ 1 ]; } }); - it( 'should return `null` is provided an empty array', function test() { - assert.isNull( rad2deg( [] ) ); + it( 'should convert radians to degrees element-wise and deep set', function test() { + var data, actual, expected; + + data = [ + {'x':[9,0]}, + {'x':[9,Math.PI/4]}, + {'x':[9,Math.PI/2]}, + {'x':[9,3*Math.PI/4]}, + {'x':[9,Math.PI]} + ]; + expected = [ + {'x':[9,0]}, + {'x':[9,45]}, + {'x':[9,90]}, + {'x':[9,135]}, + {'x':[9,180]} + ]; + + actual = rad2deg( data, { + 'path': 'x.1' + }); + assert.strictEqual( actual, data ); + assert.deepEqual( actual, expected ); + + // Specify a path with a custom separator... + data = [ + {'x':[9,0]}, + {'x':[9,Math.PI/4]}, + {'x':[9,Math.PI/2]}, + {'x':[9,3*Math.PI/4]}, + {'x':[9,Math.PI]} + ]; + + actual = rad2deg( data, { + 'path': 'x/1', + 'sep': '/' + }); + assert.strictEqual( actual, data ); + assert.deepEqual( actual, expected ); + }); + + it( 'should convert radians to degrees element-wise when provided a matrix', function test() { + var mat, + out, + d1, + d2, + d3, + i; + + d1 = new Int16Array( 25 ); + d2 = new Float64Array( 25 ); + d3 = new Int16Array( 25 ); + for ( i = 0; i < d1.length; i++ ) { + d1[ i ] = Math.random() * ( 2 * Math.PI ); + d2[ i ] = d1[ i ] * 180 / Math.PI; + d3[ i ] = d1[ i ] * 180 / Math.PI; + } + mat = matrix( d1, [5,5], 'int16' ); + out = rad2deg( mat ); + + assert.deepEqual( out.data, d2 ); + + // Mutate... + out = rad2deg( mat, { + 'copy': false + }); + assert.strictEqual( mat, out ); + assert.deepEqual( mat.data, d3 ); + }); + + it( 'should convert radians to degrees element-wise and return a matrix of a specific type', function test() { + var mat, + out, + d1, + d2, + i; + + d1 = new Int16Array( 25 ); + d2 = new Float32Array( 25 ); + for ( i = 0; i < d1.length; i++ ) { + d1[ i ] = Math.random() * ( 2 * Math.PI ); + d2[ i ] = d1[ i ] * 180 / Math.PI; + } + mat = matrix( d1, [5,5], 'int16' ); + out = rad2deg( mat, { + 'dtype': 'float32' + }); + + assert.strictEqual( out.dtype, 'float32' ); + assert.deepEqual( out.data, d2 ); + }); + + it( 'should return an empty data structure if provided an empty data structure', function test() { + assert.deepEqual( rad2deg( [] ), [] ); + assert.deepEqual( rad2deg( matrix( [0,0] ) ).data, new Float64Array() ); + assert.deepEqual( rad2deg( new Int8Array() ), new Float64Array() ); }); }); diff --git a/test/test.matrix.js b/test/test.matrix.js new file mode 100644 index 0000000..b8f350a --- /dev/null +++ b/test/test.matrix.js @@ -0,0 +1,80 @@ +/* global describe, it, require, beforeEach */ +'use strict'; + +// MODULES // + +var // Expectation library: + chai = require( 'chai' ), + + // Matrix data structure: + matrix = require( 'dstructs-matrix' ), + + // Module to be tested: + rad2deg = require( './../lib/matrix.js' ); + + +// VARIABLES // + +var expect = chai.expect, + assert = chai.assert; + + +// TESTS // + +describe( 'matrix rad2deg', function tests() { + + var out, + mat, + d1, + d2, + i; + + d1 = new Int16Array( 25 ); + d2 = new Int16Array( 25 ); + for ( i = 0; i < d1.length; i++ ) { + d1[ i ] = Math.random() * ( 2 * Math.PI ); + d2[ i ] = d1[ i ] * 180 / Math.PI; + } + + beforeEach( function before() { + mat = matrix( d1, [5,5], 'int16' ); + out = matrix( d2, [5,5], 'int16' ); + }); + + it( 'should export a function', function test() { + expect( rad2deg ).to.be.a( 'function' ); + }); + + it( 'should throw an error if provided unequal length matrices', function test() { + expect( badValues ).to.throw( Error ); + function badValues() { + rad2deg( matrix( [10,10] ), mat ); + } + }); + + it( 'should conert radians to degrees for each matrix element', function test() { + var actual; + + actual = matrix( [5,5], 'int16' ); + actual = rad2deg( actual, mat ); + + assert.deepEqual( actual.data, out.data ); + }); + + it( 'should return an empty matrix if provided an empty matrix', function test() { + var out, mat, expected; + + out = matrix( [0,0] ); + expected = matrix( [0,0] ).data; + + mat = matrix( [0,10] ); + assert.deepEqual( rad2deg( out, mat ).data, expected ); + + mat = matrix( [10,0] ); + assert.deepEqual( rad2deg( out, mat ).data, expected ); + + mat = matrix( [0,0] ); + assert.deepEqual( rad2deg( out, mat ).data, expected ); + }); + +}); diff --git a/test/test.number.js b/test/test.number.js new file mode 100644 index 0000000..cdde2d8 --- /dev/null +++ b/test/test.number.js @@ -0,0 +1,46 @@ +/* global describe, it, require */ +'use strict'; + +// MODULES // + +var // Expectation library: + chai = require( 'chai' ), + + // Validate a value is NaN: + isnan = require( 'validate.io-nan' ), + + // Module to be tested: + rad2deg = require( './../lib/number.js' ); + + +// VARIABLES // + +var expect = chai.expect, + assert = chai.assert; + + +// TESTS // + +describe( 'number rad2deg', function tests() { + + it( 'should export a function', function test() { + expect( rad2deg ).to.be.a( 'function' ); + }); + + it( 'should convert radians to degrees', function test() { + var actual; + + actual = rad2deg( Math.PI/2 ); + assert.closeTo( actual, 90, 1e-10 ); + + actual = rad2deg( Math.PI/6 ); + assert.closeTo( actual, 30, 1e-10 ); + + actual = rad2deg( -3*Math.PI/2 ); + assert.closeTo( actual, -270, 1e-10 ); + + actual = rad2deg( NaN ); + assert.isTrue( isnan( actual ) ); + }); + +}); diff --git a/test/test.typedarray.js b/test/test.typedarray.js new file mode 100644 index 0000000..9dbae53 --- /dev/null +++ b/test/test.typedarray.js @@ -0,0 +1,43 @@ +/* global describe, it, require */ +'use strict'; + +// MODULES // + +var // Expectation library: + chai = require( 'chai' ), + + // Module to be tested: + rad2deg = require( './../lib/array.js' ); + + +// VARIABLES // + +var expect = chai.expect, + assert = chai.assert; + + +// TESTS // + +describe( 'typed-array sqrt', function tests() { + + it( 'should export a function', function test() { + expect( rad2deg ).to.be.a( 'function' ); + }); + + it( 'should convert radians to degrees', function test() { + var data, actual, expected; + + data = new Float64Array( [ 0, Math.PI/4, Math.PI/2, 3*Math.PI/4, Math.PI ] ); + actual = new Float64Array( data.length ); + + actual = rad2deg( actual, data ); + expected = new Float64Array( [ 0, 45, 90, 135, 180 ] ); + + assert.deepEqual( actual, expected ); + }); + + it( 'should return an empty array if provided an empty array', function test() { + assert.deepEqual( rad2deg( new Int8Array(), new Int8Array() ), new Int8Array() ); + }); + +}); diff --git a/test/test.validate.js b/test/test.validate.js new file mode 100644 index 0000000..e21b68c --- /dev/null +++ b/test/test.validate.js @@ -0,0 +1,177 @@ +/* global describe, it, require */ +'use strict'; + +// MODULES // + +var // Expectation library: + chai = require( 'chai' ), + + // Module to be tested: + validate = require( './../lib/validate.js' ); + + +// VARIABLES // + +var expect = chai.expect, + assert = chai.assert; + + +// TESTS // + +describe( 'validate', function tests() { + + it( 'should export a function', function test() { + expect( validate ).to.be.a( 'function' ); + }); + + it( 'should return an error if provided an options argument which is not an object', function test() { + var values = [ + '5', + 5, + true, + undefined, + null, + NaN, + function(){}, + [] + ]; + + for ( var i = 0; i < values.length; i++ ) { + assert.isTrue( validate( {}, values[ i ] ) instanceof TypeError ); + } + }); + + it( 'should return an error if provided an accessor which is not a function', function test() { + var values, err; + + values = [ + '5', + 5, + true, + undefined, + null, + NaN, + [], + {} + ]; + + for ( var i = 0; i < values.length; i++ ) { + err = validate( {}, { + 'accessor': values[ i ] + }); + assert.isTrue( err instanceof TypeError ); + } + }); + + it( 'should return an error if provided a copy option which is not a boolean primitive', function test() { + var values, err; + + values = [ + '5', + 5, + new Boolean( true ), + undefined, + null, + NaN, + [], + {}, + function(){} + ]; + + for ( var i = 0; i < values.length; i++ ) { + err = validate( {}, { + 'copy': values[ i ] + }); + assert.isTrue( err instanceof TypeError ); + } + }); + + it( 'should return an error if provided a path option which is not a string primitive', function test() { + var values, err; + + values = [ + 5, + true, + undefined, + null, + NaN, + [], + {}, + function(){} + ]; + + for ( var i = 0; i < values.length; i++ ) { + err = validate( {}, { + 'path': values[ i ] + }); + assert.isTrue( err instanceof TypeError ); + } + }); + + it( 'should return an error if provided a separator option which is not a string primitive', function test() { + var values, err; + + values = [ + 5, + true, + undefined, + null, + NaN, + [], + {}, + function(){} + ]; + + for ( var i = 0; i < values.length; i++ ) { + err = validate( {}, { + 'sep': values[ i ] + }); + assert.isTrue( err instanceof TypeError ); + } + }); + + it( 'should return an error if provided a dtype option which is not a string primitive', function test() { + var values, err; + + values = [ + 5, + true, + undefined, + null, + NaN, + [], + {}, + function(){} + ]; + + for ( var i = 0; i < values.length; i++ ) { + err = validate( {}, { + 'dtype': values[ i ] + }); + assert.isTrue( err instanceof TypeError ); + } + }); + + it( 'should return null if all options are valid', function test() { + var err; + + err = validate( {}, { + 'accessor': function getValue(){}, + 'copy': false, + 'deepset': true, + 'path': 'x/y', + 'sep': '/', + 'dtype': 'int32' + }); + + assert.isNull( err ); + + err = validate( {}, { + 'beep': true, // misc options + 'boop': 'bop' + }); + + assert.isNull( err ); + }); + +});