Compare commits

...

7 Commits

Author SHA1 Message Date
Alan K f331092772 Create CNAME 2017-05-25 17:21:19 -04:00
Alan K cda0babfd7 Tests for Filer v0.0.44 2015-07-21 14:40:45 -04:00
Alan K 9baf9438ce Create gh-pages branch via GitHub 2014-12-17 17:22:38 -05:00
Alan K 6ba5c99396 update perf/ and tests/ 2014-12-17 02:54:29 -05:00
Alan K 7f8fb90c29 Tests for Filer v0.0.41 2014-12-17 02:53:04 -05:00
Alan K c2e9b38159 Tests for Filer v0.0.37 2014-12-17 02:35:22 -05:00
Alan K 15c5eac309 Tests for Filer v0.0.36 2014-12-02 13:45:29 -05:00
90 changed files with 26235 additions and 1124 deletions

1
CNAME Normal file
View File

@ -0,0 +1 @@
filer.js.org

10075
dist/filer-perf.js vendored Normal file

File diff suppressed because it is too large Load Diff

5908
dist/filer-test.js vendored

File diff suppressed because it is too large Load Diff

BIN
images/bg_hr.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 B

BIN
images/blacktocat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

BIN
images/icon_download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

BIN
images/sprite_download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

1567
index.html Normal file

File diff suppressed because it is too large Load Diff

1
javascripts/main.js Normal file
View File

@ -0,0 +1 @@
console.log('This would be the main JS file.');

1
params.json Normal file

File diff suppressed because one or more lines are too long

13
perf/index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<progress id="progress" value=0></progress>
<div id="output"></div>
<div id="stderr"></div>
</body>
<script type="text/javascript" src="simple-statistics/src/simple_statistics.js"></script>
<script src="../dist/filer-perf.js"></script>
</html>

120
perf/index.js Normal file
View File

@ -0,0 +1,120 @@
var Filer = require('..');
var util = require('../tests/lib/test-utils.js');
function setImmediate(cb) {
setTimeout(cb, 0);
}
function parse_query() {
var query = window.location.search.substring(1);
var parsed = {};
query.split('&').forEach(function(pair) {
pair = pair.split('=');
var key = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1]);
parsed[key] = value;
});
return parsed;
}
var query = parse_query();
function time(test, cb) {
var start = performance.now();
function done() {
var end = performance.now();
cb(end - start);
}
test(done);
}
var random_data = new Buffer(1024); // 1kB buffer
var read_buffer = new Buffer(1024);
function run(iter) {
iter = (undefined == iter) ? 0 : iter;
function before() {
util.setup(function() {
setImmediate(during);
});
}
function during() {
var fs = util.fs();
window.crypto.getRandomValues(random_data);
time(function(done) {
fs.mkdir('/tmp', function(err) {
fs.stat('/tmp', function(err, stats) {
fs.open('/tmp/test', 'w', function(err, fd) {
fs.write(fd, random_data, null, null, null, function(err, nbytes) {
fs.close(fd, function(err) {
fs.stat('/tmp/test', function(err, stats) {
fs.open('/tmp/test', 'r', function(err, fd) {
fs.read(fd, read_buffer, null, null, null, function(err, nbytes) {
fs.close(fd, function(err) {
fs.unlink('/tmp/test', function(err) {
done();
});});});});});});});});});});
}, after);
}
function after(dt) {
util.cleanup(complete.bind(null, iter, dt));
}
before();
}
var results = [];
function complete(iter, result) {
results.push(result);
if(++iter < iterations) {
setImmediate(run.bind(null, iter));
} else {
do_stats();
}
progress.value = iter;
}
function do_stats() {
var output = document.getElementById("output");
var stats = {
mean: ss.mean(results) + " ms",
min: ss.min(results),
max: ss.max(results),
med_abs_dev: ss.median_absolute_deviation(results),
};
var t = document.createElement("table");
var tbody = document.createElement("tbody");
var keys = Object.keys(stats);
keys.forEach(function(key) {
var row = document.createElement("tr");
var key_cell = document.createElement("td");
var key_cell_text = document.createTextNode(key);
key_cell.appendChild(key_cell_text);
row.appendChild(key_cell);
var val_cell = document.createElement("td");
var val_cell_text = document.createTextNode(stats[key]);
val_cell.appendChild(val_cell_text);
row.appendChild(val_cell);
tbody.appendChild(row);
});
t.appendChild(tbody);
output.appendChild(t);
}
var query = parse_query();
var iterations = query.iterations || 10;
var progress = document.getElementById("progress");
progress.max = iterations;
run();

3
perf/simple-statistics/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
components
build
node_modules

View File

@ -0,0 +1,8 @@
{
"indent": 4,
"undef": true,
"unused": true,
"globals": {
"require": true
}
}

View File

@ -0,0 +1,7 @@
language: node_js
node_js:
- 0.10
script:
- npm install
- npm test
- npm run cov

View File

