@stdlib/random-streams-triangular-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish_cli.yml +165 -0
- package/CONTRIBUTORS +39 -0
- package/LICENSE +177 -0
- package/NOTICE +1 -0
- package/README.md +230 -0
- package/bin/cli +195 -0
- package/docs/usage.txt +15 -0
- package/etc/cli_opts.json +24 -0
- package/package.json +78 -0
- package/test/fixtures/bad_state.txt +0 -0
- package/test/fixtures/state.txt +0 -0
- package/test/fixtures/write_error.js.txt +42 -0
- package/test/test.cli.js +524 -0
package/bin/cli
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @license Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2018 The Stdlib Authors.
|
|
7
|
+
*
|
|
8
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
9
|
+
* you may not use this file except in compliance with the License.
|
|
10
|
+
* You may obtain a copy of the License at
|
|
11
|
+
*
|
|
12
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
+
*
|
|
14
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
+
* See the License for the specific language governing permissions and
|
|
18
|
+
* limitations under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
'use strict';
|
|
22
|
+
|
|
23
|
+
// MODULES //
|
|
24
|
+
|
|
25
|
+
var proc = require( 'process' );
|
|
26
|
+
var resolve = require( 'path' ).resolve;
|
|
27
|
+
var readFileSync = require( '@stdlib/fs-read-file' ).sync;
|
|
28
|
+
var writeFileSync = require( '@stdlib/fs-write-file' ).sync;
|
|
29
|
+
var CLI = require( '@stdlib/cli-ctor' );
|
|
30
|
+
var stdout = require( '@stdlib/streams-node-stdout' );
|
|
31
|
+
var cwd = require( '@stdlib/process-cwd' );
|
|
32
|
+
var Uint8Array = require( '@stdlib/array-uint8' );
|
|
33
|
+
var Uint32Array = require( '@stdlib/array-uint32' );
|
|
34
|
+
var isUint8Array = require( '@stdlib/assert-is-uint8array' );
|
|
35
|
+
var isInteger = require( '@stdlib/assert-is-integer' ).isPrimitive;
|
|
36
|
+
var gcopy = require( '@stdlib/blas-base-gcopy' );
|
|
37
|
+
var array2buffer = require( '@stdlib/buffer-from-array' );
|
|
38
|
+
var randomStream = require( '@stdlib/random-streams-triangular' );
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
// FUNCTIONS //
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Callback invoked once a source stream ends.
|
|
45
|
+
*
|
|
46
|
+
* @private
|
|
47
|
+
*/
|
|
48
|
+
function onEnd() {
|
|
49
|
+
// Append a trailing newline in accordance with standard POSIX behavior:
|
|
50
|
+
console.log( '' ); // eslint-disable-line no-console
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Attempts to load a PRNG state.
|
|
55
|
+
*
|
|
56
|
+
* @private
|
|
57
|
+
* @param {string} filepath - absolute path to file containing PRNG state
|
|
58
|
+
* @returns {(Uint32Array|Error)} PRNG state or an error
|
|
59
|
+
*/
|
|
60
|
+
function loadState( filepath ) {
|
|
61
|
+
var state;
|
|
62
|
+
var len;
|
|
63
|
+
|
|
64
|
+
state = readFileSync( filepath );
|
|
65
|
+
if ( state instanceof Error ) {
|
|
66
|
+
return state;
|
|
67
|
+
}
|
|
68
|
+
len = state.length;
|
|
69
|
+
|
|
70
|
+
// For older Node.js environments, convert the `Buffer` to a `Uint8Array`...
|
|
71
|
+
if ( !isUint8Array( state ) ) {
|
|
72
|
+
state = gcopy( len, state, 1, new Uint8Array( len ), 1 );
|
|
73
|
+
}
|
|
74
|
+
// Create a PRNG state array "view":
|
|
75
|
+
len /= Uint32Array.BYTES_PER_ELEMENT;
|
|
76
|
+
if ( !isInteger( len ) ) {
|
|
77
|
+
return new RangeError( 'invalid option. `state` has an invalid length.' );
|
|
78
|
+
}
|
|
79
|
+
return new Uint32Array( state.buffer, state.byteOffset, len );
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
// MAIN //
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Main execution sequence.
|
|
87
|
+
*
|
|
88
|
+
* @private
|
|
89
|
+
* @returns {void}
|
|
90
|
+
*/
|
|
91
|
+
function main() {
|
|
92
|
+
var stream;
|
|
93
|
+
var flags;
|
|
94
|
+
var opts;
|
|
95
|
+
var args;
|
|
96
|
+
var cli;
|
|
97
|
+
var err;
|
|
98
|
+
var dir;
|
|
99
|
+
var i;
|
|
100
|
+
|
|
101
|
+
// Create a command-line interface:
|
|
102
|
+
cli = new CLI({
|
|
103
|
+
'pkg': require( './../package.json' ),
|
|
104
|
+
'options': require( './../etc/cli_opts.json' ),
|
|
105
|
+
'help': readFileSync( resolve( __dirname, '..', 'docs', 'usage.txt' ), {
|
|
106
|
+
'encoding': 'utf8'
|
|
107
|
+
})
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Get any provided command-line options:
|
|
111
|
+
flags = cli.flags();
|
|
112
|
+
if ( flags.help || flags.version ) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Get the current working directory:
|
|
117
|
+
dir = cwd();
|
|
118
|
+
|
|
119
|
+
// Get any provided command-line arguments:
|
|
120
|
+
args = cli.args();
|
|
121
|
+
if ( args.length < 3 ) {
|
|
122
|
+
err = new Error( 'insufficient arguments. Must provide distribution parameters.' );
|
|
123
|
+
return onError( err );
|
|
124
|
+
}
|
|
125
|
+
args[ 0 ] = parseFloat( args[ 0 ] );
|
|
126
|
+
args[ 1 ] = parseFloat( args[ 1 ] );
|
|
127
|
+
args[ 2 ] = parseFloat( args[ 2 ] );
|
|
128
|
+
|
|
129
|
+
opts = {};
|
|
130
|
+
if ( flags.iter ) {
|
|
131
|
+
opts.iter = parseInt( flags.iter, 10 );
|
|
132
|
+
}
|
|
133
|
+
if ( flags.sep ) {
|
|
134
|
+
opts.sep = flags.sep;
|
|
135
|
+
}
|
|
136
|
+
if ( flags.state ) {
|
|
137
|
+
opts.state = loadState( resolve( dir, flags.state ) );
|
|
138
|
+
if ( opts.state instanceof Error ) {
|
|
139
|
+
return onError( opts.state );
|
|
140
|
+
}
|
|
141
|
+
} else if ( flags.seed ) {
|
|
142
|
+
opts.seed = flags.seed.split( ',' );
|
|
143
|
+
for ( i = 0; i < opts.seed.length; i++ ) {
|
|
144
|
+
opts.seed[ i ] = parseInt( opts.seed[ i ], 10 );
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if ( flags.snapshot ) {
|
|
148
|
+
proc.on( 'exit', onExit );
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Create a source stream and pipe to `stdout`:
|
|
152
|
+
stream = randomStream( args[ 0 ], args[ 1 ], args[ 2 ], opts );
|
|
153
|
+
stream.on( 'end', onEnd );
|
|
154
|
+
|
|
155
|
+
stream.pipe( stdout );
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Callback invoked upon exiting the process.
|
|
159
|
+
*
|
|
160
|
+
* @private
|
|
161
|
+
* @param {integer} code - exit code
|
|
162
|
+
*/
|
|
163
|
+
function onExit( code ) {
|
|
164
|
+
var state;
|
|
165
|
+
var err;
|
|
166
|
+
|
|
167
|
+
// Get the current PRNG state:
|
|
168
|
+
state = stream.state;
|
|
169
|
+
|
|
170
|
+
// Create a byte array "view":
|
|
171
|
+
state = new Uint8Array( state.buffer, state.byteOffset, stream.byteLength ); // eslint-disable-line max-len
|
|
172
|
+
|
|
173
|
+
// Convert the byte array to a `Buffer` (with support for older Node.js environments):
|
|
174
|
+
state = array2buffer( state );
|
|
175
|
+
|
|
176
|
+
// Attempt to write the state to file:
|
|
177
|
+
err = writeFileSync( resolve( dir, flags.snapshot ), state );
|
|
178
|
+
if ( err ) {
|
|
179
|
+
onError( err, code || 1 );
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Callback invoked upon encountering an error.
|
|
185
|
+
*
|
|
186
|
+
* @private
|
|
187
|
+
* @param {Error} error - error
|
|
188
|
+
* @param {integer} [code] - exit code
|
|
189
|
+
*/
|
|
190
|
+
function onError( error, code ) {
|
|
191
|
+
cli.error( error, code || 1 );
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
main();
|
package/docs/usage.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
Usage: random-triangular [options] <a> <b> <c>
|
|
3
|
+
|
|
4
|
+
Options:
|
|
5
|
+
|
|
6
|
+
-h, --help Print this message.
|
|
7
|
+
-V, --version Print the package version.
|
|
8
|
+
--sep sep Separator used to join streamed data. Default: '\n'.
|
|
9
|
+
-n, --iter iterations Number of pseudorandom numbers.
|
|
10
|
+
--seed seed Pseudorandom number generator seed.
|
|
11
|
+
--state filepath Path to a file containing the pseudorandom number
|
|
12
|
+
generator state.
|
|
13
|
+
--snapshot filepath Output file path for saving the pseudorandom number
|
|
14
|
+
generator state upon exit.
|
|
15
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stdlib/random-streams-triangular-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Create a readable stream for generating pseudorandom numbers drawn from a triangular distribution.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "The Stdlib Authors",
|
|
8
|
+
"url": "https://github.com/stdlib-js/stdlib/graphs/contributors"
|
|
9
|
+
},
|
|
10
|
+
"contributors": [
|
|
11
|
+
{
|
|
12
|
+
"name": "The Stdlib Authors",
|
|
13
|
+
"url": "https://github.com/stdlib-js/stdlib/graphs/contributors"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"bin": {
|
|
17
|
+
"random-triangular": "./bin/cli"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://stdlib.io",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git://github.com/stdlib-js/random-streams-triangular.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/stdlib-js/stdlib/issues"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@stdlib/array-uint32": "^0.1.0",
|
|
29
|
+
"@stdlib/array-uint8": "^0.1.0",
|
|
30
|
+
"@stdlib/assert-is-integer": "^0.1.0",
|
|
31
|
+
"@stdlib/assert-is-uint8array": "^0.1.0",
|
|
32
|
+
"@stdlib/blas-base-gcopy": "^0.1.0",
|
|
33
|
+
"@stdlib/buffer-from-array": "^0.1.0",
|
|
34
|
+
"@stdlib/cli-ctor": "^0.1.0",
|
|
35
|
+
"@stdlib/fs-read-file": "^0.1.0",
|
|
36
|
+
"@stdlib/fs-write-file": "^0.1.0",
|
|
37
|
+
"@stdlib/math-base-assert-is-nan": "^0.1.0",
|
|
38
|
+
"@stdlib/process-cwd": "^0.1.0",
|
|
39
|
+
"@stdlib/random-base-triangular": "^0.1.0",
|
|
40
|
+
"@stdlib/streams-node-stdout": "^0.1.0",
|
|
41
|
+
"@stdlib/random-streams-triangular": "0.1.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@stdlib/assert-is-browser": "^0.1.0",
|
|
45
|
+
"@stdlib/assert-is-windows": "^0.1.0",
|
|
46
|
+
"@stdlib/fs-exists": "^0.1.0",
|
|
47
|
+
"@stdlib/fs-unlink": "^0.1.0",
|
|
48
|
+
"@stdlib/process-exec-path": "^0.1.0",
|
|
49
|
+
"@stdlib/string-replace": "^0.1.0",
|
|
50
|
+
"tape": "git+https://github.com/kgryte/tape.git#fix/globby",
|
|
51
|
+
"proxyquire": "^2.0.0",
|
|
52
|
+
"istanbul": "^0.4.1",
|
|
53
|
+
"tap-min": "git+https://github.com/Planeshifter/tap-min.git"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"stdlib",
|
|
57
|
+
"stdmath",
|
|
58
|
+
"mathematics",
|
|
59
|
+
"math",
|
|
60
|
+
"statistics",
|
|
61
|
+
"stats",
|
|
62
|
+
"prng",
|
|
63
|
+
"rng",
|
|
64
|
+
"pseudorandom",
|
|
65
|
+
"random",
|
|
66
|
+
"rand",
|
|
67
|
+
"triangular",
|
|
68
|
+
"continuous",
|
|
69
|
+
"readable",
|
|
70
|
+
"stream",
|
|
71
|
+
"seed",
|
|
72
|
+
"seedable"
|
|
73
|
+
],
|
|
74
|
+
"funding": {
|
|
75
|
+
"type": "opencollective",
|
|
76
|
+
"url": "https://opencollective.com/stdlib"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Apache-2.0
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2018 The Stdlib Authors.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
var proc = require( 'process' );
|
|
20
|
+
var resolve = require( 'path' ).resolve;
|
|
21
|
+
var proxyquire = require( 'proxyquire' );
|
|
22
|
+
|
|
23
|
+
var fpath = resolve( __dirname, '..', 'bin', 'cli' );
|
|
24
|
+
|
|
25
|
+
proc.stdin.isTTY = true;
|
|
26
|
+
proc.argv[ 2 ] = 2.0;
|
|
27
|
+
proc.argv[ 3 ] = 5.0;
|
|
28
|
+
proc.argv[ 4 ] = 4.0;
|
|
29
|
+
proc.argv[ 5 ] = '--iter';
|
|
30
|
+
proc.argv[ 6 ] = '10';
|
|
31
|
+
proc.argv[ 7 ] = '--snapshot';
|
|
32
|
+
proc.argv[ 8 ] = resolve( __dirname, 'fixtures', 'tmp_state.txt' );
|
|
33
|
+
|
|
34
|
+
proxyquire( fpath, {
|
|
35
|
+
'@stdlib/fs-write-file': {
|
|
36
|
+
'sync': writeFile
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function writeFile() {
|
|
41
|
+
return new Error( 'beep' );
|
|
42
|
+
}
|