@ -0,0 +1,242 @@
Basic contracts of functions:
* Functions do not modify their arguments e.g. change their order
* Invalid input, like empty lists to functions that need 1+ items to work, will cause functions to return `null`.
# Basic Array Operations
### .mixin(array)
_Optionally_ mix in the following functions into the `Array` prototype. Otherwise
you can use them off of the simple-statistics object itself.
If given a particular array instance as an argument, this adds the functions
only to that array rather than the global `Array.prototype`. Without an argument,
it runs on the global `Array.prototype`.
### .mean(x)
Mean of a single-dimensional Array of numbers. _Also available as `.average(x)`_
### .sum(x)
Sum of a single-dimensional Array of numbers.
### .mode(x)
Returns the number that appears most frequently in a single-dimensional Array
of numbers. If there are multiple modes, the one that appears last
is returned.
### .variance(x)
[Variance](http://en.wikipedia.org/wiki/Variance) of a single-dimensional Array of numbers.
### .standard_deviation(x)
[Standard Deviation](http://en.wikipedia.org/wiki/Standard_deviation) of a single-dimensional Array of numbers.
### .sample(array, n)
Return a [simple random sample](http://en.wikipedia.org/wiki/Simple_random_sample)
of the given array. The sampling is _without replacement_, and uses a Fisher-Yates
sample to randomize.
### .median_absolute_deviation(x)
The Median Absolute Deviation (MAD) is a robust measure of statistical
dispersion. It is more resilient to outliers than the standard deviation.
Accepts a single-dimensional array of numbers and returns a dispersion value.
Also aliased to `.mad(x)` for brevity.
### .median(x)
[Median](http://en.wikipedia.org/wiki/Median) of a single-dimensional array of numbers.
### .geometric_mean(x)
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
### .harmonic_mean(x)
[Harmonic mean](http://en.wikipedia.org/wiki/Harmonic_mean) of a single-dimensional array of **positive** numbers.
### .root_mean_square(x)
[Root mean square (RMS)](http://en.wikipedia.org/wiki/Root_mean_square) of a single-dimensional array of numbers.
Also aliased to `.rms(x)` for brevity.
### .min(x)
Finds the minimum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
### .max(x)
Finds the maximum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
### .t_test(sample, x)
Does a [student's t-test](http://en.wikipedia.org/wiki/Student's_t-test) of a dataset `sample`, represented by a single-dimensional array of numbers. `x` is the known value, and the result is a measure of [statistical significance](http://en.wikipedia.org/wiki/Statistical_significance).
### .t_test_two_sample(sample_x, sample_y, difference)
The two-sample t-test is used to compare samples from two populations or groups,
confirming or denying the suspicion (null hypothesis) that the populations are
the same. It returns a t-value that you can then look up to give certain
judgements of confidence based on a t distribution table.
This implementation expects the samples `sample_x` and `sample_y` to be given
as one-dimensional arrays of more than one number each.
### .sample_variance(x)
Produces [sample variance](http://mathworld.wolfram.com/SampleVariance.html)
of a single-dimensional array of numbers.
### .sample_covariance(a, b)
Produces [sample covariance](http://en.wikipedia.org/wiki/Sample_mean_and_sample_covariance)
of two single-dimensional arrays of numbers.
### .sample_correlation(a, b)
Produces [sample correlation](http://en.wikipedia.org/wiki/Correlation_and_dependence)
of two single-dimensional arrays of numbers.
### .quantile(sample, p)
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
at p. For those familiary with the `k/q` syntax, `p == k/q`. `sample` must
be a single-dimensional array of numbers. p must be a number greater than or equal to
than zero and less or equal to than one, or an array of numbers following that rule.
If an array is given, an array of results will be returned instead of a single
number.
### .chunk(sample, chunkSize)
Given a `sample` array, and a positive integer `chunkSize`, splits an array
into chunks of `chunkSize` size and returns an array of those chunks. This
does not change the input value. If the length of `sample` is not divisible
by `chunkSize`, the last array will be shorter than the rest.
### .shuffle(sample)
Given a `sample` array (with any type of contents), return a random permutation
of that array, using the [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
algorithm.
### .shuffle_in_place(sample)
Given a `sample` array (with any type of contents), return a random permutation
of that array, using the [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
algorithm.
This changes the input array in-place, as well as returns it - unlike `.shuffle()`,
it does not create a shallow copy of the array.
### .quantile_sorted(sample, p)
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
at p. `sample` must be a one-dimensional _sorted_ array of numbers, and
`p` must be a single number from zero to one.
### .iqr(sample)
Calculates the [Interquartile range](http://en.wikipedia.org/wiki/Interquartile_range) of
a sample - the difference between the upper and lower quartiles. Useful
as a measure of dispersion.
_Also available as `.interquartile_range(x)`_
### .sample_skewness(sample)
Calculates the [skewness](http://en.wikipedia.org/wiki/Skewness) of
a sample, a measure of the extent to which a probability distribution of a
real-valued random variable "leans" to one side of the mean.
The skewness value can be positive or negative, or even undefined.
This implementation uses the [Fisher-Pearson standardized moment coefficient](http://en.wikipedia.org/wiki/Skewness#Pearson.27s_skewness_coefficients),
which means that it behaves the same as Excel, Minitab, SAS, and SPSS.
Skewness is only valid for samples of over three values.
### .jenks(data, number_of_classes)
Find the [Jenks Natural Breaks](http://en.wikipedia.org/wiki/Jenks_natural_breaks_optimization) for
a single-dimensional array of numbers as input and a desired `number_of_classes`.
The result is a single-dimensional with class breaks, including the minimum
and maximum of the input array.
### .r_squared(data, function)
Find the [r-squared](http://en.wikipedia.org/wiki/Coefficient_of_determination) value of a particular dataset, expressed as a two-dimensional `Array` of numbers, against a `Function`.
var r_squared = ss.r_squared([[1, 1]], function(x) { return x * 2; });
### .cumulative_std_normal_probability(z)
Look up the given `z` value in a [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table)
to calculate the probability of a random variable appearing with a given value.
### .z_score(x, mean, standard_deviation)
The standard score is the number of standard deviations an observation
or datum is above or below the mean.
### .standard_normal_table
A [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table) from
which to pull values of Φ (phi).
## Regression
### .linear_regression()
Create a new linear regression solver.
#### .data([[1, 1], [2, 2]])
Set the data of a linear regression. The input is a two-dimensional array of numbers, which are treated as coordinates, like `[[x, y], [x1, y1]]`.
#### .line()
Get the linear regression line: this returns a function that you can
give `x` values and it will return `y` values. Internally, this uses the `m()`
and `b()` values and the classic `y = mx + b` equation.
var linear_regression_line = ss.linear_regression()
.data([[0, 1], [2, 2], [3, 3]]).line();
linear_regression_line(5);
#### .m()
Just get the slope of the fitted regression line, the `m` component of the full
line equation. Returns a number.
#### .b()
Just get the y-intercept of the fitted regression line, the `b` component
of the line equation. Returns a number.
## Classification
### .bayesian()
Create a naïve bayesian classifier.
### .train(item, category)
Train the classifier to classify a certain item, given as an object with keys,
to be in a certain category, given as a string.
### .score(item)
Get the classifications of a certain item, given as an object of
`category -> score` mappings.
var bayes = ss.bayesian();
bayes.train({ species: 'Cat' }, 'animal');
bayes.score({ species: 'Cat' });
// { animal: 1 }

View File

@ -0,0 +1,60 @@
# CHANGELOG
## 0.9.0
* Adds `.sample` for simple random sampling
* Adds `.shuffle` and `.shuffle_in_place` for random permutations
* Adds `.chunk` for splitting arrays into chunked subsets
## 0.8.1
* fixes a bug in `mode` that favored the last new number
## 0.8.0
* `mixin` can now take an array in order to mixin functions into a single array
instance rather than the global Array prototype.
## 0.7.0
* Adds `simple_statistics.harmonic_mean` thanks to [jseppi](https://github.com/jseppi)
## 0.6.0
* Adds `simple_statistics.quantile_sorted` thanks to [rluta](http://github.com/rluta)
* `simple_statistics.quantile` now accepts a sorted list of quantiles as a second argument
* Improved test coverage
## 0.5.0
* Adds `simple_statistics.cumulative_std_normal_probability` by [doronlinder](https://github.com/doronlinder)
* Adds `simple_statistics.z_score` by doronlinder
* Adds `simple_statistics.standard_normal_table`
## 0.4.0
* Adds `simple_statistics.median_absolute_deviation()` by siculars
* Adds `simple_statistics.iqr()` by siculars
* Adds `simple_statistics.skewness()` by Doron Linder
* Lower-level accessors for linear regression allow users to do the line
equation themselves
## 0.3.0
* Adds `simple_statistics.jenks()`
* Adds `simple_statistics.jenksMatrices()`
* Improves test coverage and validation
## 0.2.0
* Adds `simple_statistics.quantile()`
* Adds `simple_statistics.mixin()`
* Adds `simple_statistics.geometric_mean()`
* Adds `simple_statistics.sample_variance()`
* Adds `simple_statistics.sample_covariance()`
## 0.1.0
* Adds `simple_statistics.t_test()`
* Adds `simple_statistics.min()`
* Adds `simple_statistics.max()`

View File

@ -0,0 +1,99 @@
# Contributing to simple-statistics
Simple statistics is a statistics library that can be both used and read.
It should help programmers learn statistics and statisticians learn programming.
In order to achieve this goal, it must be **simple** and **explanatory**.
## Simple
`simple-statistics` is written in a subset of JavaScript. Unused features
include:
* [Conditional Operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)
* [ES5 Array methods](http://ie.microsoft.com/TestDrive/HTML5/ECMAScript5Array/Default.html)
* `with`, `eval`, and other forms of `eval`
* Most micro-optimizations, like [alternative for loop forms](http://jsperf.com/loops/70)
* [Shortcut branching](http://javascriptweblog.wordpress.com/2010/07/26/no-more-ifs-alternatives-to-statement-branching-in-javascript/)
## Explanatory
Example:
```js
// # harmonic mean
//
// a mean function typically used to find the average of rates
//
// this is the reciprocal of the arithmetic mean of the reciprocals
// of the input numbers
//
// This runs on `O(n)`, linear time in respect to the array
```
`simple-statistics` tries to stay away from speaking only in the language of math:
for instance, while JavaScript supports UTF8 characters like π, they are not used
in the source:
* UTF8 in JavaScript on pages without specific meta-tag or Content-Type encodings will fail
* UTF8 can be hard to type, since users need to memorize key combinations or code points
* Mathematical symbols have meanings that are often better communicated by words:
in the form of code, we do not run out of space on the paper, and can afford
to call a variable `reciprocal_sum` instead of `r`.
Every function has a comment that ideally includes:
* The English, long-form name of the method
* What the method does
* What purpose the method typically serves
* A link to a longer description on Wikipedia, Mathematica, or another
web-accessible, non-paywalled source
* The efficiency of the function in terms of Big-O notation, if appropriate
* If the function depends on another function in the library, a note of this, like
`depends on mean()`
## Tests
`simple-statistics` has a testsuite located in `test/spec/`. Each test file
covers a specific topic and tries to test against known values:
* Values produced by trusted statistics software like R or scipy
* Common-sense results
Tests can be run in [node.js](http://nodejs.org/) and are run on every commit
to GitHub by Travis-CI.
To run tests:
```sh
npm install
npm test
```
## Documentation
While the code is meant to readable, it is not documentation. We maintain
documentation in `API.md`, which has the simple form:
```md
### .geometric_mean(x)
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
```
This file is written in [Markdown](https://daringfireball.net/projects/markdown/) and
specifies which functions are available, what type of arguments they receive,
what they compute, and what type of answer they return.
## Code Style
We use the [Airbnb style for Javascript](https://github.com/airbnb/javascript) with
only one difference:
**4 space soft tabs always for Javascript, not 2.**
No aligned `=`, no aligned arguments, spaces are either indents or the 1
space between expressions. No hard tabs.
* All comparisons should be as strict and obvious as possible: prefer `(foo === 0)` to
`(!foo)`.
* Straightforward code is more important than most optimizations.

View File

@ -0,0 +1,13 @@
Copyright (c) 2014, Tom MacWright
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

View File

@ -0,0 +1,7 @@
docs:
docco src/*.js
test:
mocha -R spec test/spec/*.js
.PHONY: docs test

View File

@ -0,0 +1,337 @@
[![Build Status](https://secure.travis-ci.org/tmcw/simple-statistics.png?branch=master)](http://travis-ci.org/tmcw/simple-statistics) [![Coverage Status](https://coveralls.io/repos/tmcw/simple-statistics/badge.png)](https://coveralls.io/r/tmcw/simple-statistics)
A JavaScript implementation of descriptive, regression, and inference statistics.
Implemented in literate JavaScript with no dependencies, designed to work
in all modern browsers (including IE) as well as in node.js.
## [API Documentation](API.md)
---
Basic contracts of functions:
* Functions do not modify their arguments e.g. change their order
* Invalid input, like empty lists to functions that need 1+ items to work, will cause functions to return `null`.
# Basic Array Operations
### .mixin(array)
_Optionally_ mix in the following functions into the `Array` prototype. Otherwise
you can use them off of the simple-statistics object itself.
If given a particular array instance as an argument, this adds the functions
only to that array rather than the global `Array.prototype`. Without an argument,
it runs on the global `Array.prototype`.
### .mean(x)
Mean of a single-dimensional Array of numbers. _Also available as `.average(x)`_
### .sum(x)
Sum of a single-dimensional Array of numbers.
### .mode(x)
Returns the number that appears most frequently in a single-dimensional Array
of numbers. If there are multiple modes, the one that appears last
is returned.
### .variance(x)
[Variance](http://en.wikipedia.org/wiki/Variance) of a single-dimensional Array of numbers.
### .standard_deviation(x)
[Standard Deviation](http://en.wikipedia.org/wiki/Standard_deviation) of a single-dimensional Array of numbers.
### .median_absolute_deviation(x)
The Median Absolute Deviation (MAD) is a robust measure of statistical
dispersion. It is more resilient to outliers than the standard deviation.
Accepts a single-dimensional array of numbers and returns a dispersion value.
Also aliased to `.mad(x)` for brevity.
### .median(x)
[Median](http://en.wikipedia.org/wiki/Median) of a single-dimensional array of numbers.
### .geometric_mean(x)
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
### .harmonic_mean(x)
[Harmonic mean](http://en.wikipedia.org/wiki/Harmonic_mean) of a single-dimensional array of **positive** numbers.
### .root_mean_square(x)
[Root mean square (RMS)](http://en.wikipedia.org/wiki/Root_mean_square) of a single-dimensional array of numbers.
### .min(x)
Finds the minimum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
### .max(x)
Finds the maximum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
### .t_test(sample, x)
Does a [student's t-test](http://en.wikipedia.org/wiki/Student's_t-test) of a dataset `sample`, represented by a single-dimensional array of numbers. `x` is the known value, and the result is a measure of [statistical significance](http://en.wikipedia.org/wiki/Statistical_significance).
### .t_test_two_sample(sample_x, sample_y, difference)
The two-sample t-test is used to compare samples from two populations or groups,
confirming or denying the suspicion (null hypothesis) that the populations are
the same. It returns a t-value that you can then look up to give certain
judgements of confidence based on a t distribution table.
This implementation expects the samples `sample_x` and `sample_y` to be given
as one-dimensional arrays of more than one number each.
### .sample_variance(x)
Produces [sample variance](http://mathworld.wolfram.com/SampleVariance.html)
of a single-dimensional array of numbers.
### .sample_covariance(a, b)
Produces [sample covariance](http://en.wikipedia.org/wiki/Sample_mean_and_sample_covariance)
of two single-dimensional arrays of numbers.
### .sample_correlation(a, b)
Produces [sample correlation](http://en.wikipedia.org/wiki/Correlation_and_dependence)
of two single-dimensional arrays of numbers.
### .quantile(sample, p)
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
at p. For those familiary with the `k/q` syntax, `p == k/q`. `sample` must
be a single-dimensional array of numbers. p must be a number greater than or equal to zero and less than or equal to one, or an array of numbers following that rule.
If an array is given, an array of results will be returned instead of a single
number.
### .chunk(sample, chunkSize)
Given a `sample` array, and a positive integer `chunkSize`, splits an array
into chunks of `chunkSize` size and returns an array of those chunks. This
does not change the input value. If the length of `sample` is not divisible
by `chunkSize`, the last array will be shorter than the rest.
### .quantile_sorted(sample, p)
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
at p. `sample` must be a one-dimensional _sorted_ array of numbers, and
`p` must be a single number greater than or equal to zero and less than or equal to one.
### .iqr(sample)
Calculates the [Interquartile range](http://en.wikipedia.org/wiki/Interquartile_range) of
a sample - the difference between the upper and lower quartiles. Useful
as a measure of dispersion.
_Also available as `.interquartile_range(x)`_
### .sample_skewness(sample)
Calculates the [skewness](http://en.wikipedia.org/wiki/Skewness) of
a sample, a measure of the extent to which a probability distribution of a
real-valued random variable "leans" to one side of the mean.
The skewness value can be positive or negative, or even undefined.
This implementation uses the [Fisher-Pearson standardized moment coefficient](http://en.wikipedia.org/wiki/Skewness#Pearson.27s_skewness_coefficients),
which means that it behaves the same as Excel, Minitab, SAS, and SPSS.
Skewness is only valid for samples of over three values.
### .jenks(data, number_of_classes)
Find the [Jenks Natural Breaks](http://en.wikipedia.org/wiki/Jenks_natural_breaks_optimization) for
a single-dimensional array of numbers as input and a desired `number_of_classes`.
The result is a single-dimensional with class breaks, including the minimum
and maximum of the input array.
### .r_squared(data, function)
Find the [r-squared](http://en.wikipedia.org/wiki/Coefficient_of_determination) value of a particular dataset, expressed as a two-dimensional `Array` of numbers, against a `Function`.
var r_squared = ss.r_squared([[1, 1]], function(x) { return x * 2; });
### .cumulative_std_normal_probability(z)
Look up the given `z` value in a [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table)
to calculate the probability of a random variable appearing with a given value.
### .z_score(x, mean, standard_deviation)
The standard score is the number of standard deviations an observation
or datum is above or below the mean.
### .standard_normal_table
A [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table) from
which to pull values of Φ (phi).
## Regression
### .linear_regression()
Create a new linear regression solver.
#### .data([[1, 1], [2, 2]])
Set the data of a linear regression. The input is a two-dimensional array of numbers, which are treated as coordinates, like `[[x, y], [x1, y1]]`.
#### .line()
Get the linear regression line: this returns a function that you can
give `x` values and it will return `y` values. Internally, this uses the `m()`
and `b()` values and the classic `y = mx + b` equation.
var linear_regression_line = ss.linear_regression()
.data([[0, 1], [2, 2], [3, 3]]).line();
linear_regression_line(5);
#### .m()
Just get the slope of the fitted regression line, the `m` component of the full
line equation. Returns a number.
#### .b()
Just get the y-intercept of the fitted regression line, the `b` component
of the line equation. Returns a number.
## Classification
### .bayesian()
Create a naïve bayesian classifier.
### .train(item, category)
Train the classifier to classify a certain item, given as an object with keys,
to be in a certain category, given as a string.
### .score(item)
Get the classifications of a certain item, given as an object of
`category -> score` mappings.
var bayes = ss.bayesian();
bayes.train({ species: 'Cat' }, 'animal');
bayes.score({ species: 'Cat' });
// { animal: 1 }
---
## [Literate Source](http://macwright.org/simple-statistics/)
## Usage
To use it in browsers, grab [simple_statistics.js](https://raw.github.com/tmcw/simple-statistics/master/src/simple_statistics.js).
To use it in node, install it with [npm](https://npmjs.org/) or add it to your package.json.
npm install simple-statistics
To use it with [component](https://github.com/component/component),
component install tmcw/simple-statistics
To use it with [bower](http://bower.io/),
bower install simple-statistics
## Basic Descriptive Statistics
```javascript
// Require simple statistics
var ss = require('simple-statistics');
// The input is a simple array
var list = [1, 2, 3];
// Many different descriptive statistics are supported
var sum = ss.sum(list),
mean = ss.mean(list),
min = ss.min(list),
geometric_mean = ss.geometric_mean(list),
max = ss.max(list),
quantile = ss.quantile(0.25);
```
## Linear Regression
```javascript
// For a linear regression, it's a two-dimensional array
var data = [ [1, 2], [2, 3] ];
// simple-statistics can produce a linear regression and return
// a friendly javascript function for the line.
var line = ss.linear_regression()
.data(data)
.line();
// get a point along the line function
line(0);
var line = ss.linear_regression()
// Get the r-squared value of the line estimation
ss.r_squared(data, line);
```
### Bayesian Classifier
```javascript
var bayes = ss.bayesian();
bayes.train({ species: 'Cat' }, 'animal');
bayes.score({ species: 'Cat' });
// { animal: 1 }
```
### Mixin Style
_This is **optional** and not used by default. You can opt-in to mixins
with `ss.mixin()`._
This mixes `simple-statistics` methods into the Array prototype - note that
[extending native objects](http://perfectionkills.com/extending-native-builtins/) is a
tricky move.
This will _only work_ if `defineProperty` is available, which means modern browsers
and nodejs - on IE8 and below, calling `ss.mixin()` will throw an exception.
```javascript
// mixin to Array class
ss.mixin();
// The input is a simple array
var list = [1, 2, 3];
// The same descriptive techniques as above, but in a simpler style
var sum = list.sum(),
mean = list.mean(),
min = list.min(),
max = list.max(),
quantile = list.quantile(0.25);
```
## Examples
* [Linear regression with simple-statistics and d3js](http://bl.ocks.org/3931800)
* [Jenks Natural Breaks with a choropleth map with d3js](http://bl.ocks.org/tmcw/4969184)
# Contributors
* Tom MacWright
* [Matt Sacks](https://github.com/mattsacks)
* Doron Linder
* [Alexander Sicular](https://github.com/siculars)

View File

@ -0,0 +1,157 @@
[![Build Status](https://secure.travis-ci.org/tmcw/simple-statistics.png?branch=master)](http://travis-ci.org/tmcw/simple-statistics)
A JavaScript implementation of descriptive, regression, and inference statistics.
Implemented in literate JavaScript with no dependencies, designed to work
in all modern browsers (including IE) as well as in node.js.
# [API](API.md)
[Full documentation](API.md)
---
```
Basic Array Operations
.mixin()
.mean(x)
.sum(x)
.variance(x)
.standard_deviation(x)
.median_absolute_deviation(x)
.median(x)
.geometric_mean(x)
.harmonic_mean(x)
.root_mean_square(x)
.min(x)
.max(x)
.t_test(sample, x)
.t_test_two_sample(sample_x, sample_y, difference)
.sample_variance(x)
.sample_covariance(x)
.sample_correlation(x)
.quantile(sample, p)
.iqr(sample)
.sample_skewness(sample)
.jenks(data, number_of_classes)
.r_squared(data, function)
.cumulative_std_normal_probability(z)
.z_score(x, mean, standard_deviation)
.standard_normal_table
Regression
.linear_regression()
.data([[1, 1], [2, 2]])
.line()
.m()
.b()
Classification
.bayesian()
.train(item, category)
.score(item)
```
---
# [Literate Source](http://macwright.org/simple-statistics/)
## Usage
To use it in browsers, grab [simple_statistics.js](https://raw.github.com/tmcw/simple-statistics/master/src/simple_statistics.js).
To use it in node, install it with [npm](https://npmjs.org/) or add it to your package.json.
npm install simple-statistics
To use it with [component](https://github.com/component/component),
component install tmcw/simple-statistics
To use it with [bower](http://bower.io/),
bower install simple-statistics
## Basic Descriptive Statistics
```javascript
// Require simple statistics
var ss = require('simple-statistics');
// The input is a simple array
var list = [1, 2, 3];
// Many different descriptive statistics are supported
var sum = ss.sum(list),
mean = ss.mean(list),
min = ss.min(list),
geometric_mean = ss.geometric_mean(list),
max = ss.max(list),
quantile = ss.quantile(0.25);
```
## Linear Regression
```javascript
// For a linear regression, it's a two-dimensional array
var data = [ [1, 2], [2, 3] ];
// simple-statistics can produce a linear regression and return
// a friendly javascript function for the line.
var line = ss.linear_regression()
.data(data)
.line();
// get a point along the line function
line(0);
var line = ss.linear_regression()
// Get the r-squared value of the line estimation
ss.r_squared(data, line);
```
### Bayesian Classifier
```javascript
var bayes = ss.bayesian();
bayes.train({ species: 'Cat' }, 'animal');
bayes.score({ species: 'Cat' });
// { animal: 1 }
```
### Mixin Style
_This is **optional** and not used by default. You can opt-in to mixins
with `ss.mixin()`._
This mixes `simple-statistics` methods into the Array prototype - note that
[extending native objects](http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/) is a
tricky move.
This will _only work_ if `defineProperty` is available, which means modern browsers
and nodejs - on IE8 and below, calling `ss.mixin()` will throw an exception.
```javascript
// mixin to Array class
ss.mixin();
// The input is a simple array
var list = [1, 2, 3];
// The same descriptive techniques as above, but in a simpler style
var sum = list.sum(),
mean = list.mean(),
min = list.min(),
max = list.max(),
quantile = list.quantile(0.25);
```
## Examples
* [Linear regression with simple-statistics and d3js](http://bl.ocks.org/3931800)
* [Jenks Natural Breaks with a choropleth map with d3js](http://bl.ocks.org/tmcw/4969184)
# Contributors
* Tom MacWright
* [Matt Sacks](https://github.com/mattsacks)
* Doron Linder
* [Alexander Sicular](https://github.com/siculars)

View File

@ -0,0 +1,23 @@
## See Also
* [stream-statistics](https://github.com/tmcw/stream-statistics), a sister project that implements
many of the same measures for streaming data - as online algorithms
### Javascript
* [science.js](https://github.com/jasondavies/science.js)
* [atoll.js](https://github.com/nsfmc/atoll.js)
* [descriptive_statistics](https://github.com/thirtysixthspan/descriptive_statistics)
* [jStat](http://www.jstat.org/)
* [classifier](https://github.com/harthur/classifier) is a naive bayesian classifier (though specialized for the words-spam case)
* [underscore.math](https://github.com/syntagmatic/underscore.math/blob/master/underscore.math.js)
### Python
* [Pandas](http://pandas.pydata.org/)
* [SciPy](http://www.scipy.org/)
### Their Own Language
* [Julia Language](http://julialang.org/)
* [R language](http://www.r-project.org/)

View File

@ -0,0 +1,20 @@
var fs = require('fs');
var readme = fs.readFileSync('README.md', 'utf8')
.split('\n');
var a = true, b = true;
fs.writeFileSync('README.md', readme.filter(function(f) {
if (f === '---') {
a = !a;
return true;
}
return a;
}).map(function(f) {
if (f === '---' && b) {
f = f + '\n\n' + fs.readFileSync('API.md', 'utf8') + '\n\n';
b = false;
}
return f;
}).join('\n'));

View File

@ -0,0 +1,11 @@
{
"name": "simple-statistics",
"version": "0.9.0",
"description": "Simple Statistics",
"repo": "tmcw/simple-statistics",
"keywords": [],
"license": "ISC",
"dependencies": {},
"development": {},
"main": "src/simple_statistics.js"
}

View File

@ -0,0 +1,13 @@
{
"name": "simple-statistics",
"version": "0.9.0",
"description": "Simple Statistics",
"repo": "tmcw/simple-statistics",
"keywords": [],
"license": "ISC",
"dependencies": {},
"development": {},
"scripts": [
"src/simple_statistics.js"
]
}

View File

@ -0,0 +1,506 @@
/*--------------------- Typography ----------------------------*/
@font-face {
font-family: 'aller-light';
src: url('public/fonts/aller-light.eot');
src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'),
url('public/fonts/aller-light.woff') format('woff'),
url('public/fonts/aller-light.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'aller-bold';
src: url('public/fonts/aller-bold.eot');
src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'),
url('public/fonts/aller-bold.woff') format('woff'),
url('public/fonts/aller-bold.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'novecento-bold';
src: url('public/fonts/novecento-bold.eot');
src: url('public/fonts/novecento-bold.eot?#iefix') format('embedded-opentype'),
url('public/fonts/novecento-bold.woff') format('woff'),
url('public/fonts/novecento-bold.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
/*--------------------- Layout ----------------------------*/
html { height: 100%; }
body {
font-family: "aller-light";
font-size: 14px;
line-height: 18px;
color: #30404f;
margin: 0; padding: 0;
height:100%;
}
#container { min-height: 100%; }
a {
color: #000;
}
b, strong {
font-weight: normal;
font-family: "aller-bold";
}
p {
margin: 15px 0 0px;
}
.annotation ul, .annotation ol {
margin: 25px 0;
}
.annotation ul li, .annotation ol li {
font-size: 14px;
line-height: 18px;
margin: 10px 0;
}
h1, h2, h3, h4, h5, h6 {
color: #112233;
line-height: 1em;
font-weight: normal;
font-family: "novecento-bold";
text-transform: uppercase;
margin: 30px 0 15px 0;
}
h1 {
margin-top: 40px;
}
hr {
border: 0;
background: 1px #ddd;
height: 1px;
margin: 20px 0;
}
pre, tt, code {
font-size: 12px; line-height: 16px;
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
.annotation pre {
display: block;
margin: 0;
padding: 7px 10px;
background: #fcfcfc;
-moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
-webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
overflow-x: auto;
}
.annotation pre code {
border: 0;
padding: 0;
background: transparent;
}
blockquote {
border-left: 5px solid #ccc;
margin: 0;
padding: 1px 0 1px 1em;
}
.sections blockquote p {
font-family: Menlo, Consolas, Monaco, monospace;
font-size: 12px; line-height: 16px;
color: #999;
margin: 10px 0 0;
white-space: pre-wrap;
}
ul.sections {
list-style: none;
padding:0 0 5px 0;;
margin:0;
}
/*
Force border-box so that % widths fit the parent
container without overlap because of margin/padding.
More Info : http://www.quirksmode.org/css/box.html
*/
ul.sections > li > div {
-moz-box-sizing: border-box; /* firefox */
-ms-box-sizing: border-box; /* ie */
-webkit-box-sizing: border-box; /* webkit */
-khtml-box-sizing: border-box; /* konqueror */
box-sizing: border-box; /* css3 */
}
/*---------------------- Jump Page -----------------------------*/
#jump_to, #jump_page {
margin: 0;
background: white;
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
font: 16px Arial;
cursor: pointer;
text-align: right;
list-style: none;
}
#jump_to a {
text-decoration: none;
}
#jump_to a.large {
display: none;
}
#jump_to a.small {
font-size: 22px;
font-weight: bold;
color: #676767;
}
#jump_to, #jump_wrapper {
position: fixed;
right: 0; top: 0;
padding: 10px 15px;
margin:0;
}
#jump_wrapper {
display: none;
padding:0;
}
#jump_to:hover #jump_wrapper {
display: block;
}
#jump_page {
padding: 5px 0 3px;
margin: 0 0 25px 25px;
}
#jump_page .source {
display: block;
padding: 15px;
text-decoration: none;
border-top: 1px solid #eee;
}
#jump_page .source:hover {
background: #f5f5ff;
}
#jump_page .source:first-child {
}
/*---------------------- Low resolutions (> 320px) ---------------------*/
@media only screen and (min-width: 320px) {
.pilwrap { display: none; }
ul.sections > li > div {
display: block;
padding:5px 10px 0 10px;
}
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
padding-left: 30px;
}
ul.sections > li > div.content {
overflow-x:auto;
-webkit-box-shadow: inset 0 0 5px #e5e5ee;
box-shadow: inset 0 0 5px #e5e5ee;
border: 1px solid #dedede;
margin:5px 10px 5px 10px;
padding-bottom: 5px;
}
ul.sections > li > div.annotation pre {
margin: 7px 0 7px;
padding-left: 15px;
}
ul.sections > li > div.annotation p tt, .annotation code {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 12px;
padding: 0 0.2em;
}
}
/*---------------------- (> 481px) ---------------------*/
@media only screen and (min-width: 481px) {
#container {
position: relative;
}
body {
background-color: #F5F5FF;
font-size: 15px;
line-height: 21px;
}
pre, tt, code {
line-height: 18px;
}
p, ul, ol {
margin: 0 0 15px;
}
#jump_to {
padding: 5px 10px;
}
#jump_wrapper {
padding: 0;
}
#jump_to, #jump_page {
font: 10px Arial;
text-transform: uppercase;
}
#jump_page .source {
padding: 5px 10px;
}
#jump_to a.large {
display: inline-block;
}
#jump_to a.small {
display: none;
}
#background {
position: absolute;
top: 0; bottom: 0;
width: 350px;
background: #fff;
border-right: 1px solid #e5e5ee;
z-index: -1;
}
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
padding-left: 40px;
}
ul.sections > li {
white-space: nowrap;
}
ul.sections > li > div {
display: inline-block;
}
ul.sections > li > div.annotation {
max-width: 350px;
min-width: 350px;
min-height: 5px;
padding: 13px;
overflow-x: hidden;
white-space: normal;
vertical-align: top;
text-align: left;
}
ul.sections > li > div.annotation pre {
margin: 15px 0 15px;
padding-left: 15px;
}
ul.sections > li > div.content {
padding: 13px;
vertical-align: top;
border: none;
-webkit-box-shadow: none;
box-shadow: none;
}
.pilwrap {
position: relative;
display: inline;
}
.pilcrow {
font: 12px Arial;
text-decoration: none;
color: #454545;
position: absolute;
top: 3px; left: -20px;
padding: 1px 2px;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
}
.for-h1 .pilcrow {
top: 47px;
}
.for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow {
top: 35px;
}
ul.sections > li > div.annotation:hover .pilcrow {
opacity: 1;
}
}
/*---------------------- (> 1025px) ---------------------*/
@media only screen and (min-width: 1025px) {
body {
font-size: 16px;
line-height: 24px;
}
#background {
width: 525px;
}
ul.sections > li > div.annotation {
max-width: 525px;
min-width: 525px;
padding: 10px 25px 1px 50px;
}
ul.sections > li > div.content {
padding: 9px 15px 16px 25px;
}
}
/*---------------------- Syntax Highlighting -----------------------------*/
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
pre code {
display: block; padding: 0.5em;
color: #000;
background: #f8f8ff
}
pre .hljs-comment,
pre .hljs-template_comment,
pre .hljs-diff .hljs-header,
pre .hljs-javadoc {
color: #408080;
font-style: italic
}
pre .hljs-keyword,
pre .hljs-assignment,
pre .hljs-literal,
pre .hljs-css .hljs-rule .hljs-keyword,
pre .hljs-winutils,
pre .hljs-javascript .hljs-title,
pre .hljs-lisp .hljs-title,
pre .hljs-subst {
color: #954121;
/*font-weight: bold*/
}
pre .hljs-number,
pre .hljs-hexcolor {
color: #40a070
}
pre .hljs-string,
pre .hljs-tag .hljs-value,
pre .hljs-phpdoc,
pre .hljs-tex .hljs-formula {
color: #219161;
}
pre .hljs-title,
pre .hljs-id {
color: #19469D;
}
pre .hljs-params {
color: #00F;
}
pre .hljs-javascript .hljs-title,
pre .hljs-lisp .hljs-title,
pre .hljs-subst {
font-weight: normal
}
pre .hljs-class .hljs-title,
pre .hljs-haskell .hljs-label,
pre .hljs-tex .hljs-command {
color: #458;
font-weight: bold
}
pre .hljs-tag,
pre .hljs-tag .hljs-title,
pre .hljs-rules .hljs-property,
pre .hljs-django .hljs-tag .hljs-keyword {
color: #000080;
font-weight: normal
}
pre .hljs-attribute,
pre .hljs-variable,
pre .hljs-instancevar,
pre .hljs-lisp .hljs-body {
color: #008080
}
pre .hljs-regexp {
color: #B68
}
pre .hljs-class {
color: #458;
font-weight: bold
}
pre .hljs-symbol,
pre .hljs-ruby .hljs-symbol .hljs-string,
pre .hljs-ruby .hljs-symbol .hljs-keyword,
pre .hljs-ruby .hljs-symbol .hljs-keymethods,
pre .hljs-lisp .hljs-keyword,
pre .hljs-tex .hljs-special,
pre .hljs-input_number {
color: #990073
}
pre .hljs-builtin,
pre .hljs-constructor,
pre .hljs-built_in,
pre .hljs-lisp .hljs-title {
color: #0086b3
}
pre .hljs-preprocessor,
pre .hljs-pi,
pre .hljs-doctype,
pre .hljs-shebang,
pre .hljs-cdata {
color: #999;
font-weight: bold
}
pre .hljs-deletion {
background: #fdd
}
pre .hljs-addition {
background: #dfd
}
pre .hljs-diff .hljs-change {
background: #0086b3
}
pre .hljs-chunk {
color: #aaa
}
pre .hljs-tex .hljs-formula {
opacity: 0.5;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<meta http-equiv="refresh" content="0;URL='docs/simple_statistics.html'">

View File

@ -0,0 +1,28 @@
{
"name": "simple-statistics",
"version": "0.9.0",
"description": "Simple Statistics",
"author": "Tom MacWright <tom@macwright.org> (http://macwright.org/)",
"repository": {
"type": "git",
"url": "git://github.com/tmcw/simple-statistics.git"
},
"dependencies": {},
"devDependencies": {
"jshint": "2.5.3",
"coveralls": "~2.11.1",
"istanbul": "~0.3.0",
"tape": "~2.14.0",
"random-js": "~1.0.4"
},
"scripts": {
"test": "tape test/*.js",
"cov": "istanbul cover ./node_modules/.bin/tape test/*.js && coveralls < ./coverage/lcov.info",
"api": "node api.js"
},
"main": "src/simple_statistics.js",
"engines": {
"node": "*"
},
"license": "ISC"
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
var ss = require('../');
var test = require('tape');
test('bayes', function(t) {
test('makes an easy call with one training round', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
t.deepEqual(bayes.score({
species: 'Cat'
}), {
animal: 1
});
t.end();
});
test('makes fify-fifty call', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'chair');
t.deepEqual(bayes.score({
species: 'Cat'
}), {
animal: 0.5,
chair: 0.5
});
t.end();
});
test('makes seventy-five/twenty-five call', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'chair');
t.deepEqual(bayes.score({
species: 'Cat'
}), {
animal: 0.75,
chair: 0.25
});
t.end();
});
test('tests multiple properties', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'chair');
bayes.train({
species: 'Cat',
color: 'white'
}, 'chair');
t.deepEqual(bayes.score({
color: 'white'
}), {
animal: 0,
chair: 0.2
});
t.end();
});
test('classifies multiple things', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Dog'
}, 'animal');
bayes.train({
species: 'Dog'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'chair');
t.deepEqual(bayes.score({
species: 'Cat'
}), {
animal: 0.25,
chair: 0.25
});
t.deepEqual(bayes.score({
species: 'Dog'
}), {
animal: 0.5,
chair: 0
});
t.end();
});
t.end();
});

View File

@ -0,0 +1,17 @@
var test = require('tape');
var ss = require('../');
test('bernoulli_distribution', function(t) {
test('can return generate probability and cumulative probability distributions for p = 0.3', function(t) {
t.equal('object', typeof ss.bernoulli_distribution(0.3));
t.equal(ss.bernoulli_distribution(0.3)[0], 0.7, ss.epsilon);
t.equal(ss.bernoulli_distribution(0.3)[1], 0.3, ss.epsilon);
t.end();
});
test('can return null when p is not a valid probability', function(t) {
t.equal(null, ss.bernoulli_distribution(-0.01), 'p should be greater than 0.0');
t.equal(null, ss.bernoulli_distribution(1.5), 'p should be less than 1.0');
t.end();
});
t.end();
});

View File

@ -0,0 +1,31 @@
var test = require('tape');
var ss = require('../');
function rnd(n) {
return parseFloat(n.toFixed(4));
}
test('binomial_distribution', function(t) {
// Data given in the [Wikipedia example](http://en.wikipedia.org/wiki/Binomial_distribution#Example) retrieved 29 Mar 2014
// Cumulative probabilities worked by hand to mitigate accumulated rounding errors.
test('can return generate probability and cumulative probability distributions for n = 6, p = 0.3', function(t) {
t.equal('object', typeof ss.binomial_distribution(6, 0.3));
t.equal(rnd(ss.binomial_distribution(6, 0.3)[0]), 0.1176, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[1]), 0.3025, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[2]), 0.3241, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[3]), 0.1852, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[4]), 0.0595, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[5]), 0.0102, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[6]), 0.0007, ss.epsilon);
t.end();
});
test('can return null when p or n are not valid parameters', function(t) {
t.equal(null, ss.binomial_distribution(0, 0.5), 'n should be strictly positive');
t.equal(null, ss.binomial_distribution(1.5, 0.5), 'n should be an integer');
t.equal(null, ss.binomial_distribution(2, -0.01), 'p should be greater than 0.0');
t.equal(null, ss.binomial_distribution(2, 1.5), 'p should be less than 1.0');
t.end();
});
t.end();
});

View File

@ -0,0 +1,23 @@
var test = require('tape');
var ss = require('../');
// Data from Poisson goodness-of-fit example 10-19 in William W. Hines & Douglas C. Montgomery,
// "Probability and Statistics in Engineering and Management Science", Wiley (1980).
var data_10_19 = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3
];
test('chi_squared_goodness_of_fit', function(t) {
test('can reject the null hypothesis with level of confidence specified at 0.05', function(t) {
t.equal(false, ss.chi_squared_goodness_of_fit(data_10_19, ss.poisson_distribution, 0.05));
t.end();
});
test('can accept the null hypothesis with level of confidence specified at 0.10', function(t) {
t.equal(true, ss.chi_squared_goodness_of_fit(data_10_19, ss.poisson_distribution, 0.10));
t.end();
});
t.end();
});

View File

@ -0,0 +1,18 @@
var test = require('tape');
var ss = require('../');
test('chunks', function(t) {
test('can get chunks of an array', function(t) {
t.deepEqual(ss.chunk([1, 2], 1), [[1], [2]]);
t.deepEqual(ss.chunk([1, 2], 2), [[1, 2]]);
t.deepEqual(ss.chunk([1, 2, 3, 4], 4), [[1, 2, 3, 4]]);
t.deepEqual(ss.chunk([1, 2, 3, 4], 2), [[1, 2], [3, 4]]);
t.deepEqual(ss.chunk([1, 2, 3, 4], 3), [[1, 2, 3], [4]]);
t.deepEqual(ss.chunk([1, 2, 3, 4, 5, 6, 7], 2), [[1, 2], [3, 4], [5, 6], [7]]);
t.deepEqual(ss.chunk([], 2), []);
t.deepEqual(ss.chunk([], 0), null);
t.deepEqual(ss.chunk([1, 2], 0), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,13 @@
var test = require('tape');
var ss = require('../');
test('cumulative_std_normal_probability', function(t) {
// https://en.wikipedia.org/wiki/Standard_normal_table#Examples_of_use
test('wikipedia test example works', function(t) {
for (var i = 0; i < ss.standard_normal_table.length; i++) {
t.equal(ss.cumulative_std_normal_probability(0.4), 0.6554);
}
t.end();
});
t.end();
});

View File

@ -0,0 +1,22 @@
var test = require('tape');
var ss = require('../');
test('factorial', function(t) {
test('can return null given a negative number', function(t) {
t.equal(null, ss.factorial(-1));
t.end();
});
test('can calculate 0! = 1', function(t) {
t.equal(ss.factorial(0), 1);
t.end();
});
test('can calculate 1! = 1', function(t) {
t.equal(ss.factorial(1), 1);
t.end();
});
test('can calculate 100! = 1', function(t) {
t.equal(ss.factorial(100), 9.33262154439441e+157);
t.end();
});
t.end();
});

View File

@ -0,0 +1,23 @@
var test = require('tape');
var ss = require('../');
test('geometric mean', function(t) {
// From http://en.wikipedia.org/wiki/Geometric_mean
test('can get the mean of two numbers', function(t) {
t.equal(ss.geometric_mean([2, 8]), 4);
t.equal(ss.geometric_mean([4, 1, 1 / 32]), 0.5);
t.equal(Math.round(ss.geometric_mean([2, 32, 1])), 4);
t.end();
});
test('returns null for empty lists', function(t) {
t.equal(ss.geometric_mean([]), null);
t.end();
});
test('returns null for lists with negative numbers', function(t) {
t.equal(ss.geometric_mean([-1]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,27 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('harmonic_mean', function(t) {
// From http://en.wikipedia.org/wiki/Harmonic_mean
test('can get the mean of two or more numbers', function(t) {
t.equal(ss.harmonic_mean([1, 1]), 1);
t.equal(rnd(ss.harmonic_mean([2, 3])), 2.4);
t.equal(ss.harmonic_mean([1, 2, 4]), 12 / 7);
t.end();
});
test('returns null for empty lists', function(t) {
t.equal(ss.harmonic_mean([]), null);
t.end();
});
test('returns null for lists with negative numbers', function(t) {
t.equal(ss.harmonic_mean([-1]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,24 @@
var test = require('tape');
var ss = require('../');
test('interquartile range (iqr)', function(t) {
// Data and results from
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
test('can get proper iqr of an even-length list', function(t) {
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
t.equal(ss.quantile(even, 0.75) - ss.quantile(even, 0.25), ss.iqr(even));
t.end();
});
test('can get proper iqr of an odd-length list', function(t) {
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
t.equal(ss.quantile(odd, 0.75) - ss.quantile(odd, 0.25), ss.iqr(odd));
t.end();
});
test('an iqr of a zero-length list produces null', function(t) {
t.equal(ss.iqr([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,14 @@
var test = require('tape');
var ss = require('../');
test('jenks', function(t) {
test('will not try to assign more classes than datapoints', function(t) {
t.equal(ss.jenks([1, 2], 3), null);
t.end();
});
test('assigns correct breaks', function(t) {
t.deepEqual(ss.jenks([1, 2, 4, 5, 7, 9, 10, 20], 3), [1, 2, 5, 20]);
t.end();
});
t.end();
});

View File

@ -0,0 +1,54 @@
var test = require('tape');
var ss = require('../');
test('linear regression', function(t) {
test('correctly generates a line for a 0, 0 to 1, 1 dataset', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 1]]);
t.equal(l.line()(0), 0);
t.equal(l.line()(0.5), 0.5);
t.equal(l.line()(1), 1);
t.end();
});
test('correctly generates a line for a 0, 0 to 1, 0 dataset', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
t.equal(l.line()(0), 0);
t.equal(l.line()(0.5), 0);
t.equal(l.line()(1), 0);
t.end();
});
test('returns the data assigned to it', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
t.deepEqual(l.data(), [[0, 0], [1, 0]]);
t.end();
});
test('handles a single-point sample', function(t) {
var l = ss.linear_regression().data([[0, 0]]).line();
t.deepEqual(l(10), 0);
t.end();
});
test('a straight line will have a slope of 0', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
t.equal(l.m(), 0);
t.equal(l.b(), 0);
t.end();
});
test('a line at 50% grade', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 0.5]]);
t.equal(l.m(), 0.5);
t.equal(l.b(), 0);
t.end();
});
test('a line with a high y-intercept', function(t) {
var l = ss.linear_regression().data([[0, 20], [1, 10]]);
t.equal(l.m(), -10);
t.equal(l.b(), 20);
t.end();
});
t.end();
});

View File

@ -0,0 +1,26 @@
var test = require('tape');
var ss = require('../');
test('median absolute deviation (mad)', function(t) {
test('median absolute deviation of an example on wikipedia', function(t) {
t.equal(ss.mad([1, 1, 2, 2, 4, 6, 9]), 1);
t.end();
});
// wolfram alpha: median absolute deviation {0,1,2,3,4,5,6,7,8,9,10}
test('median absolute deviation of 0-10', function(t) {
t.equal(ss.mad([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 3);
t.end();
});
test('median absolute deviation of one number is zero', function(t) {
t.equal(ss.mad([1]), 0);
t.end();
});
test('zero-length corner case', function(t) {
t.equal(ss.mad([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,18 @@
var test = require('tape');
var ss = require('../');
test('mean', function(t) {
test('can get the mean of two numbers', function(t) {
t.equal(ss.mean([1, 2]), 1.5);
t.end();
});
test('can get the mean of one number', function(t) {
t.equal(ss.mean([1]), 1);
t.end();
});
test('an empty list has no average', function(t) {
t.equal(ss.mean([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,38 @@
var test = require('tape');
var ss = require('../');
test('median', function(t) {
test('can get the median of three numbers', function(t) {
t.equal(ss.median([1, 2, 3]), 2);
t.end();
});
test('can get the median of two numbers', function(t) {
t.equal(ss.median([1, 2]), 1.5);
t.end();
});
test('can get the median of four numbers', function(t) {
t.equal(ss.median([1, 2, 3, 4]), 2.5);
t.end();
});
test('gives null for the median of an empty list', function(t) {
t.equal(ss.median([]), null);
t.end();
});
test('sorts numbers numerically', function(t) {
t.equal(ss.median([8, 9, 10]), 9);
t.end();
});
test('does not change the sorting order of its input', function(t) {
var x = [1, 0];
t.equal(ss.median(x), 0.5);
t.equal(x[0], 1);
t.equal(x[1], 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,23 @@
var test = require('tape');
var ss = require('../');
test('min', function(t) {
test('can get the minimum of one number', function(t) {
t.equal(ss.min([1]), 1);
t.end();
});
test('can get the minimum of three numbers', function(t) {
t.equal(ss.min([1, 7, -1000]), -1000);
t.end();
});
t.end();
});
test('max', function(t) {
test('can get the maximum of three numbers', function(t) {
t.equal(ss.max([1, 7, -1000]), 7);
t.end();
});
t.end();
});

View File

@ -0,0 +1,34 @@
var test = require('tape');
var ss = require('../');
test('mixin', function(t) {
test('can mix into a single array', function(t) {
var even = ss.mixin([2, 4, 6, 8]);
t.equal(even.sum(), 20);
t.equal(even.mean(), 5);
t.equal(even.max(), 8);
t.equal(even.min(), 2);
t.equal(even.sample_skewness(), 0);
t.end();
});
test('can mix into Array.prototype', function(t) {
ss.mixin();
var even = [2, 4, 6, 8];
t.equal(even.sum(), 20);
t.equal(even.mean(), 5);
t.equal(even.max(), 8);
t.equal(even.min(), 2);
t.equal(even.sample_skewness(), 0);
t.end();
});
test('mixins can take arguments', function(t) {
ss.mixin();
var even = [2, 4, 6, 8];
t.equal(even.quantile(0.2), 2);
t.equal(even.quantile(0.8), 8);
t.end();
});
t.end();
});

View File

@ -0,0 +1,37 @@
var test = require('tape');
var ss = require('../');
test('mode', function(t) {
test('the mode of a single-number array is that one number', function(t) {
t.equal(ss.mode([1]), 1);
t.end();
});
test('the mode of a two-number array is that one number', function(t) {
t.equal(ss.mode([1, 1]), 1);
t.end();
});
test('other cases', function(t) {
t.equal(ss.mode([1, 1, 2]), 1);
t.equal(ss.mode([1, 1, 2, 3]), 1);
t.equal(ss.mode([1, 1, 2, 3, 3]), 1);
t.equal(ss.mode([1, 1, 2, 3, 3, 3]), 3);
t.equal(ss.mode([1, 1, 2, 2, 2, 2, 3, 3, 3]), 2);
t.equal(ss.mode([1, 2, 3, 4, 5]), 1);
t.equal(ss.mode([1, 2, 3, 4, 5, 5]), 5);
t.equal(ss.mode([1, 1, 1, 2, 2, 3, 3, 4, 4]), 1);
t.end();
});
test('the mode of an empty array is null', function(t) {
t.equal(ss.mode([]), null);
t.end();
});
test('the mode of a three-number array with two same numbers is the repeated one', function(t) {
t.equal(ss.mode([1, 2, 2]), 2);
t.end();
});
t.end();
});

View File

@ -0,0 +1,60 @@
var test = require('tape');
var ss = require('../');
test('natural distribution and z-score', function(t) {
test('normal table is exposed in the API', function(t) {
t.equal(ss.standard_normal_table.length, 310);
t.equal(ss.standard_normal_table[0], 0.5);
t.end();
});
test('P(Z <= 0.4) is 0.6554', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
t.equal(ss.cumulative_std_normal_probability(0.4), 0.6554);
t.end();
});
test('P(Z <= -1.20) is 0.1151', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
t.equal(ss.cumulative_std_normal_probability(-1.20), 0.1151);
t.end();
});
test('P(X <= 82) when X ~ N (80, 25) is 0.6554', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
// What is the probability that a student scores an 82 or less?
t.equal(ss.cumulative_std_normal_probability(ss.z_score(82, 80, 5)), 0.6554);
t.end();
});
test('P(X >= 90) when X ~ N (80, 25) is 0.0228', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
// What is the probability that a student scores a 90 or more?
t.equal(+(1 - ss.cumulative_std_normal_probability(ss.z_score(90, 80, 5))).toPrecision(5), 0.0228);
t.end();
});
test('P(X <= 74) when X ~ N (80, 25) is 0.1151', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
// What is the probability that a student scores a 74 or less?
t.equal(ss.cumulative_std_normal_probability(ss.z_score(74, 80, 5)), 0.1151);
t.end();
});
test('P(78 <= X <= 88) when X ~ N (80, 25) is 0.6006', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
// What is the probability that a student scores between 78 and 88?
var prob88 = ss.cumulative_std_normal_probability(ss.z_score(88, 80, 5)),
prob78 = ss.cumulative_std_normal_probability(ss.z_score(78, 80, 5));
t.equal(+(prob88 - prob78).toPrecision(5), 0.6006);
t.end();
});
t.end();
});

View File

@ -0,0 +1,37 @@
var test = require('tape');
var ss = require('../');
function rnd(n) {
return parseFloat(n.toFixed(4));
}
// expected cumulative probabilities taken from Appendix 1, Table I of William W. Hines & Douglas C.
// Montgomery, "Probability and Statistics in Engineering and Management Science", Wiley (1980).
test('poisson_distribution', function(t) {
test('can return generate probability and cumulative probability distributions for lambda = 3.0', function(t) {
t.equal('object', typeof ss.poisson_distribution(3.0));
t.equal(rnd(ss.poisson_distribution(3.0)[3]), 0.2240, ss.epsilon);
t.end();
});
test('can generate probability and cumulative probability distributions for lambda = 4.0', function(t) {
t.equal('object', typeof ss.poisson_distribution(4.0));
t.equal(rnd(ss.poisson_distribution(4.0)[2]), 0.1465, ss.epsilon);
t.end();
});
test('can generate probability and cumulative probability distributions for lambda = 5.5', function(t) {
t.equal('object', typeof ss.poisson_distribution(5.5));
t.equal(rnd(ss.poisson_distribution(5.5)[7]), 0.1234, ss.epsilon);
t.end();
});
test('can generate probability and cumulative probability distributions for lambda = 9.5', function(t) {
t.equal('object', typeof ss.poisson_distribution(9.5));
t.equal(rnd(ss.poisson_distribution(9.5)[17]), 0.0088, ss.epsilon);
t.end();
});
test('can return null when lambda <= 0', function(t) {
t.equal(null, ss.poisson_distribution(0));
t.equal(null, ss.poisson_distribution(-10));
t.end();
});
t.end();
});

View File

@ -0,0 +1,64 @@
var test = require('tape');
var ss = require('../');
test('quantile', function(t) {
// Data and results from
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
test('can get proper quantiles of an even-length list', function(t) {
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
t.equal(ss.quantile(even, 0.25), 7);
t.equal(ss.quantile(even, 0.5), 9);
t.equal(ss.quantile(even, 0.75), 15);
t.end();
});
test('can get proper quantiles of an odd-length list', function(t) {
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
t.equal(ss.quantile(odd, 0.25), 7);
t.equal(ss.quantile(odd, 0.5), 9);
t.equal(ss.quantile(odd, 0.75), 15);
t.end();
});
test('the median quantile is equal to the median', function(t) {
var rand = [1, 4, 5, 8];
t.equal(ss.quantile(rand, 0.5), ss.median(rand));
var rand2 = [10, 50, 2, 4, 4, 5, 8];
t.equal(ss.quantile(rand2, 0.5), ss.median(rand2));
t.end();
});
test('a zero-length list produces null', function(t) {
t.equal(ss.quantile([], 0.5), null);
t.end();
});
test('test odd-value case', function(t) {
t.equal(ss.quantile([0, 1, 2, 3, 4], 0.2), 1);
t.end();
});
test('bad bounds produce null', function(t) {
t.equal(ss.quantile([1, 2, 3], 1.1), null);
t.equal(ss.quantile([1, 2, 3], -0.5), null);
t.end();
});
test('max quantile is equal to the max', function(t) {
t.equal(ss.quantile([1, 2, 3], 1), ss.max([1, 2, 3]));
t.end();
});
test('min quantile is equal to the min', function(t) {
t.equal(ss.quantile([1, 2, 3], 0), ss.min([1, 2, 3]));
t.end();
});
test('if quantile arg is an array, response is an array of quantiles', function(t) {
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
t.deepEqual(ss.quantile(odd, [0, 0.25, 0.5, 0.75, 1]), [3, 7, 9, 15, 20]);
t.deepEqual(ss.quantile(odd, [0.75, 0.5]), [15, 9]);
t.end();
});
t.end();
});

View File

@ -0,0 +1,15 @@
var test = require('tape');
var ss = require('../');
test('quantile_sorted', function(t) {
// Data and results from
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
test('can get proper quantiles of an even-length list', function(t) {
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
t.equal(ss.quantile_sorted(even, 0.25), 7);
t.equal(ss.quantile_sorted(even, 0.5), 9);
t.equal(ss.quantile_sorted(even, 0.75), 15);
t.end();
});
t.end();
});

View File

@ -0,0 +1,26 @@
var test = require('tape');
var ss = require('../');
test('r-squared', function(t) {
test('says that the r squared of a two-point line is perfect', function(t) {
var d = [[0, 0], [1, 1]];
var l = ss.linear_regression().data(d);
t.equal(ss.r_squared(d, l.line()), 1);
t.end();
});
test('says that the r squared of a three-point line is not perfect', function(t) {
var d = [[0, 0], [0.5, 0.2], [1, 1]];
var l = ss.linear_regression().data(d);
t.notEqual(ss.r_squared(d, l.line()), 1);
t.end();
});
test('r-squared of single sample is 1', function(t) {
var d = [[0, 0]];
var l = ss.linear_regression().data(d);
t.equal(ss.r_squared(d, l.line()), 1);
t.end();
});
t.end();
});

View File

@ -0,0 +1,23 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('root_mean_square', function(t) {
// From http://en.wikipedia.org/wiki/Root_mean_square
test('can get the RMS of two or more numbers', function(t) {
t.equal(ss.root_mean_square([1, 1]), 1);
t.equal(rnd(ss.root_mean_square([3, 4, 5])), 4.082);
t.equal(rnd(ss.root_mean_square([-0.1, 5, -2, 10])), 5.679);
t.end();
});
test('returns null for empty lists', function(t) {
t.equal(ss.root_mean_square([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,19 @@
var test = require('tape');
var Random = require('random-js');
var random = new Random(Random.engines.mt19937().seed(0));
var ss = require('../');
function rng() { return random.real(0, 1); }
test('sample', function(t) {
t.deepEqual(ss.sample([], 0, rng), [], 'edge case - zero array');
t.deepEqual(ss.sample([], 2, rng), [], 'edge case - zero array');
t.deepEqual(ss.sample([1,2,3], 0, rng, 0), [], 'edge case - zero array');
t.deepEqual(ss.sample([1,2,3], 1, rng), [1], 'edge case - sample of 1');
t.deepEqual(ss.sample([1,2,3], 1, rng), [2]);
t.deepEqual(ss.sample([1,2,3], 3, rng), [2,3,1]);
t.deepEqual(ss.sample([1,2,3,4], 2, rng), [3,1]);
t.deepEqual(ss.sample([1,2,3,4,6,7,8], 2, rng), [8,7]);
t.deepEqual(ss.sample(['foo', 'bar'], 1, rng), ['foo'], 'non-number contents');
t.end();
});

View File

@ -0,0 +1,29 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('sample correlation', function(t) {
test('can get the sample correlation of identical arrays', function(t) {
var data = [1, 2, 3, 4, 5, 6];
t.equal(rnd(ss.sample_correlation(data, data)), 1);
t.end();
});
test('can get the sample correlation of different arrays', function(t) {
var a = [1, 2, 3, 4, 5, 6];
var b = [2, 2, 3, 4, 5, 60];
t.equal(rnd(ss.sample_correlation(a, b)), 0.691);
t.end();
});
test('zero-length corner case', function(t) {
t.equal(rnd(ss.sample_correlation([], [])), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,34 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('sample covariance', function(t) {
test('can get perfect negative covariance', function(t) {
var x = [1, 2, 3, 4, 5, 6];
var y = [6, 5, 4, 3, 2, 1];
t.equal(rnd(ss.sample_covariance(x, y)), -3.5);
t.end();
});
test('covariance of something with itself is its variance', function(t) {
var x = [1, 2, 3, 4, 5, 6];
t.equal(rnd(ss.sample_covariance(x, x)), 3.5);
t.end();
});
test('covariance is zero for something with no correlation', function(t) {
var x = [1, 2, 3, 4, 5, 6];
var y = [1, 1, 2, 2, 1, 1];
t.equal(rnd(ss.sample_covariance(x, y)), 0);
t.end();
});
test('zero-length corner case', function(t) {
t.equal(rnd(ss.sample_covariance([], [])), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,48 @@
var test = require('tape');
var ss = require('../');
test('sample skewness', function(t) {
test('the skewness of an empty sample is null', function(t) {
var data = [];
t.equal(ss.sample_skewness(data), null);
t.end();
});
test('the skewness of an sample with one number is null', function(t) {
var data = [1];
t.equal(ss.sample_skewness(data), null);
t.end();
});
test('the skewness of an sample with two numbers is null', function(t) {
var data = [1, 2];
t.equal(ss.sample_skewness(data), null);
t.end();
});
test('can calculate the skewness of SAS example 1', function(t) {
// Data and answer taken from SKEWNESS function documentation at
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
var data = [0, 1, 1];
t.equal(+ss.sample_skewness(data).toPrecision(10), -1.732050808);
t.end();
});
test('can calculate the skewness of SAS example 2', function(t) {
// Data and answer taken from SKEWNESS function documentation at
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
var data = [2, 4, 6, 3, 1];
t.equal(+ss.sample_skewness(data).toPrecision(10), 0.5901286564);
t.end();
});
test('can calculate the skewness of SAS example 3', function(t) {
// Data and answer taken from SKEWNESS function documentation at
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
var data = [2, 0, 0];
t.equal(+ss.sample_skewness(data).toPrecision(10), 1.732050808);
t.end();
});
t.end();
});

View File

@ -0,0 +1,19 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('sample_standard_deviation', function(t) {
test('can get the standard deviation of an example on wikipedia', function(t) {
t.equal(rnd(ss.sample_standard_deviation([2, 4, 4, 4, 5, 5, 7, 9])), 2.138);
t.end();
});
test('zero-length corner case', function(t) {
t.equal(rnd(ss.sample_standard_deviation([])), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,38 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('sample variance', function(t) {
test('can get the sample variance of a six-sided die', function(t) {
t.equal(rnd(ss.sample_variance([1, 2, 3, 4, 5, 6])), 3.5);
t.end();
});
// confirmed in R
//
// > var(1:10)
// [1] 9.166667
test('can get the sample variance of numbers 1-10', function(t) {
t.equal(rnd(ss.sample_variance([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), 9.167);
t.end();
});
test('the sample variance of two numbers that are the same is 0', function(t) {
t.equal(rnd(ss.sample_variance([1, 1])), 0);
t.end();
});
test('the sample variance of one number is null', function(t) {
t.equal(ss.sample_variance([1]), null);
t.end();
});
test('the sample variance of no numbers is null', function(t) {
t.equal(ss.sample_variance([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,24 @@
var test = require('tape');
var Random = require('random-js');
var random = new Random(Random.engines.mt19937().seed(0));
var ss = require('../');
function rng() { return random.real(0, 1); }
test('shuffle', function(t) {
var input = [1, 2, 3, 4, 5, 6];
t.deepEqual(ss.shuffle([], rng), []);
t.deepEqual(ss.shuffle(input, rng), [1, 5, 3, 2, 4, 6]);
t.deepEqual(input, [1, 2, 3, 4, 5, 6], 'does not change original array');
t.deepEqual(ss.shuffle(input, rng), [5, 4, 1, 3, 6, 2]);
t.deepEqual(input, [1, 2, 3, 4, 5, 6], 'does not change original array');
t.end();
});
test('shuffle_in_place', function(t) {
var input = [1, 2, 3, 4, 5, 6];
t.deepEqual(ss.shuffle_in_place([], rng), []);
t.deepEqual(ss.shuffle_in_place(input, rng), [6, 1, 5, 2, 4, 3]);
t.deepEqual(input, [6, 1, 5, 2, 4, 3], 'changes original array');
t.end();
});

View File

@ -0,0 +1,39 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('standard_deviation', function(t) {
test('can get the standard deviation of an example on wikipedia', function(t) {
t.equal(rnd(ss.standard_deviation([2, 4, 4, 4, 5, 5, 7, 9])), 2);
t.end();
});
// confirmed with numpy
// In [4]: numpy.std([1,2,3])
// Out[4]: 0.81649658092772603
test('can get the standard deviation of 1-3', function(t) {
t.equal(rnd(ss.standard_deviation([1, 2, 3])), 0.816);
t.end();
});
test('zero-length array corner case', function(t) {
t.equal(rnd(ss.standard_deviation([])), 0);
t.end();
});
// In [6]: numpy.std([0,1,2,3,4,5,6,7,8,9,10])
// Out[6]: 3.1622776601683795
test('can get the standard deviation of 1-10', function(t) {
t.equal(rnd(ss.standard_deviation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), 3.162);
t.end();
});
test('the standard deviation of one number is zero', function(t) {
t.equal(rnd(ss.standard_deviation([1])), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,14 @@
var test = require('tape');
var ss = require('../');
test('standard_normal_table', function(t) {
test('all entries are numeric', function(t) {
for (var i = 0; i < ss.standard_normal_table.length; i++) {
t.equal(typeof ss.standard_normal_table[i], 'number');
t.ok(ss.standard_normal_table[i] >= 0);
t.ok(ss.standard_normal_table[i] <= 1);
}
t.end();
});
t.end();
});

View File

@ -0,0 +1,15 @@
var test = require('tape');
var ss = require('../');
test('sum', function(t) {
test('can get the sum of two numbers', function(t) {
t.equal(ss.sum([1, 2]), 3);
t.end();
});
test('the sum of no numbers is zero', function(t) {
t.equal(ss.sum([]), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,38 @@
var test = require('tape'),
ss = require('../');
test('t test', function(t) {
test('can compare a known value to the mean of samples', function(t) {
var res = ss.t_test([1, 2, 3, 4, 5, 6], 3.385);
t.equal(res, 0.1649415480881466);
t.end();
});
test('can test independency of two samples', function(t) {
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6], 0);
t.equal(res, -2.1908902300206643);
t.end();
});
test('can test independency of two samples (mu == -2)', function(t) {
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6], -2);
t.equal(res, 0);
t.end();
});
test('can test independency of two samples of different lengths', function(t) {
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6, 1, 2, 0]);
t.equal(res, -0.4165977904505309);
t.end();
});
test('has an edge case for one sample being of size zero', function(t) {
t.equal(ss.t_test_two_sample([1, 2, 3, 4], []), null);
t.equal(ss.t_test_two_sample([], [1, 2, 3, 4]), null);
t.equal(ss.t_test_two_sample([], []), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,24 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('variance', function(t) {
test('can get the variance of a six-sided die', function(t) {
t.equal(rnd(ss.variance([1, 2, 3, 4, 5, 6])), 2.917);
t.end();
});
test('the variance of one number is zero', function(t) {
t.equal(rnd(ss.variance([1])), 0);
t.end();
});
test('the variance of no numbers is null', function(t) {
t.equal(ss.variance([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,70 @@
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f0f3f3; }
.highlight .c { color: #0099FF; font-style: italic } /* Comment */
.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */
.highlight .k { color: #006699; font-weight: bold } /* Keyword */
.highlight .o { color: #555555 } /* Operator */
.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #009999 } /* Comment.Preproc */
.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */
.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */
.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
.highlight .go { color: #AAAAAA } /* Generic.Output */
.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #99CC66 } /* Generic.Traceback */
.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #006699 } /* Keyword.Pseudo */
.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #FF6600 } /* Literal.Number */
.highlight .s { color: #CC3300 } /* Literal.String */
.highlight .na { color: #330099 } /* Name.Attribute */
.highlight .nb { color: #336666 } /* Name.Builtin */
.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */
.highlight .no { color: #336600 } /* Name.Constant */
.highlight .nd { color: #9999FF } /* Name.Decorator */
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #CC00FF } /* Name.Function */
.highlight .nl { color: #9999FF } /* Name.Label */
.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #003333 } /* Name.Variable */
.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #FF6600 } /* Literal.Number.Float */
.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */
.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */
.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */
.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */
.highlight .sc { color: #CC3300 } /* Literal.String.Char */
.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #CC3300 } /* Literal.String.Double */
.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */
.highlight .si { color: #AA0000 } /* Literal.String.Interpol */
.highlight .sx { color: #CC3300 } /* Literal.String.Other */
.highlight .sr { color: #33AAAA } /* Literal.String.Regex */
.highlight .s1 { color: #CC3300 } /* Literal.String.Single */
.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */
.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #003333 } /* Name.Variable.Class */
.highlight .vg { color: #003333 } /* Name.Variable.Global */
.highlight .vi { color: #003333 } /* Name.Variable.Instance */
.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */
.type-csharp .highlight .k { color: #0000FF }
.type-csharp .highlight .kt { color: #0000FF }
.type-csharp .highlight .nf { color: #000000; font-weight: normal }
.type-csharp .highlight .nc { color: #2B91AF }
.type-csharp .highlight .nn { color: #000000 }
.type-csharp .highlight .s { color: #A31515 }
.type-csharp .highlight .sc { color: #A31515 }

425
stylesheets/stylesheet.css Normal file
View File

@ -0,0 +1,425 @@
/*******************************************************************************
Slate Theme for GitHub Pages
by Jason Costello, @jsncostello
*******************************************************************************/
@import url(pygment_trac.css);
/*******************************************************************************
MeyerWeb Reset
*******************************************************************************/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
ol, ul {
list-style: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/*******************************************************************************
Theme Styles
*******************************************************************************/
body {
box-sizing: border-box;
color:#373737;
background: #212121;
font-size: 16px;
font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 {
margin: 10px 0;
font-weight: 700;
color:#222222;
font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif;
letter-spacing: -1px;
}
h1 {
font-size: 36px;
font-weight: 700;
}
h2 {
padding-bottom: 10px;
font-size: 32px;
background: url('../images/bg_hr.png') repeat-x bottom;
}
h3 {
font-size: 24px;
}
h4 {
font-size: 21px;
}
h5 {
font-size: 18px;
}
h6 {
font-size: 16px;
}
p {
margin: 10px 0 15px 0;
}
footer p {
color: #f2f2f2;
}
a {
text-decoration: none;
color: #007edf;
text-shadow: none;
transition: color 0.5s ease;
transition: text-shadow 0.5s ease;
-webkit-transition: color 0.5s ease;
-webkit-transition: text-shadow 0.5s ease;
-moz-transition: color 0.5s ease;
-moz-transition: text-shadow 0.5s ease;
-o-transition: color 0.5s ease;
-o-transition: text-shadow 0.5s ease;
-ms-transition: color 0.5s ease;
-ms-transition: text-shadow 0.5s ease;
}
a:hover, a:focus {text-decoration: underline;}
footer a {
color: #F2F2F2;
text-decoration: underline;
}
em {
font-style: italic;
}
strong {
font-weight: bold;
}
img {
position: relative;
margin: 0 auto;
max-width: 739px;
padding: 5px;
margin: 10px 0 10px 0;
border: 1px solid #ebebeb;
box-shadow: 0 0 5px #ebebeb;
-webkit-box-shadow: 0 0 5px #ebebeb;
-moz-box-shadow: 0 0 5px #ebebeb;
-o-box-shadow: 0 0 5px #ebebeb;
-ms-box-shadow: 0 0 5px #ebebeb;
}
p img {
display: inline;
margin: 0;
padding: 0;
vertical-align: middle;
text-align: center;
border: none;
}
pre, code {
width: 100%;
color: #222;
background-color: #fff;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
font-size: 14px;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
}
pre {
width: 100%;
padding: 10px;
box-shadow: 0 0 10px rgba(0,0,0,.1);
overflow: auto;
}
code {
padding: 3px;
margin: 0 3px;
box-shadow: 0 0 10px rgba(0,0,0,.1);
}
pre code {
display: block;
box-shadow: none;
}
blockquote {
color: #666;
margin-bottom: 20px;
padding: 0 0 0 20px;
border-left: 3px solid #bbb;
}
ul, ol, dl {
margin-bottom: 15px
}
ul {
list-style-position: inside;
list-style: disc;
padding-left: 20px;
}
ol {
list-style-position: inside;
list-style: decimal;
padding-left: 20px;
}
dl dt {
font-weight: bold;
}
dl dd {
padding-left: 20px;
font-style: italic;
}
dl p {
padding-left: 20px;
font-style: italic;
}
hr {
height: 1px;
margin-bottom: 5px;
border: none;
background: url('../images/bg_hr.png') repeat-x center;
}
table {
border: 1px solid #373737;
margin-bottom: 20px;
text-align: left;
}
th {
font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif;
padding: 10px;
background: #373737;
color: #fff;
}
td {
padding: 10px;
border: 1px solid #373737;
}
form {
background: #f2f2f2;
padding: 20px;
}
/*******************************************************************************
Full-Width Styles
*******************************************************************************/
.outer {
width: 100%;
}
.inner {
position: relative;
max-width: 640px;
padding: 20px 10px;
margin: 0 auto;
}
#forkme_banner {
display: block;
position: absolute;
top:0;
right: 10px;
z-index: 10;
padding: 10px 50px 10px 10px;
color: #fff;
background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%;
font-weight: 700;
box-shadow: 0 0 10px rgba(0,0,0,.5);
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
#header_wrap {
background: #212121;
background: -moz-linear-gradient(top, #373737, #212121);
background: -webkit-linear-gradient(top, #373737, #212121);
background: -ms-linear-gradient(top, #373737, #212121);
background: -o-linear-gradient(top, #373737, #212121);
background: linear-gradient(top, #373737, #212121);
}
#header_wrap .inner {
padding: 50px 10px 30px 10px;
}
#project_title {
margin: 0;
color: #fff;
font-size: 42px;
font-weight: 700;
text-shadow: #111 0px 0px 10px;
}
#project_tagline {
color: #fff;
font-size: 24px;
font-weight: 300;
background: none;
text-shadow: #111 0px 0px 10px;
}
#downloads {
position: absolute;
width: 210px;
z-index: 10;
bottom: -40px;
right: 0;
height: 70px;
background: url('../images/icon_download.png') no-repeat 0% 90%;
}
.zip_download_link {
display: block;
float: right;
width: 90px;
height:70px;
text-indent: -5000px;
overflow: hidden;
background: url(../images/sprite_download.png) no-repeat bottom left;
}
.tar_download_link {
display: block;
float: right;
width: 90px;
height:70px;
text-indent: -5000px;
overflow: hidden;
background: url(../images/sprite_download.png) no-repeat bottom right;
margin-left: 10px;
}
.zip_download_link:hover {
background: url(../images/sprite_download.png) no-repeat top left;
}
.tar_download_link:hover {
background: url(../images/sprite_download.png) no-repeat top right;
}
#main_content_wrap {
background: #f2f2f2;
border-top: 1px solid #111;
border-bottom: 1px solid #111;
}
#main_content {
padding-top: 40px;
}
#footer_wrap {
background: #212121;
}
/*******************************************************************************
Small Device Styles
*******************************************************************************/
@media screen and (max-width: 480px) {
body {
font-size:14px;
}
#downloads {
display: none;
}
.inner {
min-width: 320px;
max-width: 480px;
}
#project_title {
font-size: 32px;
}
h1 {
font-size: 28px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 21px;
}
h4 {
font-size: 18px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 12px;
}
code, pre {
min-width: 320px;
max-width: 480px;
font-size: 11px;
}
}

View File

@ -8,7 +8,7 @@ describe('sh.cd doesn\'t seem to be working from a relative path if I am one or
it('should properly deal with relative paths missing ./ and ../', function(done) { it('should properly deal with relative paths missing ./ and ../', function(done) {
var fs = util.fs(); var fs = util.fs();
var sh = fs.Shell(); var sh = new fs.Shell();
sh.mkdirp('/home/scott', function(err) { sh.mkdirp('/home/scott', function(err) {
if(err) throw err; if(err) throw err;

View File

@ -9,7 +9,7 @@ describe('sh.ls and deep directory trees', function() {
it('should not crash when calling sh.ls() on deep directory layouts', function(done) { it('should not crash when calling sh.ls() on deep directory layouts', function(done) {
var fs = util.fs(); var fs = util.fs();
var sh = fs.Shell(); var sh = new fs.Shell();
var path = ''; var path = '';
for(var i=0; i<50; i++) { for(var i=0; i<50; i++) {
@ -29,7 +29,7 @@ describe('sh.ls and deep directory trees', function() {
it('should not crash when calling sh.ls() on wide directory layouts', function(done) { it('should not crash when calling sh.ls() on wide directory layouts', function(done) {
var fs = util.fs(); var fs = util.fs();
var sh = fs.Shell(); var sh = new fs.Shell();
var dirName = '/dir'; var dirName = '/dir';

View File

@ -38,6 +38,7 @@ require("./spec/times.spec");
require("./spec/time-flags.spec"); require("./spec/time-flags.spec");
require("./spec/fs.watch.spec"); require("./spec/fs.watch.spec");
require("./spec/errors.spec"); require("./spec/errors.spec");
require("./spec/fs.shell.spec");
// Filer.FileSystem.providers.* // Filer.FileSystem.providers.*
require("./spec/providers/providers.spec"); require("./spec/providers/providers.spec");
@ -54,6 +55,7 @@ require("./spec/shell/ls.spec");
require("./spec/shell/rm.spec"); require("./spec/shell/rm.spec");
require("./spec/shell/env.spec"); require("./spec/shell/env.spec");
require("./spec/shell/mkdirp.spec"); require("./spec/shell/mkdirp.spec");
require("./spec/shell/find.spec");
// Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test) // Ported node.js tests (filenames match names in https://github.com/joyent/node/tree/master/test)
require("./spec/node-js/simple/test-fs-mkdir"); require("./spec/node-js/simple/test-fs-mkdir");

View File

@ -17,6 +17,8 @@ function IndexedDBTestProvider(name) {
var that = this; var that = this;
function cleanup(callback) { function cleanup(callback) {
callback = callback || function(){};
if(!that.provider || _done) { if(!that.provider || _done) {
return callback(); return callback();
} }
@ -27,7 +29,6 @@ function IndexedDBTestProvider(name) {
that.provider.db.close(); that.provider.db.close();
} }
callback = callback || function(){};
var request = indexedDB.deleteDatabase(name); var request = indexedDB.deleteDatabase(name);
function finished() { function finished() {
that.provider = null; that.provider = null;

View File

@ -4,6 +4,8 @@ function MemoryTestProvider(name) {
var that = this; var that = this;
function cleanup(callback) { function cleanup(callback) {
callback = callback || function(){};
that.provider = null; that.provider = null;
callback(); callback();
} }

View File

@ -85,7 +85,8 @@
} }
function shell(options) { function shell(options) {
return fs().Shell(options); var _fs = fs();
return new _fs.Shell(options);
} }
function cleanup(callback) { function cleanup(callback) {

View File

@ -12,9 +12,12 @@ function WebSQLTestProvider(name) {
var that = this; var that = this;
function cleanup(callback) { function cleanup(callback) {
callback = callback || function(){};
if(!that.provider || _done) { if(!that.provider || _done) {
return callback(); return callback();
} }
// Provider is there, but db was never touched // Provider is there, but db was never touched
if(!that.provider.db) { if(!that.provider.db) {
return callback(); return callback();

View File

@ -9,4 +9,8 @@ describe("Filer", function() {
it("has FileSystem constructor", function() { it("has FileSystem constructor", function() {
expect(typeof Filer.FileSystem).to.equal('function'); expect(typeof Filer.FileSystem).to.equal('function');
}); });
it("has Shell constructor", function() {
expect(typeof Filer.Shell).to.equal('function');
});
}); });

View File

@ -61,4 +61,28 @@ describe('fs.read', function() {
}); });
}); });
}); });
it('should fail to read a directory', function(done) {
var fs = util.fs();
var buf = new Filer.Buffer(20);
var buf2 = new Filer.Buffer(20);
buf.fill(0);
buf2.fill(0);
fs.mkdir('/mydir', function(error) {
if(error) throw err;
fs.open('/mydir', 'r', function(error, fd) {
if(error) throw error;
fs.read(fd, buf, 0, buf.length, 0, function(error, result) {
expect(error).to.exist;
expect(error.code).to.equal('EISDIR');
expect(result).to.equal(0);
expect(buf).to.deep.equal(buf2);
done();
});
});
});
});
}); });

View File

@ -47,4 +47,108 @@ describe('fs.rename', function() {
}); });
}); });
}); });
it('should rename an existing directory', function(done) {
var fs = util.fs();
fs.mkdir('/mydir', function(error) {
if(error) throw error;
fs.rename('/mydir', '/myotherdir', function(error) {
expect(error).not.to.exist;
fs.stat('/mydir', function(error) {
expect(error).to.exist;
expect(error.code).to.equal('ENOENT');
fs.stat('/myotherdir', function(error, result) {
expect(error).not.to.exist;
expect(result.nlinks).to.equal(1);
done();
});
});
});
});
});
it('should rename an existing directory if the new path points to an existing directory', function(done) {
var fs = util.fs();
fs.mkdir('/mydir', function(error) {
if(error) throw error;
fs.mkdir('/myotherdir', function(error) {
if(error) throw error;
fs.rename('/mydir', '/myotherdir', function(error) {
expect(error).not.to.exist;
fs.stat('/mydir', function(error) {
expect(error).to.exist;
expect(error.code).to.equal('ENOENT');
fs.stat('/myotherdir', function(error, result) {
expect(error).not.to.exist;
expect(result.nlinks).to.equal(1);
done();
});
});
});
});
});
});
it('should fail to rename an existing directory if the new path points to an existing directory that is not empty', function(done) {
var fs = util.fs();
fs.mkdir('/mydir', function(error) {
if(error) throw error;
fs.mkdir('/myotherdir', function(error) {
if(error) throw error;
fs.writeFile('/myotherdir/myfile', 'This is a file', function(error) {
if(error) throw error;
fs.rename('/mydir', '/myotherdir', function(error) {
expect(error).to.exist;
expect(error.code).to.equal('ENOTEMPTY');
fs.stat('/mydir', function(error) {
expect(error).not.to.exist;
fs.stat('/myotherdir', function(error) {
expect(error).not.to.exist;
done();
});
});
});
});
});
});
});
it('should fail to rename an existing directory if the new path points to an existing file', function(done) {
var fs = util.fs();
fs.mkdir('/mydir', function(error) {
if(error) throw error;
fs.writeFile('/myfile', 'This is a file', function(error) {
if(error) throw error;
fs.rename('/mydir', '/myfile', function(error) {
expect(error).to.exist;
expect(error.code).to.equal('ENOTDIR');
fs.stat('/mydir', function(error) {
expect(error).not.to.exist;
fs.stat('/myfile', function(error) {
expect(error).not.to.exist;
done();
});
});
});
});
});
});
}); });

View File

@ -0,0 +1,33 @@
var Filer = require('../..');
var util = require('../lib/test-utils.js');
var expect = require('chai').expect;
describe("fs.Shell", function() {
beforeEach(util.setup);
afterEach(util.cleanup);
it("is a function", function(done) {
var fs = util.fs();
expect(typeof fs.Shell).to.equal('function');
done();
});
it('should return a FileSystemShell instance', function(done) {
var fs = util.fs();
var sh = new fs.Shell();
expect(sh.prototype).to.deep.equal((new Filer.Shell(fs)).prototype);
done();
});
it('should reflect changes to the prototype', function(done){
var fs = util.fs();
var sh = new fs.Shell();
Filer.Shell.prototype.test = "foo";
expect(sh.test).to.equal("foo");
done();
});
});

View File

@ -223,4 +223,22 @@ describe('path resolution', function() {
}); });
}); });
}); });
it('should properly add trailing slashes with Path.addTrailing()', function() {
var Path = Filer.Path;
expect(Path.addTrailing('/')).to.equal('/');
expect(Path.addTrailing('/////')).to.equal('/');
expect(Path.addTrailing('.')).to.equal('./');
expect(Path.addTrailing('/dir')).to.equal('/dir/');
expect(Path.addTrailing('/dir/')).to.equal('/dir/');
});
it('should properly remove trailing slashes with Path.removeTrailing()', function() {
var Path = Filer.Path;
expect(Path.removeTrailing('/')).to.equal('/');
expect(Path.removeTrailing('/////')).to.equal('/');
expect(Path.removeTrailing('./')).to.equal('.');
expect(Path.removeTrailing('/dir/')).to.equal('/dir');
expect(Path.removeTrailing('/dir//')).to.equal('/dir');
});
}); });

View File

@ -13,7 +13,7 @@ describe('FileSystemShell.cat', function() {
it('should fail when files argument is absent', function(done) { it('should fail when files argument is absent', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.cat(null, function(error, data) { shell.cat(null, function(error, data) {
expect(error).to.exist; expect(error).to.exist;
@ -25,7 +25,7 @@ describe('FileSystemShell.cat', function() {
it('should return the contents of a single file', function(done) { it('should return the contents of a single file', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var contents = "file contents"; var contents = "file contents";
fs.writeFile('/file', contents, function(err) { fs.writeFile('/file', contents, function(err) {
@ -41,7 +41,7 @@ describe('FileSystemShell.cat', function() {
it('should return the contents of multiple files', function(done) { it('should return the contents of multiple files', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var contents = "file contents"; var contents = "file contents";
var contents2 = contents + '\n' + contents; var contents2 = contents + '\n' + contents;
@ -62,7 +62,7 @@ describe('FileSystemShell.cat', function() {
it('should fail if any of multiple file paths is invalid', function(done) { it('should fail if any of multiple file paths is invalid', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var contents = "file contents"; var contents = "file contents";
var contents2 = contents + '\n' + contents; var contents2 = contents + '\n' + contents;

View File

@ -18,7 +18,7 @@ describe('FileSystemShell.cd', function() {
it('should allow changing the path to a valid dir', function(done) { it('should allow changing the path to a valid dir', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
if(err) throw err; if(err) throw err;
@ -34,7 +34,7 @@ describe('FileSystemShell.cd', function() {
it('should fail when changing the path to an invalid dir', function(done) { it('should fail when changing the path to an invalid dir', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
if(err) throw err; if(err) throw err;
@ -51,7 +51,7 @@ describe('FileSystemShell.cd', function() {
it('should fail when changing the path to a file', function(done) { it('should fail when changing the path to a file', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.writeFile('/file', 'file', function(err) { fs.writeFile('/file', 'file', function(err) {
if(err) throw err; if(err) throw err;
@ -68,7 +68,7 @@ describe('FileSystemShell.cd', function() {
it('should allow relative paths for a valid dir', function(done) { it('should allow relative paths for a valid dir', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
if(err) throw err; if(err) throw err;
@ -84,7 +84,7 @@ describe('FileSystemShell.cd', function() {
it('should allow .. in paths for a valid dir', function(done) { it('should allow .. in paths for a valid dir', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
if(err) throw err; if(err) throw err;
@ -111,7 +111,7 @@ describe('FileSystemShell.cd', function() {
fs.symlink('/dir', '/link', function(error) { fs.symlink('/dir', '/link', function(error) {
if(error) throw error; if(error) throw error;
var shell = fs.Shell(); var shell = new fs.Shell();
shell.cd('link', function(error) { shell.cd('link', function(error) {
expect(error).not.to.exist; expect(error).not.to.exist;
expect(shell.pwd()).to.equal('/link'); expect(shell.pwd()).to.equal('/link');

View File

@ -34,7 +34,7 @@ describe('FileSystemShell.env', function() {
it('should fail when dirs argument is absent', function(done) { it('should fail when dirs argument is absent', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.cat(null, function(error, list) { shell.cat(null, function(error, list) {
expect(error).to.exist; expect(error).to.exist;
@ -46,7 +46,7 @@ describe('FileSystemShell.env', function() {
it('should give new value for shell.pwd() when cwd changes', function(done) { it('should give new value for shell.pwd() when cwd changes', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
if(err) throw err; if(err) throw err;
@ -62,7 +62,7 @@ describe('FileSystemShell.env', function() {
it('should create/return the default tmp dir', function(done) { it('should create/return the default tmp dir', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
expect(shell.env.get('TMP')).to.equal('/tmp'); expect(shell.env.get('TMP')).to.equal('/tmp');
shell.tempDir(function(err, tmp) { shell.tempDir(function(err, tmp) {
@ -77,7 +77,7 @@ describe('FileSystemShell.env', function() {
it('should create/return the tmp dir specified in env.TMP', function(done) { it('should create/return the tmp dir specified in env.TMP', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell({ var shell = new fs.Shell({
env: { env: {
TMP: '/tempdir' TMP: '/tempdir'
} }
@ -96,7 +96,7 @@ describe('FileSystemShell.env', function() {
it('should allow repeated calls to tempDir()', function(done) { it('should allow repeated calls to tempDir()', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
expect(shell.env.get('TMP')).to.equal('/tmp'); expect(shell.env.get('TMP')).to.equal('/tmp');
shell.tempDir(function(err, tmp) { shell.tempDir(function(err, tmp) {

View File

@ -13,7 +13,7 @@ describe('FileSystemShell.exec', function() {
it('should be able to execute a command .js file from the filesystem', function(done) { it('should be able to execute a command .js file from the filesystem', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var cmdString = "fs.writeFile(args[0], args[1], callback);"; var cmdString = "fs.writeFile(args[0], args[1], callback);";
fs.writeFile('/cmd.js', cmdString, function(error) { fs.writeFile('/cmd.js', cmdString, function(error) {

View File

@ -0,0 +1,206 @@
var Filer = require('../../..');
var util = require('../../lib/test-utils.js');
var expect = require('chai').expect;
describe('FileSystemShell.find', function() {
beforeEach(function(done) {
util.setup(function() {
var fs = util.fs();
/**
* Create a basic fs layout for each test:
*
* /
* --file1
* --file2
* --dir1/
* --file3
* --subdir1/
* --dir2/
* --file4
*/
fs.writeFile('/file1', 'file1', function(err) {
if(err) throw err;
fs.writeFile('/file2', 'file2', function(err) {
if(err) throw err;
fs.mkdir('/dir1', function(err) {
if(err) throw err;
fs.writeFile('/dir1/file3', 'file3', function(err) {
if(err) throw err;
fs.mkdir('/dir1/subdir1', function(err) {
if(err) throw err;
fs.mkdir('/dir2', function(err) {
if(err) throw err;
fs.writeFile('/dir2/file4', 'file4', function(err) {
if(err) throw err;
done();
});
});
});
});
});
});
});
});
});
afterEach(util.cleanup);
it('should be a function', function() {
var shell = util.shell();
expect(shell.find).to.be.a('function');
});
it('should fail when path does not exist', function(done) {
var shell = util.shell();
shell.find('/no-such-folder', function(err, found) {
expect(err).to.exist;
expect(err.code).to.equal('ENOENT');
expect(found).not.to.exist;
done();
});
});
it('should fail when path exists but is non-dir', function(done) {
var shell = util.shell();
shell.find('/file1', function(err, found) {
expect(err).to.exist;
expect(err.code).to.equal('ENOTDIR');
expect(found).not.to.exist;
done();
});
});
it('should find all paths in the filesystem with no options', function(done) {
var shell = util.shell();
shell.find('/', function(err, found) {
expect(err).not.to.exist;
var expected = [
'/',
'/file1',
'/file2',
'/dir1/',
'/dir1/file3',
'/dir1/subdir1/',
'/dir2/',
'/dir2/file4'
];
expect(found).to.deep.equal(expected);
done();
});
});
it('should get same paths in exec as are found when complete', function(done) {
var shell = util.shell();
var pathsSeen = [];
function processPath(path, next) {
pathsSeen.push(path);
next();
}
shell.find('/', {exec: processPath}, function(err, found) {
expect(err).not.to.exist;
expect(found).to.deep.equal(pathsSeen);
done();
});
});
it('should return only paths that match a regex pattern', function(done) {
var shell = util.shell();
shell.find('/', {regex: /file\d$/}, function(err, found) {
expect(err).not.to.exist;
var expected = [
'/file1',
'/file2',
'/dir1/file3',
'/dir2/file4'
];
expect(found).to.deep.equal(expected);
done();
});
});
it('should append a / to the end of a dir path', function(done) {
var shell = util.shell();
var dirsSeen = 0;
function endsWith(str, suffix) {
var lastIndex = str.lastIndexOf(suffix);
return (lastIndex !== -1) && (lastIndex + suffix.length === str.length);
}
function processPath(path, next) {
expect(endsWith(path, '/')).to.be.true;
dirsSeen++;
next();
}
shell.find('/', {regex: /dir\d$/, exec: processPath}, function(err) {
expect(err).not.to.exist;
expect(dirsSeen).to.equal(3);
done();
});
});
it('should only look below the specified dir path', function(done) {
var shell = util.shell();
shell.find('/dir1', function(err, found) {
expect(err).not.to.exist;
var expected = [
'/dir1/',
'/dir1/file3',
'/dir1/subdir1/'
];
expect(found).to.deep.equal(expected);
done();
});
});
it('should allow using options.name to match basename with a pattern', function(done) {
var shell = util.shell();
shell.find('/', {name: 'file*'}, function(err, found) {
expect(err).not.to.exist;
var expected = [
'/file1',
'/file2',
'/dir1/file3',
'/dir2/file4'
];
expect(found).to.deep.equal(expected);
done();
});
});
it('should allow using options.path to match dirname with a pattern', function(done) {
var shell = util.shell();
shell.find('/', {name: '*ir1*'}, function(err, found) {
expect(err).not.to.exist;
var expected = [
'/dir1/',
'/dir1/subdir1/'
];
expect(found).to.deep.equal(expected);
done();
});
});
});

View File

@ -13,7 +13,7 @@ describe('FileSystemShell.ls', function() {
it('should fail when dirs argument is absent', function(done) { it('should fail when dirs argument is absent', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.cat(null, function(error, list) { shell.cat(null, function(error, list) {
expect(error).to.exist; expect(error).to.exist;
@ -25,7 +25,7 @@ describe('FileSystemShell.ls', function() {
it('should return the contents of a simple dir', function(done) { it('should return the contents of a simple dir', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var contents = "a"; var contents = "a";
var contents2 = "bb"; var contents2 = "bb";
@ -63,7 +63,7 @@ describe('FileSystemShell.ls', function() {
it('should return the shallow contents of a dir tree', function(done) { it('should return the shallow contents of a dir tree', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var contents = "a"; var contents = "a";
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
@ -119,7 +119,7 @@ describe('FileSystemShell.ls', function() {
it('should return the deep contents of a dir tree', function(done) { it('should return the deep contents of a dir tree', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var contents = "a"; var contents = "a";
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {

View File

@ -13,7 +13,7 @@ describe('FileSystemShell.mkdirp', function() {
it('should fail without a path provided', function(done) { it('should fail without a path provided', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.mkdirp(null, function(err) { shell.mkdirp(null, function(err) {
expect(err).to.exist; expect(err).to.exist;
@ -24,7 +24,7 @@ describe('FileSystemShell.mkdirp', function() {
it('should succeed if provided path is root', function(done) { it('should succeed if provided path is root', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.mkdirp('/', function(err) { shell.mkdirp('/', function(err) {
expect(err).to.not.exist; expect(err).to.not.exist;
done(); done();
@ -33,7 +33,7 @@ describe('FileSystemShell.mkdirp', function() {
it('should succeed if the directory exists', function(done) { it('should succeed if the directory exists', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/test', function(err){ fs.mkdir('/test', function(err){
expect(err).to.not.exist; expect(err).to.not.exist;
shell.mkdirp('/test',function(err) { shell.mkdirp('/test',function(err) {
@ -45,7 +45,7 @@ describe('FileSystemShell.mkdirp', function() {
it('fail if a file name is provided', function(done) { it('fail if a file name is provided', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.writeFile('/test.txt', 'test', function(err){ fs.writeFile('/test.txt', 'test', function(err){
expect(err).to.not.exist; expect(err).to.not.exist;
shell.mkdirp('/test.txt', function(err) { shell.mkdirp('/test.txt', function(err) {
@ -58,7 +58,7 @@ describe('FileSystemShell.mkdirp', function() {
it('should succeed on a folder on root (\'/test\')', function(done) { it('should succeed on a folder on root (\'/test\')', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.mkdirp('/test', function(err) { shell.mkdirp('/test', function(err) {
expect(err).to.not.exist; expect(err).to.not.exist;
fs.exists('/test', function(dir){ fs.exists('/test', function(dir){
@ -70,7 +70,7 @@ describe('FileSystemShell.mkdirp', function() {
it('should succeed on a folder with a nonexistant parent (\'/test/test\')', function(done) { it('should succeed on a folder with a nonexistant parent (\'/test/test\')', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.mkdirp('/test/test', function(err) { shell.mkdirp('/test/test', function(err) {
expect(err).to.not.exist; expect(err).to.not.exist;
fs.exists('/test', function(dir1){ fs.exists('/test', function(dir1){
@ -85,7 +85,7 @@ describe('FileSystemShell.mkdirp', function() {
it('should fail on a folder with a file for its parent (\'/test.txt/test\')', function(done) { it('should fail on a folder with a file for its parent (\'/test.txt/test\')', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.writeFile('/test.txt', 'test', function(err){ fs.writeFile('/test.txt', 'test', function(err){
expect(err).to.not.exist; expect(err).to.not.exist;
shell.mkdirp('/test.txt/test', function(err) { shell.mkdirp('/test.txt/test', function(err) {

View File

@ -13,7 +13,7 @@ describe('FileSystemShell.rm', function() {
it('should fail when path argument is absent', function(done) { it('should fail when path argument is absent', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.rm(null, function(error, list) { shell.rm(null, function(error, list) {
expect(error).to.exist; expect(error).to.exist;
@ -25,7 +25,7 @@ describe('FileSystemShell.rm', function() {
it('should remove a single file', function(done) { it('should remove a single file', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var contents = "a"; var contents = "a";
fs.writeFile('/file', contents, function(err) { fs.writeFile('/file', contents, function(err) {
@ -45,7 +45,7 @@ describe('FileSystemShell.rm', function() {
it('should remove an empty dir', function(done) { it('should remove an empty dir', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
if(err) throw err; if(err) throw err;
@ -64,7 +64,7 @@ describe('FileSystemShell.rm', function() {
it('should fail to remove a non-empty dir', function(done) { it('should fail to remove a non-empty dir', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
if(err) throw err; if(err) throw err;
@ -83,7 +83,7 @@ describe('FileSystemShell.rm', function() {
it('should remove a non-empty dir with option.recursive set', function(done) { it('should remove a non-empty dir with option.recursive set', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {
if(err) throw err; if(err) throw err;
@ -106,7 +106,7 @@ describe('FileSystemShell.rm', function() {
it('should work on a complex dir structure', function(done) { it('should work on a complex dir structure', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var contents = "a"; var contents = "a";
fs.mkdir('/dir', function(err) { fs.mkdir('/dir', function(err) {

View File

@ -20,7 +20,7 @@ describe('FileSystemShell.touch', function() {
it('should create a new file if path does not exist', function(done) { it('should create a new file if path does not exist', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.touch('/newfile', function(error) { shell.touch('/newfile', function(error) {
if(error) throw error; if(error) throw error;
@ -35,7 +35,7 @@ describe('FileSystemShell.touch', function() {
it('should skip creating a new file if options.updateOnly is true', function(done) { it('should skip creating a new file if options.updateOnly is true', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
shell.touch('/newfile', { updateOnly: true }, function(error) { shell.touch('/newfile', { updateOnly: true }, function(error) {
if(error) throw error; if(error) throw error;
@ -49,7 +49,7 @@ describe('FileSystemShell.touch', function() {
it('should update times if path does exist', function(done) { it('should update times if path does exist', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var atime = Date.parse('1 Oct 2000 15:33:22'); var atime = Date.parse('1 Oct 2000 15:33:22');
var mtime = Date.parse('30 Sep 2000 06:43:54'); var mtime = Date.parse('30 Sep 2000 06:43:54');
@ -80,7 +80,7 @@ describe('FileSystemShell.touch', function() {
it('should update times to specified date if path does exist', function(done) { it('should update times to specified date if path does exist', function(done) {
var fs = util.fs(); var fs = util.fs();
var shell = fs.Shell(); var shell = new fs.Shell();
var date = Date.parse('1 Oct 2001 15:33:22'); var date = Date.parse('1 Oct 2001 15:33:22');
fs.open('/newfile', 'w', function (error, fd) { fs.open('/newfile', 'w', function (error, fd) {