Remove outdated submodule
This commit is contained in:
parent
fc8eebf132
commit
9c6cdc62a0
|
@ -1 +0,0 @@
|
|||
Subproject commit 3974d0d370bd35f5fde203769d9351689b22b517
|
|
@ -1,29 +0,0 @@
|
|||
meta:
|
||||
author: Stephen Hutchings
|
||||
homepage: http://typicons.com/
|
||||
twitter: https://twitter.com/Typicons/
|
||||
license: CC BY-SA 3.0
|
||||
license_url: http://creativecommons.org/licenses/by-sa/3.0/
|
||||
|
||||
css_prefix: "typcn"
|
||||
columns: 12
|
||||
|
||||
transform:
|
||||
baseline: 0.2
|
||||
rescale: 1
|
||||
offset: 0
|
||||
|
||||
font:
|
||||
version: "2.0.2"
|
||||
|
||||
# lowercase only
|
||||
fontname: typicons
|
||||
|
||||
fullname: Typicons
|
||||
familyname: Typicons
|
||||
|
||||
copyright: (c) Stephen Hutchings 2012
|
||||
|
||||
ascent: 800
|
||||
descent: 200
|
||||
weight: Book
|
|
@ -1 +0,0 @@
|
|||
../yamljs/bin/json2yaml
|
|
@ -1 +0,0 @@
|
|||
../yamljs/bin/yaml2json
|
|
@ -1,2 +0,0 @@
|
|||
.DS_Store
|
||||
node_modules
|
|
@ -1,19 +0,0 @@
|
|||
Copyright (c) 2010 Jeremy Faivre
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -1,163 +0,0 @@
|
|||
yaml.js
|
||||
=======
|
||||
|
||||
Standalone JavaScript YAML 1.2 Parser & Encoder. Works under node.js and all major browsers. Also brings command line YAML/JSON conversion tools.
|
||||
|
||||
Mainly inspired from [Symfony Yaml Component](https://github.com/symfony/Yaml).
|
||||
|
||||
How to use
|
||||
----------
|
||||
|
||||
Import yaml.js in your html page:
|
||||
|
||||
``` html
|
||||
<script type="text/javascript" src="yaml.js"></script>
|
||||
```
|
||||
|
||||
Parse yaml string:
|
||||
|
||||
``` js
|
||||
nativeObject = YAML.parse(yamlString);
|
||||
```
|
||||
|
||||
Dump native object into yaml string:
|
||||
|
||||
``` js
|
||||
yamlString = YAML.stringify(nativeObject[, inline /* @integer depth to start using inline notation at */[, spaces /* @integer number of spaces to use for indentation */] ]);
|
||||
```
|
||||
|
||||
Load yaml file:
|
||||
|
||||
``` js
|
||||
nativeObject = YAML.load('file.yml');
|
||||
```
|
||||
|
||||
Load yaml file:
|
||||
|
||||
``` js
|
||||
YAML.load('file.yml', function(result)
|
||||
{
|
||||
nativeObject = result;
|
||||
});
|
||||
```
|
||||
|
||||
Use with node.js
|
||||
----------------
|
||||
|
||||
Install module:
|
||||
|
||||
``` bash
|
||||
npm install yamljs
|
||||
```
|
||||
|
||||
Use it:
|
||||
|
||||
``` js
|
||||
YAML = require('yamljs');
|
||||
|
||||
// parse YAML string
|
||||
nativeObject = YAML.parse(yamlString);
|
||||
|
||||
// Generate YAML
|
||||
yamlString = YAML.stringify(nativeObject, 4);
|
||||
|
||||
// Load yaml file using require
|
||||
nativeObject = require('./myfile.yml');
|
||||
|
||||
// Load yaml file using YAML.load
|
||||
nativeObject = YAML.load('myfile.yml');
|
||||
```
|
||||
|
||||
Command line tools
|
||||
------------------
|
||||
|
||||
You can enable the command line tools by installing yamljs as a global module:
|
||||
|
||||
``` bash
|
||||
npm install -g yamljs
|
||||
```
|
||||
|
||||
Then, two cli commands should become available: **yaml2json** and **json2yaml**. They let you convert YAML to JSON and JSON to YAML very easily.
|
||||
|
||||
**yaml2json**
|
||||
|
||||
```
|
||||
usage: yaml2json [-h] [-v] [-p] [-i INDENTATION] [-s] [-r] [-w] input
|
||||
|
||||
Positional arguments:
|
||||
input YAML file or directory containing YAML files.
|
||||
|
||||
Optional arguments:
|
||||
-h, --help Show this help message and exit.
|
||||
-v, --version Show program's version number and exit.
|
||||
-p, --pretty Output pretty (indented) JSON.
|
||||
-i INDENTATION, --indentation INDENTATION
|
||||
Number of space characters used to indent code (use
|
||||
with --pretty, default: 2).
|
||||
-s, --save Save output inside JSON file(s) with the same name.
|
||||
-r, --recursive If the input is a directory, also find YAML files in
|
||||
sub-directories recursively.
|
||||
-w, --watch Watch for changes.
|
||||
```
|
||||
|
||||
**json2yaml**
|
||||
|
||||
```
|
||||
usage: json2yaml [-h] [-v] [-d DEPTH] [-i INDENTATION] [-s] [-r] [-w] input
|
||||
|
||||
Positional arguments:
|
||||
input JSON file or directory containing JSON files.
|
||||
|
||||
Optional arguments:
|
||||
-h, --help Show this help message and exit.
|
||||
-v, --version Show program's version number and exit.
|
||||
-d DEPTH, --depth DEPTH
|
||||
Set minimum level of depth before generating inline
|
||||
YAML (default: 2).
|
||||
-i INDENTATION, --indentation INDENTATION
|
||||
Number of space characters used to indent code
|
||||
(default: 2).
|
||||
-s, --save Save output inside YML file(s) with the same name.
|
||||
-r, --recursive If the input is a directory, also find JSON files in
|
||||
sub-directories recursively.
|
||||
-w, --watch Watch for changes.
|
||||
```
|
||||
|
||||
**examples**
|
||||
|
||||
``` bash
|
||||
# Convert YAML to JSON and output resulting JSON on the console
|
||||
yaml2json myfile.yml
|
||||
|
||||
# Store output inside a JSON file
|
||||
yaml2json myfile.yml > ouput.json
|
||||
|
||||
# Output "pretty" (indented) JSON
|
||||
yaml2json myfile.yml --pretty
|
||||
|
||||
# Save the output inside a file called myfile.json
|
||||
yaml2json myfile.yml --pretty --save
|
||||
|
||||
# Watch a full directory and convert any YAML file into its JSON equivalent
|
||||
yaml2json mydirectory --pretty --save --recursive
|
||||
|
||||
# Convert JSON to YAML and store output inside a JSON file
|
||||
json2yaml myfile.json > ouput.yml
|
||||
|
||||
# Output YAML that will be inlined only after 8 levels of indentation
|
||||
json2yaml myfile.json --depth 8
|
||||
|
||||
# Save the output inside a file called myfile.json with 4 spaces for each indentation
|
||||
json2yaml myfile.json --indentation 4
|
||||
|
||||
# Watch a full directory and convert any JSON file into its YAML equivalent
|
||||
json2yaml mydirectory --pretty --save --recursive
|
||||
```
|
||||
|
||||
Important
|
||||
---------
|
||||
|
||||
Symfony dropped support for YAML 1.1 spec. This means that `yes`, `no` and similar no longer convert to their *boolean* equivalents.
|
||||
|
||||
The internal `Yaml().load()` and `Yaml().loadFile()` methods renamed to `Yaml().parse()` and `Yaml().parseFile()` respectively. Exceptions replaced with `YamlParseException` object.
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* yaml2json cli program
|
||||
*/
|
||||
|
||||
var YAML = require('./yaml.js');
|
||||
|
||||
var ArgumentParser = require('argparse').ArgumentParser;
|
||||
var cli = new ArgumentParser({
|
||||
prog: "json2yaml",
|
||||
version: require('../package.json').version,
|
||||
addHelp: true
|
||||
});
|
||||
|
||||
cli.addArgument(
|
||||
['-d', '--depth'],
|
||||
{
|
||||
action: 'store',
|
||||
type: 'int',
|
||||
help: 'Set minimum level of depth before generating inline YAML (default: 2).'
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(
|
||||
['-i', '--indentation'],
|
||||
{
|
||||
action: 'store',
|
||||
type: 'int',
|
||||
help: 'Number of space characters used to indent code (default: 2).',
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(
|
||||
['-s', '--save'],
|
||||
{
|
||||
help: 'Save output inside YML file(s) with the same name.',
|
||||
action: 'storeTrue'
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(
|
||||
['-r', '--recursive'],
|
||||
{
|
||||
help: 'If the input is a directory, also find JSON files in sub-directories recursively.',
|
||||
action: 'storeTrue'
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(
|
||||
['-w', '--watch'],
|
||||
{
|
||||
help: 'Watch for changes.',
|
||||
action: 'storeTrue'
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(['input'], {
|
||||
help: 'JSON file or directory containing JSON files.'
|
||||
});
|
||||
|
||||
try {
|
||||
var options = cli.parseArgs();
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var glob = require('glob');
|
||||
|
||||
var rootPath = process.cwd();
|
||||
var parsePath = function(input) {
|
||||
var output;
|
||||
if (!(input != null)) {
|
||||
return rootPath;
|
||||
}
|
||||
output = path.normalize(input);
|
||||
if (output.length === 0) {
|
||||
return rootPath;
|
||||
}
|
||||
if (output.charAt(0) !== '/') {
|
||||
output = path.normalize(rootPath + '/./' + output);
|
||||
}
|
||||
if (output.length > 1 && output.charAt(output.length - 1) === '/') {
|
||||
return output.substr(0, output.length - 1);
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
// Find files
|
||||
var findFiles = function(input) {
|
||||
var isDirectory = fs.statSync(input).isDirectory();
|
||||
var files = [];
|
||||
|
||||
if (!isDirectory) {
|
||||
files.push(input);
|
||||
}
|
||||
else {
|
||||
if (options.recursive) {
|
||||
files = files.concat(glob.sync(input+'/**/*.json'));
|
||||
}
|
||||
else {
|
||||
files = files.concat(glob.sync(input+'/*.json'));
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
// Convert to JSON
|
||||
var convertToYAML = function(input, inline, save, spaces) {
|
||||
var yaml;
|
||||
if (inline == null) inline = 2;
|
||||
if (spaces == null) spaces = 2;
|
||||
|
||||
yaml = YAML.stringify(JSON.parse(fs.readFileSync(input)), inline, spaces);
|
||||
|
||||
if (!save) {
|
||||
// Ouput result
|
||||
process.stdout.write(yaml);
|
||||
}
|
||||
else {
|
||||
var output;
|
||||
if (input.substring(input.length-5) == '.json') {
|
||||
output = input.substr(0, input.length-5) + '.yaml';
|
||||
}
|
||||
else {
|
||||
output = input + '.yaml';
|
||||
}
|
||||
|
||||
// Write file
|
||||
var file = fs.openSync(output, 'w+');
|
||||
fs.writeSync(file, yaml);
|
||||
fs.closeSync(file);
|
||||
process.stdout.write("saved "+output+"\n");
|
||||
}
|
||||
};
|
||||
|
||||
var input = parsePath(options.input);
|
||||
var mtimes = [];
|
||||
|
||||
var runCommand = function() {
|
||||
try {
|
||||
var files = findFiles(input);
|
||||
var len = files.length;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
var file = files[i];
|
||||
var stat = fs.statSync(file);
|
||||
var time = stat.mtime.getTime();
|
||||
if (!stat.isDirectory()) {
|
||||
if (!mtimes[file] || mtimes[file] < time) {
|
||||
mtimes[file] = time;
|
||||
convertToYAML(file, options.depth, options.save, options.indentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
process.stderr.write((e.message ? e.message : e)+"\n");
|
||||
}
|
||||
};
|
||||
|
||||
if (!options.watch) {
|
||||
runCommand();
|
||||
} else {
|
||||
runCommand();
|
||||
setInterval(runCommand, 1000);
|
||||
}
|
||||
} catch (e) {
|
||||
process.stderr.write((e.message ? e.message : e)+"\n");
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,175 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* yaml2json cli program
|
||||
*/
|
||||
|
||||
var YAML = require('./yaml.js');
|
||||
|
||||
var ArgumentParser = require('argparse').ArgumentParser;
|
||||
var cli = new ArgumentParser({
|
||||
prog: "yaml2json",
|
||||
version: require('../package.json').version,
|
||||
addHelp: true
|
||||
});
|
||||
|
||||
cli.addArgument(
|
||||
['-p', '--pretty'],
|
||||
{
|
||||
help: 'Output pretty (indented) JSON.',
|
||||
action: 'storeTrue'
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(
|
||||
['-i', '--indentation'],
|
||||
{
|
||||
action: 'store',
|
||||
type: 'int',
|
||||
help: 'Number of space characters used to indent code (use with --pretty, default: 2).',
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(
|
||||
['-s', '--save'],
|
||||
{
|
||||
help: 'Save output inside JSON file(s) with the same name.',
|
||||
action: 'storeTrue'
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(
|
||||
['-r', '--recursive'],
|
||||
{
|
||||
help: 'If the input is a directory, also find YAML files in sub-directories recursively.',
|
||||
action: 'storeTrue'
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(
|
||||
['-w', '--watch'],
|
||||
{
|
||||
help: 'Watch for changes.',
|
||||
action: 'storeTrue'
|
||||
}
|
||||
);
|
||||
|
||||
cli.addArgument(['input'], {
|
||||
help: 'YAML file or directory containing YAML files.'
|
||||
});
|
||||
|
||||
try {
|
||||
var options = cli.parseArgs();
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var glob = require('glob');
|
||||
|
||||
var rootPath = process.cwd();
|
||||
var parsePath = function(input) {
|
||||
var output;
|
||||
if (!(input != null)) {
|
||||
return rootPath;
|
||||
}
|
||||
output = path.normalize(input);
|
||||
if (output.length === 0) {
|
||||
return rootPath;
|
||||
}
|
||||
if (output.charAt(0) !== '/') {
|
||||
output = path.normalize(rootPath + '/./' + output);
|
||||
}
|
||||
if (output.length > 1 && output.charAt(output.length - 1) === '/') {
|
||||
return output.substr(0, output.length - 1);
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
// Find files
|
||||
var findFiles = function(input) {
|
||||
var isDirectory = fs.statSync(input).isDirectory();
|
||||
var files = [];
|
||||
|
||||
if (!isDirectory) {
|
||||
files.push(input);
|
||||
}
|
||||
else {
|
||||
if (options.recursive) {
|
||||
files = files.concat(glob.sync(input+'/**/*.yml'));
|
||||
files = files.concat(glob.sync(input+'/**/*.yaml'));
|
||||
}
|
||||
else {
|
||||
files = files.concat(glob.sync(input+'/*.yml'));
|
||||
files = files.concat(glob.sync(input+'/*.yaml'));
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
};
|
||||
|
||||
// Convert to JSON
|
||||
var convertToJSON = function(input, pretty, save, spaces) {
|
||||
var json;
|
||||
if (spaces == null) spaces = 2;
|
||||
if (pretty) {
|
||||
json = JSON.stringify(YAML.load(input), null, spaces);
|
||||
}
|
||||
else {
|
||||
json = JSON.stringify(YAML.load(input));
|
||||
}
|
||||
|
||||
if (!save) {
|
||||
// Ouput result
|
||||
process.stdout.write(json+"\n");
|
||||
}
|
||||
else {
|
||||
var output;
|
||||
if (input.substring(input.length-4) == '.yml') {
|
||||
output = input.substr(0, input.length-4) + '.json';
|
||||
}
|
||||
else if (input.substring(input.length-5) == '.yaml') {
|
||||
output = input.substr(0, input.length-5) + '.json';
|
||||
}
|
||||
else {
|
||||
output = input + '.json';
|
||||
}
|
||||
|
||||
// Write file
|
||||
var file = fs.openSync(output, 'w+');
|
||||
fs.writeSync(file, json);
|
||||
fs.closeSync(file);
|
||||
process.stdout.write("saved "+output+"\n");
|
||||
}
|
||||
};
|
||||
|
||||
var input = parsePath(options.input);
|
||||
var mtimes = [];
|
||||
|
||||
var runCommand = function() {
|
||||
try {
|
||||
var files = findFiles(input);
|
||||
var len = files.length;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
var file = files[i];
|
||||
var stat = fs.statSync(file);
|
||||
var time = stat.mtime.getTime();
|
||||
if (!stat.isDirectory()) {
|
||||
if (!mtimes[file] || mtimes[file] < time) {
|
||||
mtimes[file] = time;
|
||||
convertToJSON(file, options.pretty, options.save, options.indentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
process.stderr.write((e.message ? e.message : e)+"\n");
|
||||
}
|
||||
};
|
||||
|
||||
if (!options.watch) {
|
||||
runCommand();
|
||||
} else {
|
||||
runCommand();
|
||||
setInterval(runCommand, 1000);
|
||||
}
|
||||
} catch (e) {
|
||||
process.stderr.write((e.message ? e.message : e)+"\n");
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
#!/bin/sh
|
||||
cd `dirname $0`
|
||||
|
||||
# Generate yaml.js
|
||||
file="bin/yaml.js"
|
||||
|
||||
> $file
|
||||
|
||||
echo Compiling $file ...
|
||||
|
||||
echo " - LICENSE"
|
||||
|
||||
echo "/*" >> $file
|
||||
cat LICENSE >> $file
|
||||
echo "\n*/" >> $file
|
||||
echo "(function(){" >> $file
|
||||
|
||||
echo " - YamlParseException.js"
|
||||
cat src/yaml/YamlParseException.js >> $file
|
||||
echo " - Yaml.js"
|
||||
cat src/yaml/Yaml.js >> $file
|
||||
echo " - YamlInline.js"
|
||||
cat src/yaml/YamlInline.js >> $file
|
||||
echo " - YamlParser.js"
|
||||
cat src/yaml/YamlParser.js >> $file
|
||||
echo " - YamlEscaper.js"
|
||||
cat src/yaml/YamlEscaper.js >> $file
|
||||
echo " - YamlUnescaper.js"
|
||||
cat src/yaml/YamlUnescaper.js >> $file
|
||||
echo " - YamlDumper.js"
|
||||
cat src/yaml/YamlDumper.js >> $file
|
||||
|
||||
echo "})();" >> $file
|
||||
|
||||
# Generate yaml.min.js
|
||||
file="bin/yaml.min.js"
|
||||
|
||||
echo "compressing..."
|
||||
echo "/*" > $file
|
||||
cat LICENSE >> $file
|
||||
echo "\n*/" >> $file
|
||||
uglifyjs -nc bin/yaml.js >> $file
|
||||
|
||||
echo "yaml.js compiled."
|
||||
echo "yaml.min.js compiled."
|
||||
|
||||
# Generate yaml2json
|
||||
echo "#!/usr/bin/env node" > bin/yaml2json
|
||||
cat src/cli/yaml2json.js >> bin/yaml2json
|
||||
chmod +x bin/yaml2json
|
||||
echo "yaml2json compiled."
|
||||
|
||||
# Generate json2yaml
|
||||
echo "#!/usr/bin/env node" > bin/json2yaml
|
||||
cat src/cli/json2yaml.js >> bin/json2yaml
|
||||
chmod +x bin/json2yaml
|
||||
echo "json2yaml compiled."
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style type="text/css">
|
||||
/*
|
||||
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
|
||||
Code licensed under the BSD License:
|
||||
http://developer.yahoo.com/yui/license.html
|
||||
version: 3.2.0
|
||||
build: 2676
|
||||
*/
|
||||
html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}
|
||||
|
||||
/*
|
||||
* Custom styles
|
||||
*/
|
||||
body {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
#parse {
|
||||
border: none;
|
||||
background-color: white;
|
||||
color: black;
|
||||
z-index: 3;
|
||||
position: absolute;
|
||||
right: 50%;
|
||||
top: 0;
|
||||
width: 100px;
|
||||
}
|
||||
#yaml {
|
||||
color: white;
|
||||
background-color: black;
|
||||
font-family: "Courier New";
|
||||
font-size: 14px;
|
||||
width: 50%;
|
||||
border: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
height: 100%;
|
||||
}
|
||||
#result {
|
||||
color: black;
|
||||
background-color: white;
|
||||
font-family: "Courier New";
|
||||
font-size: 15px;
|
||||
width: 50%;
|
||||
border: none;
|
||||
position: absolute;
|
||||
top: 5em;
|
||||
left: 50%;
|
||||
overflow: auto;
|
||||
z-index: 2;
|
||||
height: 100%;
|
||||
}
|
||||
#tests {
|
||||
width: 50%;
|
||||
border: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- standalone yaml.js library -->
|
||||
<script type="text/javascript" src="../bin/yaml.js"></script>
|
||||
|
||||
<title>yaml.js demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form action="" onsubmit="return false;">
|
||||
<textarea name="yaml" id="yaml" cols="70" rows="20">--- !clarkevans.com/^invoice
|
||||
invoice: 34843
|
||||
date : 2001-01-23
|
||||
bill-to: &id001
|
||||
given : Chris
|
||||
family : Dumars
|
||||
address:
|
||||
lines: |
|
||||
458 Walkman Dr.
|
||||
Suite #292
|
||||
city : Royal Oak
|
||||
state : MI
|
||||
postal : 48046
|
||||
ship-to: *id001
|
||||
product:
|
||||
- sku : "BL394D"
|
||||
quantity : 4
|
||||
description : Basketball
|
||||
price : 450.00
|
||||
- sku : BL4438H
|
||||
quantity : 1
|
||||
description : Super Hoop
|
||||
price : 2392.00
|
||||
tax : 251.42
|
||||
total: 4443.52
|
||||
comments: >
|
||||
Late afternoon is best.
|
||||
Backup contact is Nancy
|
||||
Billsmer @ 338-4338.
|
||||
</textarea>
|
||||
<input type="button" id="parse" name="parse" value="Parse »" onclick="try{document.getElementById('result').innerHTML=JSON.stringify(YAML.parse(document.getElementById('yaml').value))}catch(e){alert(e);}" />
|
||||
<div id="tests"><span>You could also try to run some <a href="tests.html" title="Jasmine tests">javascript tests</a> based on <a href="http://www.yaml.org/YAML_for_ruby.html">YAML cookbook for Ruby</a>. All tests should pass. Those that don't are commented out; they deal with multiple YAML documents in one stream which is not supported by yaml.js (and Symfony)</span></div>
|
||||
<div id="result"></div>
|
||||
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -1,109 +0,0 @@
|
|||
0.1.15 / 2013-05-13
|
||||
-------------------
|
||||
|
||||
* Fixed #55, @trebor89
|
||||
|
||||
|
||||
0.1.14 / 2013-05-12
|
||||
-------------------
|
||||
|
||||
* Fixed #62, @maxtaco
|
||||
|
||||
|
||||
0.1.13 / 2013-04-08
|
||||
-------------------
|
||||
|
||||
* Added `.npmignore` to reduce package size
|
||||
|
||||
|
||||
0.1.12 / 2013-02-10
|
||||
-------------------
|
||||
|
||||
* Fixed conflictHandler (#46), @hpaulj
|
||||
|
||||
|
||||
0.1.11 / 2013-02-07
|
||||
-------------------
|
||||
|
||||
* Multiple bugfixes, @hpaulj
|
||||
* Added 70+ tests (ported from python), @hpaulj
|
||||
* Added conflictHandler, @applepicke
|
||||
* Added fromfilePrefixChar, @hpaulj
|
||||
|
||||
|
||||
0.1.10 / 2012-12-30
|
||||
-------------------
|
||||
|
||||
* Added [mutual exclusion](http://docs.python.org/dev/library/argparse.html#mutual-exclusion)
|
||||
support, thanks to @hpaulj
|
||||
* Fixed options check for `storeConst` & `appendConst` actions, thanks to @hpaulj
|
||||
|
||||
|
||||
0.1.9 / 2012-12-27
|
||||
------------------
|
||||
|
||||
* Fixed option dest interferens with other options (issue #23), thanks to @hpaulj
|
||||
* Fixed default value behavior with `*` positionals, thanks to @hpaulj
|
||||
* Improve `getDefault()` behavior, thanks to @hpaulj
|
||||
* Imrove negative argument parsing, thanks to @hpaulj
|
||||
|
||||
|
||||
0.1.8 / 2012-12-01
|
||||
------------------
|
||||
|
||||
* Fixed parser parents (issue #19), thanks to @hpaulj
|
||||
* Fixed negative argument parse (issue #20), thanks to @hpaulj
|
||||
|
||||
|
||||
0.1.7 / 2012-10-14
|
||||
------------------
|
||||
|
||||
* Fixed 'choices' argument parse (issue #16)
|
||||
* Fixed stderr output (issue #15)
|
||||
|
||||
|
||||
0.1.6 / 2012-09-09
|
||||
------------------
|
||||
|
||||
* Fixed check for conflict of options (thanks to @tomxtobin)
|
||||
|
||||
|
||||
0.1.5 / 2012-09-03
|
||||
------------------
|
||||
|
||||
* Fix parser #setDefaults method (thanks to @tomxtobin)
|
||||
|
||||
|
||||
0.1.4 / 2012-07-30
|
||||
------------------
|
||||
|
||||
* Fixed pseudo-argument support (thanks to @CGamesPlay)
|
||||
* Fixed addHelp default (should be true), if not set (thanks to @benblank)
|
||||
|
||||
|
||||
0.1.3 / 2012-06-27
|
||||
------------------
|
||||
|
||||
* Fixed formatter api name: Formatter -> HelpFormatter
|
||||
|
||||
|
||||
0.1.2 / 2012-05-29
|
||||
------------------
|
||||
|
||||
* Added basic tests
|
||||
* Removed excess whitespace in help
|
||||
* Fixed error reporting, when parcer with subcommands
|
||||
called with empty arguments
|
||||
|
||||
|
||||
0.1.1 / 2012-05-23
|
||||
------------------
|
||||
|
||||
* Fixed line wrapping in help formatter
|
||||
* Added better error reporting on invalid arguments
|
||||
|
||||
|
||||
0.1.0 / 2012-05-16
|
||||
------------------
|
||||
|
||||
* First release.
|
|
@ -1,21 +0,0 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (C) 2012 by Vitaly Puzrin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -1,239 +0,0 @@
|
|||
argparse
|
||||
========
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/nodeca/argparse.png?branch=master)](http://travis-ci.org/nodeca/argparse)
|
||||
|
||||
CLI arguments parser for node.js. Javascript port of python's
|
||||
[argparse](http://docs.python.org/dev/library/argparse.html) module
|
||||
(original version 3.2). That's a full port, except some very rare options,
|
||||
recorded in issue tracker.
|
||||
|
||||
**NB.** Method names changed to camelCase. See [generated docs](http://nodeca.github.com/argparse/).
|
||||
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
test.js file:
|
||||
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp:true,
|
||||
description: 'Argparse example'
|
||||
});
|
||||
parser.addArgument(
|
||||
[ '-f', '--foo' ],
|
||||
{
|
||||
help: 'foo bar'
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
[ '-b', '--bar' ],
|
||||
{
|
||||
help: 'bar foo'
|
||||
}
|
||||
);
|
||||
var args = parser.parseArgs();
|
||||
console.dir(args);
|
||||
```
|
||||
|
||||
Display help:
|
||||
|
||||
```
|
||||
$ ./test.js -h
|
||||
usage: example.js [-h] [-v] [-f FOO] [-b BAR]
|
||||
|
||||
Argparse example
|
||||
|
||||
Optional arguments:
|
||||
-h, --help Show this help message and exit.
|
||||
-v, --version Show program's version number and exit.
|
||||
-f FOO, --foo FOO foo bar
|
||||
-b BAR, --bar BAR bar foo
|
||||
```
|
||||
|
||||
Parse arguments:
|
||||
|
||||
```
|
||||
$ ./test.js -f=3 --bar=4
|
||||
{ foo: '3', bar: '4' }
|
||||
```
|
||||
|
||||
More [examples](https://github.com/nodeca/argparse/tree/master/examples).
|
||||
|
||||
|
||||
ArgumentParser objects
|
||||
======================
|
||||
|
||||
```
|
||||
new ArgumentParser({paramters hash});
|
||||
```
|
||||
|
||||
Creates a new ArgumentParser object.
|
||||
|
||||
**Supported params:**
|
||||
|
||||
- ```description``` - Text to display before the argument help.
|
||||
- ```epilog``` - Text to display after the argument help.
|
||||
- ```addHelp``` - Add a -h/–help option to the parser. (default: True)
|
||||
- ```argumentDefault``` - Set the global default value for arguments. (default: None)
|
||||
- ```parents``` - A list of ArgumentParser objects whose arguments should also be included.
|
||||
- ```prefixChars``` - The set of characters that prefix optional arguments. (default: ‘-‘)
|
||||
- ```formatterClass``` - A class for customizing the help output.
|
||||
- ```prog``` - The name of the program (default: sys.argv[0])
|
||||
- ```usage``` - The string describing the program usage (default: generated)
|
||||
- ```conflictHandler``` - Usually unnecessary, defines strategy for resolving conflicting optionals.
|
||||
|
||||
**Not supportied yet**
|
||||
|
||||
- ```fromfilePrefixChars``` - The set of characters that prefix files from which additional arguments should be read.
|
||||
|
||||
|
||||
Details in [original ArgumentParser guide](http://docs.python.org/dev/library/argparse.html#argumentparser-objects)
|
||||
|
||||
|
||||
addArgument() method
|
||||
====================
|
||||
|
||||
```
|
||||
ArgumentParser.addArgument([names or flags], {options})
|
||||
```
|
||||
|
||||
Defines how a single command-line argument should be parsed.
|
||||
|
||||
- ```name or flags``` - Either a name or a list of option strings, e.g. foo or -f, --foo.
|
||||
|
||||
Options:
|
||||
|
||||
- ```action``` - The basic type of action to be taken when this argument is encountered at the command line.
|
||||
- ```nargs```- The number of command-line arguments that should be consumed.
|
||||
- ```constant``` - A constant value required by some action and nargs selections.
|
||||
- ```defaultValue``` - The value produced if the argument is absent from the command line.
|
||||
- ```type``` - The type to which the command-line argument should be converted.
|
||||
- ```choices``` - A container of the allowable values for the argument.
|
||||
- ```required``` - Whether or not the command-line option may be omitted (optionals only).
|
||||
- ```help``` - A brief description of what the argument does.
|
||||
- ```metavar``` - A name for the argument in usage messages.
|
||||
- ```dest``` - The name of the attribute to be added to the object returned by parseArgs().
|
||||
|
||||
Details in [original add_argument guide](http://docs.python.org/dev/library/argparse.html#the-add-argument-method)
|
||||
|
||||
|
||||
Action (some details)
|
||||
================
|
||||
|
||||
ArgumentParser objects associate command-line arguments with actions.
|
||||
These actions can do just about anything with the command-line arguments associated
|
||||
with them, though most actions simply add an attribute to the object returned by
|
||||
parseArgs(). The action keyword argument specifies how the command-line arguments
|
||||
should be handled. The supported actions are:
|
||||
|
||||
- ```store``` - Just stores the argument’s value. This is the default action.
|
||||
- ```storeConst``` - Stores value, specified by the const keyword argument.
|
||||
(Note that the const keyword argument defaults to the rather unhelpful None.)
|
||||
The 'storeConst' action is most commonly used with optional arguments, that
|
||||
specify some sort of flag.
|
||||
- ```storeTrue``` and ```storeFalse``` - Stores values True and False
|
||||
respectively. These are special cases of 'storeConst'.
|
||||
- ```append``` - Stores a list, and appends each argument value to the list.
|
||||
This is useful to allow an option to be specified multiple times.
|
||||
- ```appendConst``` - Stores a list, and appends value, specified by the
|
||||
const keyword argument to the list. (Note, that the const keyword argument defaults
|
||||
is None.) The 'appendConst' action is typically used when multiple arguments need
|
||||
to store constants to the same list.
|
||||
- ```count``` - Counts the number of times a keyword argument occurs. For example,
|
||||
used for increasing verbosity levels.
|
||||
- ```help``` - Prints a complete help message for all the options in the current
|
||||
parser and then exits. By default a help action is automatically added to the parser.
|
||||
See ArgumentParser for details of how the output is created.
|
||||
- ```version``` - Prints version information and exit. Expects a `version=`
|
||||
keyword argument in the addArgument() call.
|
||||
|
||||
Details in [original action guide](http://docs.python.org/dev/library/argparse.html#action)
|
||||
|
||||
|
||||
Sub-commands
|
||||
============
|
||||
|
||||
ArgumentParser.addSubparsers()
|
||||
|
||||
Many programs split their functionality into a number of sub-commands, for
|
||||
example, the svn program can invoke sub-commands like `svn checkout`, `svn update`,
|
||||
and `svn commit`. Splitting up functionality this way can be a particularly good
|
||||
idea when a program performs several different functions which require different
|
||||
kinds of command-line arguments. `ArgumentParser` supports creation of such
|
||||
sub-commands with `addSubparsers()` method. The `addSubparsers()` method is
|
||||
normally called with no arguments and returns an special action object.
|
||||
This object has a single method `addParser()`, which takes a command name and
|
||||
any `ArgumentParser` constructor arguments, and returns an `ArgumentParser` object
|
||||
that can be modified as usual.
|
||||
|
||||
Example:
|
||||
|
||||
sub_commands.js
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp:true,
|
||||
description: 'Argparse examples: sub-commands',
|
||||
});
|
||||
|
||||
var subparsers = parser.addSubparsers({
|
||||
title:'subcommands',
|
||||
dest:"subcommand_name"
|
||||
});
|
||||
|
||||
var bar = subparsers.addParser('c1', {addHelp:true});
|
||||
bar.addArgument(
|
||||
[ '-f', '--foo' ],
|
||||
{
|
||||
action: 'store',
|
||||
help: 'foo3 bar3'
|
||||
}
|
||||
);
|
||||
var bar = subparsers.addParser(
|
||||
'c2',
|
||||
{aliases:['co'], addHelp:true}
|
||||
);
|
||||
bar.addArgument(
|
||||
[ '-b', '--bar' ],
|
||||
{
|
||||
action: 'store',
|
||||
type: 'int',
|
||||
help: 'foo3 bar3'
|
||||
}
|
||||
);
|
||||
|
||||
var args = parser.parseArgs();
|
||||
console.dir(args);
|
||||
|
||||
```
|
||||
|
||||
Details in [original sub-commands guide](http://docs.python.org/dev/library/argparse.html#sub-commands)
|
||||
|
||||
|
||||
Contributors
|
||||
============
|
||||
|
||||
- [Eugene Shkuropat](https://github.com/shkuropat)
|
||||
- [Paul Jacobson](https://github.com/hpaulj)
|
||||
|
||||
[others](https://github.com/nodeca/argparse/graphs/contributors)
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Copyright (c) 2012 [Vitaly Puzrin](https://github.com/puzrin).
|
||||
Released under the MIT license. See
|
||||
[LICENSE](https://github.com/nodeca/argparse/blob/master/LICENSE) for details.
|
||||
|
||||
|
36
support/process/node_modules/yamljs/node_modules/argparse/examples/arguments.js
generated
vendored
36
support/process/node_modules/yamljs/node_modules/argparse/examples/arguments.js
generated
vendored
|
@ -1,36 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp: true,
|
||||
description: 'Argparse examples: arguments'
|
||||
});
|
||||
parser.addArgument(
|
||||
[ '-f', '--foo' ],
|
||||
{
|
||||
help: 'foo bar'
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
[ '-b', '--bar' ],
|
||||
{
|
||||
help: 'bar foo'
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
parser.printHelp();
|
||||
console.log('-----------');
|
||||
|
||||
var args;
|
||||
args = parser.parseArgs('-f 1 -b2'.split(' '));
|
||||
console.dir(args);
|
||||
console.log('-----------');
|
||||
args = parser.parseArgs('-f=3 --bar=4'.split(' '));
|
||||
console.dir(args);
|
||||
console.log('-----------');
|
||||
args = parser.parseArgs('--foo 5 --bar 6'.split(' '));
|
||||
console.dir(args);
|
||||
console.log('-----------');
|
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp: true,
|
||||
description: 'Argparse examples: choice'
|
||||
});
|
||||
|
||||
parser.addArgument(['foo'], {choices: 'abc'});
|
||||
|
||||
parser.printHelp();
|
||||
console.log('-----------');
|
||||
|
||||
var args;
|
||||
args = parser.parseArgs(['c']);
|
||||
console.dir(args);
|
||||
console.log('-----------');
|
||||
parser.parseArgs(['X']);
|
||||
console.dir(args);
|
||||
|
59
support/process/node_modules/yamljs/node_modules/argparse/examples/constants.js
generated
vendored
59
support/process/node_modules/yamljs/node_modules/argparse/examples/constants.js
generated
vendored
|
@ -1,59 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp: true,
|
||||
description: 'Argparse examples: constant'
|
||||
});
|
||||
|
||||
parser.addArgument(
|
||||
[ '-a'],
|
||||
{
|
||||
action: 'storeConst',
|
||||
dest: 'answer',
|
||||
help: 'store constant',
|
||||
constant: 42
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
[ '--str' ],
|
||||
{
|
||||
action: 'appendConst',
|
||||
dest: 'types',
|
||||
help: 'append constant "str" to types',
|
||||
constant: 'str'
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
[ '--int' ],
|
||||
{
|
||||
action: 'appendConst',
|
||||
dest: 'types',
|
||||
help: 'append constant "int" to types',
|
||||
constant: 'int'
|
||||
}
|
||||
);
|
||||
|
||||
parser.addArgument(
|
||||
[ '--true' ],
|
||||
{
|
||||
action: 'storeTrue',
|
||||
help: 'store true constant'
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
[ '--false' ],
|
||||
{
|
||||
action: 'storeFalse',
|
||||
help: 'store false constant'
|
||||
}
|
||||
);
|
||||
|
||||
parser.printHelp();
|
||||
console.log('-----------');
|
||||
|
||||
var args;
|
||||
args = parser.parseArgs('-a --str --int --true'.split(' '));
|
||||
console.dir(args);
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp: true,
|
||||
description: 'Argparse examples: help',
|
||||
epilog: 'help epilog',
|
||||
prog: 'help_example_prog',
|
||||
usage: 'Usage %(prog)s <agrs>'
|
||||
});
|
||||
parser.printHelp();
|
|
@ -1,33 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp: true,
|
||||
description: 'Argparse examples: nargs'
|
||||
});
|
||||
parser.addArgument(
|
||||
[ '-f', '--foo' ],
|
||||
{
|
||||
help: 'foo bar',
|
||||
nargs: 1
|
||||
}
|
||||
);
|
||||
parser.addArgument(
|
||||
[ '-b', '--bar' ],
|
||||
{
|
||||
help: 'bar foo',
|
||||
nargs: '*'
|
||||
}
|
||||
);
|
||||
|
||||
parser.printHelp();
|
||||
console.log('-----------');
|
||||
|
||||
var args;
|
||||
args = parser.parseArgs('--foo a --bar c d'.split(' '));
|
||||
console.dir(args);
|
||||
console.log('-----------');
|
||||
args = parser.parseArgs('--bar b c f --foo a'.split(' '));
|
||||
console.dir(args);
|
|
@ -1,28 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
|
||||
var args;
|
||||
var parent_parser = new ArgumentParser({ addHelp: false });
|
||||
// note addHelp:false to prevent duplication of the -h option
|
||||
parent_parser.addArgument(
|
||||
['--parent'],
|
||||
{ type: 'int', description: 'parent' }
|
||||
);
|
||||
|
||||
var foo_parser = new ArgumentParser({
|
||||
parents: [ parent_parser ],
|
||||
description: 'child1'
|
||||
});
|
||||
foo_parser.addArgument(['foo']);
|
||||
args = foo_parser.parseArgs(['--parent', '2', 'XXX']);
|
||||
console.log(args);
|
||||
|
||||
var bar_parser = new ArgumentParser({
|
||||
parents: [ parent_parser ],
|
||||
description: 'child2'
|
||||
});
|
||||
bar_parser.addArgument(['--bar']);
|
||||
args = bar_parser.parseArgs(['--bar', 'YYY']);
|
||||
console.log(args);
|
23
support/process/node_modules/yamljs/node_modules/argparse/examples/prefix_chars.js
generated
vendored
23
support/process/node_modules/yamljs/node_modules/argparse/examples/prefix_chars.js
generated
vendored
|
@ -1,23 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp: true,
|
||||
description: 'Argparse examples: prefix_chars',
|
||||
prefixChars: '-+'
|
||||
});
|
||||
parser.addArgument(['+f', '++foo']);
|
||||
parser.addArgument(['++bar'], {action: 'storeTrue'});
|
||||
|
||||
parser.printHelp();
|
||||
console.log('-----------');
|
||||
|
||||
var args;
|
||||
args = parser.parseArgs(['+f', '1']);
|
||||
console.dir(args);
|
||||
args = parser.parseArgs(['++bar']);
|
||||
console.dir(args);
|
||||
args = parser.parseArgs(['++foo', '2', '++bar']);
|
||||
console.dir(args);
|
49
support/process/node_modules/yamljs/node_modules/argparse/examples/sub_commands.js
generated
vendored
49
support/process/node_modules/yamljs/node_modules/argparse/examples/sub_commands.js
generated
vendored
|
@ -1,49 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({
|
||||
version: '0.0.1',
|
||||
addHelp: true,
|
||||
description: 'Argparse examples: sub-commands'
|
||||
});
|
||||
|
||||
var subparsers = parser.addSubparsers({
|
||||
title: 'subcommands',
|
||||
dest: "subcommand_name"
|
||||
});
|
||||
|
||||
var bar = subparsers.addParser('c1', {addHelp: true, help: 'c1 help'});
|
||||
bar.addArgument(
|
||||
[ '-f', '--foo' ],
|
||||
{
|
||||
action: 'store',
|
||||
help: 'foo3 bar3'
|
||||
}
|
||||
);
|
||||
var bar = subparsers.addParser(
|
||||
'c2',
|
||||
{aliases: ['co'], addHelp: true, help: 'c2 help'}
|
||||
);
|
||||
bar.addArgument(
|
||||
[ '-b', '--bar' ],
|
||||
{
|
||||
action: 'store',
|
||||
type: 'int',
|
||||
help: 'foo3 bar3'
|
||||
}
|
||||
);
|
||||
parser.printHelp();
|
||||
console.log('-----------');
|
||||
|
||||
var args;
|
||||
args = parser.parseArgs('c1 -f 2'.split(' '));
|
||||
console.dir(args);
|
||||
console.log('-----------');
|
||||
args = parser.parseArgs('c2 -b 1'.split(' '));
|
||||
console.dir(args);
|
||||
console.log('-----------');
|
||||
args = parser.parseArgs('co -b 1'.split(' '));
|
||||
console.dir(args);
|
||||
console.log('-----------');
|
||||
parser.parseArgs(['c1', '-h']);
|
|
@ -1,35 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
var ArgumentParser = require('../lib/argparse').ArgumentParser;
|
||||
var parser = new ArgumentParser({ description: 'Process some integers.' });
|
||||
|
||||
|
||||
function sum(arr) {
|
||||
return arr.reduce(function (a, b) {
|
||||
return a + b;
|
||||
}, 0);
|
||||
}
|
||||
function max(arr) {
|
||||
return Math.max.apply(Math, arr);
|
||||
}
|
||||
|
||||
|
||||
parser.addArgument(['integers'], {
|
||||
metavar: 'N',
|
||||
type: 'int',
|
||||
nargs: '+',
|
||||
help: 'an integer for the accumulator'
|
||||
});
|
||||
parser.addArgument(['--sum'], {
|
||||
dest: 'accumulate',
|
||||
action: 'storeConst',
|
||||
constant: sum,
|
||||
defaultValue: max,
|
||||
help: 'sum the integers (default: find the max)'
|
||||
});
|
||||
|
||||
var args = parser.parseArgs('--sum 1 2 -1'.split(' '));
|
||||
console.log(args.accumulate(args.integers));
|
270
support/process/node_modules/yamljs/node_modules/argparse/examples/testformatters.js
generated
vendored
270
support/process/node_modules/yamljs/node_modules/argparse/examples/testformatters.js
generated
vendored
|
@ -1,270 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var a, group, parser, helptext;
|
||||
|
||||
var assert = require('assert');
|
||||
var _ = require('underscore');
|
||||
_.str = require('underscore.string');
|
||||
var print = function () {
|
||||
return console.log.apply(console, arguments);
|
||||
};
|
||||
// print = function () {};
|
||||
|
||||
var argparse = require('argparse');
|
||||
|
||||
print("TEST argparse.ArgumentDefaultsHelpFormatter");
|
||||
|
||||
parser = new argparse.ArgumentParser({
|
||||
debug: true,
|
||||
formatterClass: argparse.ArgumentDefaultsHelpFormatter,
|
||||
description: 'description'
|
||||
});
|
||||
|
||||
parser.addArgument(['--foo'], {
|
||||
help: 'foo help - oh and by the way, %(defaultValue)s'
|
||||
});
|
||||
|
||||
parser.addArgument(['--bar'], {
|
||||
action: 'storeTrue',
|
||||
help: 'bar help'
|
||||
});
|
||||
|
||||
parser.addArgument(['spam'], {
|
||||
help: 'spam help'
|
||||
});
|
||||
|
||||
parser.addArgument(['badger'], {
|
||||
nargs: '?',
|
||||
defaultValue: 'wooden',
|
||||
help: 'badger help'
|
||||
});
|
||||
|
||||
group = parser.addArgumentGroup({
|
||||
title: 'title',
|
||||
description: 'group description'
|
||||
});
|
||||
|
||||
group.addArgument(['--baz'], {
|
||||
type: 'int',
|
||||
defaultValue: 42,
|
||||
help: 'baz help'
|
||||
});
|
||||
|
||||
helptext = parser.formatHelp();
|
||||
print(helptext);
|
||||
// test selected clips
|
||||
assert(helptext.match(/badger help \(default: wooden\)/));
|
||||
assert(helptext.match(/foo help - oh and by the way, null/));
|
||||
assert(helptext.match(/bar help \(default: false\)/));
|
||||
assert(helptext.match(/title:\n {2}group description/)); // test indent
|
||||
assert(helptext.match(/baz help \(default: 42\)/im));
|
||||
|
||||
/*
|
||||
usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
|
||||
|
||||
description
|
||||
|
||||
positional arguments:
|
||||
spam spam help
|
||||
badger badger help (default: wooden)
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--foo FOO foo help - oh and by the way, null
|
||||
--bar bar help (default: false)
|
||||
|
||||
title:
|
||||
group description
|
||||
|
||||
--baz BAZ baz help (default: 42)
|
||||
*/
|
||||
|
||||
print("TEST argparse.RawDescriptionHelpFormatter");
|
||||
|
||||
parser = new argparse.ArgumentParser({
|
||||
debug: true,
|
||||
prog: 'PROG',
|
||||
formatterClass: argparse.RawDescriptionHelpFormatter,
|
||||
description: 'Keep the formatting\n' +
|
||||
' exactly as it is written\n' +
|
||||
'\n' +
|
||||
'here\n'
|
||||
});
|
||||
|
||||
a = parser.addArgument(['--foo'], {
|
||||
help: ' foo help should not\n' +
|
||||
' retain this odd formatting'
|
||||
});
|
||||
|
||||
parser.addArgument(['spam'], {
|
||||
'help': 'spam help'
|
||||
});
|
||||
|
||||
group = parser.addArgumentGroup({
|
||||
title: 'title',
|
||||
description: ' This text\n' +
|
||||
' should be indented\n' +
|
||||
' exactly like it is here\n'
|
||||
});
|
||||
|
||||
group.addArgument(['--bar'], {
|
||||
help: 'bar help'
|
||||
});
|
||||
|
||||
helptext = parser.formatHelp();
|
||||
print(helptext);
|
||||
// test selected clips
|
||||
assert(helptext.match(parser.description));
|
||||
assert.equal(helptext.match(a.help), null);
|
||||
assert(helptext.match(/foo help should not retain this odd formatting/));
|
||||
|
||||
/*
|
||||
class TestHelpRawDescription(HelpTestCase):
|
||||
"""Test the RawTextHelpFormatter"""
|
||||
....
|
||||
|
||||
usage: PROG [-h] [--foo FOO] [--bar BAR] spam
|
||||
|
||||
Keep the formatting
|
||||
exactly as it is written
|
||||
|
||||
here
|
||||
|
||||
positional arguments:
|
||||
spam spam help
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--foo FOO foo help should not retain this odd formatting
|
||||
|
||||
title:
|
||||
This text
|
||||
should be indented
|
||||
exactly like it is here
|
||||
|
||||
--bar BAR bar help
|
||||
*/
|
||||
|
||||
|
||||
print("TEST argparse.RawTextHelpFormatter");
|
||||
|
||||
parser = new argparse.ArgumentParser({
|
||||
debug: true,
|
||||
prog: 'PROG',
|
||||
formatterClass: argparse.RawTextHelpFormatter,
|
||||
description: 'Keep the formatting\n' +
|
||||
' exactly as it is written\n' +
|
||||
'\n' +
|
||||
'here\n'
|
||||
});
|
||||
|
||||
parser.addArgument(['--baz'], {
|
||||
help: ' baz help should also\n' +
|
||||
'appear as given here'
|
||||
});
|
||||
|
||||
a = parser.addArgument(['--foo'], {
|
||||
help: ' foo help should also\n' +
|
||||
'appear as given here'
|
||||
});
|
||||
|
||||
parser.addArgument(['spam'], {
|
||||
'help': 'spam help'
|
||||
});
|
||||
|
||||
group = parser.addArgumentGroup({
|
||||
title: 'title',
|
||||
description: ' This text\n' +
|
||||
' should be indented\n' +
|
||||
' exactly like it is here\n'
|
||||
});
|
||||
|
||||
group.addArgument(['--bar'], {
|
||||
help: 'bar help'
|
||||
});
|
||||
|
||||
helptext = parser.formatHelp();
|
||||
print(helptext);
|
||||
// test selected clips
|
||||
assert(helptext.match(parser.description));
|
||||
assert(helptext.match(/( {14})appear as given here/gm));
|
||||
|
||||
/*
|
||||
class TestHelpRawText(HelpTestCase):
|
||||
"""Test the RawTextHelpFormatter"""
|
||||
|
||||
usage: PROG [-h] [--foo FOO] [--bar BAR] spam
|
||||
|
||||
Keep the formatting
|
||||
exactly as it is written
|
||||
|
||||
here
|
||||
|
||||
positional arguments:
|
||||
spam spam help
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--foo FOO foo help should also
|
||||
appear as given here
|
||||
|
||||
title:
|
||||
This text
|
||||
should be indented
|
||||
exactly like it is here
|
||||
|
||||
--bar BAR bar help
|
||||
*/
|
||||
|
||||
|
||||
print("TEST metavar as a tuple");
|
||||
|
||||
parser = new argparse.ArgumentParser({
|
||||
prog: 'PROG'
|
||||
});
|
||||
|
||||
parser.addArgument(['-w'], {
|
||||
help: 'w',
|
||||
nargs: '+',
|
||||
metavar: ['W1', 'W2']
|
||||
});
|
||||
|
||||
parser.addArgument(['-x'], {
|
||||
help: 'x',
|
||||
nargs: '*',
|
||||
metavar: ['X1', 'X2']
|
||||
});
|
||||
|
||||
parser.addArgument(['-y'], {
|
||||
help: 'y',
|
||||
nargs: 3,
|
||||
metavar: ['Y1', 'Y2', 'Y3']
|
||||
});
|
||||
|
||||
parser.addArgument(['-z'], {
|
||||
help: 'z',
|
||||
nargs: '?',
|
||||
metavar: ['Z1']
|
||||
});
|
||||
|
||||
helptext = parser.formatHelp();
|
||||
print(helptext);
|
||||
var ustring = 'PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] [-z [Z1]]';
|
||||
ustring = ustring.replace(/\[/g, '\\[').replace(/\]/g, '\\]');
|
||||
// print(ustring)
|
||||
assert(helptext.match(new RegExp(ustring)));
|
||||
|
||||
/*
|
||||
class TestHelpTupleMetavar(HelpTestCase):
|
||||
"""Test specifying metavar as a tuple"""
|
||||
|
||||
usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] [-z [Z1]]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-w W1 [W2 ...] w
|
||||
-x [X1 [X2 ...]] x
|
||||
-y Y1 Y2 Y3 y
|
||||
-z [Z1] z
|
||||
*/
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('./lib/argparse');
|
|
@ -1,146 +0,0 @@
|
|||
/**
|
||||
* class Action
|
||||
*
|
||||
* Base class for all actions
|
||||
* Do not call in your code, use this class only for inherits your own action
|
||||
*
|
||||
* Information about how to convert command line strings to Javascript objects.
|
||||
* Action objects are used by an ArgumentParser to represent the information
|
||||
* needed to parse a single argument from one or more strings from the command
|
||||
* line. The keyword arguments to the Action constructor are also all attributes
|
||||
* of Action instances.
|
||||
*
|
||||
* #####Alowed keywords:
|
||||
*
|
||||
* - `store`
|
||||
* - `storeConstant`
|
||||
* - `storeTrue`
|
||||
* - `storeFalse`
|
||||
* - `append`
|
||||
* - `appendConstant`
|
||||
* - `count`
|
||||
* - `help`
|
||||
* - `version`
|
||||
*
|
||||
* Information about action options see [[Action.new]]
|
||||
*
|
||||
* See also [original guide](http://docs.python.org/dev/library/argparse.html#action)
|
||||
*
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
// Constants
|
||||
var $$ = require('./const');
|
||||
|
||||
|
||||
/**
|
||||
* new Action(options)
|
||||
*
|
||||
* Base class for all actions. Used only for inherits
|
||||
*
|
||||
*
|
||||
* ##### Options:
|
||||
*
|
||||
* - `optionStrings` A list of command-line option strings for the action.
|
||||
* - `dest` Attribute to hold the created object(s)
|
||||
* - `nargs` The number of command-line arguments that should be consumed.
|
||||
* By default, one argument will be consumed and a single value will be
|
||||
* produced.
|
||||
* - `constant` Default value for an action with no value.
|
||||
* - `defaultValue` The value to be produced if the option is not specified.
|
||||
* - `type` Cast to 'string'|'int'|'float'|'complex'|function (string). If
|
||||
* None, 'string'.
|
||||
* - `choices` The choices available.
|
||||
* - `required` True if the action must always be specified at the command
|
||||
* line.
|
||||
* - `help` The help describing the argument.
|
||||
* - `metavar` The name to be used for the option's argument with the help
|
||||
* string. If None, the 'dest' value will be used as the name.
|
||||
*
|
||||
* ##### nargs supported values:
|
||||
*
|
||||
* - `N` (an integer) consumes N arguments (and produces a list)
|
||||
* - `?` consumes zero or one arguments
|
||||
* - `*` consumes zero or more arguments (and produces a list)
|
||||
* - `+` consumes one or more arguments (and produces a list)
|
||||
*
|
||||
* Note: that the difference between the default and nargs=1 is that with the
|
||||
* default, a single value will be produced, while with nargs=1, a list
|
||||
* containing a single value will be produced.
|
||||
**/
|
||||
var Action = module.exports = function Action(options) {
|
||||
options = options || {};
|
||||
this.optionStrings = options.optionStrings || [];
|
||||
this.dest = options.dest;
|
||||
this.nargs = options.nargs !== undefined ? options.nargs : null;
|
||||
this.constant = options.constant !== undefined ? options.constant : null;
|
||||
this.defaultValue = options.defaultValue;
|
||||
this.type = options.type !== undefined ? options.type : null;
|
||||
this.choices = options.choices !== undefined ? options.choices : null;
|
||||
this.required = options.required !== undefined ? options.required: false;
|
||||
this.help = options.help !== undefined ? options.help : null;
|
||||
this.metavar = options.metavar !== undefined ? options.metavar : null;
|
||||
|
||||
if (!(this.optionStrings instanceof Array)) {
|
||||
throw new Error('optionStrings should be an array');
|
||||
}
|
||||
if (this.required !== undefined && typeof(this.required) !== 'boolean') {
|
||||
throw new Error('required should be a boolean');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Action#getName -> String
|
||||
*
|
||||
* Tells action name
|
||||
**/
|
||||
Action.prototype.getName = function () {
|
||||
if (this.optionStrings.length > 0) {
|
||||
return this.optionStrings.join('/');
|
||||
} else if (this.metavar !== null && this.metavar !== $$.SUPPRESS) {
|
||||
return this.metavar;
|
||||
} else if (this.dest !== undefined && this.dest !== $$.SUPPRESS) {
|
||||
return this.dest;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Action#isOptional -> Boolean
|
||||
*
|
||||
* Return true if optional
|
||||
**/
|
||||
Action.prototype.isOptional = function () {
|
||||
return !this.isPositional();
|
||||
};
|
||||
|
||||
/**
|
||||
* Action#isPositional -> Boolean
|
||||
*
|
||||
* Return true if positional
|
||||
**/
|
||||
Action.prototype.isPositional = function () {
|
||||
return (this.optionStrings.length === 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Action#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Should be implemented in inherited classes
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* ActionCount.prototype.call = function (parser, namespace, values, optionString) {
|
||||
* namespace.set(this.dest, (namespace[this.dest] || 0) + 1);
|
||||
* };
|
||||
*
|
||||
**/
|
||||
Action.prototype.call = function () {
|
||||
throw new Error('.call() not defined');// Not Implemented error
|
||||
};
|
55
support/process/node_modules/yamljs/node_modules/argparse/lib/action/append.js
generated
vendored
55
support/process/node_modules/yamljs/node_modules/argparse/lib/action/append.js
generated
vendored
|
@ -1,55 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionAppend
|
||||
*
|
||||
* This action stores a list, and appends each argument value to the list.
|
||||
* This is useful to allow an option to be specified multiple times.
|
||||
* This class inherided from [[Action]]
|
||||
*
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
// Constants
|
||||
var $$ = require('../const');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionAppend(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
* Note: options.nargs should be optional for constants
|
||||
* and more then zero for other
|
||||
**/
|
||||
var ActionAppend = module.exports = function ActionAppend(options) {
|
||||
options = options || {};
|
||||
if (this.nargs <= 0) {
|
||||
throw new Error('nargs for append actions must be > 0; if arg ' +
|
||||
'strings are not supplying the value to append, ' +
|
||||
'the append const action may be more appropriate');
|
||||
}
|
||||
if (!!this.constant && this.nargs !== $$.OPTIONAL) {
|
||||
throw new Error('nargs must be OPTIONAL to supply const');
|
||||
}
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionAppend, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionAppend#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionAppend.prototype.call = function (parser, namespace, values) {
|
||||
var items = [].concat(namespace[this.dest] || []); // or _.clone
|
||||
items.push(values);
|
||||
namespace.set(this.dest, items);
|
||||
};
|
||||
|
||||
|
47
support/process/node_modules/yamljs/node_modules/argparse/lib/action/append/constant.js
generated
vendored
47
support/process/node_modules/yamljs/node_modules/argparse/lib/action/append/constant.js
generated
vendored
|
@ -1,47 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionAppendConstant
|
||||
*
|
||||
* This stores a list, and appends the value specified by
|
||||
* the const keyword argument to the list.
|
||||
* (Note that the const keyword argument defaults to null.)
|
||||
* The 'appendConst' action is typically useful when multiple
|
||||
* arguments need to store constants to the same list.
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../../action');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionAppendConstant(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionAppendConstant = module.exports = function ActionAppendConstant(options) {
|
||||
options = options || {};
|
||||
options.nargs = 0;
|
||||
if (options.constant === undefined) {
|
||||
throw new Error('constant option is required for appendAction');
|
||||
}
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionAppendConstant, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionAppendConstant#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionAppendConstant.prototype.call = function (parser, namespace) {
|
||||
var items = [].concat(namespace[this.dest] || []);
|
||||
items.push(this.constant);
|
||||
namespace.set(this.dest, items);
|
||||
};
|
|
@ -1,40 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionCount
|
||||
*
|
||||
* This counts the number of times a keyword argument occurs.
|
||||
* For example, this is useful for increasing verbosity levels
|
||||
*
|
||||
* This class inherided from [[Action]]
|
||||
*
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionCount(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionCount = module.exports = function ActionCount(options) {
|
||||
options = options || {};
|
||||
options.nargs = 0;
|
||||
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionCount, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionCount#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionCount.prototype.call = function (parser, namespace) {
|
||||
namespace.set(this.dest, (namespace[this.dest] || 0) + 1);
|
||||
};
|
|
@ -1,48 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionHelp
|
||||
*
|
||||
* Support action for printing help
|
||||
* This class inherided from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
// Constants
|
||||
var $$ = require('../const');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionHelp(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionHelp = module.exports = function ActionHelp(options) {
|
||||
options = options || {};
|
||||
if (options.defaultValue !== null) {
|
||||
options.defaultValue = options.defaultValue;
|
||||
}
|
||||
else {
|
||||
options.defaultValue = $$.SUPPRESS;
|
||||
}
|
||||
options.dest = (options.dest !== null ? options.dest: $$.SUPPRESS);
|
||||
options.nargs = 0;
|
||||
Action.call(this, options);
|
||||
|
||||
};
|
||||
util.inherits(ActionHelp, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionHelp#call(parser, namespace, values, optionString)
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Print help and exit
|
||||
**/
|
||||
ActionHelp.prototype.call = function (parser) {
|
||||
parser.printHelp();
|
||||
parser.exit();
|
||||
};
|
|
@ -1,50 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionStore
|
||||
*
|
||||
* This action just stores the argument’s value. This is the default action.
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
*
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
// Constants
|
||||
var $$ = require('../const');
|
||||
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionStore(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionStore = module.exports = function ActionStore(options) {
|
||||
options = options || {};
|
||||
if (this.nargs <= 0) {
|
||||
throw new Error('nargs for store actions must be > 0; if you ' +
|
||||
'have nothing to store, actions such as store ' +
|
||||
'true or store const may be more appropriate');
|
||||
|
||||
}
|
||||
if (this.constant !== undefined && this.nargs !== $$.OPTIONAL) {
|
||||
throw new Error('nargs must be OPTIONAL to supply const');
|
||||
}
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionStore, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionStore#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionStore.prototype.call = function (parser, namespace, values) {
|
||||
namespace.set(this.dest, values);
|
||||
};
|
43
support/process/node_modules/yamljs/node_modules/argparse/lib/action/store/constant.js
generated
vendored
43
support/process/node_modules/yamljs/node_modules/argparse/lib/action/store/constant.js
generated
vendored
|
@ -1,43 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionStoreConstant
|
||||
*
|
||||
* This action stores the value specified by the const keyword argument.
|
||||
* (Note that the const keyword argument defaults to the rather unhelpful null.)
|
||||
* The 'store_const' action is most commonly used with optional
|
||||
* arguments that specify some sort of flag.
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../../action');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionStoreConstant(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionStoreConstant = module.exports = function ActionStoreConstant(options) {
|
||||
options = options || {};
|
||||
options.nargs = 0;
|
||||
if (options.constant === undefined) {
|
||||
throw new Error('constant option is required for storeAction');
|
||||
}
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionStoreConstant, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionStoreConstant#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Save result in namespace object
|
||||
**/
|
||||
ActionStoreConstant.prototype.call = function (parser, namespace) {
|
||||
namespace.set(this.dest, this.constant);
|
||||
};
|
27
support/process/node_modules/yamljs/node_modules/argparse/lib/action/store/false.js
generated
vendored
27
support/process/node_modules/yamljs/node_modules/argparse/lib/action/store/false.js
generated
vendored
|
@ -1,27 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionStoreFalse
|
||||
*
|
||||
* This action store the values False respectively.
|
||||
* This is special cases of 'storeConst'
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var ActionStoreConstant = require('./constant');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionStoreFalse(options)
|
||||
* - options (object): hash of options see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionStoreFalse = module.exports = function ActionStoreFalse(options) {
|
||||
options = options || {};
|
||||
options.constant = false;
|
||||
options.defaultValue = options.defaultValue !== null ? options.defaultValue: true;
|
||||
ActionStoreConstant.call(this, options);
|
||||
};
|
||||
util.inherits(ActionStoreFalse, ActionStoreConstant);
|
26
support/process/node_modules/yamljs/node_modules/argparse/lib/action/store/true.js
generated
vendored
26
support/process/node_modules/yamljs/node_modules/argparse/lib/action/store/true.js
generated
vendored
|
@ -1,26 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionStoreTrue
|
||||
*
|
||||
* This action store the values True respectively.
|
||||
* This isspecial cases of 'storeConst'
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var ActionStoreConstant = require('./constant');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionStoreTrue(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionStoreTrue = module.exports = function ActionStoreTrue(options) {
|
||||
options = options || {};
|
||||
options.constant = true;
|
||||
options.defaultValue = options.defaultValue !== null ? options.defaultValue: false;
|
||||
ActionStoreConstant.call(this, options);
|
||||
};
|
||||
util.inherits(ActionStoreTrue, ActionStoreConstant);
|
148
support/process/node_modules/yamljs/node_modules/argparse/lib/action/subparsers.js
generated
vendored
148
support/process/node_modules/yamljs/node_modules/argparse/lib/action/subparsers.js
generated
vendored
|
@ -1,148 +0,0 @@
|
|||
/** internal
|
||||
* class ActionSubparsers
|
||||
*
|
||||
* Support the creation of such sub-commands with the addSubparsers()
|
||||
*
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var format = require('util').format;
|
||||
var _ = require('underscore');
|
||||
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
// Constants
|
||||
var $$ = require('../const');
|
||||
|
||||
// Errors
|
||||
var argumentErrorHelper = require('../argument/error');
|
||||
|
||||
|
||||
/*:nodoc:*
|
||||
* new ChoicesPseudoAction(name, help)
|
||||
*
|
||||
* Create pseudo action for correct help text
|
||||
*
|
||||
**/
|
||||
var ChoicesPseudoAction = function (name, help) {
|
||||
var options = {
|
||||
optionStrings: [],
|
||||
dest: name,
|
||||
help: help
|
||||
};
|
||||
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ChoicesPseudoAction, Action);
|
||||
|
||||
/**
|
||||
* new ActionSubparsers(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionSubparsers = module.exports = function ActionSubparsers(options) {
|
||||
options = options || {};
|
||||
options.dest = options.dest || $$.SUPPRESS;
|
||||
options.nargs = $$.PARSER;
|
||||
|
||||
this.debug = (options.debug === true);
|
||||
|
||||
this._progPrefix = options.prog;
|
||||
this._parserClass = options.parserClass;
|
||||
this._nameParserMap = {};
|
||||
this._choicesActions = [];
|
||||
|
||||
options.choices = this._nameParserMap;
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionSubparsers, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionSubparsers#addParser(name, options) -> ArgumentParser
|
||||
* - name (string): sub-command name
|
||||
* - options (object): see [[ArgumentParser.new]]
|
||||
*
|
||||
* Note:
|
||||
* addParser supports an additional aliases option,
|
||||
* which allows multiple strings to refer to the same subparser.
|
||||
* This example, like svn, aliases co as a shorthand for checkout
|
||||
*
|
||||
**/
|
||||
ActionSubparsers.prototype.addParser = function (name, options) {
|
||||
var parser;
|
||||
|
||||
var self = this;
|
||||
|
||||
options = options || {};
|
||||
|
||||
options.debug = (this.debug === true);
|
||||
|
||||
// set program from the existing prefix
|
||||
if (!options.prog) {
|
||||
options.prog = this._progPrefix + ' ' + name;
|
||||
}
|
||||
|
||||
var aliases = options.aliases || [];
|
||||
|
||||
// create a pseudo-action to hold the choice help
|
||||
if (!!options.help || _.isString(options.help)) {
|
||||
var help = options.help;
|
||||
delete options.help;
|
||||
|
||||
var choiceAction = new ChoicesPseudoAction(name, help);
|
||||
this._choicesActions.push(choiceAction);
|
||||
}
|
||||
|
||||
// create the parser and add it to the map
|
||||
parser = new this._parserClass(options);
|
||||
this._nameParserMap[name] = parser;
|
||||
|
||||
// make parser available under aliases also
|
||||
aliases.forEach(function (alias) {
|
||||
self._nameParserMap[alias] = parser;
|
||||
});
|
||||
|
||||
return parser;
|
||||
};
|
||||
|
||||
ActionSubparsers.prototype._getSubactions = function () {
|
||||
return this._choicesActions;
|
||||
};
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionSubparsers#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Call the action. Parse input aguments
|
||||
**/
|
||||
ActionSubparsers.prototype.call = function (parser, namespace, values) {
|
||||
var parserName = values[0];
|
||||
var argStrings = values.slice(1);
|
||||
|
||||
// set the parser name if requested
|
||||
if (this.dest !== $$.SUPPRESS) {
|
||||
namespace[this.dest] = parserName;
|
||||
}
|
||||
|
||||
// select the parser
|
||||
if (!!this._nameParserMap[parserName]) {
|
||||
parser = this._nameParserMap[parserName];
|
||||
} else {
|
||||
throw argumentErrorHelper(format(
|
||||
'Unknown parser "%s" (choices: [%s]).',
|
||||
parserName,
|
||||
_.keys(this._nameParserMap).join(', ')
|
||||
));
|
||||
}
|
||||
|
||||
// parse all the remaining options into the namespace
|
||||
parser.parseArgs(argStrings, namespace);
|
||||
};
|
||||
|
||||
|
50
support/process/node_modules/yamljs/node_modules/argparse/lib/action/version.js
generated
vendored
50
support/process/node_modules/yamljs/node_modules/argparse/lib/action/version.js
generated
vendored
|
@ -1,50 +0,0 @@
|
|||
/*:nodoc:*
|
||||
* class ActionVersion
|
||||
*
|
||||
* Support action for printing program version
|
||||
* This class inherited from [[Action]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var Action = require('../action');
|
||||
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
var $$ = require('../const');
|
||||
|
||||
/*:nodoc:*
|
||||
* new ActionVersion(options)
|
||||
* - options (object): options hash see [[Action.new]]
|
||||
*
|
||||
**/
|
||||
var ActionVersion = module.exports = function ActionVersion(options) {
|
||||
options = options || {};
|
||||
options.defaultValue = (!!options.defaultValue ? options.defaultValue: $$.SUPPRESS);
|
||||
options.dest = (options.dest || $$.SUPPRESS);
|
||||
options.nargs = 0;
|
||||
this.version = options.version;
|
||||
Action.call(this, options);
|
||||
};
|
||||
util.inherits(ActionVersion, Action);
|
||||
|
||||
/*:nodoc:*
|
||||
* ActionVersion#call(parser, namespace, values, optionString) -> Void
|
||||
* - parser (ArgumentParser): current parser
|
||||
* - namespace (Namespace): namespace for output data
|
||||
* - values (Array): parsed values
|
||||
* - optionString (Array): input option string(not parsed)
|
||||
*
|
||||
* Print version and exit
|
||||
**/
|
||||
ActionVersion.prototype.call = function (parser) {
|
||||
var version = this.version || parser.version;
|
||||
var formatter = parser._getFormatter();
|
||||
formatter.addText(version);
|
||||
parser.exit(0, formatter.formatHelp());
|
||||
};
|
||||
|
||||
|
||||
|
481
support/process/node_modules/yamljs/node_modules/argparse/lib/action_container.js
generated
vendored
481
support/process/node_modules/yamljs/node_modules/argparse/lib/action_container.js
generated
vendored
|
@ -1,481 +0,0 @@
|
|||
/** internal
|
||||
* class ActionContainer
|
||||
*
|
||||
* Action container. Parent for [[ArgumentParser]] and [[ArgumentGroup]]
|
||||
**/
|
||||
|
||||
'use strict';
|
||||
|
||||
var format = require('util').format;
|
||||
var _ = require('underscore');
|
||||
|
||||
_.str = require('underscore.string');
|
||||
|
||||
// Constants
|
||||
var $$ = require('./const');
|
||||
|
||||
//Actions
|
||||
var ActionHelp = require('./action/help');
|
||||
var ActionAppend = require('./action/append');
|
||||
var ActionAppendConstant = require('./action/append/constant');
|
||||
var ActionCount = require('./action/count');
|
||||
var ActionStore = require('./action/store');
|
||||
var ActionStoreConstant = require('./action/store/constant');
|
||||
var ActionStoreTrue = require('./action/store/true');
|
||||
var ActionStoreFalse = require('./action/store/false');
|
||||
var ActionVersion = require('./action/version');
|
||||
var ActionSubparsers = require('./action/subparsers');
|
||||
|
||||
// Errors
|
||||
var argumentErrorHelper = require('./argument/error');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* new ActionContainer(options)
|
||||
*
|
||||
* Action container. Parent for [[ArgumentParser]] and [[ArgumentGroup]]
|
||||
*
|
||||
* ##### Options:
|
||||
*
|
||||
* - `description` -- A description of what the program does
|
||||
* - `prefixChars` -- Characters that prefix optional arguments
|
||||
* - `argumentDefault` -- The default value for all arguments
|
||||
* - `conflictHandler` -- The conflict handler to use for duplicate arguments
|
||||
**/
|
||||
var ActionContainer = module.exports = function ActionContainer(options) {
|
||||
options = options || {};
|
||||
|
||||
this.description = options.description;
|
||||
this.argumentDefault = options.argumentDefault;
|
||||
this.prefixChars = options.prefixChars || '';
|
||||
this.conflictHandler = options.conflictHandler;
|
||||
|
||||
// set up registries
|
||||
this._registries = {};
|
||||
|
||||
// register actions
|
||||
this.register('action', null, ActionStore);
|
||||
this.register('action', 'store', ActionStore);
|
||||
this.register('action', 'storeConst', ActionStoreConstant);
|
||||
this.register('action', 'storeTrue', ActionStoreTrue);
|
||||
this.register('action', 'storeFalse', ActionStoreFalse);
|
||||
this.register('action', 'append', ActionAppend);
|
||||
this.register('action', 'appendConst', ActionAppendConstant);
|
||||
this.register('action', 'count', ActionCount);
|
||||
this.register('action', 'help', ActionHelp);
|
||||
this.register('action', 'version', ActionVersion);
|
||||
this.register('action', 'parsers', ActionSubparsers);
|
||||
|
||||
// raise an exception if the conflict handler is invalid
|
||||
this._getHandler();
|
||||
|
||||
// action storage
|
||||
this._actions = [];
|
||||
this._optionStringActions = {};
|
||||
|
||||
// groups
|
||||
this._actionGroups = [];
|
||||
this._mutuallyExclusiveGroups = [];
|
||||
|
||||
// defaults storage
|
||||
this._defaults = {};
|
||||
|
||||
// determines whether an "option" looks like a negative number
|
||||
// -1, -1.5 -5e+4
|
||||
this._regexpNegativeNumber = new RegExp('^[-]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$');
|
||||
|
||||
// whether or not there are any optionals that look like negative
|
||||
// numbers -- uses a list so it can be shared and edited
|
||||
this._hasNegativeNumberOptionals = [];
|
||||
};
|
||||
|
||||
// Groups must be required, then ActionContainer already defined
|
||||
var ArgumentGroup = require('./argument/group');
|
||||
var MutuallyExclusiveGroup = require('./argument/exclusive');
|
||||
|
||||
//
|
||||
// Registration methods
|
||||
//
|
||||
|
||||
/**
|
||||
* ActionContainer#register(registryName, value, object) -> Void
|
||||
* - registryName (String) : object type action|type
|
||||
* - value (string) : keyword
|
||||
* - object (Object|Function) : handler
|
||||
*
|
||||
* Register handlers
|
||||
**/
|
||||
ActionContainer.prototype.register = function (registryName, value, object) {
|
||||
this._registries[registryName] = this._registries[registryName] || {};
|
||||
this._registries[registryName][value] = object;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._registryGet = function (registryName, value, defaultValue) {
|
||||
if (3 > arguments.length) {
|
||||
defaultValue = null;
|
||||
}
|
||||
return this._registries[registryName][value] || defaultValue;
|
||||
};
|
||||
|
||||
//
|
||||
// Namespace default accessor methods
|
||||
//
|
||||
|
||||
/**
|
||||
* ActionContainer#setDefaults(options) -> Void
|
||||
* - options (object):hash of options see [[Action.new]]
|
||||
*
|
||||
* Set defaults
|
||||
**/
|
||||
ActionContainer.prototype.setDefaults = function (options) {
|
||||
options = options || {};
|
||||
for (var property in options) {
|
||||
this._defaults[property] = options[property];
|
||||
}
|
||||
|
||||
// if these defaults match any existing arguments, replace the previous
|
||||
// default on the object with the new one
|
||||
this._actions.forEach(function (action) {
|
||||
if (action.dest in options) {
|
||||
action.defaultValue = options[action.dest];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* ActionContainer#getDefault(dest) -> Mixed
|
||||
* - dest (string): action destination
|
||||
*
|
||||
* Return action default value
|
||||
**/
|
||||
ActionContainer.prototype.getDefault = function (dest) {
|
||||
var result = (_.has(this._defaults, dest)) ? this._defaults[dest] : null;
|
||||
|
||||
this._actions.forEach(function (action) {
|
||||
if (action.dest === dest && _.has(action, 'defaultValue')) {
|
||||
result = action.defaultValue;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
//
|
||||
// Adding argument actions
|
||||
//
|
||||
|
||||
/**
|
||||
* ActionContainer#addArgument(args, options) -> Object
|
||||
* - args (Array): array of argument keys
|
||||
* - options (Object): action objects see [[Action.new]]
|
||||
*
|
||||
* #### Examples
|
||||
* - addArgument([-f, --foo], {action:'store', defaultValue=1, ...})
|
||||
* - addArgument(['bar'], action: 'store', nargs:1, ...})
|
||||
**/
|
||||
ActionContainer.prototype.addArgument = function (args, options) {
|
||||
args = args;
|
||||
options = options || {};
|
||||
|
||||
if (!_.isArray(args)) {
|
||||
throw new TypeError('addArgument first argument should be an array');
|
||||
}
|
||||
if (!_.isObject(options) || _.isArray(options)) {
|
||||
throw new TypeError('addArgument second argument should be a hash');
|
||||
}
|
||||
|
||||
// if no positional args are supplied or only one is supplied and
|
||||
// it doesn't look like an option string, parse a positional argument
|
||||
if (!args || args.length === 1 && this.prefixChars.indexOf(args[0][0]) < 0) {
|
||||
if (args && !!options.dest) {
|
||||
throw new Error('dest supplied twice for positional argument');
|
||||
}
|
||||
options = this._getPositional(args, options);
|
||||
|
||||
// otherwise, we're adding an optional argument
|
||||
} else {
|
||||
options = this._getOptional(args, options);
|
||||
}
|
||||
|
||||
// if no default was supplied, use the parser-level default
|
||||
if (_.isUndefined(options.defaultValue)) {
|
||||
var dest = options.dest;
|
||||
if (_.has(this._defaults, dest)) {
|
||||
options.defaultValue = this._defaults[dest];
|
||||
} else if (!_.isUndefined(this.argumentDefault)) {
|
||||
options.defaultValue = this.argumentDefault;
|
||||
}
|
||||
}
|
||||
|
||||
// create the action object, and add it to the parser
|
||||
var ActionClass = this._popActionClass(options);
|
||||
if (! _.isFunction(ActionClass)) {
|
||||
throw new Error(format('Unknown action "%s".', ActionClass));
|
||||
}
|
||||
var action = new ActionClass(options);
|
||||
|
||||
// throw an error if the action type is not callable
|
||||
var typeFunction = this._registryGet('type', action.type, action.type);
|
||||
if (!_.isFunction(typeFunction)) {
|
||||
throw new Error(format('"%s" is not callable', typeFunction));
|
||||
}
|
||||
|
||||
return this._addAction(action);
|
||||
};
|
||||
|
||||
/**
|
||||
* ActionContainer#addArgumentGroup(options) -> ArgumentGroup
|
||||
* - options (Object): hash of options see [[ArgumentGroup.new]]
|
||||
*
|
||||
* Create new arguments groups
|
||||
**/
|
||||
ActionContainer.prototype.addArgumentGroup = function (options) {
|
||||
var group = new ArgumentGroup(this, options);
|
||||
this._actionGroups.push(group);
|
||||
return group;
|
||||
};
|
||||
|
||||
/**
|
||||
* ActionContainer#addMutuallyExclusiveGroup(options) -> ArgumentGroup
|
||||
* - options (Object): {required: false}
|
||||
*
|
||||
* Create new mutual exclusive groups
|
||||
**/
|
||||
ActionContainer.prototype.addMutuallyExclusiveGroup = function (options) {
|
||||
var group = new MutuallyExclusiveGroup(this, options);
|
||||
this._mutuallyExclusiveGroups.push(group);
|
||||
return group;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._addAction = function (action) {
|
||||
var self = this;
|
||||
|
||||
// resolve any conflicts
|
||||
this._checkConflict(action);
|
||||
|
||||
// add to actions list
|
||||
this._actions.push(action);
|
||||
action.container = this;
|
||||
|
||||
// index the action by any option strings it has
|
||||
action.optionStrings.forEach(function (optionString) {
|
||||
self._optionStringActions[optionString] = action;
|
||||
});
|
||||
|
||||
// set the flag if any option strings look like negative numbers
|
||||
action.optionStrings.forEach(function (optionString) {
|
||||
if (optionString.match(self._regexpNegativeNumber)) {
|
||||
if (!_.any(self._hasNegativeNumberOptionals)) {
|
||||
self._hasNegativeNumberOptionals.push(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// return the created action
|
||||
return action;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._removeAction = function (action) {
|
||||
var actionIndex = this._actions.indexOf(action);
|
||||
if (actionIndex >= 0) {
|
||||
this._actions.splice(actionIndex, 1);
|
||||
}
|
||||
};
|
||||
|
||||
ActionContainer.prototype._addContainerActions = function (container) {
|
||||
// collect groups by titles
|
||||
var titleGroupMap = {};
|
||||
this._actionGroups.forEach(function (group) {
|
||||
if (titleGroupMap[group.title]) {
|
||||
throw new Error(format('Cannot merge actions - two groups are named "%s".', group.title));
|
||||
}
|
||||
titleGroupMap[group.title] = group;
|
||||
});
|
||||
|
||||
// map each action to its group
|
||||
var groupMap = {};
|
||||
function actionHash(action) {
|
||||
// unique (hopefully?) string suitable as dictionary key
|
||||
return action.getName();
|
||||
}
|
||||
container._actionGroups.forEach(function (group) {
|
||||
// if a group with the title exists, use that, otherwise
|
||||
// create a new group matching the container's group
|
||||
if (!titleGroupMap[group.title]) {
|
||||
titleGroupMap[group.title] = this.addArgumentGroup({
|
||||
title: group.title,
|
||||
description: group.description
|
||||
});
|
||||
}
|
||||
|
||||
// map the actions to their new group
|
||||
group._groupActions.forEach(function (action) {
|
||||
groupMap[actionHash(action)] = titleGroupMap[group.title];
|
||||
});
|
||||
}, this);
|
||||
|
||||
// add container's mutually exclusive groups
|
||||
// NOTE: if add_mutually_exclusive_group ever gains title= and
|
||||
// description= then this code will need to be expanded as above
|
||||
var mutexGroup;
|
||||
container._mutuallyExclusiveGroups.forEach(function (group) {
|
||||
mutexGroup = this.addMutuallyExclusiveGroup({
|
||||
required: group.required
|
||||
});
|
||||
// map the actions to their new mutex group
|
||||
group._groupActions.forEach(function (action) {
|
||||
groupMap[actionHash(action)] = mutexGroup;
|
||||
});
|
||||
}, this); // forEach takes a 'this' argument
|
||||
|
||||
// add all actions to this container or their group
|
||||
container._actions.forEach(function (action) {
|
||||
var key = actionHash(action);
|
||||
if (!!groupMap[key]) {
|
||||
groupMap[key]._addAction(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._addAction(action);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
ActionContainer.prototype._getPositional = function (dest, options) {
|
||||
if (_.isArray(dest)) {
|
||||
dest = _.first(dest);
|
||||
}
|
||||
// make sure required is not specified
|
||||
if (options.required) {
|
||||
throw new Error('"required" is an invalid argument for positionals.');
|
||||
}
|
||||
|
||||
// mark positional arguments as required if at least one is
|
||||
// always required
|
||||
if (options.nargs !== $$.OPTIONAL && options.nargs !== $$.ZERO_OR_MORE) {
|
||||
options.required = true;
|
||||
}
|
||||
if (options.nargs === $$.ZERO_OR_MORE && options.defaultValue === undefined) {
|
||||
options.required = true;
|
||||
}
|
||||
|
||||
// return the keyword arguments with no option strings
|
||||
options.dest = dest;
|
||||
options.optionStrings = [];
|
||||
return options;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._getOptional = function (args, options) {
|
||||
var prefixChars = this.prefixChars;
|
||||
var optionStrings = [];
|
||||
var optionStringsLong = [];
|
||||
|
||||
// determine short and long option strings
|
||||
args.forEach(function (optionString) {
|
||||
// error on strings that don't start with an appropriate prefix
|
||||
if (prefixChars.indexOf(optionString[0]) < 0) {
|
||||
throw new Error(format('Invalid option string "%s": must start with a "%s".',
|
||||
optionString,
|
||||
prefixChars
|
||||
));
|
||||
}
|
||||
|
||||
// strings starting with two prefix characters are long options
|
||||
optionStrings.push(optionString);
|
||||
if (optionString.length > 1 && prefixChars.indexOf(optionString[1]) >= 0) {
|
||||
optionStringsLong.push(optionString);
|
||||
}
|
||||
});
|
||||
|
||||
// infer dest, '--foo-bar' -> 'foo_bar' and '-x' -> 'x'
|
||||
var dest = options.dest || null;
|
||||
delete options.dest;
|
||||
|
||||
if (!dest) {
|
||||
var optionStringDest = optionStringsLong.length ? optionStringsLong[0] :optionStrings[0];
|
||||
dest = _.str.strip(optionStringDest, this.prefixChars);
|
||||
|
||||
if (dest.length === 0) {
|
||||
throw new Error(
|
||||
format('dest= is required for options like "%s"', optionStrings.join(', '))
|
||||
);
|
||||
}
|
||||
dest = dest.replace(/-/g, '_');
|
||||
}
|
||||
|
||||
// return the updated keyword arguments
|
||||
options.dest = dest;
|
||||
options.optionStrings = optionStrings;
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._popActionClass = function (options, defaultValue) {
|
||||
defaultValue = defaultValue || null;
|
||||
|
||||
var action = (options.action || defaultValue);
|
||||
delete options.action;
|
||||
|
||||
var actionClass = this._registryGet('action', action, action);
|
||||
return actionClass;
|
||||
};
|
||||
|
||||
ActionContainer.prototype._getHandler = function () {
|
||||
var handlerString = this.conflictHandler;
|
||||
var handlerFuncName = "_handleConflict" + _.str.capitalize(handlerString);
|
||||
var func = this[handlerFuncName];
|
||||
if (typeof func === 'undefined') {
|
||||
var msg = "invalid conflict resolution value: " + handlerString;
|
||||
throw new Error(msg);
|
||||
} else {
|
||||
return func;
|
||||
}
|
||||
};
|
||||
|
||||
ActionContainer.prototype._checkConflict = function (action) {
|
||||
var optionStringActions = this._optionStringActions;
|
||||
var conflictOptionals = [];
|
||||
|
||||
// find all options that conflict with this option
|
||||
// collect pairs, the string, and an existing action that it conflicts with
|
||||
action.optionStrings.forEach(function (optionString) {
|
||||
var conflOptional = optionStringActions[optionString];
|
||||
if (typeof conflOptional !== 'undefined') {
|
||||
conflictOptionals.push([optionString, conflOptional]);
|
||||
}
|
||||
});
|
||||
|
||||
if (conflictOptionals.length > 0) {
|
||||
var conflictHandler = this._getHandler();
|
||||
conflictHandler.call(this, action, conflictOptionals);
|
||||
}
|
||||
};
|
||||
|
||||
ActionContainer.prototype._handleConflictError = function (action, conflOptionals) {
|
||||
var conflicts = _.map(conflOptionals, function (pair) {return pair[0]; });
|
||||
conflicts = conflicts.join(', ');
|
||||
throw argumentErrorHelper(
|
||||
action,
|
||||
format('Conflicting option string(s): %s', conflicts)
|
||||
);
|
||||
};
|
||||
|
||||
ActionContainer.prototype._handleConflictResolve = function (action, conflOptionals) {
|
||||
// remove all conflicting options
|
||||
var self = this;
|
||||
conflOptionals.forEach(function (pair) {
|
||||
var optionString = pair[0];
|
||||
var conflictingAction = pair[1];
|
||||
// remove the conflicting option string
|
||||
var i = conflictingAction.optionStrings.indexOf(optionString);
|
||||
if (i >= 0) {
|
||||
conflictingAction.optionStrings.splice(i, 1);
|
||||
}
|
||||
delete self._optionStringActions[optionString];
|
||||
// if the option now has no option string, remove it from the
|
||||
// container holding it
|
||||
if (conflictingAction.optionStrings.length === 0) {
|
||||
conflictingAction.container._removeAction(conflictingAction);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports.ArgumentParser = require('./argument_parser.js');
|
||||
module.exports.Namespace = require('./namespace');
|
||||
module.exports.Action = require('./action');
|
||||
module.exports.HelpFormatter = require('./help/formatter.js');
|
||||
module.exports.Const = require('./const.js');
|
||||
|
||||
module.exports.ArgumentDefaultsHelpFormatter =
|
||||
require('./help/added_formatters.js').ArgumentDefaultsHelpFormatter;
|
||||
module.exports.RawDescriptionHelpFormatter =
|
||||
require('./help/added_formatters.js').RawDescriptionHelpFormatter;
|
||||
module.exports.RawTextHelpFormatter =
|
||||
require('./help/added_formatters.js').RawTextHelpFormatter;
|
50
support/process/node_modules/yamljs/node_modules/argparse/lib/argument/error.js
generated
vendored
50
support/process/node_modules/yamljs/node_modules/argparse/lib/argument/error.js
generated
vendored
|
@ -1,50 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
var format = require('util').format;
|
||||
|
||||
|
||||
var ERR_CODE = 'ARGError';
|
||||
|
||||
/*:nodoc:*
|
||||
* argumentError(argument, message) -> TypeError
|
||||
* - argument (Object): action with broken argument
|
||||
* - message (String): error message
|
||||
*
|
||||
* Error format helper. An error from creating or using an argument
|
||||
* (optional or positional). The string value of this exception
|
||||
* is the message, augmented with information
|
||||
* about the argument that caused it.
|
||||
*
|
||||
* #####Example
|
||||
*
|
||||
* var argumentErrorHelper = require('./argument/error');
|
||||
* if (conflictOptionals.length > 0) {
|
||||
* throw argumentErrorHelper(
|
||||
* action,
|
||||
* format('Conflicting option string(s): %s', conflictOptionals.join(', '))
|
||||
* );
|
||||
* }
|
||||
*
|
||||
**/
|
||||
module.exports = function (argument, message) {
|
||||
var argumentName = null;
|
||||
var errMessage;
|
||||
var err;
|
||||
|
||||
if (argument.getName) {
|
||||
argumentName = argument.getName();
|
||||
} else {
|
||||
argumentName = '' + argument;
|
||||
}
|
||||
|
||||
if (!argumentName) {
|
||||
errMessage = message;
|
||||
} else {
|
||||
errMessage = format('argument "%s": %s', argumentName, message);
|
||||
}
|
||||
|
||||
err = new TypeError(errMessage);
|
||||
err.code = ERR_CODE;
|
||||
return err;
|
||||
};
|
54
support/process/node_modules/yamljs/node_modules/argparse/lib/argument/exclusive.js
generated
vendored
54
support/process/node_modules/yamljs/node_modules/argparse/lib/argument/exclusive.js
generated
vendored
|
@ -1,54 +0,0 @@
|
|||
/** internal
|
||||
* class MutuallyExclusiveGroup
|
||||
*
|
||||
* Group arguments.
|
||||
* By default, ArgumentParser groups command-line arguments
|
||||
* into “positional arguments” and “optional arguments”
|
||||
* when displaying help messages. When there is a better
|
||||
* conceptual grouping of arguments than this default one,
|
||||
* appropriate groups can be created using the addArgumentGroup() method
|
||||
*
|
||||
* This class inherited from [[ArgumentContainer]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var ArgumentGroup = require('./group');
|
||||
|
||||
/**
|
||||
* new MutuallyExclusiveGroup(container, options)
|
||||
* - container (object): main container
|
||||
* - options (object): options.required -> true/false
|
||||
*
|
||||
* `required` could be an argument itself, but making it a property of
|
||||
* the options argument is more consistent with the JS adaptation of the Python)
|
||||
**/
|
||||
var MutuallyExclusiveGroup = module.exports = function MutuallyExclusiveGroup(container, options) {
|
||||
var required;
|
||||
options = options || {};
|
||||
required = options.required || false;
|
||||
ArgumentGroup.call(this, container);
|
||||
this.required = required;
|
||||
|
||||
};
|
||||
util.inherits(MutuallyExclusiveGroup, ArgumentGroup);
|
||||
|
||||
|
||||
MutuallyExclusiveGroup.prototype._addAction = function (action) {
|
||||
var msg;
|
||||
if (action.required) {
|
||||
msg = 'mutually exclusive arguments must be optional';
|
||||
throw new Error(msg);
|
||||
}
|
||||
action = this._container._addAction(action);
|
||||
this._groupActions.push(action);
|
||||
return action;
|
||||
};
|
||||
|
||||
|
||||
MutuallyExclusiveGroup.prototype._removeAction = function (action) {
|
||||
this._container._removeAction(action);
|
||||
this._groupActions.remove(action);
|
||||
};
|
||||
|
75
support/process/node_modules/yamljs/node_modules/argparse/lib/argument/group.js
generated
vendored
75
support/process/node_modules/yamljs/node_modules/argparse/lib/argument/group.js
generated
vendored
|
@ -1,75 +0,0 @@
|
|||
/** internal
|
||||
* class ArgumentGroup
|
||||
*
|
||||
* Group arguments.
|
||||
* By default, ArgumentParser groups command-line arguments
|
||||
* into “positional arguments” and “optional arguments”
|
||||
* when displaying help messages. When there is a better
|
||||
* conceptual grouping of arguments than this default one,
|
||||
* appropriate groups can be created using the addArgumentGroup() method
|
||||
*
|
||||
* This class inherited from [[ArgumentContainer]]
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var ActionContainer = require('../action_container');
|
||||
|
||||
|
||||
/**
|
||||
* new ArgumentGroup(container, options)
|
||||
* - container (object): main container
|
||||
* - options (object): hash of group options
|
||||
*
|
||||
* #### options
|
||||
* - **prefixChars** group name prefix
|
||||
* - **argumentDefault** default argument value
|
||||
* - **title** group title
|
||||
* - **description** group description
|
||||
*
|
||||
**/
|
||||
var ArgumentGroup = module.exports = function ArgumentGroup(container, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// add any missing keyword arguments by checking the container
|
||||
options.conflictHandler = (options.conflictHandler || container.conflictHandler);
|
||||
options.prefixChars = (options.prefixChars || container.prefixChars);
|
||||
options.argumentDefault = (options.argumentDefault || container.argumentDefault);
|
||||
|
||||
ActionContainer.call(this, options);
|
||||
|
||||
// group attributes
|
||||
this.title = options.title;
|
||||
this._groupActions = [];
|
||||
|
||||
// share most attributes with the container
|
||||
this._container = container;
|
||||
this._registries = container._registries;
|
||||
this._actions = container._actions;
|
||||
this._optionStringActions = container._optionStringActions;
|
||||
this._defaults = container._defaults;
|
||||
this._hasNegativeNumberOptionals = container._hasNegativeNumberOptionals;
|
||||
this._mutuallyExclusiveGroups = container._mutuallyExclusiveGroups;
|
||||
};
|
||||
util.inherits(ArgumentGroup, ActionContainer);
|
||||
|
||||
|
||||
ArgumentGroup.prototype._addAction = function (action) {
|
||||
// Parent add action
|
||||
action = ActionContainer.prototype._addAction.call(this, action);
|
||||
this._groupActions.push(action);
|
||||
return action;
|
||||
};
|
||||
|
||||
|
||||
ArgumentGroup.prototype._removeAction = function (action) {
|
||||
// Parent remove action
|
||||
ActionContainer.prototype._removeAction.call(this, action);
|
||||
var actionIndex = this._groupActions.indexOf(action);
|
||||
if (actionIndex >= 0) {
|
||||
this._groupActions.splice(actionIndex, 1);
|
||||
}
|
||||
};
|
||||
|
1165
support/process/node_modules/yamljs/node_modules/argparse/lib/argument_parser.js
generated
vendored
1165
support/process/node_modules/yamljs/node_modules/argparse/lib/argument_parser.js
generated
vendored
File diff suppressed because it is too large
Load Diff
|
@ -1,18 +0,0 @@
|
|||
//
|
||||
// Constants
|
||||
//
|
||||
module.exports.EOL = '\n';
|
||||
|
||||
module.exports.SUPPRESS = '==SUPPRESS==';
|
||||
|
||||
module.exports.OPTIONAL = '?';
|
||||
|
||||
module.exports.ZERO_OR_MORE = '*';
|
||||
|
||||
module.exports.ONE_OR_MORE = '+';
|
||||
|
||||
module.exports.PARSER = 'A...';
|
||||
|
||||
module.exports.REMAINDER = '...';
|
||||
|
||||
module.exports._UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args';
|
88
support/process/node_modules/yamljs/node_modules/argparse/lib/help/added_formatters.js
generated
vendored
88
support/process/node_modules/yamljs/node_modules/argparse/lib/help/added_formatters.js
generated
vendored
|
@ -1,88 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var _ = require('underscore');
|
||||
_.str = require('underscore.string');
|
||||
|
||||
// Constants
|
||||
var $$ = require('../const');
|
||||
|
||||
var HelpFormatter = require('./formatter.js');
|
||||
|
||||
/**
|
||||
* new RawDescriptionHelpFormatter(options)
|
||||
* new ArgumentParser({formatterClass: argparse.RawDescriptionHelpFormatter, ...})
|
||||
*
|
||||
* Help message formatter which adds default values to argument help.
|
||||
*
|
||||
* Only the name of this class is considered a public API. All the methods
|
||||
* provided by the class are considered an implementation detail.
|
||||
**/
|
||||
|
||||
var ArgumentDefaultsHelpFormatter = function ArgumentDefaultsHelpFormatter(options) {
|
||||
HelpFormatter.call(this, options);
|
||||
};
|
||||
|
||||
util.inherits(ArgumentDefaultsHelpFormatter, HelpFormatter);
|
||||
|
||||
ArgumentDefaultsHelpFormatter.prototype._getHelpString = function (action) {
|
||||
var help = action.help;
|
||||
if (action.help.indexOf('%(defaultValue)s') === -1) {
|
||||
if (action.defaultValue !== $$.SUPPRESS) {
|
||||
var defaulting_nargs = [$$.OPTIONAL, $$.ZERO_OR_MORE];
|
||||
if (action.isOptional() || (defaulting_nargs.indexOf(action.nargs) >= 0)) {
|
||||
help += ' (default: %(defaultValue)s)';
|
||||
}
|
||||
}
|
||||
}
|
||||
return help;
|
||||
};
|
||||
|
||||
module.exports.ArgumentDefaultsHelpFormatter = ArgumentDefaultsHelpFormatter;
|
||||
|
||||
/**
|
||||
* new RawDescriptionHelpFormatter(options)
|
||||
* new ArgumentParser({formatterClass: argparse.RawDescriptionHelpFormatter, ...})
|
||||
*
|
||||
* Help message formatter which retains any formatting in descriptions.
|
||||
*
|
||||
* Only the name of this class is considered a public API. All the methods
|
||||
* provided by the class are considered an implementation detail.
|
||||
**/
|
||||
|
||||
var RawDescriptionHelpFormatter = function RawDescriptionHelpFormatter(options) {
|
||||
HelpFormatter.call(this, options);
|
||||
};
|
||||
|
||||
util.inherits(RawDescriptionHelpFormatter, HelpFormatter);
|
||||
|
||||
RawDescriptionHelpFormatter.prototype._fillText = function (text, width, indent) {
|
||||
var lines = text.split('\n');
|
||||
lines = lines.map(function (line) {
|
||||
return _.str.rtrim(indent + line);
|
||||
});
|
||||
return lines.join('\n');
|
||||
};
|
||||
module.exports.RawDescriptionHelpFormatter = RawDescriptionHelpFormatter;
|
||||
|
||||
/**
|
||||
* new RawTextHelpFormatter(options)
|
||||
* new ArgumentParser({formatterClass: argparse.RawTextHelpFormatter, ...})
|
||||
*
|
||||
* Help message formatter which retains formatting of all help text.
|
||||
*
|
||||
* Only the name of this class is considered a public API. All the methods
|
||||
* provided by the class are considered an implementation detail.
|
||||
**/
|
||||
|
||||
var RawTextHelpFormatter = function RawTextHelpFormatter(options) {
|
||||
RawDescriptionHelpFormatter.call(this, options);
|
||||
};
|
||||
|
||||
util.inherits(RawTextHelpFormatter, RawDescriptionHelpFormatter);
|
||||
|
||||
RawTextHelpFormatter.prototype._splitLines = function (text) {
|
||||
return text.split('\n');
|
||||
};
|
||||
|
||||
module.exports.RawTextHelpFormatter = RawTextHelpFormatter;
|
803
support/process/node_modules/yamljs/node_modules/argparse/lib/help/formatter.js
generated
vendored
803
support/process/node_modules/yamljs/node_modules/argparse/lib/help/formatter.js
generated
vendored
|
@ -1,803 +0,0 @@
|
|||
/**
|
||||
* class HelpFormatter
|
||||
*
|
||||
* Formatter for generating usage messages and argument help strings. Only the
|
||||
* name of this class is considered a public API. All the methods provided by
|
||||
* the class are considered an implementation detail.
|
||||
*
|
||||
* Do not call in your code, use this class only for inherits your own forvatter
|
||||
*
|
||||
* ToDo add [additonal formatters][1]
|
||||
*
|
||||
* [1]:http://docs.python.org/dev/library/argparse.html#formatter-class
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
_.str = require('underscore.string');
|
||||
|
||||
// Constants
|
||||
var $$ = require('../const');
|
||||
|
||||
|
||||
/*:nodoc:* internal
|
||||
* new Support(parent, heding)
|
||||
* - parent (object): parent section
|
||||
* - heading (string): header string
|
||||
*
|
||||
**/
|
||||
function Section(parent, heading) {
|
||||
this._parent = parent;
|
||||
this._heading = heading;
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
/*:nodoc:* internal
|
||||
* Section#addItem(callback) -> Void
|
||||
* - callback (array): tuple with function and args
|
||||
*
|
||||
* Add function for single element
|
||||
**/
|
||||
Section.prototype.addItem = function (callback) {
|
||||
this._items.push(callback);
|
||||
};
|
||||
|
||||
/*:nodoc:* internal
|
||||
* Section#formatHelp(formatter) -> string
|
||||
* - formatter (HelpFormatter): current formatter
|
||||
*
|
||||
* Form help section string
|
||||
*
|
||||
**/
|
||||
Section.prototype.formatHelp = function (formatter) {
|
||||
var itemHelp, heading;
|
||||
|
||||
// format the indented section
|
||||
if (!!this._parent) {
|
||||
formatter._indent();
|
||||
}
|
||||
|
||||
itemHelp = this._items.map(function (item) {
|
||||
var obj, func, args;
|
||||
|
||||
obj = formatter;
|
||||
func = item[0];
|
||||
args = item[1];
|
||||
return func.apply(obj, args);
|
||||
});
|
||||
itemHelp = formatter._joinParts(itemHelp);
|
||||
|
||||
if (!!this._parent) {
|
||||
formatter._dedent();
|
||||
}
|
||||
|
||||
// return nothing if the section was empty
|
||||
if (!itemHelp) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// add the heading if the section was non-empty
|
||||
heading = '';
|
||||
if (!!this._heading && this._heading !== $$.SUPPRESS) {
|
||||
var currentIndent = formatter.currentIndent;
|
||||
heading = _.str.repeat(' ', currentIndent) + this._heading + ':' + $$.EOL;
|
||||
}
|
||||
|
||||
// join the section-initialize newline, the heading and the help
|
||||
return formatter._joinParts([$$.EOL, heading, itemHelp, $$.EOL]);
|
||||
};
|
||||
|
||||
/**
|
||||
* new HelpFormatter(options)
|
||||
*
|
||||
* #### Options:
|
||||
* - `prog`: program name
|
||||
* - `indentIncriment`: indent step, default value 2
|
||||
* - `maxHelpPosition`: max help position, default value = 24
|
||||
* - `width`: line width
|
||||
*
|
||||
**/
|
||||
var HelpFormatter = module.exports = function HelpFormatter(options) {
|
||||
options = options || {};
|
||||
|
||||
this._prog = options.prog;
|
||||
|
||||
this._maxHelpPosition = options.maxHelpPosition || 24;
|
||||
this._width = (options.width || ((process.env.COLUMNS || 80) - 2));
|
||||
|
||||
this._currentIndent = 0;
|
||||
this._indentIncriment = options.indentIncriment || 2;
|
||||
this._level = 0;
|
||||
this._actionMaxLength = 0;
|
||||
|
||||
this._rootSection = new Section(null);
|
||||
this._currentSection = this._rootSection;
|
||||
|
||||
this._whitespaceMatcher = new RegExp('\\s+', 'g');
|
||||
this._longBreakMatcher = new RegExp($$.EOL + $$.EOL + $$.EOL + '+', 'g');
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._indent = function () {
|
||||
this._currentIndent += this._indentIncriment;
|
||||
this._level += 1;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._dedent = function () {
|
||||
this._currentIndent -= this._indentIncriment;
|
||||
this._level -= 1;
|
||||
if (this._currentIndent < 0) {
|
||||
throw new Error('Indent decreased below 0.');
|
||||
}
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._addItem = function (func, args) {
|
||||
this._currentSection.addItem([func, args]);
|
||||
};
|
||||
|
||||
//
|
||||
// Message building methods
|
||||
//
|
||||
|
||||
/**
|
||||
* HelpFormatter#startSection(heading) -> Void
|
||||
* - heading (string): header string
|
||||
*
|
||||
* Start new help section
|
||||
*
|
||||
* See alse [code example][1]
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.startSection(actionGroup.title);
|
||||
* formatter.addText(actionGroup.description);
|
||||
* formatter.addArguments(actionGroup._groupActions);
|
||||
* formatter.endSection();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.startSection = function (heading) {
|
||||
this._indent();
|
||||
var section = new Section(this._currentSection, heading);
|
||||
var func = section.formatHelp.bind(section);
|
||||
this._addItem(func, [this]);
|
||||
this._currentSection = section;
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#endSection -> Void
|
||||
*
|
||||
* End help section
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.startSection(actionGroup.title);
|
||||
* formatter.addText(actionGroup.description);
|
||||
* formatter.addArguments(actionGroup._groupActions);
|
||||
* formatter.endSection();
|
||||
**/
|
||||
HelpFormatter.prototype.endSection = function () {
|
||||
this._currentSection = this._currentSection._parent;
|
||||
this._dedent();
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#addText(text) -> Void
|
||||
* - text (string): plain text
|
||||
*
|
||||
* Add plain text into current section
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.startSection(actionGroup.title);
|
||||
* formatter.addText(actionGroup.description);
|
||||
* formatter.addArguments(actionGroup._groupActions);
|
||||
* formatter.endSection();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.addText = function (text) {
|
||||
if (!!text && text !== $$.SUPPRESS) {
|
||||
this._addItem(this._formatText, [text]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#addUsage(usage, actions, groups, prefix) -> Void
|
||||
* - usage (string): usage text
|
||||
* - actions (array): actions list
|
||||
* - groups (array): groups list
|
||||
* - prefix (string): usage prefix
|
||||
*
|
||||
* Add usage data into current section
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.addUsage(this.usage, this._actions, []);
|
||||
* return formatter.formatHelp();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.addUsage = function (usage, actions, groups, prefix) {
|
||||
if (usage !== $$.SUPPRESS) {
|
||||
this._addItem(this._formatUsage, [usage, actions, groups, prefix]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#addArgument(action) -> Void
|
||||
* - action (object): action
|
||||
*
|
||||
* Add argument into current section
|
||||
*
|
||||
* Single variant of [[HelpFormatter#addArguments]]
|
||||
**/
|
||||
HelpFormatter.prototype.addArgument = function (action) {
|
||||
if (action.help !== $$.SUPPRESS) {
|
||||
var self = this;
|
||||
|
||||
// find all invocations
|
||||
var invocations = [this._formatActionInvocation(action)];
|
||||
var invocationLength = invocations[0].length;
|
||||
|
||||
var actionLength;
|
||||
|
||||
if (!!action._getSubactions) {
|
||||
this._indent();
|
||||
action._getSubactions().forEach(function (subaction) {
|
||||
|
||||
var invocationNew = self._formatActionInvocation(subaction);
|
||||
invocations.push(invocationNew);
|
||||
invocationLength = Math.max(invocationLength, invocationNew.length);
|
||||
|
||||
});
|
||||
this._dedent();
|
||||
}
|
||||
|
||||
// update the maximum item length
|
||||
actionLength = invocationLength + this._currentIndent;
|
||||
this._actionMaxLength = Math.max(this._actionMaxLength, actionLength);
|
||||
|
||||
// add the item to the list
|
||||
this._addItem(this._formatAction, [action]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HelpFormatter#addArguments(actions) -> Void
|
||||
* - actions (array): actions list
|
||||
*
|
||||
* Mass add arguments into current section
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.startSection(actionGroup.title);
|
||||
* formatter.addText(actionGroup.description);
|
||||
* formatter.addArguments(actionGroup._groupActions);
|
||||
* formatter.endSection();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.addArguments = function (actions) {
|
||||
var self = this;
|
||||
actions.forEach(function (action) {
|
||||
self.addArgument(action);
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Help-formatting methods
|
||||
//
|
||||
|
||||
/**
|
||||
* HelpFormatter#formatHelp -> string
|
||||
*
|
||||
* Format help
|
||||
*
|
||||
* ##### Example
|
||||
*
|
||||
* formatter.addText(this.epilog);
|
||||
* return formatter.formatHelp();
|
||||
*
|
||||
**/
|
||||
HelpFormatter.prototype.formatHelp = function () {
|
||||
var help = this._rootSection.formatHelp(this);
|
||||
if (help) {
|
||||
help = help.replace(this._longBreakMatcher, $$.EOL + $$.EOL);
|
||||
help = _.str.strip(help, $$.EOL) + $$.EOL;
|
||||
}
|
||||
return help;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._joinParts = function (partStrings) {
|
||||
return partStrings.filter(function (part) {
|
||||
return (!!part && part !== $$.SUPPRESS);
|
||||
}).join('');
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatUsage = function (usage, actions, groups, prefix) {
|
||||
if (!prefix && !_.isString(prefix)) {
|
||||
prefix = 'usage: ';
|
||||
}
|
||||
|
||||
actions = actions || [];
|
||||
groups = groups || [];
|
||||
|
||||
|
||||
// if usage is specified, use that
|
||||
if (usage) {
|
||||
usage = _.str.sprintf(usage, {prog: this._prog});
|
||||
|
||||
// if no optionals or positionals are available, usage is just prog
|
||||
} else if (!usage && actions.length === 0) {
|
||||
usage = this._prog;
|
||||
|
||||
// if optionals and positionals are available, calculate usage
|
||||
} else if (!usage) {
|
||||
var prog = this._prog;
|
||||
var optionals = [];
|
||||
var positionals = [];
|
||||
var actionUsage;
|
||||
var textWidth;
|
||||
|
||||
// split optionals from positionals
|
||||
actions.forEach(function (action) {
|
||||
if (action.isOptional()) {
|
||||
optionals.push(action);
|
||||
} else {
|
||||
positionals.push(action);
|
||||
}
|
||||
});
|
||||
|
||||
// build full usage string
|
||||
actionUsage = this._formatActionsUsage([].concat(optionals, positionals), groups);
|
||||
usage = [prog, actionUsage].join(' ');
|
||||
|
||||
// wrap the usage parts if it's too long
|
||||
textWidth = this._width - this._currentIndent;
|
||||
if ((prefix.length + usage.length) > textWidth) {
|
||||
|
||||
// break usage into wrappable parts
|
||||
var regexpPart = new RegExp('\\(.*?\\)+|\\[.*?\\]+|\\S+', 'g');
|
||||
var optionalUsage = this._formatActionsUsage(optionals, groups);
|
||||
var positionalUsage = this._formatActionsUsage(positionals, groups);
|
||||
|
||||
|
||||
var optionalParts = optionalUsage.match(regexpPart);
|
||||
var positionalParts = positionalUsage.match(regexpPart) || [];
|
||||
|
||||
if (optionalParts.join(' ') !== optionalUsage) {
|
||||
throw new Error('assert "optionalParts.join(\' \') === optionalUsage"');
|
||||
}
|
||||
if (positionalParts.join(' ') !== positionalUsage) {
|
||||
throw new Error('assert "positionalParts.join(\' \') === positionalUsage"');
|
||||
}
|
||||
|
||||
// helper for wrapping lines
|
||||
var _getLines = function (parts, indent, prefix) {
|
||||
var lines = [];
|
||||
var line = [];
|
||||
|
||||
var lineLength = !!prefix ? prefix.length - 1: indent.length - 1;
|
||||
|
||||
parts.forEach(function (part) {
|
||||
if (lineLength + 1 + part.length > textWidth) {
|
||||
lines.push(indent + line.join(' '));
|
||||
line = [];
|
||||
lineLength = indent.length - 1;
|
||||
}
|
||||
line.push(part);
|
||||
lineLength += part.length + 1;
|
||||
});
|
||||
|
||||
if (line) {
|
||||
lines.push(indent + line.join(' '));
|
||||
}
|
||||
if (prefix) {
|
||||
lines[0] = lines[0].substr(indent.length);
|
||||
}
|
||||
return lines;
|
||||
};
|
||||
|
||||
var lines, indent, parts;
|
||||
// if prog is short, follow it with optionals or positionals
|
||||
if (prefix.length + prog.length <= 0.75 * textWidth) {
|
||||
indent = _.str.repeat(' ', (prefix.length + prog.length + 1));
|
||||
if (optionalParts) {
|
||||
lines = [].concat(
|
||||
_getLines([prog].concat(optionalParts), indent, prefix),
|
||||
_getLines(positionalParts, indent)
|
||||
);
|
||||
} else if (positionalParts) {
|
||||
lines = _getLines([prog].concat(positionalParts), indent, prefix);
|
||||
} else {
|
||||
lines = [prog];
|
||||
}
|
||||
|
||||
// if prog is long, put it on its own line
|
||||
} else {
|
||||
indent = _.str.repeat(' ', prefix.length);
|
||||
parts = optionalParts + positionalParts;
|
||||
lines = _getLines(parts, indent);
|
||||
if (lines.length > 1) {
|
||||
lines = [].concat(
|
||||
_getLines(optionalParts, indent),
|
||||
_getLines(positionalParts, indent)
|
||||
);
|
||||
}
|
||||
lines = [prog] + lines;
|
||||
}
|
||||
// join lines into usage
|
||||
usage = lines.join($$.EOL);
|
||||
}
|
||||
}
|
||||
|
||||
// prefix with 'usage:'
|
||||
return prefix + usage + $$.EOL + $$.EOL;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatActionsUsage = function (actions, groups) {
|
||||
// find group indices and identify actions in groups
|
||||
var groupActions = [];
|
||||
var inserts = [];
|
||||
var self = this;
|
||||
|
||||
groups.forEach(function (group) {
|
||||
var end;
|
||||
var i;
|
||||
|
||||
var start = actions.indexOf(group._groupActions[0]);
|
||||
if (start >= 0) {
|
||||
end = start + group._groupActions.length;
|
||||
|
||||
//if (actions.slice(start, end) === group._groupActions) {
|
||||
if (_.isEqual(actions.slice(start, end), group._groupActions)) {
|
||||
group._groupActions.forEach(function (action) {
|
||||
groupActions.push(action);
|
||||
});
|
||||
|
||||
if (!group.required) {
|
||||
if (!!inserts[start]) {
|
||||
inserts[start] += ' [';
|
||||
}
|
||||
else {
|
||||
inserts[start] = '[';
|
||||
}
|
||||
inserts[end] = ']';
|
||||
} else {
|
||||
if (!!inserts[start]) {
|
||||
inserts[start] += ' (';
|
||||
}
|
||||
else {
|
||||
inserts[start] = '(';
|
||||
}
|
||||
inserts[end] = ')';
|
||||
}
|
||||
for (i = start + 1; i < end; i += 1) {
|
||||
inserts[i] = '|';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// collect all actions format strings
|
||||
var parts = [];
|
||||
|
||||
actions.forEach(function (action, actionIndex) {
|
||||
var part;
|
||||
var optionString;
|
||||
var argsDefault;
|
||||
var argsString;
|
||||
|
||||
// suppressed arguments are marked with None
|
||||
// remove | separators for suppressed arguments
|
||||
if (action.help === $$.SUPPRESS) {
|
||||
parts.push(null);
|
||||
if (inserts[actionIndex] === '|') {
|
||||
inserts.splice(actionIndex, actionIndex);
|
||||
} else if (inserts[actionIndex + 1] === '|') {
|
||||
inserts.splice(actionIndex + 1, actionIndex + 1);
|
||||
}
|
||||
|
||||
// produce all arg strings
|
||||
} else if (!action.isOptional()) {
|
||||
part = self._formatArgs(action, action.dest);
|
||||
|
||||
// if it's in a group, strip the outer []
|
||||
if (groupActions.indexOf(action) >= 0) {
|
||||
if (part[0] === '[' && part[part.length - 1] === ']') {
|
||||
part = part.slice(1, -1);
|
||||
}
|
||||
}
|
||||
// add the action string to the list
|
||||
parts.push(part);
|
||||
|
||||
// produce the first way to invoke the option in brackets
|
||||
} else {
|
||||
optionString = action.optionStrings[0];
|
||||
|
||||
// if the Optional doesn't take a value, format is: -s or --long
|
||||
if (action.nargs === 0) {
|
||||
part = '' + optionString;
|
||||
|
||||
// if the Optional takes a value, format is: -s ARGS or --long ARGS
|
||||
} else {
|
||||
argsDefault = action.dest.toUpperCase();
|
||||
argsString = self._formatArgs(action, argsDefault);
|
||||
part = optionString + ' ' + argsString;
|
||||
}
|
||||
// make it look optional if it's not required or in a group
|
||||
if (!action.required && groupActions.indexOf(action) < 0) {
|
||||
part = '[' + part + ']';
|
||||
}
|
||||
// add the action string to the list
|
||||
parts.push(part);
|
||||
}
|
||||
});
|
||||
|
||||
// insert things at the necessary indices
|
||||
for (var i = inserts.length - 1; i >= 0; --i) {
|
||||
if (inserts[i] !== null) {
|
||||
parts.splice(i, 0, inserts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// join all the action items with spaces
|
||||
var text = parts.filter(function (part) {
|
||||
return !!part;
|
||||
}).join(' ');
|
||||
|
||||
// clean up separators for mutually exclusive groups
|
||||
text = text.replace(/([\[(]) /g, '$1'); // remove spaces
|
||||
text = text.replace(/ ([\])])/g, '$1');
|
||||
text = text.replace(/\[ *\]/g, ''); // remove empty groups
|
||||
text = text.replace(/\( *\)/g, '');
|
||||
text = text.replace(/\(([^|]*)\)/g, '$1'); // remove () from single action groups
|
||||
|
||||
text = _.str.strip(text);
|
||||
|
||||
// return the text
|
||||
return text;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatText = function (text) {
|
||||
text = _.str.sprintf(text, {prog: this._prog});
|
||||
var textWidth = this._width - this._currentIndent;
|
||||
var indentIncriment = _.str.repeat(' ', this._currentIndent);
|
||||
return this._fillText(text, textWidth, indentIncriment) + $$.EOL + $$.EOL;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatAction = function (action) {
|
||||
var self = this;
|
||||
|
||||
var helpText;
|
||||
var helpLines;
|
||||
var parts;
|
||||
var indentFirst;
|
||||
|
||||
// determine the required width and the entry label
|
||||
var helpPosition = Math.min(this._actionMaxLength + 2, this._maxHelpPosition);
|
||||
var helpWidth = this._width - helpPosition;
|
||||
var actionWidth = helpPosition - this._currentIndent - 2;
|
||||
var actionHeader = this._formatActionInvocation(action);
|
||||
|
||||
// no help; start on same line and add a final newline
|
||||
if (!action.help) {
|
||||
actionHeader = _.str.repeat(' ', this._currentIndent) + actionHeader + $$.EOL;
|
||||
|
||||
// short action name; start on the same line and pad two spaces
|
||||
} else if (actionHeader.length <= actionWidth) {
|
||||
actionHeader = _.str.repeat(' ', this._currentIndent) +
|
||||
actionHeader +
|
||||
' ' +
|
||||
_.str.repeat(' ', actionWidth - actionHeader.length);
|
||||
indentFirst = 0;
|
||||
|
||||
// long action name; start on the next line
|
||||
} else {
|
||||
actionHeader = _.str.repeat(' ', this._currentIndent) + actionHeader + $$.EOL;
|
||||
indentFirst = helpPosition;
|
||||
}
|
||||
|
||||
// collect the pieces of the action help
|
||||
parts = [actionHeader];
|
||||
|
||||
// if there was help for the action, add lines of help text
|
||||
if (!!action.help) {
|
||||
helpText = this._expandHelp(action);
|
||||
helpLines = this._splitLines(helpText, helpWidth);
|
||||
parts.push(_.str.repeat(' ', indentFirst) + helpLines[0] + $$.EOL);
|
||||
helpLines.slice(1).forEach(function (line) {
|
||||
parts.push(_.str.repeat(' ', helpPosition) + line + $$.EOL);
|
||||
});
|
||||
|
||||
// or add a newline if the description doesn't end with one
|
||||
} else if (actionHeader.charAt(actionHeader.length - 1) !== $$.EOL) {
|
||||
parts.push($$.EOL);
|
||||
}
|
||||
// if there are any sub-actions, add their help as well
|
||||
if (!!action._getSubactions) {
|
||||
this._indent();
|
||||
action._getSubactions().forEach(function (subaction) {
|
||||
parts.push(self._formatAction(subaction));
|
||||
});
|
||||
this._dedent();
|
||||
}
|
||||
// return a single string
|
||||
return this._joinParts(parts);
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatActionInvocation = function (action) {
|
||||
if (!action.isOptional()) {
|
||||
var format_func = this._metavarFormatter(action, action.dest);
|
||||
var metavars = format_func(1);
|
||||
return metavars[0];
|
||||
} else {
|
||||
var parts = [];
|
||||
var argsDefault;
|
||||
var argsString;
|
||||
|
||||
// if the Optional doesn't take a value, format is: -s, --long
|
||||
if (action.nargs === 0) {
|
||||
parts = parts.concat(action.optionStrings);
|
||||
|
||||
// if the Optional takes a value, format is: -s ARGS, --long ARGS
|
||||
} else {
|
||||
argsDefault = action.dest.toUpperCase();
|
||||
argsString = this._formatArgs(action, argsDefault);
|
||||
action.optionStrings.forEach(function (optionString) {
|
||||
parts.push(optionString + ' ' + argsString);
|
||||
});
|
||||
}
|
||||
return parts.join(', ');
|
||||
}
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._metavarFormatter = function (action, metavarDefault) {
|
||||
var result;
|
||||
|
||||
if (!!action.metavar || action.metavar === '') {
|
||||
result = action.metavar;
|
||||
} else if (!!action.choices) {
|
||||
var choices = action.choices;
|
||||
|
||||
if (_.isString(choices)) {
|
||||
choices = choices.split('').join(', ');
|
||||
} else if (_.isArray(choices)) {
|
||||
choices = choices.join(',');
|
||||
}
|
||||
else
|
||||
{
|
||||
choices = _.keys(choices).join(',');
|
||||
}
|
||||
result = '{' + choices + '}';
|
||||
} else {
|
||||
result = metavarDefault;
|
||||
}
|
||||
|
||||
return function (size) {
|
||||
if (Array.isArray(result)) {
|
||||
return result;
|
||||
} else {
|
||||
var metavars = [];
|
||||
for (var i = 0; i < size; i += 1) {
|
||||
metavars.push(result);
|
||||
}
|
||||
return metavars;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._formatArgs = function (action, metavarDefault) {
|
||||
var result;
|
||||
var metavars;
|
||||
|
||||
var buildMetavar = this._metavarFormatter(action, metavarDefault);
|
||||
|
||||
switch (action.nargs) {
|
||||
case undefined:
|
||||
case null:
|
||||
metavars = buildMetavar(1);
|
||||
result = '' + metavars[0];
|
||||
break;
|
||||
case $$.OPTIONAL:
|
||||
metavars = buildMetavar(1);
|
||||
result = '[' + metavars[0] + ']';
|
||||
break;
|
||||
case $$.ZERO_OR_MORE:
|
||||
metavars = buildMetavar(2);
|
||||
result = '[' + metavars[0] + ' [' + metavars[1] + ' ...]]';
|
||||
break;
|
||||
case $$.ONE_OR_MORE:
|
||||
metavars = buildMetavar(2);
|
||||
result = '' + metavars[0] + ' [' + metavars[1] + ' ...]';
|
||||
break;
|
||||
case $$.REMAINDER:
|
||||
result = '...';
|
||||
break;
|
||||
case $$.PARSER:
|
||||
metavars = buildMetavar(1);
|
||||
result = metavars[0] + ' ...';
|
||||
break;
|
||||
default:
|
||||
metavars = buildMetavar(action.nargs);
|
||||
result = metavars.join(' ');
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._expandHelp = function (action) {
|
||||
var actionProperty;
|
||||
var actionValue;
|
||||
|
||||
var params = {prog: this._prog};
|
||||
|
||||
for (actionProperty in action) {
|
||||
if (action.hasOwnProperty(actionProperty)) {
|
||||
actionValue = action[actionProperty];
|
||||
|
||||
if (actionValue !== $$.SUPPRESS) {
|
||||
params[actionProperty] = actionValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!!params.choices) {
|
||||
if (_.isString(params.choices)) {
|
||||
params.choices = params.choices.split('').join(', ');
|
||||
}
|
||||
else if (_.isArray(params.choices)) {
|
||||
params.choices = params.choices.join(', ');
|
||||
}
|
||||
else {
|
||||
params.choices = _.keys(params.choices).join(', ');
|
||||
}
|
||||
}
|
||||
|
||||
return _.str.sprintf(this._getHelpString(action), params);
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._splitLines = function (text, width) {
|
||||
var lines = [];
|
||||
var delimiters = [" ", ".", ",", "!", "?"];
|
||||
var re = new RegExp('[' + delimiters.join('') + '][^' + delimiters.join('') + ']*$');
|
||||
|
||||
text = text.replace(/[\n\|\t]/g, ' ');
|
||||
|
||||
text = _.str.strip(text);
|
||||
text = text.replace(this._whitespaceMatcher, ' ');
|
||||
|
||||
// Wraps the single paragraph in text (a string) so every line
|
||||
// is at most width characters long.
|
||||
text.split($$.EOL).forEach(function (line) {
|
||||
if (width >= line.length) {
|
||||
lines.push(line);
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapStart = 0;
|
||||
var wrapEnd = width;
|
||||
var delimiterIndex = 0;
|
||||
while (wrapEnd <= line.length) {
|
||||
if (wrapEnd !== line.length && delimiters.indexOf(line[wrapEnd] < -1)) {
|
||||
delimiterIndex = (re.exec(line.substring(wrapStart, wrapEnd)) || {}).index;
|
||||
wrapEnd = wrapStart + delimiterIndex + 1;
|
||||
}
|
||||
lines.push(line.substring(wrapStart, wrapEnd));
|
||||
wrapStart = wrapEnd;
|
||||
wrapEnd += width;
|
||||
}
|
||||
if (wrapStart < line.length) {
|
||||
lines.push(line.substring(wrapStart, wrapEnd));
|
||||
}
|
||||
});
|
||||
|
||||
return lines;
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._fillText = function (text, width, indent) {
|
||||
var lines = this._splitLines(text, width);
|
||||
lines = lines.map(function (line) {
|
||||
return indent + line;
|
||||
});
|
||||
return lines.join($$.EOL);
|
||||
};
|
||||
|
||||
HelpFormatter.prototype._getHelpString = function (action) {
|
||||
return action.help;
|
||||
};
|
|
@ -1,77 +0,0 @@
|
|||
/**
|
||||
* class Namespace
|
||||
*
|
||||
* Simple object for storing attributes. Implements equality by attribute names
|
||||
* and values, and provides a simple string representation.
|
||||
*
|
||||
* See also [original guide][1]
|
||||
*
|
||||
* [1]:http://docs.python.org/dev/library/argparse.html#the-namespace-object
|
||||
**/
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
|
||||
/**
|
||||
* new Namespace(options)
|
||||
* - options(object): predefined propertis for result object
|
||||
*
|
||||
**/
|
||||
var Namespace = module.exports = function Namespace(options) {
|
||||
_.extend(this, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Namespace#isset(key) -> Boolean
|
||||
* - key (string|number): property name
|
||||
*
|
||||
* Tells whenever `namespace` contains given `key` or not.
|
||||
**/
|
||||
Namespace.prototype.isset = function (key) {
|
||||
return _.has(this, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Namespace#set(key, value) -> self
|
||||
* -key (string|number|object): propery name
|
||||
* -value (mixed): new property value
|
||||
*
|
||||
* Set the property named key with value.
|
||||
* If key object then set all key properties to namespace object
|
||||
**/
|
||||
Namespace.prototype.set = function (key, value) {
|
||||
if (typeof (key) === 'object') {
|
||||
_.extend(this, key);
|
||||
} else {
|
||||
this[key] = value;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Namespace#get(key, defaultValue) -> mixed
|
||||
* - key (string|number): property name
|
||||
* - defaultValue (mixed): default value
|
||||
*
|
||||
* Return the property key or defaulValue if not set
|
||||
**/
|
||||
Namespace.prototype.get = function (key, defaultValue) {
|
||||
return !this[key] ? defaultValue: this[key];
|
||||
};
|
||||
|
||||
/**
|
||||
* Namespace#unset(key, defaultValue) -> mixed
|
||||
* - key (string|number): property name
|
||||
* - defaultValue (mixed): default value
|
||||
*
|
||||
* Return data[key](and delete it) or defaultValue
|
||||
**/
|
||||
Namespace.prototype.unset = function (key, defaultValue) {
|
||||
var value = this[key];
|
||||
if (value !== null) {
|
||||
delete this[key];
|
||||
return value;
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
language: ruby
|
||||
rvm:
|
||||
- 1.9.3
|
||||
|
||||
before_script:
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
- sleep 2
|
|
@ -1,4 +0,0 @@
|
|||
source :rubygems
|
||||
|
||||
gem 'uglifier'
|
||||
gem 'rake'
|
|
@ -1,17 +0,0 @@
|
|||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
execjs (1.4.0)
|
||||
multi_json (~> 1.0)
|
||||
multi_json (1.3.6)
|
||||
rake (0.9.2.2)
|
||||
uglifier (1.3.0)
|
||||
execjs (>= 0.3.0)
|
||||
multi_json (~> 1.0, >= 1.0.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
rake
|
||||
uglifier
|
|
@ -1,744 +0,0 @@
|
|||
# Underscore.string [![Build Status](https://secure.travis-ci.org/epeli/underscore.string.png?branch=master)](http://travis-ci.org/epeli/underscore.string) #
|
||||
|
||||
|
||||
|
||||
Javascript lacks complete string manipulation operations.
|
||||
This an attempt to fill that gap. List of build-in methods can be found
|
||||
for example from [Dive Into JavaScript][d].
|
||||
|
||||
[d]: http://www.diveintojavascript.com/core-javascript-reference/the-string-object
|
||||
|
||||
|
||||
As name states this an extension for [Underscore.js][u], but it can be used
|
||||
independently from **_s**-global variable. But with Underscore.js you can
|
||||
use Object-Oriented style and chaining:
|
||||
|
||||
[u]: http://documentcloud.github.com/underscore/
|
||||
|
||||
```javascript
|
||||
_(" epeli ").chain().trim().capitalize().value()
|
||||
=> "Epeli"
|
||||
```
|
||||
|
||||
## Download ##
|
||||
|
||||
* [Development version](https://raw.github.com/epeli/underscore.string/master/lib/underscore.string.js) *Uncompressed with Comments 18kb*
|
||||
* [Production version](https://github.com/epeli/underscore.string/raw/master/dist/underscore.string.min.js) *Minified 7kb*
|
||||
|
||||
|
||||
## Node.js installation ##
|
||||
|
||||
**npm package**
|
||||
|
||||
npm install underscore.string
|
||||
|
||||
**Standalone usage**:
|
||||
|
||||
```javascript
|
||||
var _s = require('underscore.string');
|
||||
```
|
||||
|
||||
**Integrate with Underscore.js**:
|
||||
|
||||
```javascript
|
||||
var _ = require('underscore');
|
||||
|
||||
// Import Underscore.string to separate object, because there are conflict functions (include, reverse, contains)
|
||||
_.str = require('underscore.string');
|
||||
|
||||
// Mix in non-conflict functions to Underscore namespace if you want
|
||||
_.mixin(_.str.exports());
|
||||
|
||||
// All functions, include conflict, will be available through _.str object
|
||||
_.str.include('Underscore.string', 'string'); // => true
|
||||
```
|
||||
|
||||
## String Functions ##
|
||||
|
||||
For availability of functions in this way you need to mix in Underscore.string functions:
|
||||
|
||||
```javascript
|
||||
_.mixin(_.string.exports());
|
||||
```
|
||||
|
||||
otherwise functions from examples will be available through _.string or _.str objects:
|
||||
|
||||
```javascript
|
||||
_.str.capitalize('epeli')
|
||||
=> "Epeli"
|
||||
```
|
||||
|
||||
**numberFormat** _.numberFormat(number, [ decimals=0, decimalSeparator='.', orderSeparator=','])
|
||||
|
||||
Formats the numbers.
|
||||
|
||||
```javascript
|
||||
_.numberFormat(1000, 2)
|
||||
=> "1,000.00"
|
||||
|
||||
_.numberFormat(123456789.123, 5, '.', ',')
|
||||
=> "123,456,789.12300"
|
||||
```
|
||||
|
||||
|
||||
**levenshtein** _.levenshtein(string1, string2)
|
||||
|
||||
Calculates [Levenshtein distance][ld] between two strings.
|
||||
[ld]: http://en.wikipedia.org/wiki/Levenshtein_distance
|
||||
|
||||
```javascript
|
||||
_.levenshtein('kitten', 'kittah')
|
||||
=> 2
|
||||
```
|
||||
|
||||
**capitalize** _.capitalize(string)
|
||||
|
||||
Converts first letter of the string to uppercase.
|
||||
|
||||
```javascript
|
||||
_.capitalize("foo Bar")
|
||||
=> "Foo Bar"
|
||||
```
|
||||
|
||||
**chop** _.chop(string, step)
|
||||
|
||||
```javascript
|
||||
_.chop('whitespace', 3)
|
||||
=> ['whi','tes','pac','e']
|
||||
```
|
||||
|
||||
**clean** _.clean(str)
|
||||
|
||||
Compress some whitespaces to one.
|
||||
|
||||
```javascript
|
||||
_.clean(" foo bar ")
|
||||
=> 'foo bar'
|
||||
```
|
||||
|
||||
**chars** _.chars(str)
|
||||
|
||||
```javascript
|
||||
_.chars('Hello')
|
||||
=> ['H','e','l','l','o']
|
||||
```
|
||||
|
||||
**swapCase** _.swapCase(str)
|
||||
|
||||
Returns a copy of the string in which all the case-based characters have had their case swapped.
|
||||
|
||||
```javascript
|
||||
_.swapCase('hELLO')
|
||||
=> 'Hello'
|
||||
```
|
||||
|
||||
**include** available only through _.str object, because Underscore has function with the same name.
|
||||
|
||||
```javascript
|
||||
_.str.include("foobar", "ob")
|
||||
=> true
|
||||
```
|
||||
|
||||
(removed) **includes** _.includes(string, substring)
|
||||
|
||||
Tests if string contains a substring.
|
||||
|
||||
```javascript
|
||||
_.includes("foobar", "ob")
|
||||
=> true
|
||||
```
|
||||
|
||||
**includes** function was removed
|
||||
|
||||
But you can create it in this way, for compatibility with previous versions:
|
||||
|
||||
```javascript
|
||||
_.includes = _.str.include
|
||||
```
|
||||
|
||||
**count** _.count(string, substring)
|
||||
|
||||
```javascript
|
||||
_('Hello world').count('l')
|
||||
=> 3
|
||||
```
|
||||
|
||||
**escapeHTML** _.escapeHTML(string)
|
||||
|
||||
Converts HTML special characters to their entity equivalents.
|
||||
|
||||
```javascript
|
||||
_('<div>Blah blah blah</div>').escapeHTML();
|
||||
=> '<div>Blah blah blah</div>'
|
||||
```
|
||||
|
||||
**unescapeHTML** _.unescapeHTML(string)
|
||||
|
||||
Converts entity characters to HTML equivalents.
|
||||
|
||||
```javascript
|
||||
_('<div>Blah blah blah</div>').unescapeHTML();
|
||||
=> '<div>Blah blah blah</div>'
|
||||
```
|
||||
|
||||
**insert** _.insert(string, index, substing)
|
||||
|
||||
```javascript
|
||||
_('Hello ').insert(6, 'world')
|
||||
=> 'Hello world'
|
||||
```
|
||||
|
||||
**isBlank** _.isBlank(string)
|
||||
|
||||
```javascript
|
||||
_('').isBlank(); // => true
|
||||
_('\n').isBlank(); // => true
|
||||
_(' ').isBlank(); // => true
|
||||
_('a').isBlank(); // => false
|
||||
```
|
||||
|
||||
**join** _.join(separator, *strings)
|
||||
|
||||
Joins strings together with given separator
|
||||
|
||||
```javascript
|
||||
_.join(" ", "foo", "bar")
|
||||
=> "foo bar"
|
||||
```
|
||||
|
||||
**lines** _.lines(str)
|
||||
|
||||
```javascript
|
||||
_.lines("Hello\nWorld")
|
||||
=> ["Hello", "World"]
|
||||
```
|
||||
|
||||
**reverse** available only through _.str object, because Underscore has function with the same name.
|
||||
|
||||
Return reversed string:
|
||||
|
||||
```javascript
|
||||
_.str.reverse("foobar")
|
||||
=> 'raboof'
|
||||
```
|
||||
|
||||
**splice** _.splice(string, index, howmany, substring)
|
||||
|
||||
Like a array splice.
|
||||
|
||||
```javascript
|
||||
_('https://edtsech@bitbucket.org/edtsech/underscore.strings').splice(30, 7, 'epeli')
|
||||
=> 'https://edtsech@bitbucket.org/epeli/underscore.strings'
|
||||
```
|
||||
|
||||
**startsWith** _.startsWith(string, starts)
|
||||
|
||||
This method checks whether string starts with starts.
|
||||
|
||||
```javascript
|
||||
_("image.gif").startsWith("image")
|
||||
=> true
|
||||
```
|
||||
|
||||
**endsWith** _.endsWith(string, ends)
|
||||
|
||||
This method checks whether string ends with ends.
|
||||
|
||||
```javascript
|
||||
_("image.gif").endsWith("gif")
|
||||
=> true
|
||||
```
|
||||
|
||||
**succ** _.succ(str)
|
||||
|
||||
Returns the successor to str.
|
||||
|
||||
```javascript
|
||||
_('a').succ()
|
||||
=> 'b'
|
||||
|
||||
_('A').succ()
|
||||
=> 'B'
|
||||
```
|
||||
|
||||
**supplant**
|
||||
|
||||
Supplant function was removed, use Underscore.js [template function][p].
|
||||
|
||||
[p]: http://documentcloud.github.com/underscore/#template
|
||||
|
||||
**strip** alias for *trim*
|
||||
|
||||
**lstrip** alias for *ltrim*
|
||||
|
||||
**rstrip** alias for *rtrim*
|
||||
|
||||
**titleize** _.titleize(string)
|
||||
|
||||
```javascript
|
||||
_('my name is epeli').titleize()
|
||||
=> 'My Name Is Epeli'
|
||||
```
|
||||
|
||||
**camelize** _.camelize(string)
|
||||
|
||||
Converts underscored or dasherized string to a camelized one
|
||||
|
||||
```javascript
|
||||
_('-moz-transform').camelize()
|
||||
=> 'MozTransform'
|
||||
```
|
||||
|
||||
**classify** _.classify(string)
|
||||
|
||||
Converts string to camelized class name
|
||||
|
||||
```javascript
|
||||
_('some_class_name').classify()
|
||||
=> 'SomeClassName'
|
||||
```
|
||||
|
||||
**underscored** _.underscored(string)
|
||||
|
||||
Converts a camelized or dasherized string into an underscored one
|
||||
|
||||
```javascript
|
||||
_('MozTransform').underscored()
|
||||
=> 'moz_transform'
|
||||
```
|
||||
|
||||
**dasherize** _.dasherize(string)
|
||||
|
||||
Converts a underscored or camelized string into an dasherized one
|
||||
|
||||
```javascript
|
||||
_('MozTransform').dasherize()
|
||||
=> '-moz-transform'
|
||||
```
|
||||
|
||||
**humanize** _.humanize(string)
|
||||
|
||||
Converts an underscored, camelized, or dasherized string into a humanized one.
|
||||
Also removes beginning and ending whitespace, and removes the postfix '_id'.
|
||||
|
||||
```javascript
|
||||
_(' capitalize dash-CamelCase_underscore trim ').humanize()
|
||||
=> 'Capitalize dash camel case underscore trim'
|
||||
```
|
||||
|
||||
**trim** _.trim(string, [characters])
|
||||
|
||||
trims defined characters from begining and ending of the string.
|
||||
Defaults to whitespace characters.
|
||||
|
||||
```javascript
|
||||
_.trim(" foobar ")
|
||||
=> "foobar"
|
||||
|
||||
_.trim("_-foobar-_", "_-")
|
||||
=> "foobar"
|
||||
```
|
||||
|
||||
|
||||
**ltrim** _.ltrim(string, [characters])
|
||||
|
||||
Left trim. Similar to trim, but only for left side.
|
||||
|
||||
|
||||
**rtrim** _.rtrim(string, [characters])
|
||||
|
||||
Right trim. Similar to trim, but only for right side.
|
||||
|
||||
**truncate** _.truncate(string, length, truncateString)
|
||||
|
||||
```javascript
|
||||
_('Hello world').truncate(5)
|
||||
=> 'Hello...'
|
||||
|
||||
_('Hello').truncate(10)
|
||||
=> 'Hello'
|
||||
```
|
||||
|
||||
**prune** _.prune(string, length, pruneString)
|
||||
|
||||
Elegant version of truncate.
|
||||
Makes sure the pruned string does not exceed the original length.
|
||||
Avoid half-chopped words when truncating.
|
||||
|
||||
```javascript
|
||||
_('Hello, world').prune(5)
|
||||
=> 'Hello...'
|
||||
|
||||
_('Hello, world').prune(8)
|
||||
=> 'Hello...'
|
||||
|
||||
_('Hello, world').prune(5, ' (read a lot more)')
|
||||
=> 'Hello, world' (as adding "(read a lot more)" would be longer than the original string)
|
||||
|
||||
_('Hello, cruel world').prune(15)
|
||||
=> 'Hello, cruel...'
|
||||
|
||||
_('Hello').prune(10)
|
||||
=> 'Hello'
|
||||
```
|
||||
|
||||
**words** _.words(str, delimiter=/\s+/)
|
||||
|
||||
Split string by delimiter (String or RegExp), /\s+/ by default.
|
||||
|
||||
```javascript
|
||||
_.words(" I love you ")
|
||||
=> ["I","love","you"]
|
||||
|
||||
_.words("I_love_you", "_")
|
||||
=> ["I","love","you"]
|
||||
|
||||
_.words("I-love-you", /-/)
|
||||
=> ["I","love","you"]
|
||||
|
||||
_.words(" ")
|
||||
=> []
|
||||
```
|
||||
|
||||
**sprintf** _.sprintf(string format, *arguments)
|
||||
|
||||
C like string formatting.
|
||||
Credits goes to [Alexandru Marasteanu][o].
|
||||
For more detailed documentation, see the [original page][o].
|
||||
|
||||
[o]: http://www.diveintojavascript.com/projects/sprintf-for-javascript
|
||||
|
||||
```javascript
|
||||
_.sprintf("%.1f", 1.17)
|
||||
"1.2"
|
||||
```
|
||||
|
||||
**pad** _.pad(str, length, [padStr, type])
|
||||
|
||||
pads the `str` with characters until the total string length is equal to the passed `length` parameter. By default, pads on the **left** with the space char (`" "`). `padStr` is truncated to a single character if necessary.
|
||||
|
||||
```javascript
|
||||
_.pad("1", 8)
|
||||
-> " 1";
|
||||
|
||||
_.pad("1", 8, '0')
|
||||
-> "00000001";
|
||||
|
||||
_.pad("1", 8, '0', 'right')
|
||||
-> "10000000";
|
||||
|
||||
_.pad("1", 8, '0', 'both')
|
||||
-> "00001000";
|
||||
|
||||
_.pad("1", 8, 'bleepblorp', 'both')
|
||||
-> "bbbb1bbb";
|
||||
```
|
||||
|
||||
**lpad** _.lpad(str, length, [padStr])
|
||||
|
||||
left-pad a string. Alias for `pad(str, length, padStr, 'left')`
|
||||
|
||||
```javascript
|
||||
_.lpad("1", 8, '0')
|
||||
-> "00000001";
|
||||
```
|
||||
|
||||
**rpad** _.rpad(str, length, [padStr])
|
||||
|
||||
right-pad a string. Alias for `pad(str, length, padStr, 'right')`
|
||||
|
||||
```javascript
|
||||
_.rpad("1", 8, '0')
|
||||
-> "10000000";
|
||||
```
|
||||
|
||||
**lrpad** _.lrpad(str, length, [padStr])
|
||||
|
||||
left/right-pad a string. Alias for `pad(str, length, padStr, 'both')`
|
||||
|
||||
```javascript
|
||||
_.lrpad("1", 8, '0')
|
||||
-> "00001000";
|
||||
```
|
||||
|
||||
**center** alias for **lrpad**
|
||||
|
||||
**ljust** alias for *rpad*
|
||||
|
||||
**rjust** alias for *lpad*
|
||||
|
||||
**toNumber** _.toNumber(string, [decimals])
|
||||
|
||||
Parse string to number. Returns NaN if string can't be parsed to number.
|
||||
|
||||
```javascript
|
||||
_('2.556').toNumber()
|
||||
=> 3
|
||||
|
||||
_('2.556').toNumber(1)
|
||||
=> 2.6
|
||||
```
|
||||
|
||||
**strRight** _.strRight(string, pattern)
|
||||
|
||||
Searches a string from left to right for a pattern and returns a substring consisting of the characters in the string that are to the right of the pattern or all string if no match found.
|
||||
|
||||
```javascript
|
||||
_('This_is_a_test_string').strRight('_')
|
||||
=> "is_a_test_string";
|
||||
```
|
||||
|
||||
**strRightBack** _.strRightBack(string, pattern)
|
||||
|
||||
Searches a string from right to left for a pattern and returns a substring consisting of the characters in the string that are to the right of the pattern or all string if no match found.
|
||||
|
||||
```javascript
|
||||
_('This_is_a_test_string').strRightBack('_')
|
||||
=> "string";
|
||||
```
|
||||
|
||||
**strLeft** _.strLeft(string, pattern)
|
||||
|
||||
Searches a string from left to right for a pattern and returns a substring consisting of the characters in the string that are to the left of the pattern or all string if no match found.
|
||||
|
||||
```javascript
|
||||
_('This_is_a_test_string').strLeft('_')
|
||||
=> "This";
|
||||
```
|
||||
|
||||
**strLeftBack** _.strLeftBack(string, pattern)
|
||||
|
||||
Searches a string from right to left for a pattern and returns a substring consisting of the characters in the string that are to the left of the pattern or all string if no match found.
|
||||
|
||||
```javascript
|
||||
_('This_is_a_test_string').strLeftBack('_')
|
||||
=> "This_is_a_test";
|
||||
```
|
||||
|
||||
**stripTags**
|
||||
|
||||
Removes all html tags from string.
|
||||
|
||||
```javascript
|
||||
_('a <a href="#">link</a>').stripTags()
|
||||
=> 'a link'
|
||||
|
||||
_('a <a href="#">link</a><script>alert("hello world!")</script>').stripTags()
|
||||
=> 'a linkalert("hello world!")'
|
||||
```
|
||||
|
||||
**toSentence** _.toSentence(array, [delimiter, lastDelimiter])
|
||||
|
||||
Join an array into a human readable sentence.
|
||||
|
||||
```javascript
|
||||
_.toSentence(['jQuery', 'Mootools', 'Prototype'])
|
||||
=> 'jQuery, Mootools and Prototype';
|
||||
|
||||
_.toSentence(['jQuery', 'Mootools', 'Prototype'], ', ', ' unt ')
|
||||
=> 'jQuery, Mootools unt Prototype';
|
||||
```
|
||||
|
||||
**toSentenceSerial** _.toSentenceSerial(array, [delimiter, lastDelimiter])
|
||||
|
||||
The same as `toSentence`, but adjusts delimeters to use [Serial comma](http://en.wikipedia.org/wiki/Serial_comma).
|
||||
|
||||
```javascript
|
||||
_.toSentenceSerial(['jQuery', 'Mootools'])
|
||||
=> 'jQuery and Mootools';
|
||||
|
||||
_.toSentenceSerial(['jQuery', 'Mootools', 'Prototype'])
|
||||
=> 'jQuery, Mootools, and Prototype'
|
||||
|
||||
_.toSentenceSerial(['jQuery', 'Mootools', 'Prototype'], ', ', ' unt ');
|
||||
=> 'jQuery, Mootools, unt Prototype';
|
||||
```
|
||||
|
||||
**repeat** _.repeat(string, count, [separator])
|
||||
|
||||
Repeats a string count times.
|
||||
|
||||
```javascript
|
||||
_.repeat("foo", 3)
|
||||
=> 'foofoofoo';
|
||||
|
||||
_.repeat("foo", 3, "bar")
|
||||
=> 'foobarfoobarfoo'
|
||||
```
|
||||
|
||||
**surround** _.surround(string, wrap)
|
||||
|
||||
Surround a string with another string.
|
||||
|
||||
```javascript
|
||||
_.surround("foo", "ab")
|
||||
=> 'abfooab';
|
||||
```
|
||||
|
||||
**quote** _.quote(string) or _.q(string)
|
||||
|
||||
Quotes a string.
|
||||
|
||||
```javascript
|
||||
_.quote('foo')
|
||||
=> '"foo"';
|
||||
```
|
||||
|
||||
|
||||
**slugify** _.slugify(string)
|
||||
|
||||
Transform text into a URL slug. Replaces whitespaces, accentuated, and special characters with a dash.
|
||||
|
||||
```javascript
|
||||
_.slugify("Un éléphant à l'orée du bois")
|
||||
=> 'un-elephant-a-loree-du-bois';
|
||||
```
|
||||
|
||||
***Caution: this function is charset dependent***
|
||||
|
||||
## Roadmap ##
|
||||
|
||||
Any suggestions or bug reports are welcome. Just email me or more preferably open an issue.
|
||||
|
||||
#### Problems
|
||||
|
||||
We lose two things for `include` and `reverse` methods from `_.string`:
|
||||
|
||||
* Calls like `_('foobar').include('bar')` aren't available;
|
||||
* Chaining isn't available too.
|
||||
|
||||
But if you need this functionality you can create aliases for conflict functions which will be convenient for you:
|
||||
|
||||
```javascript
|
||||
_.mixin({
|
||||
includeString: _.str.include,
|
||||
reverseString: _.str.reverse
|
||||
})
|
||||
|
||||
// Now wrapper calls and chaining are available.
|
||||
_('foobar').chain().reverseString().includeString('rab').value()
|
||||
```
|
||||
|
||||
#### Standalone Usage
|
||||
|
||||
If you are using Underscore.string without Underscore. You also have `_.string` namespace for it and `_.str` alias
|
||||
But of course you can just reassign `_` variable with `_.string`
|
||||
|
||||
```javascript
|
||||
_ = _.string
|
||||
```
|
||||
|
||||
## Changelog ##
|
||||
|
||||
### 2.3.1 ###
|
||||
|
||||
* Changed integration logic, now trying everything in order
|
||||
* Fixed classify method to chew some unexpected input
|
||||
* Fixed toNumber method failing to recognize '0.0' as a proper number
|
||||
|
||||
|
||||
### 2.3.0 ###
|
||||
|
||||
* Added `numberformat` method
|
||||
* Added `levenshtein` method (Levenshtein distance calculation)
|
||||
* Added `swapCase` method
|
||||
* Changed default behavior of `words` method
|
||||
* Added `toSentenceSerial` method
|
||||
* Added `surround` and `quote` methods
|
||||
|
||||
### 2.2.0 ###
|
||||
|
||||
* Capitalize method behavior changed
|
||||
* Various perfomance tweaks
|
||||
|
||||
### 2.1.1###
|
||||
|
||||
* Fixed words method bug
|
||||
* Added classify method
|
||||
|
||||
### 2.1.0 ###
|
||||
|
||||
* AMD support
|
||||
* Added toSentence method
|
||||
* Added slugify method
|
||||
* Lots of speed optimizations
|
||||
|
||||
### 2.0.0 ###
|
||||
|
||||
* Added prune, humanize functions
|
||||
* Added _.string (_.str) namespace for Underscore.string library
|
||||
* Removed includes function
|
||||
|
||||
For upgrading to this version you need to mix in Underscore.string library to Underscore object:
|
||||
|
||||
```javascript
|
||||
_.mixin(_.string.exports());
|
||||
```
|
||||
|
||||
and all non-conflict Underscore.string functions will be available through Underscore object.
|
||||
Also function `includes` has been removed, you should replace this function by `_.str.include`
|
||||
or create alias `_.includes = _.str.include` and all your code will work fine.
|
||||
|
||||
### 1.1.6 ###
|
||||
|
||||
* Fixed reverse and truncate
|
||||
* Added isBlank, stripTags, inlude(alias for includes)
|
||||
* Added uglifier compression
|
||||
|
||||
### 1.1.5 ###
|
||||
|
||||
* Added strRight, strRightBack, strLeft, strLeftBack
|
||||
|
||||
### 1.1.4 ###
|
||||
|
||||
* Added pad, lpad, rpad, lrpad methods and aliases center, ljust, rjust
|
||||
* Integration with Underscore 1.1.6
|
||||
|
||||
### 1.1.3 ###
|
||||
|
||||
* Added methods: underscored, camelize, dasherize
|
||||
* Support newer version of npm
|
||||
|
||||
### 1.1.2 ###
|
||||
|
||||
* Created functions: lines, chars, words functions
|
||||
|
||||
### 1.0.2 ###
|
||||
|
||||
* Created integration test suite with underscore.js 1.1.4 (now it's absolutely compatible)
|
||||
* Removed 'reverse' function, because this function override underscore.js 'reverse'
|
||||
|
||||
## Contribute ##
|
||||
|
||||
* Fork & pull request. Don't forget about tests.
|
||||
* If you planning add some feature please create issue before.
|
||||
|
||||
Otherwise changes will be rejected.
|
||||
|
||||
## Contributors list ##
|
||||
[Can be found here](https://github.com/epeli/underscore.string/graphs/contributors).
|
||||
|
||||
|
||||
## Licence ##
|
||||
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2011 Esa-Matti Suuronen esa-matti@suuronen.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -1,23 +0,0 @@
|
|||
# encoding: utf-8
|
||||
task default: :test
|
||||
|
||||
desc 'Use UglifyJS to compress Underscore.string'
|
||||
task :build do
|
||||
require 'uglifier'
|
||||
source = File.read('lib/underscore.string.js')
|
||||
compressed = Uglifier.compile(source, copyright: false)
|
||||
File.open('dist/underscore.string.min.js', 'w'){ |f| f.write compressed }
|
||||
compression_rate = compressed.length.to_f/source.length
|
||||
puts "compressed dist/underscore.string.min.js: #{compressed.length}/#{source.length} #{(compression_rate * 100).round}%"
|
||||
end
|
||||
|
||||
desc 'Run tests'
|
||||
task :test do
|
||||
puts "Running underscore.string test suite."
|
||||
result1 = system %{phantomjs ./test/run-qunit.js "test/test.html"}
|
||||
|
||||
puts "Running Underscore test suite."
|
||||
result2 = system %{phantomjs ./test/run-qunit.js "test/test_underscore/index.html"}
|
||||
|
||||
exit(result1 && result2 ? 0 : 1)
|
||||
end
|
File diff suppressed because one or more lines are too long
|
@ -1,614 +0,0 @@
|
|||
// Underscore.string
|
||||
// (c) 2010 Esa-Matti Suuronen <esa-matti aet suuronen dot org>
|
||||
// Underscore.string is freely distributable under the terms of the MIT license.
|
||||
// Documentation: https://github.com/epeli/underscore.string
|
||||
// Some code is borrowed from MooTools and Alexandru Marasteanu.
|
||||
// Version '2.3.1'
|
||||
|
||||
!function(root, String){
|
||||
'use strict';
|
||||
|
||||
// Defining helper functions.
|
||||
|
||||
var nativeTrim = String.prototype.trim;
|
||||
var nativeTrimRight = String.prototype.trimRight;
|
||||
var nativeTrimLeft = String.prototype.trimLeft;
|
||||
|
||||
var parseNumber = function(source) { return source * 1 || 0; };
|
||||
|
||||
var strRepeat = function(str, qty){
|
||||
if (qty < 1) return '';
|
||||
var result = '';
|
||||
while (qty > 0) {
|
||||
if (qty & 1) result += str;
|
||||
qty >>= 1, str += str;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var slice = [].slice;
|
||||
|
||||
var defaultToWhiteSpace = function(characters) {
|
||||
if (characters == null)
|
||||
return '\\s';
|
||||
else if (characters.source)
|
||||
return characters.source;
|
||||
else
|
||||
return '[' + _s.escapeRegExp(characters) + ']';
|
||||
};
|
||||
|
||||
var escapeChars = {
|
||||
lt: '<',
|
||||
gt: '>',
|
||||
quot: '"',
|
||||
amp: '&',
|
||||
apos: "'"
|
||||
};
|
||||
|
||||
var reversedEscapeChars = {};
|
||||
for(var key in escapeChars) reversedEscapeChars[escapeChars[key]] = key;
|
||||
reversedEscapeChars["'"] = '#39';
|
||||
|
||||
// sprintf() for JavaScript 0.7-beta1
|
||||
// http://www.diveintojavascript.com/projects/javascript-sprintf
|
||||
//
|
||||
// Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
|
||||
// All rights reserved.
|
||||
|
||||
var sprintf = (function() {
|
||||
function get_type(variable) {
|
||||
return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
|
||||
}
|
||||
|
||||
var str_repeat = strRepeat;
|
||||
|
||||
var str_format = function() {
|
||||
if (!str_format.cache.hasOwnProperty(arguments[0])) {
|
||||
str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
|
||||
}
|
||||
return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
|
||||
};
|
||||
|
||||
str_format.format = function(parse_tree, argv) {
|
||||
var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
|
||||
for (i = 0; i < tree_length; i++) {
|
||||
node_type = get_type(parse_tree[i]);
|
||||
if (node_type === 'string') {
|
||||
output.push(parse_tree[i]);
|
||||
}
|
||||
else if (node_type === 'array') {
|
||||
match = parse_tree[i]; // convenience purposes only
|
||||
if (match[2]) { // keyword argument
|
||||
arg = argv[cursor];
|
||||
for (k = 0; k < match[2].length; k++) {
|
||||
if (!arg.hasOwnProperty(match[2][k])) {
|
||||
throw new Error(sprintf('[_.sprintf] property "%s" does not exist', match[2][k]));
|
||||
}
|
||||
arg = arg[match[2][k]];
|
||||
}
|
||||
} else if (match[1]) { // positional argument (explicit)
|
||||
arg = argv[match[1]];
|
||||
}
|
||||
else { // positional argument (implicit)
|
||||
arg = argv[cursor++];
|
||||
}
|
||||
|
||||
if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
|
||||
throw new Error(sprintf('[_.sprintf] expecting number but found %s', get_type(arg)));
|
||||
}
|
||||
switch (match[8]) {
|
||||
case 'b': arg = arg.toString(2); break;
|
||||
case 'c': arg = String.fromCharCode(arg); break;
|
||||
case 'd': arg = parseInt(arg, 10); break;
|
||||
case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
|
||||
case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
|
||||
case 'o': arg = arg.toString(8); break;
|
||||
case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
|
||||
case 'u': arg = Math.abs(arg); break;
|
||||
case 'x': arg = arg.toString(16); break;
|
||||
case 'X': arg = arg.toString(16).toUpperCase(); break;
|
||||
}
|
||||
arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
|
||||
pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
|
||||
pad_length = match[6] - String(arg).length;
|
||||
pad = match[6] ? str_repeat(pad_character, pad_length) : '';
|
||||
output.push(match[5] ? arg + pad : pad + arg);
|
||||
}
|
||||
}
|
||||
return output.join('');
|
||||
};
|
||||
|
||||
str_format.cache = {};
|
||||
|
||||
str_format.parse = function(fmt) {
|
||||
var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
|
||||
while (_fmt) {
|
||||
if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
|
||||
parse_tree.push(match[0]);
|
||||
}
|
||||
else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
|
||||
parse_tree.push('%');
|
||||
}
|
||||
else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
|
||||
if (match[2]) {
|
||||
arg_names |= 1;
|
||||
var field_list = [], replacement_field = match[2], field_match = [];
|
||||
if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
|
||||
field_list.push(field_match[1]);
|
||||
while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
|
||||
if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
|
||||
field_list.push(field_match[1]);
|
||||
}
|
||||
else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
|
||||
field_list.push(field_match[1]);
|
||||
}
|
||||
else {
|
||||
throw new Error('[_.sprintf] huh?');
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error('[_.sprintf] huh?');
|
||||
}
|
||||
match[2] = field_list;
|
||||
}
|
||||
else {
|
||||
arg_names |= 2;
|
||||
}
|
||||
if (arg_names === 3) {
|
||||
throw new Error('[_.sprintf] mixing positional and named placeholders is not (yet) supported');
|
||||
}
|
||||
parse_tree.push(match);
|
||||
}
|
||||
else {
|
||||
throw new Error('[_.sprintf] huh?');
|
||||
}
|
||||
_fmt = _fmt.substring(match[0].length);
|
||||
}
|
||||
return parse_tree;
|
||||
};
|
||||
|
||||
return str_format;
|
||||
})();
|
||||
|
||||
|
||||
|
||||
// Defining underscore.string
|
||||
|
||||
var _s = {
|
||||
|
||||
VERSION: '2.3.1',
|
||||
|
||||
isBlank: function(str){
|
||||
if (str == null) str = '';
|
||||
return (/^\s*$/).test(str);
|
||||
},
|
||||
|
||||
stripTags: function(str){
|
||||
if (str == null) return '';
|
||||
return String(str).replace(/<\/?[^>]+>/g, '');
|
||||
},
|
||||
|
||||
capitalize : function(str){
|
||||
str = str == null ? '' : String(str);
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
},
|
||||
|
||||
chop: function(str, step){
|
||||
if (str == null) return [];
|
||||
str = String(str);
|
||||
step = ~~step;
|
||||
return step > 0 ? str.match(new RegExp('.{1,' + step + '}', 'g')) : [str];
|
||||
},
|
||||
|
||||
clean: function(str){
|
||||
return _s.strip(str).replace(/\s+/g, ' ');
|
||||
},
|
||||
|
||||
count: function(str, substr){
|
||||
if (str == null || substr == null) return 0;
|
||||
|
||||
str = String(str);
|
||||
substr = String(substr);
|
||||
|
||||
var count = 0,
|
||||
pos = 0,
|
||||
length = substr.length;
|
||||
|
||||
while (true) {
|
||||
pos = str.indexOf(substr, pos);
|
||||
if (pos === -1) break;
|
||||
count++;
|
||||
pos += length;
|
||||
}
|
||||
|
||||
return count;
|
||||
},
|
||||
|
||||
chars: function(str) {
|
||||
if (str == null) return [];
|
||||
return String(str).split('');
|
||||
},
|
||||
|
||||
swapCase: function(str) {
|
||||
if (str == null) return '';
|
||||
return String(str).replace(/\S/g, function(c){
|
||||
return c === c.toUpperCase() ? c.toLowerCase() : c.toUpperCase();
|
||||
});
|
||||
},
|
||||
|
||||
escapeHTML: function(str) {
|
||||
if (str == null) return '';
|
||||
return String(str).replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; });
|
||||
},
|
||||
|
||||
unescapeHTML: function(str) {
|
||||
if (str == null) return '';
|
||||
return String(str).replace(/\&([^;]+);/g, function(entity, entityCode){
|
||||
var match;
|
||||
|
||||
if (entityCode in escapeChars) {
|
||||
return escapeChars[entityCode];
|
||||
} else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) {
|
||||
return String.fromCharCode(parseInt(match[1], 16));
|
||||
} else if (match = entityCode.match(/^#(\d+)$/)) {
|
||||
return String.fromCharCode(~~match[1]);
|
||||
} else {
|
||||
return entity;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
escapeRegExp: function(str){
|
||||
if (str == null) return '';
|
||||
return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
|
||||
},
|
||||
|
||||
splice: function(str, i, howmany, substr){
|
||||
var arr = _s.chars(str);
|
||||
arr.splice(~~i, ~~howmany, substr);
|
||||
return arr.join('');
|
||||
},
|
||||
|
||||
insert: function(str, i, substr){
|
||||
return _s.splice(str, i, 0, substr);
|
||||
},
|
||||
|
||||
include: function(str, needle){
|
||||
if (needle === '') return true;
|
||||
if (str == null) return false;
|
||||
return String(str).indexOf(needle) !== -1;
|
||||
},
|
||||
|
||||
join: function() {
|
||||
var args = slice.call(arguments),
|
||||
separator = args.shift();
|
||||
|
||||
if (separator == null) separator = '';
|
||||
|
||||
return args.join(separator);
|
||||
},
|
||||
|
||||
lines: function(str) {
|
||||
if (str == null) return [];
|
||||
return String(str).split("\n");
|
||||
},
|
||||
|
||||
reverse: function(str){
|
||||
return _s.chars(str).reverse().join('');
|
||||
},
|
||||
|
||||
startsWith: function(str, starts){
|
||||
if (starts === '') return true;
|
||||
if (str == null || starts == null) return false;
|
||||
str = String(str); starts = String(starts);
|
||||
return str.length >= starts.length && str.slice(0, starts.length) === starts;
|
||||
},
|
||||
|
||||
endsWith: function(str, ends){
|
||||
if (ends === '') return true;
|
||||
if (str == null || ends == null) return false;
|
||||
str = String(str); ends = String(ends);
|
||||
return str.length >= ends.length && str.slice(str.length - ends.length) === ends;
|
||||
},
|
||||
|
||||
succ: function(str){
|
||||
if (str == null) return '';
|
||||
str = String(str);
|
||||
return str.slice(0, -1) + String.fromCharCode(str.charCodeAt(str.length-1) + 1);
|
||||
},
|
||||
|
||||
titleize: function(str){
|
||||
if (str == null) return '';
|
||||
return String(str).replace(/(?:^|\s)\S/g, function(c){ return c.toUpperCase(); });
|
||||
},
|
||||
|
||||
camelize: function(str){
|
||||
return _s.trim(str).replace(/[-_\s]+(.)?/g, function(match, c){ return c.toUpperCase(); });
|
||||
},
|
||||
|
||||
underscored: function(str){
|
||||
return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
|
||||
},
|
||||
|
||||
dasherize: function(str){
|
||||
return _s.trim(str).replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase();
|
||||
},
|
||||
|
||||
classify: function(str){
|
||||
return _s.titleize(String(str).replace(/[\W_]/g, ' ')).replace(/\s/g, '');
|
||||
},
|
||||
|
||||
humanize: function(str){
|
||||
return _s.capitalize(_s.underscored(str).replace(/_id$/,'').replace(/_/g, ' '));
|
||||
},
|
||||
|
||||
trim: function(str, characters){
|
||||
if (str == null) return '';
|
||||
if (!characters && nativeTrim) return nativeTrim.call(str);
|
||||
characters = defaultToWhiteSpace(characters);
|
||||
return String(str).replace(new RegExp('\^' + characters + '+|' + characters + '+$', 'g'), '');
|
||||
},
|
||||
|
||||
ltrim: function(str, characters){
|
||||
if (str == null) return '';
|
||||
if (!characters && nativeTrimLeft) return nativeTrimLeft.call(str);
|
||||
characters = defaultToWhiteSpace(characters);
|
||||
return String(str).replace(new RegExp('^' + characters + '+'), '');
|
||||
},
|
||||
|
||||
rtrim: function(str, characters){
|
||||
if (str == null) return '';
|
||||
if (!characters && nativeTrimRight) return nativeTrimRight.call(str);
|
||||
characters = defaultToWhiteSpace(characters);
|
||||
return String(str).replace(new RegExp(characters + '+$'), '');
|
||||
},
|
||||
|
||||
truncate: function(str, length, truncateStr){
|
||||
if (str == null) return '';
|
||||
str = String(str); truncateStr = truncateStr || '...';
|
||||
length = ~~length;
|
||||
return str.length > length ? str.slice(0, length) + truncateStr : str;
|
||||
},
|
||||
|
||||
/**
|
||||
* _s.prune: a more elegant version of truncate
|
||||
* prune extra chars, never leaving a half-chopped word.
|
||||
* @author github.com/rwz
|
||||
*/
|
||||
prune: function(str, length, pruneStr){
|
||||
if (str == null) return '';
|
||||
|
||||
str = String(str); length = ~~length;
|
||||
pruneStr = pruneStr != null ? String(pruneStr) : '...';
|
||||
|
||||
if (str.length <= length) return str;
|
||||
|
||||
var tmpl = function(c){ return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' '; },
|
||||
template = str.slice(0, length+1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA'
|
||||
|
||||
if (template.slice(template.length-2).match(/\w\w/))
|
||||
template = template.replace(/\s*\S+$/, '');
|
||||
else
|
||||
template = _s.rtrim(template.slice(0, template.length-1));
|
||||
|
||||
return (template+pruneStr).length > str.length ? str : str.slice(0, template.length)+pruneStr;
|
||||
},
|
||||
|
||||
words: function(str, delimiter) {
|
||||
if (_s.isBlank(str)) return [];
|
||||
return _s.trim(str, delimiter).split(delimiter || /\s+/);
|
||||
},
|
||||
|
||||
pad: function(str, length, padStr, type) {
|
||||
str = str == null ? '' : String(str);
|
||||
length = ~~length;
|
||||
|
||||
var padlen = 0;
|
||||
|
||||
if (!padStr)
|
||||
padStr = ' ';
|
||||
else if (padStr.length > 1)
|
||||
padStr = padStr.charAt(0);
|
||||
|
||||
switch(type) {
|
||||
case 'right':
|
||||
padlen = length - str.length;
|
||||
return str + strRepeat(padStr, padlen);
|
||||
case 'both':
|
||||
padlen = length - str.length;
|
||||
return strRepeat(padStr, Math.ceil(padlen/2)) + str
|
||||
+ strRepeat(padStr, Math.floor(padlen/2));
|
||||
default: // 'left'
|
||||
padlen = length - str.length;
|
||||
return strRepeat(padStr, padlen) + str;
|
||||
}
|
||||
},
|
||||
|
||||
lpad: function(str, length, padStr) {
|
||||
return _s.pad(str, length, padStr);
|
||||
},
|
||||
|
||||
rpad: function(str, length, padStr) {
|
||||
return _s.pad(str, length, padStr, 'right');
|
||||
},
|
||||
|
||||
lrpad: function(str, length, padStr) {
|
||||
return _s.pad(str, length, padStr, 'both');
|
||||
},
|
||||
|
||||
sprintf: sprintf,
|
||||
|
||||
vsprintf: function(fmt, argv){
|
||||
argv.unshift(fmt);
|
||||
return sprintf.apply(null, argv);
|
||||
},
|
||||
|
||||
toNumber: function(str, decimals) {
|
||||
if (!str) return 0;
|
||||
str = _s.trim(str);
|
||||
if (!str.match(/^-?\d+(?:\.\d+)?$/)) return NaN;
|
||||
return parseNumber(parseNumber(str).toFixed(~~decimals));
|
||||
},
|
||||
|
||||
numberFormat : function(number, dec, dsep, tsep) {
|
||||
if (isNaN(number) || number == null) return '';
|
||||
|
||||
number = number.toFixed(~~dec);
|
||||
tsep = typeof tsep == 'string' ? tsep : ',';
|
||||
|
||||
var parts = number.split('.'), fnums = parts[0],
|
||||
decimals = parts[1] ? (dsep || '.') + parts[1] : '';
|
||||
|
||||
return fnums.replace(/(\d)(?=(?:\d{3})+$)/g, '$1' + tsep) + decimals;
|
||||
},
|
||||
|
||||
strRight: function(str, sep){
|
||||
if (str == null) return '';
|
||||
str = String(str); sep = sep != null ? String(sep) : sep;
|
||||
var pos = !sep ? -1 : str.indexOf(sep);
|
||||
return ~pos ? str.slice(pos+sep.length, str.length) : str;
|
||||
},
|
||||
|
||||
strRightBack: function(str, sep){
|
||||
if (str == null) return '';
|
||||
str = String(str); sep = sep != null ? String(sep) : sep;
|
||||
var pos = !sep ? -1 : str.lastIndexOf(sep);
|
||||
return ~pos ? str.slice(pos+sep.length, str.length) : str;
|
||||
},
|
||||
|
||||
strLeft: function(str, sep){
|
||||
if (str == null) return '';
|
||||
str = String(str); sep = sep != null ? String(sep) : sep;
|
||||
var pos = !sep ? -1 : str.indexOf(sep);
|
||||
return ~pos ? str.slice(0, pos) : str;
|
||||
},
|
||||
|
||||
strLeftBack: function(str, sep){
|
||||
if (str == null) return '';
|
||||
str += ''; sep = sep != null ? ''+sep : sep;
|
||||
var pos = str.lastIndexOf(sep);
|
||||
return ~pos ? str.slice(0, pos) : str;
|
||||
},
|
||||
|
||||
toSentence: function(array, separator, lastSeparator, serial) {
|
||||
separator = separator || ', '
|
||||
lastSeparator = lastSeparator || ' and '
|
||||
var a = array.slice(), lastMember = a.pop();
|
||||
|
||||
if (array.length > 2 && serial) lastSeparator = _s.rtrim(separator) + lastSeparator;
|
||||
|
||||
return a.length ? a.join(separator) + lastSeparator + lastMember : lastMember;
|
||||
},
|
||||
|
||||
toSentenceSerial: function() {
|
||||
var args = slice.call(arguments);
|
||||
args[3] = true;
|
||||
return _s.toSentence.apply(_s, args);
|
||||
},
|
||||
|
||||
slugify: function(str) {
|
||||
if (str == null) return '';
|
||||
|
||||
var from = "ąàáäâãåæćęèéëêìíïîłńòóöôõøùúüûñçżź",
|
||||
to = "aaaaaaaaceeeeeiiiilnoooooouuuunczz",
|
||||
regex = new RegExp(defaultToWhiteSpace(from), 'g');
|
||||
|
||||
str = String(str).toLowerCase().replace(regex, function(c){
|
||||
var index = from.indexOf(c);
|
||||
return to.charAt(index) || '-';
|
||||
});
|
||||
|
||||
return _s.dasherize(str.replace(/[^\w\s-]/g, ''));
|
||||
},
|
||||
|
||||
surround: function(str, wrapper) {
|
||||
return [wrapper, str, wrapper].join('');
|
||||
},
|
||||
|
||||
quote: function(str) {
|
||||
return _s.surround(str, '"');
|
||||
},
|
||||
|
||||
exports: function() {
|
||||
var result = {};
|
||||
|
||||
for (var prop in this) {
|
||||
if (!this.hasOwnProperty(prop) || prop.match(/^(?:include|contains|reverse)$/)) continue;
|
||||
result[prop] = this[prop];
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
repeat: function(str, qty, separator){
|
||||
if (str == null) return '';
|
||||
|
||||
qty = ~~qty;
|
||||
|
||||
// using faster implementation if separator is not needed;
|
||||
if (separator == null) return strRepeat(String(str), qty);
|
||||
|
||||
// this one is about 300x slower in Google Chrome
|
||||
for (var repeat = []; qty > 0; repeat[--qty] = str) {}
|
||||
return repeat.join(separator);
|
||||
},
|
||||
|
||||
levenshtein: function(str1, str2) {
|
||||
if (str1 == null && str2 == null) return 0;
|
||||
if (str1 == null) return String(str2).length;
|
||||
if (str2 == null) return String(str1).length;
|
||||
|
||||
str1 = String(str1); str2 = String(str2);
|
||||
|
||||
var current = [], prev, value;
|
||||
|
||||
for (var i = 0; i <= str2.length; i++)
|
||||
for (var j = 0; j <= str1.length; j++) {
|
||||
if (i && j)
|
||||
if (str1.charAt(j - 1) === str2.charAt(i - 1))
|
||||
value = prev;
|
||||
else
|
||||
value = Math.min(current[j], current[j - 1], prev) + 1;
|
||||
else
|
||||
value = i + j;
|
||||
|
||||
prev = current[j];
|
||||
current[j] = value;
|
||||
}
|
||||
|
||||
return current.pop();
|
||||
}
|
||||
};
|
||||
|
||||
// Aliases
|
||||
|
||||
_s.strip = _s.trim;
|
||||
_s.lstrip = _s.ltrim;
|
||||
_s.rstrip = _s.rtrim;
|
||||
_s.center = _s.lrpad;
|
||||
_s.rjust = _s.lpad;
|
||||
_s.ljust = _s.rpad;
|
||||
_s.contains = _s.include;
|
||||
_s.q = _s.quote;
|
||||
|
||||
// Exporting
|
||||
|
||||
// CommonJS module is defined
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports)
|
||||
module.exports = _s;
|
||||
|
||||
exports._s = _s;
|
||||
}
|
||||
|
||||
// Register as a named module with AMD.
|
||||
if (typeof define === 'function' && define.amd)
|
||||
define('underscore.string', [], function(){ return _s; });
|
||||
|
||||
|
||||
// Integrate with Underscore.js if defined
|
||||
// or create our own underscore object.
|
||||
root._ = root._ || {};
|
||||
root._.string = root._.str = _s;
|
||||
}(this, String);
|
File diff suppressed because one or more lines are too long
|
@ -1,45 +0,0 @@
|
|||
function waitFor(test, complete, timeout) {
|
||||
var result, start = new Date().getTime()
|
||||
setInterval(function interval() {
|
||||
if ((new Date().getTime() - start < timeout) && !result) {
|
||||
result = test()
|
||||
} else {
|
||||
if (!result) {
|
||||
phantom.exit(1)
|
||||
} else {
|
||||
complete()
|
||||
clearInterval(interval)
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
|
||||
var fs = require('fs'), page = require('webpage').create();
|
||||
var url = 'file://localhost' + fs.workingDirectory + '/' + phantom.args[0];
|
||||
|
||||
page.onConsoleMessage = function(msg) {
|
||||
console.log(msg)
|
||||
}
|
||||
|
||||
page.open(url, function(status) {
|
||||
waitFor(function() {
|
||||
return page.evaluate(function(){
|
||||
var el = document.getElementById('qunit-testresult')
|
||||
return el && el.innerText.match('completed')
|
||||
})
|
||||
}, function() {
|
||||
var failures = page.evaluate(function() {
|
||||
var el = document.getElementById('qunit-testresult'),
|
||||
fails = document.getElementsByClassName('fail')
|
||||
|
||||
for (var i = 0; i < fails.length; i++)
|
||||
console.log(fails[i].innerText)
|
||||
|
||||
console.log(el.innerText)
|
||||
|
||||
return parseInt(el.getElementsByClassName('failed')[0].innerHTML)
|
||||
})
|
||||
phantom.exit(failures > 0 ? 1 : 0)
|
||||
}, 10000)
|
||||
})
|
|
@ -1,148 +0,0 @@
|
|||
(function() {
|
||||
|
||||
JSLitmus.test('levenshtein', function() {
|
||||
return [
|
||||
_.levenshtein('pineapple', 'potato'),
|
||||
_.levenshtein('seven', 'eight'),
|
||||
_.levenshtein('the very same string', 'the very same string'),
|
||||
_.levenshtein('very very very long string', 'something completely different')
|
||||
];
|
||||
});
|
||||
|
||||
|
||||
JSLitmus.test('trimNoNative', function() {
|
||||
return _.trim(" foobar ", " ");
|
||||
});
|
||||
|
||||
JSLitmus.test('trim', function() {
|
||||
return _.trim(" foobar ");
|
||||
});
|
||||
|
||||
JSLitmus.test('trim object-oriented', function() {
|
||||
return _(" foobar ").trim();
|
||||
});
|
||||
|
||||
JSLitmus.test('trim jQuery', function() {
|
||||
return jQuery.trim(" foobar ");
|
||||
});
|
||||
|
||||
JSLitmus.test('ltrimp', function() {
|
||||
return _.ltrim(" foobar ", " ");
|
||||
});
|
||||
|
||||
JSLitmus.test('rtrimp', function() {
|
||||
return _.rtrim(" foobar ", " ");
|
||||
});
|
||||
|
||||
JSLitmus.test('startsWith', function() {
|
||||
return _.startsWith("foobar", "foo");
|
||||
});
|
||||
|
||||
JSLitmus.test('endsWith', function() {
|
||||
return _.endsWith("foobar", "xx");
|
||||
});
|
||||
|
||||
JSLitmus.test('chop', function(){
|
||||
return _('whitespace').chop(2);
|
||||
});
|
||||
|
||||
JSLitmus.test('count', function(){
|
||||
return _('Hello worls').count('l');
|
||||
});
|
||||
|
||||
JSLitmus.test('insert', function() {
|
||||
return _('Hello ').insert(6, 'world');
|
||||
});
|
||||
|
||||
JSLitmus.test('splice', function() {
|
||||
return _('https://edtsech@bitbucket.org/edtsech/underscore.strings').splice(30, 7, 'epeli');
|
||||
});
|
||||
|
||||
JSLitmus.test('succ', function(){
|
||||
var let = 'a', alphabet = [];
|
||||
|
||||
for (var i=0; i < 26; i++) {
|
||||
alphabet.push(let);
|
||||
let = _(let).succ();
|
||||
}
|
||||
|
||||
return alphabet;
|
||||
});
|
||||
|
||||
JSLitmus.test('titleize', function(){
|
||||
return _('the titleize string method').titleize();
|
||||
});
|
||||
|
||||
JSLitmus.test('truncate', function(){
|
||||
return _('Hello world').truncate(5);
|
||||
});
|
||||
|
||||
JSLitmus.test('prune', function(){
|
||||
return _('Hello world').prune(5);
|
||||
});
|
||||
|
||||
JSLitmus.test('isBlank', function(){
|
||||
return _('').isBlank();
|
||||
});
|
||||
|
||||
JSLitmus.test('escapeHTML', function(){
|
||||
_('<div>Blah blah blah</div>').escapeHTML();
|
||||
});
|
||||
|
||||
JSLitmus.test('unescapeHTML', function(){
|
||||
_('<div>Blah blah blah</div>').unescapeHTML();
|
||||
});
|
||||
|
||||
JSLitmus.test('reverse', function(){
|
||||
_('Hello World').reverse();
|
||||
});
|
||||
|
||||
JSLitmus.test('pad default', function(){
|
||||
_('foo').pad(12);
|
||||
});
|
||||
|
||||
JSLitmus.test('pad hash left', function(){
|
||||
_('foo').pad(12, '#');
|
||||
});
|
||||
|
||||
JSLitmus.test('pad hash right', function(){
|
||||
_('foo').pad(12, '#', 'right');
|
||||
});
|
||||
|
||||
JSLitmus.test('pad hash both', function(){
|
||||
_('foo').pad(12, '#', 'both');
|
||||
});
|
||||
|
||||
JSLitmus.test('pad hash both longPad', function(){
|
||||
_('foo').pad(12, 'f00f00f00', 'both');
|
||||
});
|
||||
|
||||
JSLitmus.test('toNumber', function(){
|
||||
_('10.232323').toNumber(2);
|
||||
});
|
||||
|
||||
JSLitmus.test('strRight', function(){
|
||||
_('aaa_bbb_ccc').strRight('_');
|
||||
});
|
||||
|
||||
JSLitmus.test('strRightBack', function(){
|
||||
_('aaa_bbb_ccc').strRightBack('_');
|
||||
});
|
||||
|
||||
JSLitmus.test('strLeft', function(){
|
||||
_('aaa_bbb_ccc').strLeft('_');
|
||||
});
|
||||
|
||||
JSLitmus.test('strLeftBack', function(){
|
||||
_('aaa_bbb_ccc').strLeftBack('_');
|
||||
});
|
||||
|
||||
JSLitmus.test('join', function(){
|
||||
_('separator').join(1, 2, 3, 4, 5, 6, 7, 8, 'foo', 'bar', 'lol', 'wut');
|
||||
});
|
||||
|
||||
JSLitmus.test('slugify', function(){
|
||||
_("Un éléphant à l'orée du bois").slugify();
|
||||
});
|
||||
|
||||
})();
|
|
@ -1,641 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
// Include Underscore.string methods to Underscore namespace
|
||||
_.mixin(_.str.exports());
|
||||
|
||||
module('String extensions');
|
||||
|
||||
test('Strings: trim', function() {
|
||||
equal(_.trim(123), '123', 'Non string');
|
||||
equal(_(' foo').trim(), 'foo');
|
||||
equal(_('foo ').trim(), 'foo');
|
||||
equal(_(' foo ').trim(), 'foo');
|
||||
equal(_(' foo ').trim(), 'foo');
|
||||
equal(_(' foo ').trim(' '), 'foo', 'Manually set whitespace');
|
||||
equal(_('\t foo \t ').trim(/\s/), 'foo', 'Manually set RegExp /\\s+/');
|
||||
|
||||
equal(_('ffoo').trim('f'), 'oo');
|
||||
equal(_('ooff').trim('f'), 'oo');
|
||||
equal(_('ffooff').trim('f'), 'oo');
|
||||
|
||||
|
||||
equal(_('_-foobar-_').trim('_-'), 'foobar');
|
||||
|
||||
equal(_('http://foo/').trim('/'), 'http://foo');
|
||||
equal(_('c:\\').trim('\\'), 'c:');
|
||||
|
||||
equal(_(123).trim(), '123');
|
||||
equal(_(123).trim(3), '12');
|
||||
equal(_('').trim(), '', 'Trim empty string should return empty string');
|
||||
equal(_(null).trim(), '', 'Trim null should return empty string');
|
||||
equal(_(undefined).trim(), '', 'Trim undefined should return empty string');
|
||||
});
|
||||
|
||||
test('String: levenshtein', function() {
|
||||
equal(_.levenshtein('Godfather', 'Godfather'), 0);
|
||||
equal(_.levenshtein('Godfather', 'Godfathe'), 1);
|
||||
equal(_.levenshtein('Godfather', 'odfather'), 1);
|
||||
equal(_.levenshtein('Godfather', 'Gdfthr'), 3);
|
||||
equal(_.levenshtein('seven', 'eight'), 5);
|
||||
equal(_.levenshtein('123', 123), 0);
|
||||
equal(_.levenshtein(321, '321'), 0);
|
||||
equal(_.levenshtein('lol', null), 3);
|
||||
equal(_.levenshtein('lol'), 3);
|
||||
equal(_.levenshtein(null, 'lol'), 3);
|
||||
equal(_.levenshtein(undefined, 'lol'), 3);
|
||||
equal(_.levenshtein(), 0);
|
||||
});
|
||||
|
||||
test('Strings: ltrim', function() {
|
||||
equal(_(' foo').ltrim(), 'foo');
|
||||
equal(_(' foo').ltrim(), 'foo');
|
||||
equal(_('foo ').ltrim(), 'foo ');
|
||||
equal(_(' foo ').ltrim(), 'foo ');
|
||||
equal(_('').ltrim(), '', 'ltrim empty string should return empty string');
|
||||
equal(_(null).ltrim(), '', 'ltrim null should return empty string');
|
||||
equal(_(undefined).ltrim(), '', 'ltrim undefined should return empty string');
|
||||
|
||||
equal(_('ffoo').ltrim('f'), 'oo');
|
||||
equal(_('ooff').ltrim('f'), 'ooff');
|
||||
equal(_('ffooff').ltrim('f'), 'ooff');
|
||||
|
||||
equal(_('_-foobar-_').ltrim('_-'), 'foobar-_');
|
||||
|
||||
equal(_(123).ltrim(1), '23');
|
||||
});
|
||||
|
||||
test('Strings: rtrim', function() {
|
||||
equal(_('http://foo/').rtrim('/'), 'http://foo', 'clean trailing slash');
|
||||
equal(_(' foo').rtrim(), ' foo');
|
||||
equal(_('foo ').rtrim(), 'foo');
|
||||
equal(_('foo ').rtrim(), 'foo');
|
||||
equal(_('foo bar ').rtrim(), 'foo bar');
|
||||
equal(_(' foo ').rtrim(), ' foo');
|
||||
|
||||
equal(_('ffoo').rtrim('f'), 'ffoo');
|
||||
equal(_('ooff').rtrim('f'), 'oo');
|
||||
equal(_('ffooff').rtrim('f'), 'ffoo');
|
||||
|
||||
equal(_('_-foobar-_').rtrim('_-'), '_-foobar');
|
||||
|
||||
equal(_(123).rtrim(3), '12');
|
||||
equal(_('').rtrim(), '', 'rtrim empty string should return empty string');
|
||||
equal(_(null).rtrim(), '', 'rtrim null should return empty string');
|
||||
});
|
||||
|
||||
test('Strings: capitalize', function() {
|
||||
equal(_('fabio').capitalize(), 'Fabio', 'First letter is upper case');
|
||||
equal(_.capitalize('fabio'), 'Fabio', 'First letter is upper case');
|
||||
equal(_.capitalize('FOO'), 'FOO', 'Other letters unchanged');
|
||||
equal(_(123).capitalize(), '123', 'Non string');
|
||||
equal(_.capitalize(''), '', 'Capitalizing empty string returns empty string');
|
||||
equal(_.capitalize(null), '', 'Capitalizing null returns empty string');
|
||||
equal(_.capitalize(undefined), '', 'Capitalizing undefined returns empty string');
|
||||
});
|
||||
|
||||
test('Strings: join', function() {
|
||||
equal(_.join('', 'foo', 'bar'), 'foobar', 'basic join');
|
||||
equal(_.join('', 1, 'foo', 2), '1foo2', 'join numbers and strings');
|
||||
equal(_.join(' ','foo', 'bar'), 'foo bar', 'join with spaces');
|
||||
equal(_.join('1', '2', '2'), '212', 'join number strings');
|
||||
equal(_.join(1, 2, 2), '212', 'join numbers');
|
||||
equal(_.join('','foo', null), 'foo', 'join null with string returns string');
|
||||
equal(_.join(null,'foo', 'bar'), 'foobar', 'join strings with null returns string');
|
||||
equal(_(' ').join('foo', 'bar'), 'foo bar', 'join object oriented');
|
||||
});
|
||||
|
||||
test('Strings: reverse', function() {
|
||||
equal(_.str.reverse('foo'), 'oof' );
|
||||
equal(_.str.reverse('foobar'), 'raboof' );
|
||||
equal(_.str.reverse('foo bar'), 'rab oof' );
|
||||
equal(_.str.reverse('saippuakauppias'), 'saippuakauppias' );
|
||||
equal(_.str.reverse(123), '321', 'Non string');
|
||||
equal(_.str.reverse(123.45), '54.321', 'Non string');
|
||||
equal(_.str.reverse(''), '', 'reversing empty string returns empty string' );
|
||||
equal(_.str.reverse(null), '', 'reversing null returns empty string' );
|
||||
equal(_.str.reverse(undefined), '', 'reversing undefined returns empty string' );
|
||||
});
|
||||
|
||||
test('Strings: clean', function() {
|
||||
equal(_(' foo bar ').clean(), 'foo bar');
|
||||
equal(_(123).clean(), '123');
|
||||
equal(_('').clean(), '', 'claning empty string returns empty string');
|
||||
equal(_(null).clean(), '', 'claning null returns empty string');
|
||||
equal(_(undefined).clean(), '', 'claning undefined returns empty string');
|
||||
});
|
||||
|
||||
test('Strings: sprintf', function() {
|
||||
// Should be very tested function already. Thanks to
|
||||
// http://www.diveintojavascript.com/projects/sprintf-for-javascript
|
||||
equal(_.sprintf('Hello %s', 'me'), 'Hello me', 'basic');
|
||||
equal(_('Hello %s').sprintf('me'), 'Hello me', 'object');
|
||||
equal(_('hello %s').chain().sprintf('me').capitalize().value(), 'Hello me', 'Chaining works');
|
||||
equal(_.sprintf('%.1f', 1.22222), '1.2', 'round');
|
||||
equal(_.sprintf('%.1f', 1.17), '1.2', 'round 2');
|
||||
equal(_.sprintf('%(id)d - %(name)s', {id: 824, name: 'Hello World'}), '824 - Hello World', 'Named replacements work');
|
||||
equal(_.sprintf('%(args[0].id)d - %(args[1].name)s', {args: [{id: 824}, {name: 'Hello World'}]}), '824 - Hello World', 'Named replacements with arrays work');
|
||||
});
|
||||
|
||||
|
||||
test('Strings: vsprintf', function() {
|
||||
equal(_.vsprintf('Hello %s', ['me']), 'Hello me', 'basic');
|
||||
equal(_('Hello %s').vsprintf(['me']), 'Hello me', 'object');
|
||||
equal(_('hello %s').chain().vsprintf(['me']).capitalize().value(), 'Hello me', 'Chaining works');
|
||||
equal(_.vsprintf('%.1f', [1.22222]), '1.2', 'round');
|
||||
equal(_.vsprintf('%.1f', [1.17]), '1.2', 'round 2');
|
||||
equal(_.vsprintf('%(id)d - %(name)s', [{id: 824, name: 'Hello World'}]), '824 - Hello World', 'Named replacement works');
|
||||
equal(_.vsprintf('%(args[0].id)d - %(args[1].name)s', [{args: [{id: 824}, {name: 'Hello World'}]}]), '824 - Hello World', 'Named replacement with arrays works');
|
||||
});
|
||||
|
||||
test('Strings: startsWith', function() {
|
||||
ok(_('foobar').startsWith('foo'), 'foobar starts with foo');
|
||||
ok(!_('oobar').startsWith('foo'), 'oobar does not start with foo');
|
||||
ok(_(12345).startsWith(123), '12345 starts with 123');
|
||||
ok(!_(2345).startsWith(123), '2345 does not start with 123');
|
||||
ok(_('').startsWith(''), 'empty string starts with empty string');
|
||||
ok(_(null).startsWith(''), 'null starts with empty string');
|
||||
ok(!_(null).startsWith('foo'), 'null starts with foo');
|
||||
});
|
||||
|
||||
test('Strings: endsWith', function() {
|
||||
ok(_('foobar').endsWith('bar'), 'foobar ends with bar');
|
||||
ok(_.endsWith('foobar', 'bar'), 'foobar ends with bar');
|
||||
ok(_.endsWith('00018-0000062.Plone.sdh264.1a7264e6912a91aa4a81b64dc5517df7b8875994.mp4', 'mp4'), 'endsWith .mp4');
|
||||
ok(!_('fooba').endsWith('bar'), 'fooba does not end with bar');
|
||||
ok(_.endsWith(12345, 45), '12345 ends with 45');
|
||||
ok(!_.endsWith(12345, 6), '12345 does not end with 6');
|
||||
ok(_('').endsWith(''), 'empty string ends with empty string');
|
||||
ok(_(null).endsWith(''), 'null ends with empty string');
|
||||
ok(!_(null).endsWith('foo'), 'null ends with foo');
|
||||
});
|
||||
|
||||
test('Strings: include', function() {
|
||||
ok(_.str.include('foobar', 'bar'), 'foobar includes bar');
|
||||
ok(!_.str.include('foobar', 'buzz'), 'foobar does not includes buzz');
|
||||
ok(_.str.include(12345, 34), '12345 includes 34');
|
||||
ok(!_.str.contains(12345, 6), '12345 does not includes 6');
|
||||
ok(!_.str.include('', 34), 'empty string includes 34');
|
||||
ok(!_.str.include(null, 34), 'null includes 34');
|
||||
ok(_.str.include(null, ''), 'null includes empty string');
|
||||
});
|
||||
|
||||
test('String: chop', function(){
|
||||
ok(_('whitespace').chop(2).length === 5, 'output [wh, it, es, pa, ce]');
|
||||
ok(_('whitespace').chop(3).length === 4, 'output [whi, tes, pac, e]');
|
||||
ok(_('whitespace').chop()[0].length === 10, 'output [whitespace]');
|
||||
ok(_(12345).chop(1).length === 5, 'output [1, 2, 3, 4, 5]');
|
||||
});
|
||||
|
||||
test('String: clean', function(){
|
||||
equal(_.clean(' foo bar '), 'foo bar');
|
||||
equal(_.clean(''), '');
|
||||
equal(_.clean(null), '');
|
||||
equal(_.clean(1), '1');
|
||||
});
|
||||
|
||||
test('String: count', function(){
|
||||
equal(_('Hello world').count('l'), 3);
|
||||
equal(_('Hello world').count('Hello'), 1);
|
||||
equal(_('Hello world').count('foo'), 0);
|
||||
equal(_('x.xx....x.x').count('x'), 5);
|
||||
equal(_('').count('x'), 0);
|
||||
equal(_(null).count('x'), 0);
|
||||
equal(_(undefined).count('x'), 0);
|
||||
equal(_(12345).count(1), 1);
|
||||
equal(_(11345).count(1), 2);
|
||||
});
|
||||
|
||||
test('String: insert', function(){
|
||||
equal(_('Hello ').insert(6, 'Jessy'), 'Hello Jessy');
|
||||
equal(_('Hello ').insert(100, 'Jessy'), 'Hello Jessy');
|
||||
equal(_('').insert(100, 'Jessy'), 'Jessy');
|
||||
equal(_(null).insert(100, 'Jessy'), 'Jessy');
|
||||
equal(_(undefined).insert(100, 'Jessy'), 'Jessy');
|
||||
equal(_(12345).insert(6, 'Jessy'), '12345Jessy');
|
||||
});
|
||||
|
||||
test('String: splice', function(){
|
||||
equal(_('https://edtsech@bitbucket.org/edtsech/underscore.strings').splice(30, 7, 'epeli'),
|
||||
'https://edtsech@bitbucket.org/epeli/underscore.strings');
|
||||
equal(_.splice(12345, 1, 2, 321), '132145', 'Non strings');
|
||||
});
|
||||
|
||||
test('String: succ', function(){
|
||||
equal(_('a').succ(), 'b');
|
||||
equal(_('A').succ(), 'B');
|
||||
equal(_('+').succ(), ',');
|
||||
equal(_(1).succ(), '2');
|
||||
});
|
||||
|
||||
test('String: titleize', function(){
|
||||
equal(_('the titleize string method').titleize(), 'The Titleize String Method');
|
||||
equal(_('the titleize string method').titleize(), 'The Titleize String Method');
|
||||
equal(_('').titleize(), '', 'Titleize empty string returns empty string');
|
||||
equal(_(null).titleize(), '', 'Titleize null returns empty string');
|
||||
equal(_(undefined).titleize(), '', 'Titleize undefined returns empty string');
|
||||
equal(_('let\'s have some fun').titleize(), 'Let\'s Have Some Fun');
|
||||
equal(_(123).titleize(), '123');
|
||||
});
|
||||
|
||||
test('String: camelize', function(){
|
||||
equal(_('the_camelize_string_method').camelize(), 'theCamelizeStringMethod');
|
||||
equal(_('-the-camelize-string-method').camelize(), 'TheCamelizeStringMethod');
|
||||
equal(_('the camelize string method').camelize(), 'theCamelizeStringMethod');
|
||||
equal(_(' the camelize string method').camelize(), 'theCamelizeStringMethod');
|
||||
equal(_('the camelize string method').camelize(), 'theCamelizeStringMethod');
|
||||
equal(_('').camelize(), '', 'Camelize empty string returns empty string');
|
||||
equal(_(null).camelize(), '', 'Camelize null returns empty string');
|
||||
equal(_(undefined).camelize(), '', 'Camelize undefined returns empty string');
|
||||
equal(_(123).camelize(), '123');
|
||||
});
|
||||
|
||||
test('String: underscored', function(){
|
||||
equal(_('the-underscored-string-method').underscored(), 'the_underscored_string_method');
|
||||
equal(_('theUnderscoredStringMethod').underscored(), 'the_underscored_string_method');
|
||||
equal(_('TheUnderscoredStringMethod').underscored(), 'the_underscored_string_method');
|
||||
equal(_(' the underscored string method').underscored(), 'the_underscored_string_method');
|
||||
equal(_('').underscored(), '');
|
||||
equal(_(null).underscored(), '');
|
||||
equal(_(undefined).underscored(), '');
|
||||
equal(_(123).underscored(), '123');
|
||||
});
|
||||
|
||||
test('String: dasherize', function(){
|
||||
equal(_('the_dasherize_string_method').dasherize(), 'the-dasherize-string-method');
|
||||
equal(_('TheDasherizeStringMethod').dasherize(), '-the-dasherize-string-method');
|
||||
equal(_('thisIsATest').dasherize(), 'this-is-a-test');
|
||||
equal(_('this Is A Test').dasherize(), 'this-is-a-test');
|
||||
equal(_('thisIsATest123').dasherize(), 'this-is-a-test123');
|
||||
equal(_('123thisIsATest').dasherize(), '123this-is-a-test');
|
||||
equal(_('the dasherize string method').dasherize(), 'the-dasherize-string-method');
|
||||
equal(_('the dasherize string method ').dasherize(), 'the-dasherize-string-method');
|
||||
equal(_('téléphone').dasherize(), 'téléphone');
|
||||
equal(_('foo$bar').dasherize(), 'foo$bar');
|
||||
equal(_('').dasherize(), '');
|
||||
equal(_(null).dasherize(), '');
|
||||
equal(_(undefined).dasherize(), '');
|
||||
equal(_(123).dasherize(), '123');
|
||||
});
|
||||
|
||||
test('String: camelize', function(){
|
||||
equal(_.camelize('-moz-transform'), 'MozTransform');
|
||||
equal(_.camelize('webkit-transform'), 'webkitTransform');
|
||||
equal(_.camelize('under_scored'), 'underScored');
|
||||
equal(_.camelize(' with spaces'), 'withSpaces');
|
||||
equal(_('').camelize(), '');
|
||||
equal(_(null).camelize(), '');
|
||||
equal(_(undefined).camelize(), '');
|
||||
});
|
||||
|
||||
test('String: join', function(){
|
||||
equal(_.join(1, 2, 3, 4), '21314');
|
||||
equal(_.join('|', 'foo', 'bar', 'baz'), 'foo|bar|baz');
|
||||
equal(_.join('',2,3,null), '23');
|
||||
equal(_.join(null,2,3), '23');
|
||||
});
|
||||
|
||||
test('String: classify', function(){
|
||||
equal(_.classify(1), '1');
|
||||
equal(_('some_class_name').classify(), 'SomeClassName');
|
||||
equal(_('my wonderfull class_name').classify(), 'MyWonderfullClassName');
|
||||
equal(_('my wonderfull.class.name').classify(), 'MyWonderfullClassName');
|
||||
});
|
||||
|
||||
test('String: humanize', function(){
|
||||
equal(_('the_humanize_string_method').humanize(), 'The humanize string method');
|
||||
equal(_('ThehumanizeStringMethod').humanize(), 'Thehumanize string method');
|
||||
equal(_('the humanize string method').humanize(), 'The humanize string method');
|
||||
equal(_('the humanize_id string method_id').humanize(), 'The humanize id string method');
|
||||
equal(_('the humanize string method ').humanize(), 'The humanize string method');
|
||||
equal(_(' capitalize dash-CamelCase_underscore trim ').humanize(), 'Capitalize dash camel case underscore trim');
|
||||
equal(_(123).humanize(), '123');
|
||||
equal(_('').humanize(), '');
|
||||
equal(_(null).humanize(), '');
|
||||
equal(_(undefined).humanize(), '');
|
||||
});
|
||||
|
||||
test('String: truncate', function(){
|
||||
equal(_('Hello world').truncate(6, 'read more'), 'Hello read more');
|
||||
equal(_('Hello world').truncate(5), 'Hello...');
|
||||
equal(_('Hello').truncate(10), 'Hello');
|
||||
equal(_('').truncate(10), '');
|
||||
equal(_(null).truncate(10), '');
|
||||
equal(_(undefined).truncate(10), '');
|
||||
equal(_(1234567890).truncate(5), '12345...');
|
||||
});
|
||||
|
||||
test('String: prune', function(){
|
||||
equal(_('Hello, cruel world').prune(6, ' read more'), 'Hello read more');
|
||||
equal(_('Hello, world').prune(5, 'read a lot more'), 'Hello, world');
|
||||
equal(_('Hello, world').prune(5), 'Hello...');
|
||||
equal(_('Hello, world').prune(8), 'Hello...');
|
||||
equal(_('Hello, cruel world').prune(15), 'Hello, cruel...');
|
||||
equal(_('Hello world').prune(22), 'Hello world');
|
||||
equal(_('Привет, жестокий мир').prune(6, ' read more'), 'Привет read more');
|
||||
equal(_('Привет, мир').prune(6, 'read a lot more'), 'Привет, мир');
|
||||
equal(_('Привет, мир').prune(6), 'Привет...');
|
||||
equal(_('Привет, мир').prune(8), 'Привет...');
|
||||
equal(_('Привет, жестокий мир').prune(16), 'Привет, жестокий...');
|
||||
equal(_('Привет, мир').prune(22), 'Привет, мир');
|
||||
equal(_('alksjd!!!!!!....').prune(100, ''), 'alksjd!!!!!!....');
|
||||
equal(_(123).prune(10), '123');
|
||||
equal(_(123).prune(1, 321), '321');
|
||||
equal(_('').prune(5), '');
|
||||
equal(_(null).prune(5), '');
|
||||
equal(_(undefined).prune(5), '');
|
||||
});
|
||||
|
||||
test('String: isBlank', function(){
|
||||
ok(_('').isBlank());
|
||||
ok(_(' ').isBlank());
|
||||
ok(_('\n').isBlank());
|
||||
ok(!_('a').isBlank());
|
||||
ok(!_('0').isBlank());
|
||||
ok(!_(0).isBlank());
|
||||
ok(_('').isBlank());
|
||||
ok(_(null).isBlank());
|
||||
ok(_(undefined).isBlank());
|
||||
});
|
||||
|
||||
test('String: escapeRegExp', function(){
|
||||
equal(_.escapeRegExp(/hello(?=\sworld)/.source), 'hello\\(\\?\\=\\\\sworld\\)', 'with lookahead');
|
||||
equal(_.escapeRegExp(/hello(?!\shell)/.source), 'hello\\(\\?\\!\\\\shell\\)', 'with negative lookahead');
|
||||
});
|
||||
|
||||
test('String: escapeHTML', function(){
|
||||
equal(_('<div>Blah & "blah" & \'blah\'</div>').escapeHTML(),
|
||||
'<div>Blah & "blah" & 'blah'</div>');
|
||||
equal(_('<').escapeHTML(), '&lt;');
|
||||
equal(_(5).escapeHTML(), '5');
|
||||
equal(_('').escapeHTML(), '');
|
||||
equal(_(null).escapeHTML(), '');
|
||||
equal(_(undefined).escapeHTML(), '');
|
||||
});
|
||||
|
||||
test('String: unescapeHTML', function(){
|
||||
equal(_('<div>Blah & "blah" & 'blah'</div>').unescapeHTML(),
|
||||
'<div>Blah & "blah" & \'blah\'</div>');
|
||||
equal(_('&lt;').unescapeHTML(), '<');
|
||||
equal(_(''').unescapeHTML(), '\'');
|
||||
equal(_(''').unescapeHTML(), '\'');
|
||||
equal(_(''').unescapeHTML(), '\'');
|
||||
equal(_('J').unescapeHTML(), 'J');
|
||||
equal(_('J').unescapeHTML(), 'J');
|
||||
equal(_('J').unescapeHTML(), 'J');
|
||||
equal(_('&_#39;').unescapeHTML(), '&_#39;');
|
||||
equal(_(''_;').unescapeHTML(), ''_;');
|
||||
equal(_('&#38;').unescapeHTML(), '&');
|
||||
equal(_('&amp;').unescapeHTML(), '&');
|
||||
equal(_('').unescapeHTML(), '');
|
||||
equal(_(null).unescapeHTML(), '');
|
||||
equal(_(undefined).unescapeHTML(), '');
|
||||
equal(_(5).unescapeHTML(), '5');
|
||||
// equal(_(undefined).unescapeHTML(), '');
|
||||
});
|
||||
|
||||
test('String: words', function() {
|
||||
deepEqual(_('I love you!').words(), ['I', 'love', 'you!']);
|
||||
deepEqual(_(' I love you! ').words(), ['I', 'love', 'you!']);
|
||||
deepEqual(_('I_love_you!').words('_'), ['I', 'love', 'you!']);
|
||||
deepEqual(_('I-love-you!').words(/-/), ['I', 'love', 'you!']);
|
||||
deepEqual(_(123).words(), ['123'], '123 number has one word "123".');
|
||||
deepEqual(_(0).words(), ['0'], 'Zero number has one word "0".');
|
||||
deepEqual(_('').words(), [], 'Empty strings has no words.');
|
||||
deepEqual(_(' ').words(), [], 'Blank strings has no words.');
|
||||
deepEqual(_(null).words(), [], 'null has no words.');
|
||||
deepEqual(_(undefined).words(), [], 'undefined has no words.');
|
||||
});
|
||||
|
||||
test('String: chars', function() {
|
||||
equal(_('Hello').chars().length, 5);
|
||||
equal(_(123).chars().length, 3);
|
||||
equal(_('').chars().length, 0);
|
||||
equal(_(null).chars().length, 0);
|
||||
equal(_(undefined).chars().length, 0);
|
||||
});
|
||||
|
||||
test('String: swapCase', function(){
|
||||
equal(_('AaBbCcDdEe').swapCase(), 'aAbBcCdDeE');
|
||||
equal(_('Hello World').swapCase(), 'hELLO wORLD');
|
||||
equal(_('').swapCase(), '');
|
||||
equal(_(null).swapCase(), '');
|
||||
equal(_(undefined).swapCase(), '');
|
||||
});
|
||||
|
||||
test('String: lines', function() {
|
||||
equal(_('Hello\nWorld').lines().length, 2);
|
||||
equal(_('Hello World').lines().length, 1);
|
||||
equal(_(123).lines().length, 1);
|
||||
equal(_('').lines().length, 1);
|
||||
equal(_(null).lines().length, 0);
|
||||
equal(_(undefined).lines().length, 0);
|
||||
});
|
||||
|
||||
test('String: pad', function() {
|
||||
equal(_('1').pad(8), ' 1');
|
||||
equal(_(1).pad(8), ' 1');
|
||||
equal(_('1').pad(8, '0'), '00000001');
|
||||
equal(_('1').pad(8, '0', 'left'), '00000001');
|
||||
equal(_('1').pad(8, '0', 'right'), '10000000');
|
||||
equal(_('1').pad(8, '0', 'both'), '00001000');
|
||||
equal(_('foo').pad(8, '0', 'both'), '000foo00');
|
||||
equal(_('foo').pad(7, '0', 'both'), '00foo00');
|
||||
equal(_('foo').pad(7, '!@$%dofjrofj', 'both'), '!!foo!!');
|
||||
equal(_('').pad(2), ' ');
|
||||
equal(_(null).pad(2), ' ');
|
||||
equal(_(undefined).pad(2), ' ');
|
||||
});
|
||||
|
||||
test('String: lpad', function() {
|
||||
equal(_('1').lpad(8), ' 1');
|
||||
equal(_(1).lpad(8), ' 1');
|
||||
equal(_('1').lpad(8, '0'), '00000001');
|
||||
equal(_('1').lpad(8, '0', 'left'), '00000001');
|
||||
equal(_('').lpad(2), ' ');
|
||||
equal(_(null).lpad(2), ' ');
|
||||
equal(_(undefined).lpad(2), ' ');
|
||||
});
|
||||
|
||||
test('String: rpad', function() {
|
||||
equal(_('1').rpad(8), '1 ');
|
||||
equal(_(1).lpad(8), ' 1');
|
||||
equal(_('1').rpad(8, '0'), '10000000');
|
||||
equal(_('foo').rpad(8, '0'), 'foo00000');
|
||||
equal(_('foo').rpad(7, '0'), 'foo0000');
|
||||
equal(_('').rpad(2), ' ');
|
||||
equal(_(null).rpad(2), ' ');
|
||||
equal(_(undefined).rpad(2), ' ');
|
||||
});
|
||||
|
||||
test('String: lrpad', function() {
|
||||
equal(_('1').lrpad(8), ' 1 ');
|
||||
equal(_(1).lrpad(8), ' 1 ');
|
||||
equal(_('1').lrpad(8, '0'), '00001000');
|
||||
equal(_('foo').lrpad(8, '0'), '000foo00');
|
||||
equal(_('foo').lrpad(7, '0'), '00foo00');
|
||||
equal(_('foo').lrpad(7, '!@$%dofjrofj'), '!!foo!!');
|
||||
equal(_('').lrpad(2), ' ');
|
||||
equal(_(null).lrpad(2), ' ');
|
||||
equal(_(undefined).lrpad(2), ' ');
|
||||
});
|
||||
|
||||
test('String: toNumber', function() {
|
||||
deepEqual(_('not a number').toNumber(), NaN);
|
||||
equal(_(0).toNumber(), 0);
|
||||
equal(_('0').toNumber(), 0);
|
||||
equal(_('0.0').toNumber(), 0);
|
||||
equal(_('0.1').toNumber(), 0);
|
||||
equal(_('0.1').toNumber(1), 0.1);
|
||||
equal(_(' 0.1 ').toNumber(1), 0.1);
|
||||
equal(_('0000').toNumber(), 0);
|
||||
equal(_('2.345').toNumber(), 2);
|
||||
equal(_('2.345').toNumber(NaN), 2);
|
||||
equal(_('2.345').toNumber(2), 2.35);
|
||||
equal(_('2.344').toNumber(2), 2.34);
|
||||
equal(_('2').toNumber(2), 2.00);
|
||||
equal(_(2).toNumber(2), 2.00);
|
||||
equal(_(-2).toNumber(), -2);
|
||||
equal(_('-2').toNumber(), -2);
|
||||
equal(_('').toNumber(), 0);
|
||||
equal(_(null).toNumber(), 0);
|
||||
equal(_(undefined).toNumber(), 0);
|
||||
});
|
||||
|
||||
test('String: numberFormat', function() {
|
||||
equal(_.numberFormat(9000), '9,000');
|
||||
equal(_.numberFormat(9000, 0), '9,000');
|
||||
equal(_.numberFormat(9000, 0, '', ''), '9000');
|
||||
equal(_.numberFormat(90000, 2), '90,000.00');
|
||||
equal(_.numberFormat(1000.754), '1,001');
|
||||
equal(_.numberFormat(1000.754, 2), '1,000.75');
|
||||
equal(_.numberFormat(1000.754, 0, ',', '.'), '1.001');
|
||||
equal(_.numberFormat(1000.754, 2, ',', '.'), '1.000,75');
|
||||
equal(_.numberFormat(1000000.754, 2, ',', '.'), '1.000.000,75');
|
||||
equal(_.numberFormat(1000000000), '1,000,000,000');
|
||||
equal(_.numberFormat(100000000), '100,000,000');
|
||||
equal(_.numberFormat('not number'), '');
|
||||
equal(_.numberFormat(), '');
|
||||
equal(_.numberFormat(null, '.', ','), '');
|
||||
equal(_.numberFormat(undefined, '.', ','), '');
|
||||
equal(_.numberFormat(new Number(5000)), '5,000');
|
||||
});
|
||||
|
||||
test('String: strRight', function() {
|
||||
equal(_('This_is_a_test_string').strRight('_'), 'is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strRight('string'), '');
|
||||
equal(_('This_is_a_test_string').strRight(), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strRight(''), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strRight('-'), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strRight(''), 'This_is_a_test_string');
|
||||
equal(_('').strRight('foo'), '');
|
||||
equal(_(null).strRight('foo'), '');
|
||||
equal(_(undefined).strRight('foo'), '');
|
||||
equal(_(12345).strRight(2), '345');
|
||||
});
|
||||
|
||||
test('String: strRightBack', function() {
|
||||
equal(_('This_is_a_test_string').strRightBack('_'), 'string');
|
||||
equal(_('This_is_a_test_string').strRightBack('string'), '');
|
||||
equal(_('This_is_a_test_string').strRightBack(), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strRightBack(''), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strRightBack('-'), 'This_is_a_test_string');
|
||||
equal(_('').strRightBack('foo'), '');
|
||||
equal(_(null).strRightBack('foo'), '');
|
||||
equal(_(undefined).strRightBack('foo'), '');
|
||||
equal(_(12345).strRightBack(2), '345');
|
||||
});
|
||||
|
||||
test('String: strLeft', function() {
|
||||
equal(_('This_is_a_test_string').strLeft('_'), 'This');
|
||||
equal(_('This_is_a_test_string').strLeft('This'), '');
|
||||
equal(_('This_is_a_test_string').strLeft(), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strLeft(''), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strLeft('-'), 'This_is_a_test_string');
|
||||
equal(_('').strLeft('foo'), '');
|
||||
equal(_(null).strLeft('foo'), '');
|
||||
equal(_(undefined).strLeft('foo'), '');
|
||||
equal(_(123454321).strLeft(3), '12');
|
||||
});
|
||||
|
||||
test('String: strLeftBack', function() {
|
||||
equal(_('This_is_a_test_string').strLeftBack('_'), 'This_is_a_test');
|
||||
equal(_('This_is_a_test_string').strLeftBack('This'), '');
|
||||
equal(_('This_is_a_test_string').strLeftBack(), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strLeftBack(''), 'This_is_a_test_string');
|
||||
equal(_('This_is_a_test_string').strLeftBack('-'), 'This_is_a_test_string');
|
||||
equal(_('').strLeftBack('foo'), '');
|
||||
equal(_(null).strLeftBack('foo'), '');
|
||||
equal(_(undefined).strLeftBack('foo'), '');
|
||||
equal(_(123454321).strLeftBack(3), '123454');
|
||||
});
|
||||
|
||||
test('Strings: stripTags', function() {
|
||||
equal(_('a <a href="#">link</a>').stripTags(), 'a link');
|
||||
equal(_('a <a href="#">link</a><script>alert("hello world!")</scr'+'ipt>').stripTags(), 'a linkalert("hello world!")');
|
||||
equal(_('<html><body>hello world</body></html>').stripTags(), 'hello world');
|
||||
equal(_(123).stripTags(), '123');
|
||||
equal(_('').stripTags(), '');
|
||||
equal(_(null).stripTags(), '');
|
||||
equal(_(undefined).stripTags(), '');
|
||||
});
|
||||
|
||||
test('Strings: toSentence', function() {
|
||||
equal(_.toSentence(['jQuery']), 'jQuery', 'array with a single element');
|
||||
equal(_.toSentence(['jQuery', 'MooTools']), 'jQuery and MooTools', 'array with two elements');
|
||||
equal(_.toSentence(['jQuery', 'MooTools', 'Prototype']), 'jQuery, MooTools and Prototype', 'array with three elements');
|
||||
equal(_.toSentence(['jQuery', 'MooTools', 'Prototype', 'YUI']), 'jQuery, MooTools, Prototype and YUI', 'array with multiple elements');
|
||||
equal(_.toSentence(['jQuery', 'MooTools', 'Prototype'], ',', ' or '), 'jQuery,MooTools or Prototype', 'handles custom separators');
|
||||
});
|
||||
|
||||
test('Strings: toSentenceSerial', function (){
|
||||
equal(_.toSentenceSerial(['jQuery']), 'jQuery');
|
||||
equal(_.toSentenceSerial(['jQuery', 'MooTools']), 'jQuery and MooTools');
|
||||
equal(_.toSentenceSerial(['jQuery', 'MooTools', 'Prototype']), 'jQuery, MooTools, and Prototype');
|
||||
});
|
||||
|
||||
test('Strings: slugify', function() {
|
||||
equal(_('Jack & Jill like numbers 1,2,3 and 4 and silly characters ?%.$!/').slugify(), 'jack-jill-like-numbers-123-and-4-and-silly-characters');
|
||||
equal(_('Un éléphant à l\'orée du bois').slugify(), 'un-elephant-a-loree-du-bois');
|
||||
equal(_('I know latin characters: á í ó ú ç ã õ ñ ü').slugify(), 'i-know-latin-characters-a-i-o-u-c-a-o-n-u');
|
||||
equal(_('I am a word too, even though I am but a single letter: i!').slugify(), 'i-am-a-word-too-even-though-i-am-but-a-single-letter-i');
|
||||
equal(_('').slugify(), '');
|
||||
equal(_(null).slugify(), '');
|
||||
equal(_(undefined).slugify(), '');
|
||||
});
|
||||
|
||||
test('Strings: quote', function(){
|
||||
equal(_.quote('foo'), '"foo"');
|
||||
equal(_.quote('"foo"'), '""foo""');
|
||||
equal(_.quote(1), '"1"');
|
||||
// alias
|
||||
equal(_.q('foo'), '"foo"');
|
||||
equal(_.q(''), '""');
|
||||
equal(_.q(null), '""');
|
||||
equal(_.q(undefined), '""');
|
||||
});
|
||||
|
||||
test('Strings: surround', function(){
|
||||
equal(_.surround('foo', 'ab'), 'abfooab');
|
||||
equal(_.surround(1, 'ab'), 'ab1ab');
|
||||
equal(_.surround(1, 2), '212');
|
||||
equal(_.surround('foo', 1), '1foo1');
|
||||
equal(_.surround('', 1), '11');
|
||||
equal(_.surround(null, 1), '11');
|
||||
equal(_.surround('foo', ''), 'foo');
|
||||
equal(_.surround('foo', null), 'foo');
|
||||
});
|
||||
|
||||
|
||||
test('Strings: repeat', function() {
|
||||
equal(_.repeat('foo'), '');
|
||||
equal(_.repeat('foo', 3), 'foofoofoo');
|
||||
equal(_.repeat('foo', '3'), 'foofoofoo');
|
||||
equal(_.repeat(123, 2), '123123');
|
||||
equal(_.repeat(1234, 2, '*'), '1234*1234');
|
||||
equal(_.repeat(1234, 2, 5), '123451234');
|
||||
equal(_.repeat('', 2), '');
|
||||
equal(_.repeat(null, 2), '');
|
||||
equal(_.repeat(undefined, 2), '');
|
||||
});
|
||||
|
||||
});
|
|
@ -1,12 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
module("String extensions");
|
||||
|
||||
test("underscore not included", function() {
|
||||
raises(function() { _("foo") }, /TypeError/);
|
||||
});
|
||||
|
||||
test("provides standalone functions", function() {
|
||||
equals(typeof _.str.trim, "function");
|
||||
});
|
||||
});
|
|
@ -1,31 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Underscore.strings Test Suite</title>
|
||||
<link rel="stylesheet" href="test_underscore/vendor/qunit.css" type="text/css" media="screen" />
|
||||
<script type="text/javascript" src="test_underscore/vendor/jquery.js"></script>
|
||||
<script type="text/javascript" src="test_underscore/vendor/qunit.js"></script>
|
||||
<script type="text/javascript" src="test_underscore/vendor/jslitmus.js"></script>
|
||||
<script type="text/javascript" src="underscore.js"></script>
|
||||
<script type="text/javascript" src="../lib/underscore.string.js"></script>
|
||||
<script type="text/javascript" src="strings.js"></script>
|
||||
<script type="text/javascript" src="speed.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Underscore.string Test Suite</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<br />
|
||||
<h1 class="qunit-header">Underscore.string Speed Suite</h1>
|
||||
<!-- <h2 class="qunit-userAgent">
|
||||
A representative sample of the functions are benchmarked here, to provide
|
||||
a sense of how fast they might run in different browsers.
|
||||
Each iteration runs on an array of 1000 elements.<br /><br />
|
||||
For example, the 'intersect' test measures the number of times you can
|
||||
find the intersection of two thousand-element arrays in one second.
|
||||
</h2> -->
|
||||
<br />
|
||||
</body>
|
||||
</html>
|
|
@ -1,18 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Underscore.strings Test Suite</title>
|
||||
<link rel="stylesheet" href="test_underscore/vendor/qunit.css" type="text/css" media="screen" />
|
||||
<script type="text/javascript" src="test_underscore/vendor/jquery.js"></script>
|
||||
<script type="text/javascript" src="test_underscore/vendor/qunit.js"></script>
|
||||
<script type="text/javascript" src="../lib/underscore.string.js"></script>
|
||||
<script type="text/javascript" src="strings_standalone.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Underscore.string Test Suite</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
</body>
|
||||
</html>
|
|
@ -1,200 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
module("Arrays");
|
||||
|
||||
test("first", function() {
|
||||
equal(_.first([1,2,3]), 1, 'can pull out the first element of an array');
|
||||
equal(_([1, 2, 3]).first(), 1, 'can perform OO-style "first()"');
|
||||
equal(_.first([1,2,3], 0).join(', '), "", 'can pass an index to first');
|
||||
equal(_.first([1,2,3], 2).join(', '), '1, 2', 'can pass an index to first');
|
||||
equal(_.first([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to first');
|
||||
var result = (function(){ return _.first(arguments); })(4, 3, 2, 1);
|
||||
equal(result, 4, 'works on an arguments object.');
|
||||
result = _.map([[1,2,3],[1,2,3]], _.first);
|
||||
equal(result.join(','), '1,1', 'works well with _.map');
|
||||
result = (function() { return _.take([1,2,3], 2); })();
|
||||
equal(result.join(','), '1,2', 'aliased as take');
|
||||
|
||||
equal(_.first(null), undefined, 'handles nulls');
|
||||
});
|
||||
|
||||
test("rest", function() {
|
||||
var numbers = [1, 2, 3, 4];
|
||||
equal(_.rest(numbers).join(", "), "2, 3, 4", 'working rest()');
|
||||
equal(_.rest(numbers, 0).join(", "), "1, 2, 3, 4", 'working rest(0)');
|
||||
equal(_.rest(numbers, 2).join(', '), '3, 4', 'rest can take an index');
|
||||
var result = (function(){ return _(arguments).tail(); })(1, 2, 3, 4);
|
||||
equal(result.join(', '), '2, 3, 4', 'aliased as tail and works on arguments object');
|
||||
result = _.map([[1,2,3],[1,2,3]], _.rest);
|
||||
equal(_.flatten(result).join(','), '2,3,2,3', 'works well with _.map');
|
||||
result = (function(){ return _(arguments).drop(); })(1, 2, 3, 4);
|
||||
equal(result.join(', '), '2, 3, 4', 'aliased as drop and works on arguments object');
|
||||
});
|
||||
|
||||
test("initial", function() {
|
||||
equal(_.initial([1,2,3,4,5]).join(", "), "1, 2, 3, 4", 'working initial()');
|
||||
equal(_.initial([1,2,3,4],2).join(", "), "1, 2", 'initial can take an index');
|
||||
var result = (function(){ return _(arguments).initial(); })(1, 2, 3, 4);
|
||||
equal(result.join(", "), "1, 2, 3", 'initial works on arguments object');
|
||||
result = _.map([[1,2,3],[1,2,3]], _.initial);
|
||||
equal(_.flatten(result).join(','), '1,2,1,2', 'initial works with _.map');
|
||||
});
|
||||
|
||||
test("last", function() {
|
||||
equal(_.last([1,2,3]), 3, 'can pull out the last element of an array');
|
||||
equal(_.last([1,2,3], 0).join(', '), "", 'can pass an index to last');
|
||||
equal(_.last([1,2,3], 2).join(', '), '2, 3', 'can pass an index to last');
|
||||
equal(_.last([1,2,3], 5).join(', '), '1, 2, 3', 'can pass an index to last');
|
||||
var result = (function(){ return _(arguments).last(); })(1, 2, 3, 4);
|
||||
equal(result, 4, 'works on an arguments object');
|
||||
result = _.map([[1,2,3],[1,2,3]], _.last);
|
||||
equal(result.join(','), '3,3', 'works well with _.map');
|
||||
|
||||
equal(_.last(null), undefined, 'handles nulls');
|
||||
});
|
||||
|
||||
test("compact", function() {
|
||||
equal(_.compact([0, 1, false, 2, false, 3]).length, 3, 'can trim out all falsy values');
|
||||
var result = (function(){ return _(arguments).compact().length; })(0, 1, false, 2, false, 3);
|
||||
equal(result, 3, 'works on an arguments object');
|
||||
});
|
||||
|
||||
test("flatten", function() {
|
||||
if (window.JSON) {
|
||||
var list = [1, [2], [3, [[[4]]]]];
|
||||
equal(JSON.stringify(_.flatten(list)), '[1,2,3,4]', 'can flatten nested arrays');
|
||||
equal(JSON.stringify(_.flatten(list, true)), '[1,2,3,[[[4]]]]', 'can shallowly flatten nested arrays');
|
||||
var result = (function(){ return _.flatten(arguments); })(1, [2], [3, [[[4]]]]);
|
||||
equal(JSON.stringify(result), '[1,2,3,4]', 'works on an arguments object');
|
||||
}
|
||||
});
|
||||
|
||||
test("without", function() {
|
||||
var list = [1, 2, 1, 0, 3, 1, 4];
|
||||
equal(_.without(list, 0, 1).join(', '), '2, 3, 4', 'can remove all instances of an object');
|
||||
var result = (function(){ return _.without(arguments, 0, 1); })(1, 2, 1, 0, 3, 1, 4);
|
||||
equal(result.join(', '), '2, 3, 4', 'works on an arguments object');
|
||||
|
||||
var list = [{one : 1}, {two : 2}];
|
||||
ok(_.without(list, {one : 1}).length == 2, 'uses real object identity for comparisons.');
|
||||
ok(_.without(list, list[0]).length == 1, 'ditto.');
|
||||
});
|
||||
|
||||
test("uniq", function() {
|
||||
var list = [1, 2, 1, 3, 1, 4];
|
||||
equal(_.uniq(list).join(', '), '1, 2, 3, 4', 'can find the unique values of an unsorted array');
|
||||
|
||||
var list = [1, 1, 1, 2, 2, 3];
|
||||
equal(_.uniq(list, true).join(', '), '1, 2, 3', 'can find the unique values of a sorted array faster');
|
||||
|
||||
var list = [{name:'moe'}, {name:'curly'}, {name:'larry'}, {name:'curly'}];
|
||||
var iterator = function(value) { return value.name; };
|
||||
equal(_.map(_.uniq(list, false, iterator), iterator).join(', '), 'moe, curly, larry', 'can find the unique values of an array using a custom iterator');
|
||||
|
||||
var iterator = function(value) { return value +1; };
|
||||
var list = [1, 2, 2, 3, 4, 4];
|
||||
equal(_.uniq(list, true, iterator).join(', '), '1, 2, 3, 4', 'iterator works with sorted array');
|
||||
|
||||
var result = (function(){ return _.uniq(arguments); })(1, 2, 1, 3, 1, 4);
|
||||
equal(result.join(', '), '1, 2, 3, 4', 'works on an arguments object');
|
||||
});
|
||||
|
||||
test("intersection", function() {
|
||||
var stooges = ['moe', 'curly', 'larry'], leaders = ['moe', 'groucho'];
|
||||
equal(_.intersection(stooges, leaders).join(''), 'moe', 'can take the set intersection of two arrays');
|
||||
equal(_(stooges).intersection(leaders).join(''), 'moe', 'can perform an OO-style intersection');
|
||||
var result = (function(){ return _.intersection(arguments, leaders); })('moe', 'curly', 'larry');
|
||||
equal(result.join(''), 'moe', 'works on an arguments object');
|
||||
});
|
||||
|
||||
test("union", function() {
|
||||
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40]);
|
||||
equal(result.join(' '), '1 2 3 30 40', 'takes the union of a list of arrays');
|
||||
|
||||
var result = _.union([1, 2, 3], [2, 30, 1], [1, 40, [1]]);
|
||||
equal(result.join(' '), '1 2 3 30 40 1', 'takes the union of a list of nested arrays');
|
||||
});
|
||||
|
||||
test("difference", function() {
|
||||
var result = _.difference([1, 2, 3], [2, 30, 40]);
|
||||
equal(result.join(' '), '1 3', 'takes the difference of two arrays');
|
||||
|
||||
var result = _.difference([1, 2, 3, 4], [2, 30, 40], [1, 11, 111]);
|
||||
equal(result.join(' '), '3 4', 'takes the difference of three arrays');
|
||||
});
|
||||
|
||||
test('zip', function() {
|
||||
var names = ['moe', 'larry', 'curly'], ages = [30, 40, 50], leaders = [true];
|
||||
var stooges = _.zip(names, ages, leaders);
|
||||
equal(String(stooges), 'moe,30,true,larry,40,,curly,50,', 'zipped together arrays of different lengths');
|
||||
});
|
||||
|
||||
test('object', function() {
|
||||
var result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]);
|
||||
var shouldBe = {moe: 30, larry: 40, curly: 50};
|
||||
ok(_.isEqual(result, shouldBe), 'two arrays zipped together into an object');
|
||||
|
||||
result = _.object([['one', 1], ['two', 2], ['three', 3]]);
|
||||
shouldBe = {one: 1, two: 2, three: 3};
|
||||
ok(_.isEqual(result, shouldBe), 'an array of pairs zipped together into an object');
|
||||
|
||||
var stooges = {moe: 30, larry: 40, curly: 50};
|
||||
ok(_.isEqual(_.object(_.pairs(stooges)), stooges), 'an object converted to pairs and back to an object');
|
||||
|
||||
ok(_.isEqual(_.object(null), {}), 'handles nulls');
|
||||
});
|
||||
|
||||
test("indexOf", function() {
|
||||
var numbers = [1, 2, 3];
|
||||
numbers.indexOf = null;
|
||||
equal(_.indexOf(numbers, 2), 1, 'can compute indexOf, even without the native function');
|
||||
var result = (function(){ return _.indexOf(arguments, 2); })(1, 2, 3);
|
||||
equal(result, 1, 'works on an arguments object');
|
||||
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
|
||||
|
||||
var numbers = [10, 20, 30, 40, 50], num = 35;
|
||||
var index = _.indexOf(numbers, num, true);
|
||||
equal(index, -1, '35 is not in the list');
|
||||
|
||||
numbers = [10, 20, 30, 40, 50]; num = 40;
|
||||
index = _.indexOf(numbers, num, true);
|
||||
equal(index, 3, '40 is in the list');
|
||||
|
||||
numbers = [1, 40, 40, 40, 40, 40, 40, 40, 50, 60, 70]; num = 40;
|
||||
index = _.indexOf(numbers, num, true);
|
||||
equal(index, 1, '40 is in the list');
|
||||
|
||||
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
|
||||
index = _.indexOf(numbers, 2, 5);
|
||||
equal(index, 7, 'supports the fromIndex argument');
|
||||
});
|
||||
|
||||
test("lastIndexOf", function() {
|
||||
var numbers = [1, 0, 1];
|
||||
equal(_.lastIndexOf(numbers, 1), 2);
|
||||
|
||||
numbers = [1, 0, 1, 0, 0, 1, 0, 0, 0];
|
||||
numbers.lastIndexOf = null;
|
||||
equal(_.lastIndexOf(numbers, 1), 5, 'can compute lastIndexOf, even without the native function');
|
||||
equal(_.lastIndexOf(numbers, 0), 8, 'lastIndexOf the other element');
|
||||
var result = (function(){ return _.lastIndexOf(arguments, 1); })(1, 0, 1, 0, 0, 1, 0, 0, 0);
|
||||
equal(result, 5, 'works on an arguments object');
|
||||
equal(_.indexOf(null, 2), -1, 'handles nulls properly');
|
||||
|
||||
numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
|
||||
index = _.lastIndexOf(numbers, 2, 2);
|
||||
equal(index, 1, 'supports the fromIndex argument');
|
||||
});
|
||||
|
||||
test("range", function() {
|
||||
equal(_.range(0).join(''), '', 'range with 0 as a first argument generates an empty array');
|
||||
equal(_.range(4).join(' '), '0 1 2 3', 'range with a single positive argument generates an array of elements 0,1,2,...,n-1');
|
||||
equal(_.range(5, 8).join(' '), '5 6 7', 'range with two arguments a & b, a<b generates an array of elements a,a+1,a+2,...,b-2,b-1');
|
||||
equal(_.range(8, 5).join(''), '', 'range with two arguments a & b, b<a generates an empty array');
|
||||
equal(_.range(3, 10, 3).join(' '), '3 6 9', 'range with three arguments a & b & c, c < b-a, a < b generates an array of elements a,a+c,a+2c,...,b - (multiplier of a) < c');
|
||||
equal(_.range(3, 10, 15).join(''), '3', 'range with three arguments a & b & c, c > b-a, a < b generates an array with a single element, equal to a');
|
||||
equal(_.range(12, 7, -2).join(' '), '12 10 8', 'range with three arguments a & b & c, a > b, c < 0 generates an array of elements a,a-c,a-2c and ends with the number not less than b');
|
||||
equal(_.range(0, -10, -1).join(' '), '0 -1 -2 -3 -4 -5 -6 -7 -8 -9', 'final example in the Python docs');
|
||||
});
|
||||
|
||||
});
|
|
@ -1,59 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
module("Chaining");
|
||||
|
||||
test("map/flatten/reduce", function() {
|
||||
var lyrics = [
|
||||
"I'm a lumberjack and I'm okay",
|
||||
"I sleep all night and I work all day",
|
||||
"He's a lumberjack and he's okay",
|
||||
"He sleeps all night and he works all day"
|
||||
];
|
||||
var counts = _(lyrics).chain()
|
||||
.map(function(line) { return line.split(''); })
|
||||
.flatten()
|
||||
.reduce(function(hash, l) {
|
||||
hash[l] = hash[l] || 0;
|
||||
hash[l]++;
|
||||
return hash;
|
||||
}, {}).value();
|
||||
ok(counts['a'] == 16 && counts['e'] == 10, 'counted all the letters in the song');
|
||||
});
|
||||
|
||||
test("select/reject/sortBy", function() {
|
||||
var numbers = [1,2,3,4,5,6,7,8,9,10];
|
||||
numbers = _(numbers).chain().select(function(n) {
|
||||
return n % 2 == 0;
|
||||
}).reject(function(n) {
|
||||
return n % 4 == 0;
|
||||
}).sortBy(function(n) {
|
||||
return -n;
|
||||
}).value();
|
||||
equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
|
||||
});
|
||||
|
||||
test("select/reject/sortBy in functional style", function() {
|
||||
var numbers = [1,2,3,4,5,6,7,8,9,10];
|
||||
numbers = _.chain(numbers).select(function(n) {
|
||||
return n % 2 == 0;
|
||||
}).reject(function(n) {
|
||||
return n % 4 == 0;
|
||||
}).sortBy(function(n) {
|
||||
return -n;
|
||||
}).value();
|
||||
equal(numbers.join(', '), "10, 6, 2", "filtered and reversed the numbers");
|
||||
});
|
||||
|
||||
test("reverse/concat/unshift/pop/map", function() {
|
||||
var numbers = [1,2,3,4,5];
|
||||
numbers = _(numbers).chain()
|
||||
.reverse()
|
||||
.concat([5, 5, 5])
|
||||
.unshift(17)
|
||||
.pop()
|
||||
.map(function(n){ return n * 2; })
|
||||
.value();
|
||||
equal(numbers.join(', '), "34, 10, 8, 6, 4, 2, 10, 10", 'can chain together array functions.');
|
||||
});
|
||||
|
||||
});
|
|
@ -1,426 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
module("Collections");
|
||||
|
||||
test("each", function() {
|
||||
_.each([1, 2, 3], function(num, i) {
|
||||
equal(num, i + 1, 'each iterators provide value and iteration count');
|
||||
});
|
||||
|
||||
var answers = [];
|
||||
_.each([1, 2, 3], function(num){ answers.push(num * this.multiplier);}, {multiplier : 5});
|
||||
equal(answers.join(', '), '5, 10, 15', 'context object property accessed');
|
||||
|
||||
answers = [];
|
||||
_.forEach([1, 2, 3], function(num){ answers.push(num); });
|
||||
equal(answers.join(', '), '1, 2, 3', 'aliased as "forEach"');
|
||||
|
||||
answers = [];
|
||||
var obj = {one : 1, two : 2, three : 3};
|
||||
obj.constructor.prototype.four = 4;
|
||||
_.each(obj, function(value, key){ answers.push(key); });
|
||||
equal(answers.join(", "), 'one, two, three', 'iterating over objects works, and ignores the object prototype.');
|
||||
delete obj.constructor.prototype.four;
|
||||
|
||||
answer = null;
|
||||
_.each([1, 2, 3], function(num, index, arr){ if (_.include(arr, num)) answer = true; });
|
||||
ok(answer, 'can reference the original collection from inside the iterator');
|
||||
|
||||
answers = 0;
|
||||
_.each(null, function(){ ++answers; });
|
||||
equal(answers, 0, 'handles a null properly');
|
||||
});
|
||||
|
||||
test('map', function() {
|
||||
var doubled = _.map([1, 2, 3], function(num){ return num * 2; });
|
||||
equal(doubled.join(', '), '2, 4, 6', 'doubled numbers');
|
||||
|
||||
doubled = _.collect([1, 2, 3], function(num){ return num * 2; });
|
||||
equal(doubled.join(', '), '2, 4, 6', 'aliased as "collect"');
|
||||
|
||||
var tripled = _.map([1, 2, 3], function(num){ return num * this.multiplier; }, {multiplier : 3});
|
||||
equal(tripled.join(', '), '3, 6, 9', 'tripled numbers with context');
|
||||
|
||||
var doubled = _([1, 2, 3]).map(function(num){ return num * 2; });
|
||||
equal(doubled.join(', '), '2, 4, 6', 'OO-style doubled numbers');
|
||||
|
||||
if (document.querySelectorAll) {
|
||||
var ids = _.map(document.querySelectorAll('#map-test *'), function(n){ return n.id; });
|
||||
deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on NodeLists.');
|
||||
}
|
||||
|
||||
var ids = _.map($('#map-test').children(), function(n){ return n.id; });
|
||||
deepEqual(ids, ['id1', 'id2'], 'Can use collection methods on jQuery Array-likes.');
|
||||
|
||||
var ids = _.map(document.images, function(n){ return n.id; });
|
||||
ok(ids[0] == 'chart_image', 'can use collection methods on HTMLCollections');
|
||||
|
||||
var ifnull = _.map(null, function(){});
|
||||
ok(_.isArray(ifnull) && ifnull.length === 0, 'handles a null properly');
|
||||
});
|
||||
|
||||
test('reduce', function() {
|
||||
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; }, 0);
|
||||
equal(sum, 6, 'can sum up an array');
|
||||
|
||||
var context = {multiplier : 3};
|
||||
sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num * this.multiplier; }, 0, context);
|
||||
equal(sum, 18, 'can reduce with a context object');
|
||||
|
||||
sum = _.inject([1, 2, 3], function(sum, num){ return sum + num; }, 0);
|
||||
equal(sum, 6, 'aliased as "inject"');
|
||||
|
||||
sum = _([1, 2, 3]).reduce(function(sum, num){ return sum + num; }, 0);
|
||||
equal(sum, 6, 'OO-style reduce');
|
||||
|
||||
var sum = _.reduce([1, 2, 3], function(sum, num){ return sum + num; });
|
||||
equal(sum, 6, 'default initial value');
|
||||
|
||||
var ifnull;
|
||||
try {
|
||||
_.reduce(null, function(){});
|
||||
} catch (ex) {
|
||||
ifnull = ex;
|
||||
}
|
||||
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
|
||||
|
||||
ok(_.reduce(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
|
||||
equal(_.reduce([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
|
||||
raises(function() { _.reduce([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
|
||||
});
|
||||
|
||||
test('reduceRight', function() {
|
||||
var list = _.reduceRight(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
|
||||
equal(list, 'bazbarfoo', 'can perform right folds');
|
||||
|
||||
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; }, '');
|
||||
equal(list, 'bazbarfoo', 'aliased as "foldr"');
|
||||
|
||||
var list = _.foldr(["foo", "bar", "baz"], function(memo, str){ return memo + str; });
|
||||
equal(list, 'bazbarfoo', 'default initial value');
|
||||
|
||||
var ifnull;
|
||||
try {
|
||||
_.reduceRight(null, function(){});
|
||||
} catch (ex) {
|
||||
ifnull = ex;
|
||||
}
|
||||
ok(ifnull instanceof TypeError, 'handles a null (without inital value) properly');
|
||||
|
||||
var sum = _.reduceRight({a: 1, b: 2, c: 3}, function(sum, num){ return sum + num; });
|
||||
equal(sum, 6, 'default initial value on object');
|
||||
|
||||
ok(_.reduceRight(null, function(){}, 138) === 138, 'handles a null (with initial value) properly');
|
||||
|
||||
equal(_.reduceRight([], function(){}, undefined), undefined, 'undefined can be passed as a special case');
|
||||
raises(function() { _.reduceRight([], function(){}); }, TypeError, 'throws an error for empty arrays with no initial value');
|
||||
|
||||
// Assert that the correct arguments are being passed.
|
||||
|
||||
var args,
|
||||
memo = {},
|
||||
object = {a: 1, b: 2},
|
||||
lastKey = _.keys(object).pop();
|
||||
|
||||
var expected = lastKey == 'a'
|
||||
? [memo, 1, 'a', object]
|
||||
: [memo, 2, 'b', object];
|
||||
|
||||
_.reduceRight(object, function() {
|
||||
args || (args = _.toArray(arguments));
|
||||
}, memo);
|
||||
|
||||
deepEqual(args, expected);
|
||||
|
||||
// And again, with numeric keys.
|
||||
|
||||
object = {'2': 'a', '1': 'b'};
|
||||
lastKey = _.keys(object).pop();
|
||||
args = null;
|
||||
|
||||
expected = lastKey == '2'
|
||||
? [memo, 'a', '2', object]
|
||||
: [memo, 'b', '1', object];
|
||||
|
||||
_.reduceRight(object, function() {
|
||||
args || (args = _.toArray(arguments));
|
||||
}, memo);
|
||||
|
||||
deepEqual(args, expected);
|
||||
});
|
||||
|
||||
test('find', function() {
|
||||
var array = [1, 2, 3, 4];
|
||||
strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`');
|
||||
strictEqual(_.find(array, function() { return false; }), void 0, 'should return `undefined` if `value` is not found');
|
||||
});
|
||||
|
||||
test('detect', function() {
|
||||
var result = _.detect([1, 2, 3], function(num){ return num * 2 == 4; });
|
||||
equal(result, 2, 'found the first "2" and broke the loop');
|
||||
});
|
||||
|
||||
test('select', function() {
|
||||
var evens = _.select([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
|
||||
equal(evens.join(', '), '2, 4, 6', 'selected each even number');
|
||||
|
||||
evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
|
||||
equal(evens.join(', '), '2, 4, 6', 'aliased as "filter"');
|
||||
});
|
||||
|
||||
test('reject', function() {
|
||||
var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
|
||||
equal(odds.join(', '), '1, 3, 5', 'rejected each even number');
|
||||
|
||||
var context = "obj";
|
||||
|
||||
var evens = _.reject([1, 2, 3, 4, 5, 6], function(num){
|
||||
equal(context, "obj");
|
||||
return num % 2 != 0;
|
||||
}, context);
|
||||
equal(evens.join(', '), '2, 4, 6', 'rejected each odd number');
|
||||
});
|
||||
|
||||
test('all', function() {
|
||||
ok(_.all([], _.identity), 'the empty set');
|
||||
ok(_.all([true, true, true], _.identity), 'all true values');
|
||||
ok(!_.all([true, false, true], _.identity), 'one false value');
|
||||
ok(_.all([0, 10, 28], function(num){ return num % 2 == 0; }), 'even numbers');
|
||||
ok(!_.all([0, 11, 28], function(num){ return num % 2 == 0; }), 'an odd number');
|
||||
ok(_.all([1], _.identity) === true, 'cast to boolean - true');
|
||||
ok(_.all([0], _.identity) === false, 'cast to boolean - false');
|
||||
ok(_.every([true, true, true], _.identity), 'aliased as "every"');
|
||||
ok(!_.all([undefined, undefined, undefined], _.identity), 'works with arrays of undefined');
|
||||
});
|
||||
|
||||
test('any', function() {
|
||||
var nativeSome = Array.prototype.some;
|
||||
Array.prototype.some = null;
|
||||
ok(!_.any([]), 'the empty set');
|
||||
ok(!_.any([false, false, false]), 'all false values');
|
||||
ok(_.any([false, false, true]), 'one true value');
|
||||
ok(_.any([null, 0, 'yes', false]), 'a string');
|
||||
ok(!_.any([null, 0, '', false]), 'falsy values');
|
||||
ok(!_.any([1, 11, 29], function(num){ return num % 2 == 0; }), 'all odd numbers');
|
||||
ok(_.any([1, 10, 29], function(num){ return num % 2 == 0; }), 'an even number');
|
||||
ok(_.any([1], _.identity) === true, 'cast to boolean - true');
|
||||
ok(_.any([0], _.identity) === false, 'cast to boolean - false');
|
||||
ok(_.some([false, false, true]), 'aliased as "some"');
|
||||
Array.prototype.some = nativeSome;
|
||||
});
|
||||
|
||||
test('include', function() {
|
||||
ok(_.include([1,2,3], 2), 'two is in the array');
|
||||
ok(!_.include([1,3,9], 2), 'two is not in the array');
|
||||
ok(_.contains({moe:1, larry:3, curly:9}, 3) === true, '_.include on objects checks their values');
|
||||
ok(_([1,2,3]).include(2), 'OO-style include');
|
||||
});
|
||||
|
||||
test('invoke', function() {
|
||||
var list = [[5, 1, 7], [3, 2, 1]];
|
||||
var result = _.invoke(list, 'sort');
|
||||
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
|
||||
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
|
||||
});
|
||||
|
||||
test('invoke w/ function reference', function() {
|
||||
var list = [[5, 1, 7], [3, 2, 1]];
|
||||
var result = _.invoke(list, Array.prototype.sort);
|
||||
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
|
||||
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
|
||||
});
|
||||
|
||||
// Relevant when using ClojureScript
|
||||
test('invoke when strings have a call method', function() {
|
||||
String.prototype.call = function() {
|
||||
return 42;
|
||||
};
|
||||
var list = [[5, 1, 7], [3, 2, 1]];
|
||||
var s = "foo";
|
||||
equal(s.call(), 42, "call function exists");
|
||||
var result = _.invoke(list, 'sort');
|
||||
equal(result[0].join(', '), '1, 5, 7', 'first array sorted');
|
||||
equal(result[1].join(', '), '1, 2, 3', 'second array sorted');
|
||||
delete String.prototype.call;
|
||||
equal(s.call, undefined, "call function removed");
|
||||
});
|
||||
|
||||
test('pluck', function() {
|
||||
var people = [{name : 'moe', age : 30}, {name : 'curly', age : 50}];
|
||||
equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'pulls names out of objects');
|
||||
});
|
||||
|
||||
test('where', function() {
|
||||
var list = [{a: 1, b: 2}, {a: 2, b: 2}, {a: 1, b: 3}, {a: 1, b: 4}];
|
||||
var result = _.where(list, {a: 1});
|
||||
equal(result.length, 3);
|
||||
equal(result[result.length - 1].b, 4);
|
||||
result = _.where(list, {b: 2});
|
||||
equal(result.length, 2);
|
||||
equal(result[0].a, 1);
|
||||
});
|
||||
|
||||
test('max', function() {
|
||||
equal(3, _.max([1, 2, 3]), 'can perform a regular Math.max');
|
||||
|
||||
var neg = _.max([1, 2, 3], function(num){ return -num; });
|
||||
equal(neg, 1, 'can perform a computation-based max');
|
||||
|
||||
equal(-Infinity, _.max({}), 'Maximum value of an empty object');
|
||||
equal(-Infinity, _.max([]), 'Maximum value of an empty array');
|
||||
|
||||
equal(299999, _.max(_.range(1,300000)), "Maximum value of a too-big array");
|
||||
});
|
||||
|
||||
test('min', function() {
|
||||
equal(1, _.min([1, 2, 3]), 'can perform a regular Math.min');
|
||||
|
||||
var neg = _.min([1, 2, 3], function(num){ return -num; });
|
||||
equal(neg, 3, 'can perform a computation-based min');
|
||||
|
||||
equal(Infinity, _.min({}), 'Minimum value of an empty object');
|
||||
equal(Infinity, _.min([]), 'Minimum value of an empty array');
|
||||
|
||||
var now = new Date(9999999999);
|
||||
var then = new Date(0);
|
||||
equal(_.min([now, then]), then);
|
||||
|
||||
equal(1, _.min(_.range(1,300000)), "Minimum value of a too-big array");
|
||||
});
|
||||
|
||||
test('sortBy', function() {
|
||||
var people = [{name : 'curly', age : 50}, {name : 'moe', age : 30}];
|
||||
people = _.sortBy(people, function(person){ return person.age; });
|
||||
equal(_.pluck(people, 'name').join(', '), 'moe, curly', 'stooges sorted by age');
|
||||
|
||||
var list = [undefined, 4, 1, undefined, 3, 2];
|
||||
equal(_.sortBy(list, _.identity).join(','), '1,2,3,4,,', 'sortBy with undefined values');
|
||||
|
||||
var list = ["one", "two", "three", "four", "five"];
|
||||
var sorted = _.sortBy(list, 'length');
|
||||
equal(sorted.join(' '), 'one two four five three', 'sorted by length');
|
||||
|
||||
function Pair(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
var collection = [
|
||||
new Pair(1, 1), new Pair(1, 2),
|
||||
new Pair(1, 3), new Pair(1, 4),
|
||||
new Pair(1, 5), new Pair(1, 6),
|
||||
new Pair(2, 1), new Pair(2, 2),
|
||||
new Pair(2, 3), new Pair(2, 4),
|
||||
new Pair(2, 5), new Pair(2, 6),
|
||||
new Pair(undefined, 1), new Pair(undefined, 2),
|
||||
new Pair(undefined, 3), new Pair(undefined, 4),
|
||||
new Pair(undefined, 5), new Pair(undefined, 6)
|
||||
];
|
||||
|
||||
var actual = _.sortBy(collection, function(pair) {
|
||||
return pair.x;
|
||||
});
|
||||
|
||||
deepEqual(actual, collection, 'sortBy should be stable');
|
||||
});
|
||||
|
||||
test('groupBy', function() {
|
||||
var parity = _.groupBy([1, 2, 3, 4, 5, 6], function(num){ return num % 2; });
|
||||
ok('0' in parity && '1' in parity, 'created a group for each value');
|
||||
equal(parity[0].join(', '), '2, 4, 6', 'put each even number in the right group');
|
||||
|
||||
var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
|
||||
var grouped = _.groupBy(list, 'length');
|
||||
equal(grouped['3'].join(' '), 'one two six ten');
|
||||
equal(grouped['4'].join(' '), 'four five nine');
|
||||
equal(grouped['5'].join(' '), 'three seven eight');
|
||||
|
||||
var context = {};
|
||||
_.groupBy([{}], function(){ ok(this === context); }, context);
|
||||
|
||||
grouped = _.groupBy([4.2, 6.1, 6.4], function(num) {
|
||||
return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
|
||||
});
|
||||
equal(grouped.constructor.length, 1);
|
||||
equal(grouped.hasOwnProperty.length, 2);
|
||||
|
||||
var array = [{}];
|
||||
_.groupBy(array, function(value, index, obj){ ok(obj === array); });
|
||||
});
|
||||
|
||||
test('countBy', function() {
|
||||
var parity = _.countBy([1, 2, 3, 4, 5], function(num){ return num % 2 == 0; });
|
||||
equal(parity['true'], 2);
|
||||
equal(parity['false'], 3);
|
||||
|
||||
var list = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
|
||||
var grouped = _.countBy(list, 'length');
|
||||
equal(grouped['3'], 4);
|
||||
equal(grouped['4'], 3);
|
||||
equal(grouped['5'], 3);
|
||||
|
||||
var context = {};
|
||||
_.countBy([{}], function(){ ok(this === context); }, context);
|
||||
|
||||
grouped = _.countBy([4.2, 6.1, 6.4], function(num) {
|
||||
return Math.floor(num) > 4 ? 'hasOwnProperty' : 'constructor';
|
||||
});
|
||||
equal(grouped.constructor, 1);
|
||||
equal(grouped.hasOwnProperty, 2);
|
||||
|
||||
var array = [{}];
|
||||
_.countBy(array, function(value, index, obj){ ok(obj === array); });
|
||||
});
|
||||
|
||||
test('sortedIndex', function() {
|
||||
var numbers = [10, 20, 30, 40, 50], num = 35;
|
||||
var indexForNum = _.sortedIndex(numbers, num);
|
||||
equal(indexForNum, 3, '35 should be inserted at index 3');
|
||||
|
||||
var indexFor30 = _.sortedIndex(numbers, 30);
|
||||
equal(indexFor30, 2, '30 should be inserted at index 2');
|
||||
|
||||
var objects = [{x: 10}, {x: 20}, {x: 30}, {x: 40}];
|
||||
var iterator = function(obj){ return obj.x; };
|
||||
strictEqual(_.sortedIndex(objects, {x: 25}, iterator), 2);
|
||||
strictEqual(_.sortedIndex(objects, {x: 35}, 'x'), 3);
|
||||
|
||||
var context = {1: 2, 2: 3, 3: 4};
|
||||
iterator = function(obj){ return this[obj]; };
|
||||
strictEqual(_.sortedIndex([1, 3], 2, iterator, context), 1);
|
||||
});
|
||||
|
||||
test('shuffle', function() {
|
||||
var numbers = _.range(10);
|
||||
var shuffled = _.shuffle(numbers).sort();
|
||||
notStrictEqual(numbers, shuffled, 'original object is unmodified');
|
||||
equal(shuffled.join(','), numbers.join(','), 'contains the same members before and after shuffle');
|
||||
});
|
||||
|
||||
test('toArray', function() {
|
||||
ok(!_.isArray(arguments), 'arguments object is not an array');
|
||||
ok(_.isArray(_.toArray(arguments)), 'arguments object converted into array');
|
||||
var a = [1,2,3];
|
||||
ok(_.toArray(a) !== a, 'array is cloned');
|
||||
equal(_.toArray(a).join(', '), '1, 2, 3', 'cloned array contains same elements');
|
||||
|
||||
var numbers = _.toArray({one : 1, two : 2, three : 3});
|
||||
equal(numbers.join(', '), '1, 2, 3', 'object flattened into array');
|
||||
});
|
||||
|
||||
test('size', function() {
|
||||
equal(_.size({one : 1, two : 2, three : 3}), 3, 'can compute the size of an object');
|
||||
equal(_.size([1, 2, 3]), 3, 'can compute the size of an array');
|
||||
|
||||
var func = function() {
|
||||
return _.size(arguments);
|
||||
};
|
||||
|
||||
equal(func(1, 2, 3, 4), 4, 'can test the size of the arguments object');
|
||||
|
||||
equal(_.size('hello'), 5, 'can compute the size of a string');
|
||||
|
||||
equal(_.size(null), 0, 'handles nulls');
|
||||
});
|
||||
|
||||
});
|
|
@ -1,259 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
module("Functions");
|
||||
|
||||
test("bind", function() {
|
||||
var context = {name : 'moe'};
|
||||
var func = function(arg) { return "name: " + (this.name || arg); };
|
||||
var bound = _.bind(func, context);
|
||||
equal(bound(), 'name: moe', 'can bind a function to a context');
|
||||
|
||||
bound = _(func).bind(context);
|
||||
equal(bound(), 'name: moe', 'can do OO-style binding');
|
||||
|
||||
bound = _.bind(func, null, 'curly');
|
||||
equal(bound(), 'name: curly', 'can bind without specifying a context');
|
||||
|
||||
func = function(salutation, name) { return salutation + ': ' + name; };
|
||||
func = _.bind(func, this, 'hello');
|
||||
equal(func('moe'), 'hello: moe', 'the function was partially applied in advance');
|
||||
|
||||
var func = _.bind(func, this, 'curly');
|
||||
equal(func(), 'hello: curly', 'the function was completely applied in advance');
|
||||
|
||||
var func = function(salutation, firstname, lastname) { return salutation + ': ' + firstname + ' ' + lastname; };
|
||||
func = _.bind(func, this, 'hello', 'moe', 'curly');
|
||||
equal(func(), 'hello: moe curly', 'the function was partially applied in advance and can accept multiple arguments');
|
||||
|
||||
func = function(context, message) { equal(this, context, message); };
|
||||
_.bind(func, 0, 0, 'can bind a function to `0`')();
|
||||
_.bind(func, '', '', 'can bind a function to an empty string')();
|
||||
_.bind(func, false, false, 'can bind a function to `false`')();
|
||||
|
||||
// These tests are only meaningful when using a browser without a native bind function
|
||||
// To test this with a modern browser, set underscore's nativeBind to undefined
|
||||
var F = function () { return this; };
|
||||
var Boundf = _.bind(F, {hello: "moe curly"});
|
||||
equal(new Boundf().hello, undefined, "function should not be bound to the context, to comply with ECMAScript 5");
|
||||
equal(Boundf().hello, "moe curly", "When called without the new operator, it's OK to be bound to the context");
|
||||
});
|
||||
|
||||
test("bindAll", function() {
|
||||
var curly = {name : 'curly'}, moe = {
|
||||
name : 'moe',
|
||||
getName : function() { return 'name: ' + this.name; },
|
||||
sayHi : function() { return 'hi: ' + this.name; }
|
||||
};
|
||||
curly.getName = moe.getName;
|
||||
_.bindAll(moe, 'getName', 'sayHi');
|
||||
curly.sayHi = moe.sayHi;
|
||||
equal(curly.getName(), 'name: curly', 'unbound function is bound to current object');
|
||||
equal(curly.sayHi(), 'hi: moe', 'bound function is still bound to original object');
|
||||
|
||||
curly = {name : 'curly'};
|
||||
moe = {
|
||||
name : 'moe',
|
||||
getName : function() { return 'name: ' + this.name; },
|
||||
sayHi : function() { return 'hi: ' + this.name; }
|
||||
};
|
||||
_.bindAll(moe);
|
||||
curly.sayHi = moe.sayHi;
|
||||
equal(curly.sayHi(), 'hi: moe', 'calling bindAll with no arguments binds all functions to the object');
|
||||
});
|
||||
|
||||
test("memoize", function() {
|
||||
var fib = function(n) {
|
||||
return n < 2 ? n : fib(n - 1) + fib(n - 2);
|
||||
};
|
||||
var fastFib = _.memoize(fib);
|
||||
equal(fib(10), 55, 'a memoized version of fibonacci produces identical results');
|
||||
equal(fastFib(10), 55, 'a memoized version of fibonacci produces identical results');
|
||||
|
||||
var o = function(str) {
|
||||
return str;
|
||||
};
|
||||
var fastO = _.memoize(o);
|
||||
equal(o('toString'), 'toString', 'checks hasOwnProperty');
|
||||
equal(fastO('toString'), 'toString', 'checks hasOwnProperty');
|
||||
});
|
||||
|
||||
asyncTest("delay", 2, function() {
|
||||
var delayed = false;
|
||||
_.delay(function(){ delayed = true; }, 100);
|
||||
setTimeout(function(){ ok(!delayed, "didn't delay the function quite yet"); }, 50);
|
||||
setTimeout(function(){ ok(delayed, 'delayed the function'); start(); }, 150);
|
||||
});
|
||||
|
||||
asyncTest("defer", 1, function() {
|
||||
var deferred = false;
|
||||
_.defer(function(bool){ deferred = bool; }, true);
|
||||
_.delay(function(){ ok(deferred, "deferred the function"); start(); }, 50);
|
||||
});
|
||||
|
||||
asyncTest("throttle", 2, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ counter++; };
|
||||
var throttledIncr = _.throttle(incr, 100);
|
||||
throttledIncr(); throttledIncr(); throttledIncr();
|
||||
setTimeout(throttledIncr, 70);
|
||||
setTimeout(throttledIncr, 120);
|
||||
setTimeout(throttledIncr, 140);
|
||||
setTimeout(throttledIncr, 190);
|
||||
setTimeout(throttledIncr, 220);
|
||||
setTimeout(throttledIncr, 240);
|
||||
_.delay(function(){ equal(counter, 1, "incr was called immediately"); }, 30);
|
||||
_.delay(function(){ equal(counter, 4, "incr was throttled"); start(); }, 400);
|
||||
});
|
||||
|
||||
asyncTest("throttle arguments", 2, function() {
|
||||
var value = 0;
|
||||
var update = function(val){ value = val; };
|
||||
var throttledUpdate = _.throttle(update, 100);
|
||||
throttledUpdate(1); throttledUpdate(2); throttledUpdate(3);
|
||||
setTimeout(function(){ throttledUpdate(4); }, 120);
|
||||
setTimeout(function(){ throttledUpdate(5); }, 140);
|
||||
setTimeout(function(){ throttledUpdate(6); }, 250);
|
||||
_.delay(function(){ equal(value, 1, "updated to latest value"); }, 40);
|
||||
_.delay(function(){ equal(value, 6, "updated to latest value"); start(); }, 400);
|
||||
});
|
||||
|
||||
asyncTest("throttle once", 2, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ return ++counter; };
|
||||
var throttledIncr = _.throttle(incr, 100);
|
||||
var result = throttledIncr();
|
||||
_.delay(function(){
|
||||
equal(result, 1, "throttled functions return their value");
|
||||
equal(counter, 1, "incr was called once"); start();
|
||||
}, 220);
|
||||
});
|
||||
|
||||
asyncTest("throttle twice", 1, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ counter++; };
|
||||
var throttledIncr = _.throttle(incr, 100);
|
||||
throttledIncr(); throttledIncr();
|
||||
_.delay(function(){ equal(counter, 2, "incr was called twice"); start(); }, 220);
|
||||
});
|
||||
|
||||
asyncTest("throttle repeatedly with results", 9, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ return ++counter; };
|
||||
var throttledIncr = _.throttle(incr, 100);
|
||||
var results = [];
|
||||
var saveResult = function() { results.push(throttledIncr()); };
|
||||
saveResult(); saveResult(); saveResult();
|
||||
setTimeout(saveResult, 70);
|
||||
setTimeout(saveResult, 120);
|
||||
setTimeout(saveResult, 140);
|
||||
setTimeout(saveResult, 190);
|
||||
setTimeout(saveResult, 240);
|
||||
setTimeout(saveResult, 260);
|
||||
_.delay(function() {
|
||||
equal(results[0], 1, "incr was called once");
|
||||
equal(results[1], 1, "incr was throttled");
|
||||
equal(results[2], 1, "incr was throttled");
|
||||
equal(results[3], 1, "incr was throttled");
|
||||
equal(results[4], 2, "incr was called twice");
|
||||
equal(results[5], 2, "incr was throttled");
|
||||
equal(results[6], 2, "incr was throttled");
|
||||
equal(results[7], 3, "incr was called thrice");
|
||||
equal(results[8], 3, "incr was throttled");
|
||||
start();
|
||||
}, 400);
|
||||
});
|
||||
|
||||
asyncTest("debounce", 1, function() {
|
||||
var counter = 0;
|
||||
var incr = function(){ counter++; };
|
||||
var debouncedIncr = _.debounce(incr, 50);
|
||||
debouncedIncr(); debouncedIncr(); debouncedIncr();
|
||||
setTimeout(debouncedIncr, 30);
|
||||
setTimeout(debouncedIncr, 60);
|
||||
setTimeout(debouncedIncr, 90);
|
||||
setTimeout(debouncedIncr, 120);
|
||||
setTimeout(debouncedIncr, 150);
|
||||
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 220);
|
||||
});
|
||||
|
||||
asyncTest("debounce asap", 5, function() {
|
||||
var a, b, c;
|
||||
var counter = 0;
|
||||
var incr = function(){ return ++counter; };
|
||||
var debouncedIncr = _.debounce(incr, 50, true);
|
||||
a = debouncedIncr();
|
||||
b = debouncedIncr();
|
||||
c = debouncedIncr();
|
||||
equal(a, 1);
|
||||
equal(b, 1);
|
||||
equal(c, 1);
|
||||
equal(counter, 1, 'incr was called immediately');
|
||||
setTimeout(debouncedIncr, 30);
|
||||
setTimeout(debouncedIncr, 60);
|
||||
setTimeout(debouncedIncr, 90);
|
||||
setTimeout(debouncedIncr, 120);
|
||||
setTimeout(debouncedIncr, 150);
|
||||
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 220);
|
||||
});
|
||||
|
||||
asyncTest("debounce asap recursively", 2, function() {
|
||||
var counter = 0;
|
||||
var debouncedIncr = _.debounce(function(){
|
||||
counter++;
|
||||
if (counter < 5) debouncedIncr();
|
||||
}, 50, true);
|
||||
debouncedIncr();
|
||||
equal(counter, 1, 'incr was called immediately');
|
||||
_.delay(function(){ equal(counter, 1, "incr was debounced"); start(); }, 70);
|
||||
});
|
||||
|
||||
test("once", function() {
|
||||
var num = 0;
|
||||
var increment = _.once(function(){ num++; });
|
||||
increment();
|
||||
increment();
|
||||
equal(num, 1);
|
||||
});
|
||||
|
||||
test("wrap", function() {
|
||||
var greet = function(name){ return "hi: " + name; };
|
||||
var backwards = _.wrap(greet, function(func, name){ return func(name) + ' ' + name.split('').reverse().join(''); });
|
||||
equal(backwards('moe'), 'hi: moe eom', 'wrapped the saluation function');
|
||||
|
||||
var inner = function(){ return "Hello "; };
|
||||
var obj = {name : "Moe"};
|
||||
obj.hi = _.wrap(inner, function(fn){ return fn() + this.name; });
|
||||
equal(obj.hi(), "Hello Moe");
|
||||
|
||||
var noop = function(){};
|
||||
var wrapped = _.wrap(noop, function(fn){ return Array.prototype.slice.call(arguments, 0); });
|
||||
var ret = wrapped(['whats', 'your'], 'vector', 'victor');
|
||||
deepEqual(ret, [noop, ['whats', 'your'], 'vector', 'victor']);
|
||||
});
|
||||
|
||||
test("compose", function() {
|
||||
var greet = function(name){ return "hi: " + name; };
|
||||
var exclaim = function(sentence){ return sentence + '!'; };
|
||||
var composed = _.compose(exclaim, greet);
|
||||
equal(composed('moe'), 'hi: moe!', 'can compose a function that takes another');
|
||||
|
||||
composed = _.compose(greet, exclaim);
|
||||
equal(composed('moe'), 'hi: moe!', 'in this case, the functions are also commutative');
|
||||
});
|
||||
|
||||
test("after", function() {
|
||||
var testAfter = function(afterAmount, timesCalled) {
|
||||
var afterCalled = 0;
|
||||
var after = _.after(afterAmount, function() {
|
||||
afterCalled++;
|
||||
});
|
||||
while (timesCalled--) after();
|
||||
return afterCalled;
|
||||
};
|
||||
|
||||
equal(testAfter(5, 5), 1, "after(N) should fire after being called N times");
|
||||
equal(testAfter(5, 4), 0, "after(N) should not fire unless called N times");
|
||||
equal(testAfter(0, 0), 1, "after(0) should fire immediately");
|
||||
});
|
||||
|
||||
});
|
|
@ -1,45 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Underscore Test Suite</title>
|
||||
<link rel="stylesheet" href="vendor/qunit.css" type="text/css" media="screen">
|
||||
<script src="vendor/jquery.js"></script>
|
||||
<script src="vendor/qunit.js"></script>
|
||||
<script src="vendor/jslitmus.js"></script>
|
||||
<script src="../underscore.js"></script>
|
||||
<script src="../../lib/underscore.string.js"></script>
|
||||
|
||||
<script src="collections.js"></script>
|
||||
<script src="arrays.js"></script>
|
||||
<script src="functions.js"></script>
|
||||
<script src="objects.js"></script>
|
||||
<script src="utility.js"></script>
|
||||
<script src="chaining.js"></script>
|
||||
<script src="speed.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture">
|
||||
<div id="map-test">
|
||||
<div id="id1"></div>
|
||||
<div id="id2"></div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<h1 class="qunit-header">Underscore Speed Suite</h1>
|
||||
<p>
|
||||
A representative sample of the functions are benchmarked here, to provide
|
||||
a sense of how fast they might run in different browsers.
|
||||
Each iteration runs on an array of 1000 elements.<br /><br />
|
||||
For example, the 'intersection' test measures the number of times you can
|
||||
find the intersection of two thousand-element arrays in one second.
|
||||
</p>
|
||||
<br>
|
||||
<script type="text/html" id="template">
|
||||
<%
|
||||
// a comment
|
||||
if (data) { data += 12345; }; %>
|
||||
<li><%= data %></li>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,548 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
module("Objects");
|
||||
|
||||
test("keys", function() {
|
||||
equal(_.keys({one : 1, two : 2}).join(', '), 'one, two', 'can extract the keys from an object');
|
||||
// the test above is not safe because it relies on for-in enumeration order
|
||||
var a = []; a[1] = 0;
|
||||
equal(_.keys(a).join(', '), '1', 'is not fooled by sparse arrays; see issue #95');
|
||||
raises(function() { _.keys(null); }, TypeError, 'throws an error for `null` values');
|
||||
raises(function() { _.keys(void 0); }, TypeError, 'throws an error for `undefined` values');
|
||||
raises(function() { _.keys(1); }, TypeError, 'throws an error for number primitives');
|
||||
raises(function() { _.keys('a'); }, TypeError, 'throws an error for string primitives');
|
||||
raises(function() { _.keys(true); }, TypeError, 'throws an error for boolean primitives');
|
||||
});
|
||||
|
||||
test("values", function() {
|
||||
equal(_.values({one: 1, two: 2}).join(', '), '1, 2', 'can extract the values from an object');
|
||||
equal(_.values({one: 1, two: 2, length: 3}).join(', '), '1, 2, 3', '... even when one of them is "length"');
|
||||
});
|
||||
|
||||
test("pairs", function() {
|
||||
deepEqual(_.pairs({one: 1, two: 2}), [['one', 1], ['two', 2]], 'can convert an object into pairs');
|
||||
deepEqual(_.pairs({one: 1, two: 2, length: 3}), [['one', 1], ['two', 2], ['length', 3]], '... even when one of them is "length"');
|
||||
});
|
||||
|
||||
test("invert", function() {
|
||||
var obj = {first: 'Moe', second: 'Larry', third: 'Curly'};
|
||||
equal(_.keys(_.invert(obj)).join(' '), 'Moe Larry Curly', 'can invert an object');
|
||||
ok(_.isEqual(_.invert(_.invert(obj)), obj), 'two inverts gets you back where you started');
|
||||
|
||||
var obj = {length: 3};
|
||||
ok(_.invert(obj)['3'] == 'length', 'can invert an object with "length"')
|
||||
});
|
||||
|
||||
test("functions", function() {
|
||||
var obj = {a : 'dash', b : _.map, c : (/yo/), d : _.reduce};
|
||||
ok(_.isEqual(['b', 'd'], _.functions(obj)), 'can grab the function names of any passed-in object');
|
||||
|
||||
var Animal = function(){};
|
||||
Animal.prototype.run = function(){};
|
||||
equal(_.functions(new Animal).join(''), 'run', 'also looks up functions on the prototype');
|
||||
});
|
||||
|
||||
test("extend", function() {
|
||||
var result;
|
||||
equal(_.extend({}, {a:'b'}).a, 'b', 'can extend an object with the attributes of another');
|
||||
equal(_.extend({a:'x'}, {a:'b'}).a, 'b', 'properties in source override destination');
|
||||
equal(_.extend({x:'x'}, {a:'b'}).x, 'x', 'properties not in source dont get overriden');
|
||||
result = _.extend({x:'x'}, {a:'a'}, {b:'b'});
|
||||
ok(_.isEqual(result, {x:'x', a:'a', b:'b'}), 'can extend from multiple source objects');
|
||||
result = _.extend({x:'x'}, {a:'a', x:2}, {a:'b'});
|
||||
ok(_.isEqual(result, {x:2, a:'b'}), 'extending from multiple source objects last property trumps');
|
||||
result = _.extend({}, {a: void 0, b: null});
|
||||
equal(_.keys(result).join(''), 'ab', 'extend does not copy undefined values');
|
||||
});
|
||||
|
||||
test("pick", function() {
|
||||
var result;
|
||||
result = _.pick({a:1, b:2, c:3}, 'a', 'c');
|
||||
ok(_.isEqual(result, {a:1, c:3}), 'can restrict properties to those named');
|
||||
result = _.pick({a:1, b:2, c:3}, ['b', 'c']);
|
||||
ok(_.isEqual(result, {b:2, c:3}), 'can restrict properties to those named in an array');
|
||||
result = _.pick({a:1, b:2, c:3}, ['a'], 'b');
|
||||
ok(_.isEqual(result, {a:1, b:2}), 'can restrict properties to those named in mixed args');
|
||||
|
||||
var Obj = function(){};
|
||||
Obj.prototype = {a: 1, b: 2, c: 3};
|
||||
ok(_.isEqual(_.pick(new Obj, 'a', 'c'), {a:1, c: 3}), 'include prototype props');
|
||||
});
|
||||
|
||||
test("omit", function() {
|
||||
var result;
|
||||
result = _.omit({a:1, b:2, c:3}, 'b');
|
||||
ok(_.isEqual(result, {a:1, c:3}), 'can omit a single named property');
|
||||
result = _.omit({a:1, b:2, c:3}, 'a', 'c');
|
||||
ok(_.isEqual(result, {b:2}), 'can omit several named properties');
|
||||
result = _.omit({a:1, b:2, c:3}, ['b', 'c']);
|
||||
ok(_.isEqual(result, {a:1}), 'can omit properties named in an array');
|
||||
|
||||
var Obj = function(){};
|
||||
Obj.prototype = {a: 1, b: 2, c: 3};
|
||||
ok(_.isEqual(_.omit(new Obj, 'b'), {a:1, c: 3}), 'include prototype props');
|
||||
});
|
||||
|
||||
test("defaults", function() {
|
||||
var result;
|
||||
var options = {zero: 0, one: 1, empty: "", nan: NaN, string: "string"};
|
||||
|
||||
_.defaults(options, {zero: 1, one: 10, twenty: 20});
|
||||
equal(options.zero, 0, 'value exists');
|
||||
equal(options.one, 1, 'value exists');
|
||||
equal(options.twenty, 20, 'default applied');
|
||||
|
||||
_.defaults(options, {empty: "full"}, {nan: "nan"}, {word: "word"}, {word: "dog"});
|
||||
equal(options.empty, "", 'value exists');
|
||||
ok(_.isNaN(options.nan), "NaN isn't overridden");
|
||||
equal(options.word, "word", 'new value is added, first one wins');
|
||||
});
|
||||
|
||||
test("clone", function() {
|
||||
var moe = {name : 'moe', lucky : [13, 27, 34]};
|
||||
var clone = _.clone(moe);
|
||||
equal(clone.name, 'moe', 'the clone as the attributes of the original');
|
||||
|
||||
clone.name = 'curly';
|
||||
ok(clone.name == 'curly' && moe.name == 'moe', 'clones can change shallow attributes without affecting the original');
|
||||
|
||||
clone.lucky.push(101);
|
||||
equal(_.last(moe.lucky), 101, 'changes to deep attributes are shared with the original');
|
||||
|
||||
equal(_.clone(undefined), void 0, 'non objects should not be changed by clone');
|
||||
equal(_.clone(1), 1, 'non objects should not be changed by clone');
|
||||
equal(_.clone(null), null, 'non objects should not be changed by clone');
|
||||
});
|
||||
|
||||
test("isEqual", function() {
|
||||
function First() {
|
||||
this.value = 1;
|
||||
}
|
||||
First.prototype.value = 1;
|
||||
function Second() {
|
||||
this.value = 1;
|
||||
}
|
||||
Second.prototype.value = 2;
|
||||
|
||||
// Basic equality and identity comparisons.
|
||||
ok(_.isEqual(null, null), "`null` is equal to `null`");
|
||||
ok(_.isEqual(), "`undefined` is equal to `undefined`");
|
||||
|
||||
ok(!_.isEqual(0, -0), "`0` is not equal to `-0`");
|
||||
ok(!_.isEqual(-0, 0), "Commutative equality is implemented for `0` and `-0`");
|
||||
ok(!_.isEqual(null, undefined), "`null` is not equal to `undefined`");
|
||||
ok(!_.isEqual(undefined, null), "Commutative equality is implemented for `null` and `undefined`");
|
||||
|
||||
// String object and primitive comparisons.
|
||||
ok(_.isEqual("Curly", "Curly"), "Identical string primitives are equal");
|
||||
ok(_.isEqual(new String("Curly"), new String("Curly")), "String objects with identical primitive values are equal");
|
||||
ok(_.isEqual(new String("Curly"), "Curly"), "String primitives and their corresponding object wrappers are equal");
|
||||
ok(_.isEqual("Curly", new String("Curly")), "Commutative equality is implemented for string objects and primitives");
|
||||
|
||||
ok(!_.isEqual("Curly", "Larry"), "String primitives with different values are not equal");
|
||||
ok(!_.isEqual(new String("Curly"), new String("Larry")), "String objects with different primitive values are not equal");
|
||||
ok(!_.isEqual(new String("Curly"), {toString: function(){ return "Curly"; }}), "String objects and objects with a custom `toString` method are not equal");
|
||||
|
||||
// Number object and primitive comparisons.
|
||||
ok(_.isEqual(75, 75), "Identical number primitives are equal");
|
||||
ok(_.isEqual(new Number(75), new Number(75)), "Number objects with identical primitive values are equal");
|
||||
ok(_.isEqual(75, new Number(75)), "Number primitives and their corresponding object wrappers are equal");
|
||||
ok(_.isEqual(new Number(75), 75), "Commutative equality is implemented for number objects and primitives");
|
||||
ok(!_.isEqual(new Number(0), -0), "`new Number(0)` and `-0` are not equal");
|
||||
ok(!_.isEqual(0, new Number(-0)), "Commutative equality is implemented for `new Number(0)` and `-0`");
|
||||
|
||||
ok(!_.isEqual(new Number(75), new Number(63)), "Number objects with different primitive values are not equal");
|
||||
ok(!_.isEqual(new Number(63), {valueOf: function(){ return 63; }}), "Number objects and objects with a `valueOf` method are not equal");
|
||||
|
||||
// Comparisons involving `NaN`.
|
||||
ok(_.isEqual(NaN, NaN), "`NaN` is equal to `NaN`");
|
||||
ok(!_.isEqual(61, NaN), "A number primitive is not equal to `NaN`");
|
||||
ok(!_.isEqual(new Number(79), NaN), "A number object is not equal to `NaN`");
|
||||
ok(!_.isEqual(Infinity, NaN), "`Infinity` is not equal to `NaN`");
|
||||
|
||||
// Boolean object and primitive comparisons.
|
||||
ok(_.isEqual(true, true), "Identical boolean primitives are equal");
|
||||
ok(_.isEqual(new Boolean, new Boolean), "Boolean objects with identical primitive values are equal");
|
||||
ok(_.isEqual(true, new Boolean(true)), "Boolean primitives and their corresponding object wrappers are equal");
|
||||
ok(_.isEqual(new Boolean(true), true), "Commutative equality is implemented for booleans");
|
||||
ok(!_.isEqual(new Boolean(true), new Boolean), "Boolean objects with different primitive values are not equal");
|
||||
|
||||
// Common type coercions.
|
||||
ok(!_.isEqual(true, new Boolean(false)), "Boolean objects are not equal to the boolean primitive `true`");
|
||||
ok(!_.isEqual("75", 75), "String and number primitives with like values are not equal");
|
||||
ok(!_.isEqual(new Number(63), new String(63)), "String and number objects with like values are not equal");
|
||||
ok(!_.isEqual(75, "75"), "Commutative equality is implemented for like string and number values");
|
||||
ok(!_.isEqual(0, ""), "Number and string primitives with like values are not equal");
|
||||
ok(!_.isEqual(1, true), "Number and boolean primitives with like values are not equal");
|
||||
ok(!_.isEqual(new Boolean(false), new Number(0)), "Boolean and number objects with like values are not equal");
|
||||
ok(!_.isEqual(false, new String("")), "Boolean primitives and string objects with like values are not equal");
|
||||
ok(!_.isEqual(12564504e5, new Date(2009, 9, 25)), "Dates and their corresponding numeric primitive values are not equal");
|
||||
|
||||
// Dates.
|
||||
ok(_.isEqual(new Date(2009, 9, 25), new Date(2009, 9, 25)), "Date objects referencing identical times are equal");
|
||||
ok(!_.isEqual(new Date(2009, 9, 25), new Date(2009, 11, 13)), "Date objects referencing different times are not equal");
|
||||
ok(!_.isEqual(new Date(2009, 11, 13), {
|
||||
getTime: function(){
|
||||
return 12606876e5;
|
||||
}
|
||||
}), "Date objects and objects with a `getTime` method are not equal");
|
||||
ok(!_.isEqual(new Date("Curly"), new Date("Curly")), "Invalid dates are not equal");
|
||||
|
||||
// Functions.
|
||||
ok(!_.isEqual(First, Second), "Different functions with identical bodies and source code representations are not equal");
|
||||
|
||||
// RegExps.
|
||||
ok(_.isEqual(/(?:)/gim, /(?:)/gim), "RegExps with equivalent patterns and flags are equal");
|
||||
ok(!_.isEqual(/(?:)/g, /(?:)/gi), "RegExps with equivalent patterns and different flags are not equal");
|
||||
ok(!_.isEqual(/Moe/gim, /Curly/gim), "RegExps with different patterns and equivalent flags are not equal");
|
||||
ok(!_.isEqual(/(?:)/gi, /(?:)/g), "Commutative equality is implemented for RegExps");
|
||||
ok(!_.isEqual(/Curly/g, {source: "Larry", global: true, ignoreCase: false, multiline: false}), "RegExps and RegExp-like objects are not equal");
|
||||
|
||||
// Empty arrays, array-like objects, and object literals.
|
||||
ok(_.isEqual({}, {}), "Empty object literals are equal");
|
||||
ok(_.isEqual([], []), "Empty array literals are equal");
|
||||
ok(_.isEqual([{}], [{}]), "Empty nested arrays and objects are equal");
|
||||
ok(!_.isEqual({length: 0}, []), "Array-like objects and arrays are not equal.");
|
||||
ok(!_.isEqual([], {length: 0}), "Commutative equality is implemented for array-like objects");
|
||||
|
||||
ok(!_.isEqual({}, []), "Object literals and array literals are not equal");
|
||||
ok(!_.isEqual([], {}), "Commutative equality is implemented for objects and arrays");
|
||||
|
||||
// Arrays with primitive and object values.
|
||||
ok(_.isEqual([1, "Larry", true], [1, "Larry", true]), "Arrays containing identical primitives are equal");
|
||||
ok(_.isEqual([(/Moe/g), new Date(2009, 9, 25)], [(/Moe/g), new Date(2009, 9, 25)]), "Arrays containing equivalent elements are equal");
|
||||
|
||||
// Multi-dimensional arrays.
|
||||
var a = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
|
||||
var b = [new Number(47), false, "Larry", /Moe/, new Date(2009, 11, 13), ['running', 'biking', new String('programming')], {a: 47}];
|
||||
ok(_.isEqual(a, b), "Arrays containing nested arrays and objects are recursively compared");
|
||||
|
||||
// Overwrite the methods defined in ES 5.1 section 15.4.4.
|
||||
a.forEach = a.map = a.filter = a.every = a.indexOf = a.lastIndexOf = a.some = a.reduce = a.reduceRight = null;
|
||||
b.join = b.pop = b.reverse = b.shift = b.slice = b.splice = b.concat = b.sort = b.unshift = null;
|
||||
|
||||
// Array elements and properties.
|
||||
ok(_.isEqual(a, b), "Arrays containing equivalent elements and different non-numeric properties are equal");
|
||||
a.push("White Rocks");
|
||||
ok(!_.isEqual(a, b), "Arrays of different lengths are not equal");
|
||||
a.push("East Boulder");
|
||||
b.push("Gunbarrel Ranch", "Teller Farm");
|
||||
ok(!_.isEqual(a, b), "Arrays of identical lengths containing different elements are not equal");
|
||||
|
||||
// Sparse arrays.
|
||||
ok(_.isEqual(Array(3), Array(3)), "Sparse arrays of identical lengths are equal");
|
||||
ok(!_.isEqual(Array(3), Array(6)), "Sparse arrays of different lengths are not equal when both are empty");
|
||||
|
||||
// Simple objects.
|
||||
ok(_.isEqual({a: "Curly", b: 1, c: true}, {a: "Curly", b: 1, c: true}), "Objects containing identical primitives are equal");
|
||||
ok(_.isEqual({a: /Curly/g, b: new Date(2009, 11, 13)}, {a: /Curly/g, b: new Date(2009, 11, 13)}), "Objects containing equivalent members are equal");
|
||||
ok(!_.isEqual({a: 63, b: 75}, {a: 61, b: 55}), "Objects of identical sizes with different values are not equal");
|
||||
ok(!_.isEqual({a: 63, b: 75}, {a: 61, c: 55}), "Objects of identical sizes with different property names are not equal");
|
||||
ok(!_.isEqual({a: 1, b: 2}, {a: 1}), "Objects of different sizes are not equal");
|
||||
ok(!_.isEqual({a: 1}, {a: 1, b: 2}), "Commutative equality is implemented for objects");
|
||||
ok(!_.isEqual({x: 1, y: undefined}, {x: 1, z: 2}), "Objects with identical keys and different values are not equivalent");
|
||||
|
||||
// `A` contains nested objects and arrays.
|
||||
a = {
|
||||
name: new String("Moe Howard"),
|
||||
age: new Number(77),
|
||||
stooge: true,
|
||||
hobbies: ["acting"],
|
||||
film: {
|
||||
name: "Sing a Song of Six Pants",
|
||||
release: new Date(1947, 9, 30),
|
||||
stars: [new String("Larry Fine"), "Shemp Howard"],
|
||||
minutes: new Number(16),
|
||||
seconds: 54
|
||||
}
|
||||
};
|
||||
|
||||
// `B` contains equivalent nested objects and arrays.
|
||||
b = {
|
||||
name: new String("Moe Howard"),
|
||||
age: new Number(77),
|
||||
stooge: true,
|
||||
hobbies: ["acting"],
|
||||
film: {
|
||||
name: "Sing a Song of Six Pants",
|
||||
release: new Date(1947, 9, 30),
|
||||
stars: [new String("Larry Fine"), "Shemp Howard"],
|
||||
minutes: new Number(16),
|
||||
seconds: 54
|
||||
}
|
||||
};
|
||||
ok(_.isEqual(a, b), "Objects with nested equivalent members are recursively compared");
|
||||
|
||||
// Instances.
|
||||
ok(_.isEqual(new First, new First), "Object instances are equal");
|
||||
ok(!_.isEqual(new First, new Second), "Objects with different constructors and identical own properties are not equal");
|
||||
ok(!_.isEqual({value: 1}, new First), "Object instances and objects sharing equivalent properties are not equal");
|
||||
ok(!_.isEqual({value: 2}, new Second), "The prototype chain of objects should not be examined");
|
||||
|
||||
// Circular Arrays.
|
||||
(a = []).push(a);
|
||||
(b = []).push(b);
|
||||
ok(_.isEqual(a, b), "Arrays containing circular references are equal");
|
||||
a.push(new String("Larry"));
|
||||
b.push(new String("Larry"));
|
||||
ok(_.isEqual(a, b), "Arrays containing circular references and equivalent properties are equal");
|
||||
a.push("Shemp");
|
||||
b.push("Curly");
|
||||
ok(!_.isEqual(a, b), "Arrays containing circular references and different properties are not equal");
|
||||
|
||||
// More circular arrays #767.
|
||||
a = ["everything is checked but", "this", "is not"];
|
||||
a[1] = a;
|
||||
b = ["everything is checked but", ["this", "array"], "is not"];
|
||||
ok(!_.isEqual(a, b), "Comparison of circular references with non-circular references are not equal");
|
||||
|
||||
// Circular Objects.
|
||||
a = {abc: null};
|
||||
b = {abc: null};
|
||||
a.abc = a;
|
||||
b.abc = b;
|
||||
ok(_.isEqual(a, b), "Objects containing circular references are equal");
|
||||
a.def = 75;
|
||||
b.def = 75;
|
||||
ok(_.isEqual(a, b), "Objects containing circular references and equivalent properties are equal");
|
||||
a.def = new Number(75);
|
||||
b.def = new Number(63);
|
||||
ok(!_.isEqual(a, b), "Objects containing circular references and different properties are not equal");
|
||||
|
||||
// More circular objects #767.
|
||||
a = {everything: "is checked", but: "this", is: "not"};
|
||||
a.but = a;
|
||||
b = {everything: "is checked", but: {that:"object"}, is: "not"};
|
||||
ok(!_.isEqual(a, b), "Comparison of circular references with non-circular object references are not equal");
|
||||
|
||||
// Cyclic Structures.
|
||||
a = [{abc: null}];
|
||||
b = [{abc: null}];
|
||||
(a[0].abc = a).push(a);
|
||||
(b[0].abc = b).push(b);
|
||||
ok(_.isEqual(a, b), "Cyclic structures are equal");
|
||||
a[0].def = "Larry";
|
||||
b[0].def = "Larry";
|
||||
ok(_.isEqual(a, b), "Cyclic structures containing equivalent properties are equal");
|
||||
a[0].def = new String("Larry");
|
||||
b[0].def = new String("Curly");
|
||||
ok(!_.isEqual(a, b), "Cyclic structures containing different properties are not equal");
|
||||
|
||||
// Complex Circular References.
|
||||
a = {foo: {b: {foo: {c: {foo: null}}}}};
|
||||
b = {foo: {b: {foo: {c: {foo: null}}}}};
|
||||
a.foo.b.foo.c.foo = a;
|
||||
b.foo.b.foo.c.foo = b;
|
||||
ok(_.isEqual(a, b), "Cyclic structures with nested and identically-named properties are equal");
|
||||
|
||||
// Chaining.
|
||||
ok(!_.isEqual(_({x: 1, y: undefined}).chain(), _({x: 1, z: 2}).chain()), 'Chained objects containing different values are not equal');
|
||||
equal(_({x: 1, y: 2}).chain().isEqual(_({x: 1, y: 2}).chain()).value(), true, '`isEqual` can be chained');
|
||||
|
||||
// Custom `isEqual` methods.
|
||||
var isEqualObj = {isEqual: function (o) { return o.isEqual == this.isEqual; }, unique: {}};
|
||||
var isEqualObjClone = {isEqual: isEqualObj.isEqual, unique: {}};
|
||||
|
||||
ok(_.isEqual(isEqualObj, isEqualObjClone), 'Both objects implement identical `isEqual` methods');
|
||||
ok(_.isEqual(isEqualObjClone, isEqualObj), 'Commutative equality is implemented for objects with custom `isEqual` methods');
|
||||
ok(!_.isEqual(isEqualObj, {}), 'Objects that do not implement equivalent `isEqual` methods are not equal');
|
||||
ok(!_.isEqual({}, isEqualObj), 'Commutative equality is implemented for objects with different `isEqual` methods');
|
||||
|
||||
// Objects from another frame.
|
||||
ok(_.isEqual({}, iObject));
|
||||
});
|
||||
|
||||
test("isEmpty", function() {
|
||||
ok(!_([1]).isEmpty(), '[1] is not empty');
|
||||
ok(_.isEmpty([]), '[] is empty');
|
||||
ok(!_.isEmpty({one : 1}), '{one : 1} is not empty');
|
||||
ok(_.isEmpty({}), '{} is empty');
|
||||
ok(_.isEmpty(new RegExp('')), 'objects with prototype properties are empty');
|
||||
ok(_.isEmpty(null), 'null is empty');
|
||||
ok(_.isEmpty(), 'undefined is empty');
|
||||
ok(_.isEmpty(''), 'the empty string is empty');
|
||||
ok(!_.isEmpty('moe'), 'but other strings are not');
|
||||
|
||||
var obj = {one : 1};
|
||||
delete obj.one;
|
||||
ok(_.isEmpty(obj), 'deleting all the keys from an object empties it');
|
||||
});
|
||||
|
||||
// Setup remote variables for iFrame tests.
|
||||
var iframe = document.createElement('iframe');
|
||||
jQuery(iframe).appendTo(document.body);
|
||||
var iDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
iDoc.write(
|
||||
"<script>\
|
||||
parent.iElement = document.createElement('div');\
|
||||
parent.iArguments = (function(){ return arguments; })(1, 2, 3);\
|
||||
parent.iArray = [1, 2, 3];\
|
||||
parent.iString = new String('hello');\
|
||||
parent.iNumber = new Number(100);\
|
||||
parent.iFunction = (function(){});\
|
||||
parent.iDate = new Date();\
|
||||
parent.iRegExp = /hi/;\
|
||||
parent.iNaN = NaN;\
|
||||
parent.iNull = null;\
|
||||
parent.iBoolean = new Boolean(false);\
|
||||
parent.iUndefined = undefined;\
|
||||
parent.iObject = {};\
|
||||
</script>"
|
||||
);
|
||||
iDoc.close();
|
||||
|
||||
test("isElement", function() {
|
||||
ok(!_.isElement('div'), 'strings are not dom elements');
|
||||
ok(_.isElement($('html')[0]), 'the html tag is a DOM element');
|
||||
ok(_.isElement(iElement), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isArguments", function() {
|
||||
var args = (function(){ return arguments; })(1, 2, 3);
|
||||
ok(!_.isArguments('string'), 'a string is not an arguments object');
|
||||
ok(!_.isArguments(_.isArguments), 'a function is not an arguments object');
|
||||
ok(_.isArguments(args), 'but the arguments object is an arguments object');
|
||||
ok(!_.isArguments(_.toArray(args)), 'but not when it\'s converted into an array');
|
||||
ok(!_.isArguments([1,2,3]), 'and not vanilla arrays.');
|
||||
ok(_.isArguments(iArguments), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isObject", function() {
|
||||
ok(_.isObject(arguments), 'the arguments object is object');
|
||||
ok(_.isObject([1, 2, 3]), 'and arrays');
|
||||
ok(_.isObject($('html')[0]), 'and DOM element');
|
||||
ok(_.isObject(iElement), 'even from another frame');
|
||||
ok(_.isObject(function () {}), 'and functions');
|
||||
ok(_.isObject(iFunction), 'even from another frame');
|
||||
ok(!_.isObject(null), 'but not null');
|
||||
ok(!_.isObject(undefined), 'and not undefined');
|
||||
ok(!_.isObject('string'), 'and not string');
|
||||
ok(!_.isObject(12), 'and not number');
|
||||
ok(!_.isObject(true), 'and not boolean');
|
||||
ok(_.isObject(new String('string')), 'but new String()');
|
||||
});
|
||||
|
||||
test("isArray", function() {
|
||||
ok(!_.isArray(arguments), 'the arguments object is not an array');
|
||||
ok(_.isArray([1, 2, 3]), 'but arrays are');
|
||||
ok(_.isArray(iArray), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isString", function() {
|
||||
ok(!_.isString(document.body), 'the document body is not a string');
|
||||
ok(_.isString([1, 2, 3].join(', ')), 'but strings are');
|
||||
ok(_.isString(iString), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isNumber", function() {
|
||||
ok(!_.isNumber('string'), 'a string is not a number');
|
||||
ok(!_.isNumber(arguments), 'the arguments object is not a number');
|
||||
ok(!_.isNumber(undefined), 'undefined is not a number');
|
||||
ok(_.isNumber(3 * 4 - 7 / 10), 'but numbers are');
|
||||
ok(_.isNumber(NaN), 'NaN *is* a number');
|
||||
ok(_.isNumber(Infinity), 'Infinity is a number');
|
||||
ok(_.isNumber(iNumber), 'even from another frame');
|
||||
ok(!_.isNumber('1'), 'numeric strings are not numbers');
|
||||
});
|
||||
|
||||
test("isBoolean", function() {
|
||||
ok(!_.isBoolean(2), 'a number is not a boolean');
|
||||
ok(!_.isBoolean("string"), 'a string is not a boolean');
|
||||
ok(!_.isBoolean("false"), 'the string "false" is not a boolean');
|
||||
ok(!_.isBoolean("true"), 'the string "true" is not a boolean');
|
||||
ok(!_.isBoolean(arguments), 'the arguments object is not a boolean');
|
||||
ok(!_.isBoolean(undefined), 'undefined is not a boolean');
|
||||
ok(!_.isBoolean(NaN), 'NaN is not a boolean');
|
||||
ok(!_.isBoolean(null), 'null is not a boolean');
|
||||
ok(_.isBoolean(true), 'but true is');
|
||||
ok(_.isBoolean(false), 'and so is false');
|
||||
ok(_.isBoolean(iBoolean), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isFunction", function() {
|
||||
ok(!_.isFunction([1, 2, 3]), 'arrays are not functions');
|
||||
ok(!_.isFunction('moe'), 'strings are not functions');
|
||||
ok(_.isFunction(_.isFunction), 'but functions are');
|
||||
ok(_.isFunction(iFunction), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isDate", function() {
|
||||
ok(!_.isDate(100), 'numbers are not dates');
|
||||
ok(!_.isDate({}), 'objects are not dates');
|
||||
ok(_.isDate(new Date()), 'but dates are');
|
||||
ok(_.isDate(iDate), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isRegExp", function() {
|
||||
ok(!_.isRegExp(_.identity), 'functions are not RegExps');
|
||||
ok(_.isRegExp(/identity/), 'but RegExps are');
|
||||
ok(_.isRegExp(iRegExp), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isFinite", function() {
|
||||
ok(!_.isFinite(undefined), 'undefined is not Finite');
|
||||
ok(!_.isFinite(null), 'null is not Finite');
|
||||
ok(!_.isFinite(NaN), 'NaN is not Finite');
|
||||
ok(!_.isFinite(Infinity), 'Infinity is not Finite');
|
||||
ok(!_.isFinite(-Infinity), '-Infinity is not Finite');
|
||||
ok(!_.isFinite('12'), 'Strings are not numbers');
|
||||
var obj = new Number(5);
|
||||
ok(_.isFinite(obj), 'Number instances can be finite');
|
||||
ok(_.isFinite(0), '0 is Finite');
|
||||
ok(_.isFinite(123), 'Ints are Finite');
|
||||
ok(_.isFinite(-12.44), 'Floats are Finite');
|
||||
});
|
||||
|
||||
test("isNaN", function() {
|
||||
ok(!_.isNaN(undefined), 'undefined is not NaN');
|
||||
ok(!_.isNaN(null), 'null is not NaN');
|
||||
ok(!_.isNaN(0), '0 is not NaN');
|
||||
ok(_.isNaN(NaN), 'but NaN is');
|
||||
ok(_.isNaN(iNaN), 'even from another frame');
|
||||
ok(_.isNaN(new Number(NaN)), 'wrapped NaN is still NaN');
|
||||
});
|
||||
|
||||
test("isNull", function() {
|
||||
ok(!_.isNull(undefined), 'undefined is not null');
|
||||
ok(!_.isNull(NaN), 'NaN is not null');
|
||||
ok(_.isNull(null), 'but null is');
|
||||
ok(_.isNull(iNull), 'even from another frame');
|
||||
});
|
||||
|
||||
test("isUndefined", function() {
|
||||
ok(!_.isUndefined(1), 'numbers are defined');
|
||||
ok(!_.isUndefined(null), 'null is defined');
|
||||
ok(!_.isUndefined(false), 'false is defined');
|
||||
ok(!_.isUndefined(NaN), 'NaN is defined');
|
||||
ok(_.isUndefined(), 'nothing is undefined');
|
||||
ok(_.isUndefined(undefined), 'undefined is undefined');
|
||||
ok(_.isUndefined(iUndefined), 'even from another frame');
|
||||
});
|
||||
|
||||
if (window.ActiveXObject) {
|
||||
test("IE host objects", function() {
|
||||
var xml = new ActiveXObject("Msxml2.DOMDocument.3.0");
|
||||
ok(!_.isNumber(xml));
|
||||
ok(!_.isBoolean(xml));
|
||||
ok(!_.isNaN(xml));
|
||||
ok(!_.isFunction(xml));
|
||||
ok(!_.isNull(xml));
|
||||
ok(!_.isUndefined(xml));
|
||||
});
|
||||
}
|
||||
|
||||
test("tap", function() {
|
||||
var intercepted = null;
|
||||
var interceptor = function(obj) { intercepted = obj; };
|
||||
var returned = _.tap(1, interceptor);
|
||||
equal(intercepted, 1, "passes tapped object to interceptor");
|
||||
equal(returned, 1, "returns tapped object");
|
||||
|
||||
returned = _([1,2,3]).chain().
|
||||
map(function(n){ return n * 2; }).
|
||||
max().
|
||||
tap(interceptor).
|
||||
value();
|
||||
ok(returned == 6 && intercepted == 6, 'can use tapped objects in a chain');
|
||||
});
|
||||
});
|
|
@ -1,75 +0,0 @@
|
|||
(function() {
|
||||
|
||||
var numbers = [];
|
||||
for (var i=0; i<1000; i++) numbers.push(i);
|
||||
var objects = _.map(numbers, function(n){ return {num : n}; });
|
||||
var randomized = _.sortBy(numbers, function(){ return Math.random(); });
|
||||
var deep = _.map(_.range(100), function() { return _.range(1000); });
|
||||
|
||||
JSLitmus.test('_.each()', function() {
|
||||
var timesTwo = [];
|
||||
_.each(numbers, function(num){ timesTwo.push(num * 2); });
|
||||
return timesTwo;
|
||||
});
|
||||
|
||||
JSLitmus.test('_(list).each()', function() {
|
||||
var timesTwo = [];
|
||||
_(numbers).each(function(num){ timesTwo.push(num * 2); });
|
||||
return timesTwo;
|
||||
});
|
||||
|
||||
JSLitmus.test('jQuery.each()', function() {
|
||||
var timesTwo = [];
|
||||
jQuery.each(numbers, function(){ timesTwo.push(this * 2); });
|
||||
return timesTwo;
|
||||
});
|
||||
|
||||
JSLitmus.test('_.map()', function() {
|
||||
return _.map(objects, function(obj){ return obj.num; });
|
||||
});
|
||||
|
||||
JSLitmus.test('jQuery.map()', function() {
|
||||
return jQuery.map(objects, function(obj){ return obj.num; });
|
||||
});
|
||||
|
||||
JSLitmus.test('_.pluck()', function() {
|
||||
return _.pluck(objects, 'num');
|
||||
});
|
||||
|
||||
JSLitmus.test('_.uniq()', function() {
|
||||
return _.uniq(randomized);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.uniq() (sorted)', function() {
|
||||
return _.uniq(numbers, true);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.sortBy()', function() {
|
||||
return _.sortBy(numbers, function(num){ return -num; });
|
||||
});
|
||||
|
||||
JSLitmus.test('_.isEqual()', function() {
|
||||
return _.isEqual(numbers, randomized);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.keys()', function() {
|
||||
return _.keys(objects);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.values()', function() {
|
||||
return _.values(objects);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.intersection()', function() {
|
||||
return _.intersection(numbers, randomized);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.range()', function() {
|
||||
return _.range(1000);
|
||||
});
|
||||
|
||||
JSLitmus.test('_.flatten()', function() {
|
||||
return _.flatten(deep);
|
||||
});
|
||||
|
||||
})();
|
|
@ -1,249 +0,0 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
var templateSettings;
|
||||
|
||||
module("Utility", {
|
||||
|
||||
setup: function() {
|
||||
templateSettings = _.clone(_.templateSettings);
|
||||
},
|
||||
|
||||
teardown: function() {
|
||||
_.templateSettings = templateSettings;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
test("#750 - Return _ instance.", 2, function() {
|
||||
var instance = _([]);
|
||||
ok(_(instance) === instance);
|
||||
ok(new _(instance) === instance);
|
||||
});
|
||||
|
||||
test("identity", function() {
|
||||
var moe = {name : 'moe'};
|
||||
equal(_.identity(moe), moe, 'moe is the same as his identity');
|
||||
});
|
||||
|
||||
test("uniqueId", function() {
|
||||
var ids = [], i = 0;
|
||||
while(i++ < 100) ids.push(_.uniqueId());
|
||||
equal(_.uniq(ids).length, ids.length, 'can generate a globally-unique stream of ids');
|
||||
});
|
||||
|
||||
test("times", function() {
|
||||
var vals = [];
|
||||
_.times(3, function (i) { vals.push(i); });
|
||||
ok(_.isEqual(vals, [0,1,2]), "is 0 indexed");
|
||||
//
|
||||
vals = [];
|
||||
_(3).times(function (i) { vals.push(i); });
|
||||
ok(_.isEqual(vals, [0,1,2]), "works as a wrapper");
|
||||
});
|
||||
|
||||
test("mixin", function() {
|
||||
_.mixin({
|
||||
myReverse: function(string) {
|
||||
return string.split('').reverse().join('');
|
||||
}
|
||||
});
|
||||
equal(_.myReverse('panacea'), 'aecanap', 'mixed in a function to _');
|
||||
equal(_('champ').myReverse(), 'pmahc', 'mixed in a function to the OOP wrapper');
|
||||
});
|
||||
|
||||
test("_.escape", function() {
|
||||
equal(_.escape("Curly & Moe"), "Curly & Moe");
|
||||
equal(_.escape("Curly & Moe"), "Curly &amp; Moe");
|
||||
equal(_.escape(null), '');
|
||||
});
|
||||
|
||||
test("_.unescape", function() {
|
||||
var string = "Curly & Moe";
|
||||
equal(_.unescape("Curly & Moe"), string);
|
||||
equal(_.unescape("Curly &amp; Moe"), "Curly & Moe");
|
||||
equal(_.unescape(null), '');
|
||||
equal(_.unescape(_.escape(string)), string);
|
||||
});
|
||||
|
||||
test("template", function() {
|
||||
var basicTemplate = _.template("<%= thing %> is gettin' on my noives!");
|
||||
var result = basicTemplate({thing : 'This'});
|
||||
equal(result, "This is gettin' on my noives!", 'can do basic attribute interpolation');
|
||||
|
||||
var sansSemicolonTemplate = _.template("A <% this %> B");
|
||||
equal(sansSemicolonTemplate(), "A B");
|
||||
|
||||
var backslashTemplate = _.template("<%= thing %> is \\ridanculous");
|
||||
equal(backslashTemplate({thing: 'This'}), "This is \\ridanculous");
|
||||
|
||||
var escapeTemplate = _.template('<%= a ? "checked=\\"checked\\"" : "" %>');
|
||||
equal(escapeTemplate({a: true}), 'checked="checked"', 'can handle slash escapes in interpolations.');
|
||||
|
||||
var fancyTemplate = _.template("<ul><% \
|
||||
for (key in people) { \
|
||||
%><li><%= people[key] %></li><% } %></ul>");
|
||||
result = fancyTemplate({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
|
||||
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
|
||||
|
||||
var escapedCharsInJavascriptTemplate = _.template("<ul><% _.each(numbers.split('\\n'), function(item) { %><li><%= item %></li><% }) %></ul>");
|
||||
result = escapedCharsInJavascriptTemplate({numbers: "one\ntwo\nthree\nfour"});
|
||||
equal(result, "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>", 'Can use escaped characters (e.g. \\n) in Javascript');
|
||||
|
||||
var namespaceCollisionTemplate = _.template("<%= pageCount %> <%= thumbnails[pageCount] %> <% _.each(thumbnails, function(p) { %><div class=\"thumbnail\" rel=\"<%= p %>\"></div><% }); %>");
|
||||
result = namespaceCollisionTemplate({
|
||||
pageCount: 3,
|
||||
thumbnails: {
|
||||
1: "p1-thumbnail.gif",
|
||||
2: "p2-thumbnail.gif",
|
||||
3: "p3-thumbnail.gif"
|
||||
}
|
||||
});
|
||||
equal(result, "3 p3-thumbnail.gif <div class=\"thumbnail\" rel=\"p1-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p2-thumbnail.gif\"></div><div class=\"thumbnail\" rel=\"p3-thumbnail.gif\"></div>");
|
||||
|
||||
var noInterpolateTemplate = _.template("<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
|
||||
result = noInterpolateTemplate();
|
||||
equal(result, "<div><p>Just some text. Hey, I know this is silly but it aids consistency.</p></div>");
|
||||
|
||||
var quoteTemplate = _.template("It's its, not it's");
|
||||
equal(quoteTemplate({}), "It's its, not it's");
|
||||
|
||||
var quoteInStatementAndBody = _.template("<%\
|
||||
if(foo == 'bar'){ \
|
||||
%>Statement quotes and 'quotes'.<% } %>");
|
||||
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
|
||||
|
||||
var withNewlinesAndTabs = _.template('This\n\t\tis: <%= x %>.\n\tok.\nend.');
|
||||
equal(withNewlinesAndTabs({x: 'that'}), 'This\n\t\tis: that.\n\tok.\nend.');
|
||||
|
||||
var template = _.template("<i><%- value %></i>");
|
||||
var result = template({value: "<script>"});
|
||||
equal(result, '<i><script></i>');
|
||||
|
||||
var stooge = {
|
||||
name: "Moe",
|
||||
template: _.template("I'm <%= this.name %>")
|
||||
};
|
||||
equal(stooge.template(), "I'm Moe");
|
||||
|
||||
if (!$.browser.msie) {
|
||||
var fromHTML = _.template($('#template').html());
|
||||
equal(fromHTML({data : 12345}).replace(/\s/g, ''), '<li>24690</li>');
|
||||
}
|
||||
|
||||
_.templateSettings = {
|
||||
evaluate : /\{\{([\s\S]+?)\}\}/g,
|
||||
interpolate : /\{\{=([\s\S]+?)\}\}/g
|
||||
};
|
||||
|
||||
var custom = _.template("<ul>{{ for (key in people) { }}<li>{{= people[key] }}</li>{{ } }}</ul>");
|
||||
result = custom({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
|
||||
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
|
||||
|
||||
var customQuote = _.template("It's its, not it's");
|
||||
equal(customQuote({}), "It's its, not it's");
|
||||
|
||||
var quoteInStatementAndBody = _.template("{{ if(foo == 'bar'){ }}Statement quotes and 'quotes'.{{ } }}");
|
||||
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
|
||||
|
||||
_.templateSettings = {
|
||||
evaluate : /<\?([\s\S]+?)\?>/g,
|
||||
interpolate : /<\?=([\s\S]+?)\?>/g
|
||||
};
|
||||
|
||||
var customWithSpecialChars = _.template("<ul><? for (key in people) { ?><li><?= people[key] ?></li><? } ?></ul>");
|
||||
result = customWithSpecialChars({people : {moe : "Moe", larry : "Larry", curly : "Curly"}});
|
||||
equal(result, "<ul><li>Moe</li><li>Larry</li><li>Curly</li></ul>", 'can run arbitrary javascript in templates');
|
||||
|
||||
var customWithSpecialCharsQuote = _.template("It's its, not it's");
|
||||
equal(customWithSpecialCharsQuote({}), "It's its, not it's");
|
||||
|
||||
var quoteInStatementAndBody = _.template("<? if(foo == 'bar'){ ?>Statement quotes and 'quotes'.<? } ?>");
|
||||
equal(quoteInStatementAndBody({foo: "bar"}), "Statement quotes and 'quotes'.");
|
||||
|
||||
_.templateSettings = {
|
||||
interpolate : /\{\{(.+?)\}\}/g
|
||||
};
|
||||
|
||||
var mustache = _.template("Hello {{planet}}!");
|
||||
equal(mustache({planet : "World"}), "Hello World!", "can mimic mustache.js");
|
||||
|
||||
var templateWithNull = _.template("a null undefined {{planet}}");
|
||||
equal(templateWithNull({planet : "world"}), "a null undefined world", "can handle missing escape and evaluate settings");
|
||||
});
|
||||
|
||||
test('_.template provides the generated function source, when a SyntaxError occurs', function() {
|
||||
try {
|
||||
_.template('<b><%= if %></b>');
|
||||
} catch (e) {
|
||||
ok(e.source.indexOf('( if )') > 0);
|
||||
}
|
||||
});
|
||||
|
||||
test('_.template handles \\u2028 & \\u2029', function() {
|
||||
var tmpl = _.template('<p>\u2028<%= "\\u2028\\u2029" %>\u2029</p>');
|
||||
strictEqual(tmpl(), '<p>\u2028\u2028\u2029\u2029</p>');
|
||||
});
|
||||
|
||||
test('result calls functions and returns primitives', function() {
|
||||
var obj = {w: '', x: 'x', y: function(){ return this.x; }};
|
||||
strictEqual(_.result(obj, 'w'), '');
|
||||
strictEqual(_.result(obj, 'x'), 'x');
|
||||
strictEqual(_.result(obj, 'y'), 'x');
|
||||
strictEqual(_.result(obj, 'z'), undefined);
|
||||
strictEqual(_.result(null, 'x'), null);
|
||||
});
|
||||
|
||||
test('_.templateSettings.variable', function() {
|
||||
var s = '<%=data.x%>';
|
||||
var data = {x: 'x'};
|
||||
strictEqual(_.template(s, data, {variable: 'data'}), 'x');
|
||||
_.templateSettings.variable = 'data';
|
||||
strictEqual(_.template(s)(data), 'x');
|
||||
});
|
||||
|
||||
test('#547 - _.templateSettings is unchanged by custom settings.', function() {
|
||||
ok(!_.templateSettings.variable);
|
||||
_.template('', {}, {variable: 'x'});
|
||||
ok(!_.templateSettings.variable);
|
||||
});
|
||||
|
||||
test('#556 - undefined template variables.', function() {
|
||||
var template = _.template('<%=x%>');
|
||||
strictEqual(template({x: null}), '');
|
||||
strictEqual(template({x: undefined}), '');
|
||||
|
||||
var templateEscaped = _.template('<%-x%>');
|
||||
strictEqual(templateEscaped({x: null}), '');
|
||||
strictEqual(templateEscaped({x: undefined}), '');
|
||||
|
||||
var templateWithProperty = _.template('<%=x.foo%>');
|
||||
strictEqual(templateWithProperty({x: {} }), '');
|
||||
strictEqual(templateWithProperty({x: {} }), '');
|
||||
|
||||
var templateWithPropertyEscaped = _.template('<%-x.foo%>');
|
||||
strictEqual(templateWithPropertyEscaped({x: {} }), '');
|
||||
strictEqual(templateWithPropertyEscaped({x: {} }), '');
|
||||
});
|
||||
|
||||
test('interpolate evaluates code only once.', 2, function() {
|
||||
var count = 0;
|
||||
var template = _.template('<%= f() %>');
|
||||
template({f: function(){ ok(!(count++)); }});
|
||||
|
||||
var countEscaped = 0;
|
||||
var templateEscaped = _.template('<%- f() %>');
|
||||
templateEscaped({f: function(){ ok(!(countEscaped++)); }});
|
||||
});
|
||||
|
||||
test('#746 - _.template settings are not modified.', 1, function() {
|
||||
var settings = {};
|
||||
_.template('', null, settings);
|
||||
deepEqual(settings, {});
|
||||
});
|
||||
|
||||
test('#779 - delimeters are applied to unescaped text.', 1, function() {
|
||||
var template = _.template('<<\nx\n>>', null, {evaluate: /<<(.*?)>>/g});
|
||||
strictEqual(template(), '<<\nx\n>>');
|
||||
});
|
||||
|
||||
});
|
File diff suppressed because it is too large
Load Diff
|
@ -1,670 +0,0 @@
|
|||
// JSLitmus.js
|
||||
//
|
||||
// History:
|
||||
// 2008-10-27: Initial release
|
||||
// 2008-11-09: Account for iteration loop overhead
|
||||
// 2008-11-13: Added OS detection
|
||||
// 2009-02-25: Create tinyURL automatically, shift-click runs tests in reverse
|
||||
//
|
||||
// Copyright (c) 2008-2009, Robert Kieffer
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the
|
||||
// Software), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(function() {
|
||||
// Private methods and state
|
||||
|
||||
// Get platform info but don't go crazy trying to recognize everything
|
||||
// that's out there. This is just for the major platforms and OSes.
|
||||
var platform = 'unknown platform', ua = navigator.userAgent;
|
||||
|
||||
// Detect OS
|
||||
var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
|
||||
var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
|
||||
if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
|
||||
|
||||
// Detect browser
|
||||
var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
|
||||
|
||||
// Detect version
|
||||
var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
|
||||
var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
|
||||
var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
|
||||
|
||||
/**
|
||||
* A smattering of methods that are needed to implement the JSLitmus testbed.
|
||||
*/
|
||||
var jsl = {
|
||||
/**
|
||||
* Enhanced version of escape()
|
||||
*/
|
||||
escape: function(s) {
|
||||
s = s.replace(/,/g, '\\,');
|
||||
s = escape(s);
|
||||
s = s.replace(/\+/g, '%2b');
|
||||
s = s.replace(/ /g, '+');
|
||||
return s;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get an element by ID.
|
||||
*/
|
||||
$: function(id) {
|
||||
return document.getElementById(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Null function
|
||||
*/
|
||||
F: function() {},
|
||||
|
||||
/**
|
||||
* Set the status shown in the UI
|
||||
*/
|
||||
status: function(msg) {
|
||||
var el = jsl.$('jsl_status');
|
||||
if (el) el.innerHTML = msg || '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a number to an abbreviated string like, "15K" or "10M"
|
||||
*/
|
||||
toLabel: function(n) {
|
||||
if (n == Infinity) {
|
||||
return 'Infinity';
|
||||
} else if (n > 1e9) {
|
||||
n = Math.round(n/1e8);
|
||||
return n/10 + 'B';
|
||||
} else if (n > 1e6) {
|
||||
n = Math.round(n/1e5);
|
||||
return n/10 + 'M';
|
||||
} else if (n > 1e3) {
|
||||
n = Math.round(n/1e2);
|
||||
return n/10 + 'K';
|
||||
}
|
||||
return n;
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy properties from src to dst
|
||||
*/
|
||||
extend: function(dst, src) {
|
||||
for (var k in src) dst[k] = src[k]; return dst;
|
||||
},
|
||||
|
||||
/**
|
||||
* Like Array.join(), but for the key-value pairs in an object
|
||||
*/
|
||||
join: function(o, delimit1, delimit2) {
|
||||
if (o.join) return o.join(delimit1); // If it's an array
|
||||
var pairs = [];
|
||||
for (var k in o) pairs.push(k + delimit1 + o[k]);
|
||||
return pairs.join(delimit2);
|
||||
},
|
||||
|
||||
/**
|
||||
* Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
|
||||
*/
|
||||
indexOf: function(arr, o) {
|
||||
if (arr.indexOf) return arr.indexOf(o);
|
||||
for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test manages a single test (created with
|
||||
* JSLitmus.test())
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
var Test = function (name, f) {
|
||||
if (!f) throw new Error('Undefined test function');
|
||||
if (!(/function[^\(]*\(([^,\)]*)/).test(f.toString())) {
|
||||
throw new Error('"' + name + '" test: Test is not a valid Function object');
|
||||
}
|
||||
this.loopArg = RegExp.$1;
|
||||
this.name = name;
|
||||
this.f = f;
|
||||
};
|
||||
|
||||
jsl.extend(Test, /** @lends Test */ {
|
||||
/** Calibration tests for establishing iteration loop overhead */
|
||||
CALIBRATIONS: [
|
||||
new Test('calibrating loop', function(count) {while (count--);}),
|
||||
new Test('calibrating function', jsl.F)
|
||||
],
|
||||
|
||||
/**
|
||||
* Run calibration tests. Returns true if calibrations are not yet
|
||||
* complete (in which case calling code should run the tests yet again).
|
||||
* onCalibrated - Callback to invoke when calibrations have finished
|
||||
*/
|
||||
calibrate: function(onCalibrated) {
|
||||
for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
|
||||
var cal = Test.CALIBRATIONS[i];
|
||||
if (cal.running) return true;
|
||||
if (!cal.count) {
|
||||
cal.isCalibration = true;
|
||||
cal.onStop = onCalibrated;
|
||||
//cal.MIN_TIME = .1; // Do calibrations quickly
|
||||
cal.run(2e4);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
jsl.extend(Test.prototype, {/** @lends Test.prototype */
|
||||
/** Initial number of iterations */
|
||||
INIT_COUNT: 10,
|
||||
/** Max iterations allowed (i.e. used to detect bad looping functions) */
|
||||
MAX_COUNT: 1e9,
|
||||
/** Minimum time a test should take to get valid results (secs) */
|
||||
MIN_TIME: .5,
|
||||
|
||||
/** Callback invoked when test state changes */
|
||||
onChange: jsl.F,
|
||||
|
||||
/** Callback invoked when test is finished */
|
||||
onStop: jsl.F,
|
||||
|
||||
/**
|
||||
* Reset test state
|
||||
*/
|
||||
reset: function() {
|
||||
delete this.count;
|
||||
delete this.time;
|
||||
delete this.running;
|
||||
delete this.error;
|
||||
},
|
||||
|
||||
/**
|
||||
* Run the test (in a timeout). We use a timeout to make sure the browser
|
||||
* has a chance to finish rendering any UI changes we've made, like
|
||||
* updating the status message.
|
||||
*/
|
||||
run: function(count) {
|
||||
count = count || this.INIT_COUNT;
|
||||
jsl.status(this.name + ' x ' + count);
|
||||
this.running = true;
|
||||
var me = this;
|
||||
setTimeout(function() {me._run(count);}, 200);
|
||||
},
|
||||
|
||||
/**
|
||||
* The nuts and bolts code that actually runs a test
|
||||
*/
|
||||
_run: function(count) {
|
||||
var me = this;
|
||||
|
||||
// Make sure calibration tests have run
|
||||
if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
|
||||
this.error = null;
|
||||
|
||||
try {
|
||||
var start, f = this.f, now, i = count;
|
||||
|
||||
// Start the timer
|
||||
start = new Date();
|
||||
|
||||
// Now for the money shot. If this is a looping function ...
|
||||
if (this.loopArg) {
|
||||
// ... let it do the iteration itself
|
||||
f(count);
|
||||
} else {
|
||||
// ... otherwise do the iteration for it
|
||||
while (i--) f();
|
||||
}
|
||||
|
||||
// Get time test took (in secs)
|
||||
this.time = Math.max(1,new Date() - start)/1000;
|
||||
|
||||
// Store iteration count and per-operation time taken
|
||||
this.count = count;
|
||||
this.period = this.time/count;
|
||||
|
||||
// Do we need to do another run?
|
||||
this.running = this.time <= this.MIN_TIME;
|
||||
|
||||
// ... if so, compute how many times we should iterate
|
||||
if (this.running) {
|
||||
// Bump the count to the nearest power of 2
|
||||
var x = this.MIN_TIME/this.time;
|
||||
var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
|
||||
count *= pow;
|
||||
if (count > this.MAX_COUNT) {
|
||||
throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Exceptions are caught and displayed in the test UI
|
||||
this.reset();
|
||||
this.error = e;
|
||||
}
|
||||
|
||||
// Figure out what to do next
|
||||
if (this.running) {
|
||||
me.run(count);
|
||||
} else {
|
||||
jsl.status('');
|
||||
me.onStop(me);
|
||||
}
|
||||
|
||||
// Finish up
|
||||
this.onChange(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the number of operations per second for this test.
|
||||
*
|
||||
* @param normalize if true, iteration loop overhead taken into account
|
||||
*/
|
||||
getHz: function(/**Boolean*/ normalize) {
|
||||
var p = this.period;
|
||||
|
||||
// Adjust period based on the calibration test time
|
||||
if (normalize && !this.isCalibration) {
|
||||
var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
|
||||
|
||||
// If the period is within 20% of the calibration time, then zero the
|
||||
// it out
|
||||
p = p < cal.period*1.2 ? 0 : p - cal.period;
|
||||
}
|
||||
|
||||
return Math.round(1/p);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a friendly string describing the test
|
||||
*/
|
||||
toString: function() {
|
||||
return this.name + ' - ' + this.time/this.count + ' secs';
|
||||
}
|
||||
});
|
||||
|
||||
// CSS we need for the UI
|
||||
var STYLESHEET = '<style> \
|
||||
#jslitmus {font-family:sans-serif; font-size: 12px;} \
|
||||
#jslitmus a {text-decoration: none;} \
|
||||
#jslitmus a:hover {text-decoration: underline;} \
|
||||
#jsl_status { \
|
||||
margin-top: 10px; \
|
||||
font-size: 10px; \
|
||||
color: #888; \
|
||||
} \
|
||||
A IMG {border:none} \
|
||||
#test_results { \
|
||||
margin-top: 10px; \
|
||||
font-size: 12px; \
|
||||
font-family: sans-serif; \
|
||||
border-collapse: collapse; \
|
||||
border-spacing: 0px; \
|
||||
} \
|
||||
#test_results th, #test_results td { \
|
||||
border: solid 1px #ccc; \
|
||||
vertical-align: top; \
|
||||
padding: 3px; \
|
||||
} \
|
||||
#test_results th { \
|
||||
vertical-align: bottom; \
|
||||
background-color: #ccc; \
|
||||
padding: 1px; \
|
||||
font-size: 10px; \
|
||||
} \
|
||||
#test_results #test_platform { \
|
||||
color: #444; \
|
||||
text-align:center; \
|
||||
} \
|
||||
#test_results .test_row { \
|
||||
color: #006; \
|
||||
cursor: pointer; \
|
||||
} \
|
||||
#test_results .test_nonlooping { \
|
||||
border-left-style: dotted; \
|
||||
border-left-width: 2px; \
|
||||
} \
|
||||
#test_results .test_looping { \
|
||||
border-left-style: solid; \
|
||||
border-left-width: 2px; \
|
||||
} \
|
||||
#test_results .test_name {white-space: nowrap;} \
|
||||
#test_results .test_pending { \
|
||||
} \
|
||||
#test_results .test_running { \
|
||||
font-style: italic; \
|
||||
} \
|
||||
#test_results .test_done {} \
|
||||
#test_results .test_done { \
|
||||
text-align: right; \
|
||||
font-family: monospace; \
|
||||
} \
|
||||
#test_results .test_error {color: #600;} \
|
||||
#test_results .test_error .error_head {font-weight:bold;} \
|
||||
#test_results .test_error .error_body {font-size:85%;} \
|
||||
#test_results .test_row:hover td { \
|
||||
background-color: #ffc; \
|
||||
text-decoration: underline; \
|
||||
} \
|
||||
#chart { \
|
||||
margin: 10px 0px; \
|
||||
width: 250px; \
|
||||
} \
|
||||
#chart img { \
|
||||
border: solid 1px #ccc; \
|
||||
margin-bottom: 5px; \
|
||||
} \
|
||||
#chart #tiny_url { \
|
||||
height: 40px; \
|
||||
width: 250px; \
|
||||
} \
|
||||
#jslitmus_credit { \
|
||||
font-size: 10px; \
|
||||
color: #888; \
|
||||
margin-top: 8px; \
|
||||
} \
|
||||
</style>';
|
||||
|
||||
// HTML markup for the UI
|
||||
var MARKUP = '<div id="jslitmus"> \
|
||||
<button onclick="JSLitmus.runAll(event)">Run Tests</button> \
|
||||
<button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
|
||||
<br \> \
|
||||
<br \> \
|
||||
<input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
|
||||
<table id="test_results"> \
|
||||
<colgroup> \
|
||||
<col /> \
|
||||
<col width="100" /> \
|
||||
</colgroup> \
|
||||
<tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
|
||||
<tr><th>Test</th><th>Ops/sec</th></tr> \
|
||||
<tr id="test_row_template" class="test_row" style="display:none"> \
|
||||
<td class="test_name"></td> \
|
||||
<td class="test_result">Ready</td> \
|
||||
</tr> \
|
||||
</table> \
|
||||
<div id="jsl_status"></div> \
|
||||
<div id="chart" style="display:none"> \
|
||||
<a id="chart_link" target="_blank"><img id="chart_image"></a> \
|
||||
TinyURL (for chart): \
|
||||
<iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
|
||||
</div> \
|
||||
<a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
|
||||
</div>';
|
||||
|
||||
/**
|
||||
* The public API for creating and running tests
|
||||
*/
|
||||
window.JSLitmus = {
|
||||
/** The list of all tests that have been registered with JSLitmus.test */
|
||||
_tests: [],
|
||||
/** The queue of tests that need to be run */
|
||||
_queue: [],
|
||||
|
||||
/**
|
||||
* The parsed query parameters the current page URL. This is provided as a
|
||||
* convenience for test functions - it's not used by JSLitmus proper
|
||||
*/
|
||||
params: {},
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
_init: function() {
|
||||
// Parse query params into JSLitmus.params[] hash
|
||||
var match = (location + '').match(/([^?#]*)(#.*)?$/);
|
||||
if (match) {
|
||||
var pairs = match[1].split('&');
|
||||
for (var i = 0; i < pairs.length; i++) {
|
||||
var pair = pairs[i].split('=');
|
||||
if (pair.length > 1) {
|
||||
var key = pair.shift();
|
||||
var value = pair.length > 1 ? pair.join('=') : pair[0];
|
||||
this.params[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write out the stylesheet. We have to do this here because IE
|
||||
// doesn't honor sheets written after the document has loaded.
|
||||
document.write(STYLESHEET);
|
||||
|
||||
// Setup the rest of the UI once the document is loaded
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener('load', this._setup, false);
|
||||
} else if (document.addEventListener) {
|
||||
document.addEventListener('load', this._setup, false);
|
||||
} else if (window.attachEvent) {
|
||||
window.attachEvent('onload', this._setup);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set up the UI
|
||||
*/
|
||||
_setup: function() {
|
||||
var el = jsl.$('jslitmus_container');
|
||||
if (!el) document.body.appendChild(el = document.createElement('div'));
|
||||
|
||||
el.innerHTML = MARKUP;
|
||||
|
||||
// Render the UI for all our tests
|
||||
for (var i=0; i < JSLitmus._tests.length; i++)
|
||||
JSLitmus.renderTest(JSLitmus._tests[i]);
|
||||
},
|
||||
|
||||
/**
|
||||
* (Re)render all the test results
|
||||
*/
|
||||
renderAll: function() {
|
||||
for (var i = 0; i < JSLitmus._tests.length; i++)
|
||||
JSLitmus.renderTest(JSLitmus._tests[i]);
|
||||
JSLitmus.renderChart();
|
||||
},
|
||||
|
||||
/**
|
||||
* (Re)render the chart graphics
|
||||
*/
|
||||
renderChart: function() {
|
||||
var url = JSLitmus.chartUrl();
|
||||
jsl.$('chart_link').href = url;
|
||||
jsl.$('chart_image').src = url;
|
||||
jsl.$('chart').style.display = '';
|
||||
|
||||
// Update the tiny URL
|
||||
jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
|
||||
},
|
||||
|
||||
/**
|
||||
* (Re)render the results for a specific test
|
||||
*/
|
||||
renderTest: function(test) {
|
||||
// Make a new row if needed
|
||||
if (!test._row) {
|
||||
var trow = jsl.$('test_row_template');
|
||||
if (!trow) return;
|
||||
|
||||
test._row = trow.cloneNode(true);
|
||||
test._row.style.display = '';
|
||||
test._row.id = '';
|
||||
test._row.onclick = function() {JSLitmus._queueTest(test);};
|
||||
test._row.title = 'Run ' + test.name + ' test';
|
||||
trow.parentNode.appendChild(test._row);
|
||||
test._row.cells[0].innerHTML = test.name;
|
||||
}
|
||||
|
||||
var cell = test._row.cells[1];
|
||||
var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
|
||||
|
||||
if (test.error) {
|
||||
cns.push('test_error');
|
||||
cell.innerHTML =
|
||||
'<div class="error_head">' + test.error + '</div>' +
|
||||
'<ul class="error_body"><li>' +
|
||||
jsl.join(test.error, ': ', '</li><li>') +
|
||||
'</li></ul>';
|
||||
} else {
|
||||
if (test.running) {
|
||||
cns.push('test_running');
|
||||
cell.innerHTML = 'running';
|
||||
} else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
|
||||
cns.push('test_pending');
|
||||
cell.innerHTML = 'pending';
|
||||
} else if (test.count) {
|
||||
cns.push('test_done');
|
||||
var hz = test.getHz(jsl.$('test_normalize').checked);
|
||||
cell.innerHTML = hz != Infinity ? hz : '∞';
|
||||
} else {
|
||||
cell.innerHTML = 'ready';
|
||||
}
|
||||
}
|
||||
cell.className = cns.join(' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new test
|
||||
*/
|
||||
test: function(name, f) {
|
||||
// Create the Test object
|
||||
var test = new Test(name, f);
|
||||
JSLitmus._tests.push(test);
|
||||
|
||||
// Re-render if the test state changes
|
||||
test.onChange = JSLitmus.renderTest;
|
||||
|
||||
// Run the next test if this one finished
|
||||
test.onStop = function(test) {
|
||||
if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
|
||||
JSLitmus.currentTest = null;
|
||||
JSLitmus._nextTest();
|
||||
};
|
||||
|
||||
// Render the new test
|
||||
this.renderTest(test);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add all tests to the run queue
|
||||
*/
|
||||
runAll: function(e) {
|
||||
e = e || window.event;
|
||||
var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all tests from the run queue. The current test has to finish on
|
||||
* it's own though
|
||||
*/
|
||||
stop: function() {
|
||||
while (JSLitmus._queue.length) {
|
||||
var test = JSLitmus._queue.shift();
|
||||
JSLitmus.renderTest(test);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Run the next test in the run queue
|
||||
*/
|
||||
_nextTest: function() {
|
||||
if (!JSLitmus.currentTest) {
|
||||
var test = JSLitmus._queue.shift();
|
||||
if (test) {
|
||||
jsl.$('stop_button').disabled = false;
|
||||
JSLitmus.currentTest = test;
|
||||
test.run();
|
||||
JSLitmus.renderTest(test);
|
||||
if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
|
||||
} else {
|
||||
jsl.$('stop_button').disabled = true;
|
||||
JSLitmus.renderChart();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a test to the run queue
|
||||
*/
|
||||
_queueTest: function(test) {
|
||||
if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
|
||||
JSLitmus._queue.push(test);
|
||||
JSLitmus.renderTest(test);
|
||||
JSLitmus._nextTest();
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a Google Chart URL that shows the data for all tests
|
||||
*/
|
||||
chartUrl: function() {
|
||||
var n = JSLitmus._tests.length, markers = [], data = [];
|
||||
var d, min = 0, max = -1e10;
|
||||
var normalize = jsl.$('test_normalize').checked;
|
||||
|
||||
// Gather test data
|
||||
for (var i=0; i < JSLitmus._tests.length; i++) {
|
||||
var test = JSLitmus._tests[i];
|
||||
if (test.count) {
|
||||
var hz = test.getHz(normalize);
|
||||
var v = hz != Infinity ? hz : 0;
|
||||
data.push(v);
|
||||
markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
|
||||
markers.length + ',10');
|
||||
max = Math.max(v, max);
|
||||
}
|
||||
}
|
||||
if (markers.length <= 0) return null;
|
||||
|
||||
// Build chart title
|
||||
var title = document.getElementsByTagName('title');
|
||||
title = (title && title.length) ? title[0].innerHTML : null;
|
||||
var chart_title = [];
|
||||
if (title) chart_title.push(title);
|
||||
chart_title.push('Ops/sec (' + platform + ')');
|
||||
|
||||
// Build labels
|
||||
var labels = [jsl.toLabel(min), jsl.toLabel(max)];
|
||||
|
||||
var w = 250, bw = 15;
|
||||
var bs = 5;
|
||||
var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
|
||||
|
||||
var params = {
|
||||
chtt: escape(chart_title.join('|')),
|
||||
chts: '000000,10',
|
||||
cht: 'bhg', // chart type
|
||||
chd: 't:' + data.join(','), // data set
|
||||
chds: min + ',' + max, // max/min of data
|
||||
chxt: 'x', // label axes
|
||||
chxl: '0:|' + labels.join('|'), // labels
|
||||
chsp: '0,1',
|
||||
chm: markers.join('|'), // test names
|
||||
chbh: [bw, 0, bs].join(','), // bar widths
|
||||
// chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
|
||||
chs: w + 'x' + h
|
||||
};
|
||||
return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
|
||||
}
|
||||
};
|
||||
|
||||
JSLitmus._init();
|
||||
})();
|
|
@ -1,235 +0,0 @@
|
|||
/**
|
||||
* QUnit v1.10.0 - A JavaScript Unit Testing Framework
|
||||
*
|
||||
* http://qunitjs.com
|
||||
*
|
||||
* Copyright 2012 jQuery Foundation and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*/
|
||||
|
||||
/** Font Family and Sizes */
|
||||
|
||||
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
|
||||
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
|
||||
#qunit-tests { font-size: smaller; }
|
||||
|
||||
|
||||
/** Resets */
|
||||
|
||||
#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
/** Header */
|
||||
|
||||
#qunit-header {
|
||||
padding: 0.5em 0 0.5em 1em;
|
||||
|
||||
color: #8699a4;
|
||||
background-color: #0d3349;
|
||||
|
||||
font-size: 1.5em;
|
||||
line-height: 1em;
|
||||
font-weight: normal;
|
||||
|
||||
border-radius: 5px 5px 0 0;
|
||||
-moz-border-radius: 5px 5px 0 0;
|
||||
-webkit-border-top-right-radius: 5px;
|
||||
-webkit-border-top-left-radius: 5px;
|
||||
}
|
||||
|
||||
#qunit-header a {
|
||||
text-decoration: none;
|
||||
color: #c2ccd1;
|
||||
}
|
||||
|
||||
#qunit-header a:hover,
|
||||
#qunit-header a:focus {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar label {
|
||||
display: inline-block;
|
||||
padding: 0 .5em 0 .1em;
|
||||
}
|
||||
|
||||
#qunit-banner {
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
#qunit-testrunner-toolbar {
|
||||
padding: 0.5em 0 0.5em 2em;
|
||||
color: #5E740B;
|
||||
background-color: #eee;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#qunit-userAgent {
|
||||
padding: 0.5em 0 0.5em 2.5em;
|
||||
background-color: #2b81af;
|
||||
color: #fff;
|
||||
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
|
||||
}
|
||||
|
||||
#qunit-modulefilter-container {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/** Tests: Pass/Fail */
|
||||
|
||||
#qunit-tests {
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#qunit-tests li {
|
||||
padding: 0.4em 0.5em 0.4em 2.5em;
|
||||
border-bottom: 1px solid #fff;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#qunit-tests li strong {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#qunit-tests li a {
|
||||
padding: 0.5em;
|
||||
color: #c2ccd1;
|
||||
text-decoration: none;
|
||||
}
|
||||
#qunit-tests li a:hover,
|
||||
#qunit-tests li a:focus {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#qunit-tests ol {
|
||||
margin-top: 0.5em;
|
||||
padding: 0.5em;
|
||||
|
||||
background-color: #fff;
|
||||
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
#qunit-tests table {
|
||||
border-collapse: collapse;
|
||||
margin-top: .2em;
|
||||
}
|
||||
|
||||
#qunit-tests th {
|
||||
text-align: right;
|
||||
vertical-align: top;
|
||||
padding: 0 .5em 0 0;
|
||||
}
|
||||
|
||||
#qunit-tests td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#qunit-tests pre {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#qunit-tests del {
|
||||
background-color: #e0f2be;
|
||||
color: #374e0c;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#qunit-tests ins {
|
||||
background-color: #ffcaca;
|
||||
color: #500;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*** Test Counts */
|
||||
|
||||
#qunit-tests b.counts { color: black; }
|
||||
#qunit-tests b.passed { color: #5E740B; }
|
||||
#qunit-tests b.failed { color: #710909; }
|
||||
|
||||
#qunit-tests li li {
|
||||
padding: 5px;
|
||||
background-color: #fff;
|
||||
border-bottom: none;
|
||||
list-style-position: inside;
|
||||
}
|
||||
|
||||
/*** Passing Styles */
|
||||
|
||||
#qunit-tests li li.pass {
|
||||
color: #3c510c;
|
||||
background-color: #fff;
|
||||
border-left: 10px solid #C6E746;
|
||||
}
|
||||
|
||||
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
|
||||
#qunit-tests .pass .test-name { color: #366097; }
|
||||
|
||||
#qunit-tests .pass .test-actual,
|
||||
#qunit-tests .pass .test-expected { color: #999999; }
|
||||
|
||||
#qunit-banner.qunit-pass { background-color: #C6E746; }
|
||||
|
||||
/*** Failing Styles */
|
||||
|
||||
#qunit-tests li li.fail {
|
||||
color: #710909;
|
||||
background-color: #fff;
|
||||
border-left: 10px solid #EE5757;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
#qunit-tests > li:last-child {
|
||||
border-radius: 0 0 5px 5px;
|
||||
-moz-border-radius: 0 0 5px 5px;
|
||||
-webkit-border-bottom-right-radius: 5px;
|
||||
-webkit-border-bottom-left-radius: 5px;
|
||||
}
|
||||
|
||||
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
|
||||
#qunit-tests .fail .test-name,
|
||||
#qunit-tests .fail .module-name { color: #000000; }
|
||||
|
||||
#qunit-tests .fail .test-actual { color: #EE5757; }
|
||||
#qunit-tests .fail .test-expected { color: green; }
|
||||
|
||||
#qunit-banner.qunit-fail { background-color: #EE5757; }
|
||||
|
||||
|
||||
/** Result */
|
||||
|
||||
#qunit-testresult {
|
||||
padding: 0.5em 0.5em 0.5em 2.5em;
|
||||
|
||||
color: #2b81af;
|
||||
background-color: #D2E0E6;
|
||||
|
||||
border-bottom: 1px solid white;
|
||||
}
|
||||
#qunit-testresult .module-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/** Fixture */
|
||||
|
||||
#qunit-fixture {
|
||||
position: absolute;
|
||||
top: -10000px;
|
||||
left: -10000px;
|
||||
width: 1000px;
|
||||
height: 1000px;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +0,0 @@
|
|||
test/
|
||||
Rakefile
|
||||
docs/
|
||||
raw/
|
|
@ -1,5 +0,0 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
||||
notifications:
|
||||
email: false
|
|
@ -1 +0,0 @@
|
|||
underscorejs.org
|
|
@ -1,9 +0,0 @@
|
|||
## How to contribute to Underscore.js
|
||||
|
||||
* Before you open a ticket or send a pull request, [search](https://github.com/documentcloud/underscore/issues) for previous discussions about the same feature or issue. Add to the earlier ticket if you find one.
|
||||
|
||||
* Before sending a pull request for a feature, be sure to have [tests](http://underscorejs.org/test/).
|
||||
|
||||
* Use the same coding style as the rest of the [codebase](https://github.com/documentcloud/underscore/blob/master/underscore.js).
|
||||
|
||||
* In your pull request, do not add documentation or re-build the minified `underscore-min.js` file. We'll do those things before cutting a new release.
|
|
@ -1,22 +0,0 @@
|
|||
Copyright (c) 2009-2013 Jeremy Ashkenas, DocumentCloud
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,19 +0,0 @@
|
|||
__
|
||||
/\ \ __
|
||||
__ __ ___ \_\ \ __ _ __ ____ ___ ___ _ __ __ /\_\ ____
|
||||
/\ \/\ \ /' _ `\ /'_ \ /'__`\/\ __\/ ,__\ / ___\ / __`\/\ __\/'__`\ \/\ \ /',__\
|
||||
\ \ \_\ \/\ \/\ \/\ \ \ \/\ __/\ \ \//\__, `\/\ \__//\ \ \ \ \ \//\ __/ __ \ \ \/\__, `\
|
||||
\ \____/\ \_\ \_\ \___,_\ \____\\ \_\\/\____/\ \____\ \____/\ \_\\ \____\/\_\ _\ \ \/\____/
|
||||
\/___/ \/_/\/_/\/__,_ /\/____/ \/_/ \/___/ \/____/\/___/ \/_/ \/____/\/_//\ \_\ \/___/
|
||||
\ \____/
|
||||
\/___/
|
||||
|
||||
Underscore.js is a utility-belt library for JavaScript that provides
|
||||
support for the usual functional suspects (each, map, reduce, filter...)
|
||||
without extending any core JavaScript objects.
|
||||
|
||||
For Docs, License, Tests, and pre-packed downloads, see:
|
||||
http://underscorejs.org
|
||||
|
||||
Many thanks to our contributors:
|
||||
https://github.com/documentcloud/underscore/contributors
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
2467
support/process/node_modules/yamljs/node_modules/argparse/node_modules/underscore/index.html
generated
vendored
2467
support/process/node_modules/yamljs/node_modules/argparse/node_modules/underscore/index.html
generated
vendored
File diff suppressed because it is too large
Load Diff
|
@ -1 +0,0 @@
|
|||
module.exports = require('./underscore');
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"name": "underscore",
|
||||
"description": "JavaScript's functional programming helper library.",
|
||||
"homepage": "http://underscorejs.org",
|
||||
"keywords": [
|
||||
"util",
|
||||
"functional",
|
||||
"server",
|
||||
"client",
|
||||
"browser"
|
||||
],
|
||||
"author": {
|
||||
"name": "Jeremy Ashkenas",
|
||||
"email": "jeremy@documentcloud.org"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/documentcloud/underscore.git"
|
||||
},
|
||||
"main": "underscore.js",
|
||||
"version": "1.4.4",
|
||||
"devDependencies": {
|
||||
"phantomjs": "0.2.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phantomjs test/vendor/runner.js test/index.html?noglobals=true"
|
||||
},
|
||||
"readme": " __\n /\\ \\ __\n __ __ ___ \\_\\ \\ __ _ __ ____ ___ ___ _ __ __ /\\_\\ ____\n /\\ \\/\\ \\ /' _ `\\ /'_ \\ /'__`\\/\\ __\\/ ,__\\ / ___\\ / __`\\/\\ __\\/'__`\\ \\/\\ \\ /',__\\\n \\ \\ \\_\\ \\/\\ \\/\\ \\/\\ \\ \\ \\/\\ __/\\ \\ \\//\\__, `\\/\\ \\__//\\ \\ \\ \\ \\ \\//\\ __/ __ \\ \\ \\/\\__, `\\\n \\ \\____/\\ \\_\\ \\_\\ \\___,_\\ \\____\\\\ \\_\\\\/\\____/\\ \\____\\ \\____/\\ \\_\\\\ \\____\\/\\_\\ _\\ \\ \\/\\____/\n \\/___/ \\/_/\\/_/\\/__,_ /\\/____/ \\/_/ \\/___/ \\/____/\\/___/ \\/_/ \\/____/\\/_//\\ \\_\\ \\/___/\n \\ \\____/\n \\/___/\n\nUnderscore.js is a utility-belt library for JavaScript that provides\nsupport for the usual functional suspects (each, map, reduce, filter...)\nwithout extending any core JavaScript objects.\n\nFor Docs, License, Tests, and pre-packed downloads, see:\nhttp://underscorejs.org\n\nMany thanks to our contributors:\nhttps://github.com/documentcloud/underscore/contributors\n",
|
||||
"readmeFilename": "README.md",
|
||||
"_id": "underscore@1.4.4",
|
||||
"_from": "underscore@~1.4.3"
|
||||
}
|
File diff suppressed because one or more lines are too long
1226
support/process/node_modules/yamljs/node_modules/argparse/node_modules/underscore/underscore.js
generated
vendored
1226
support/process/node_modules/yamljs/node_modules/argparse/node_modules/underscore/underscore.js
generated
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,2 +0,0 @@
|
|||
.*.swp
|
||||
test/a/
|
|
@ -1,3 +0,0 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
|
@ -1,27 +0,0 @@
|
|||
Copyright (c) Isaac Z. Schlueter ("Author")
|
||||
All rights reserved.
|
||||
|
||||
The BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,233 +0,0 @@
|
|||
# Glob
|
||||
|
||||
This is a glob implementation in JavaScript. It uses the `minimatch`
|
||||
library to do its matching.
|
||||
|
||||
## Attention: node-glob users!
|
||||
|
||||
The API has changed dramatically between 2.x and 3.x. This library is
|
||||
now 100% JavaScript, and the integer flags have been replaced with an
|
||||
options object.
|
||||
|
||||
Also, there's an event emitter class, proper tests, and all the other
|
||||
things you've come to expect from node modules.
|
||||
|
||||
And best of all, no compilation!
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
var glob = require("glob")
|
||||
|
||||
// options is optional
|
||||
glob("**/*.js", options, function (er, files) {
|
||||
// files is an array of filenames.
|
||||
// If the `nonull` option is set, and nothing
|
||||
// was found, then files is ["**/*.js"]
|
||||
// er is an error object or null.
|
||||
})
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
Please see the [minimatch
|
||||
documentation](https://github.com/isaacs/minimatch) for more details.
|
||||
|
||||
Supports these glob features:
|
||||
|
||||
* Brace Expansion
|
||||
* Extended glob matching
|
||||
* "Globstar" `**` matching
|
||||
|
||||
See:
|
||||
|
||||
* `man sh`
|
||||
* `man bash`
|
||||
* `man 3 fnmatch`
|
||||
* `man 5 gitignore`
|
||||
* [minimatch documentation](https://github.com/isaacs/minimatch)
|
||||
|
||||
## glob(pattern, [options], cb)
|
||||
|
||||
* `pattern` {String} Pattern to be matched
|
||||
* `options` {Object}
|
||||
* `cb` {Function}
|
||||
* `err` {Error | null}
|
||||
* `matches` {Array<String>} filenames found matching the pattern
|
||||
|
||||
Perform an asynchronous glob search.
|
||||
|
||||
## glob.sync(pattern, [options]
|
||||
|
||||
* `pattern` {String} Pattern to be matched
|
||||
* `options` {Object}
|
||||
* return: {Array<String>} filenames found matching the pattern
|
||||
|
||||
Perform a synchronous glob search.
|
||||
|
||||
## Class: glob.Glob
|
||||
|
||||
Create a Glob object by instanting the `glob.Glob` class.
|
||||
|
||||
```javascript
|
||||
var Glob = require("glob").Glob
|
||||
var mg = new Glob(pattern, options, cb)
|
||||
```
|
||||
|
||||
It's an EventEmitter, and starts walking the filesystem to find matches
|
||||
immediately.
|
||||
|
||||
### new glob.Glob(pattern, [options], [cb])
|
||||
|
||||
* `pattern` {String} pattern to search for
|
||||
* `options` {Object}
|
||||
* `cb` {Function} Called when an error occurs, or matches are found
|
||||
* `err` {Error | null}
|
||||
* `matches` {Array<String>} filenames found matching the pattern
|
||||
|
||||
Note that if the `sync` flag is set in the options, then matches will
|
||||
be immediately available on the `g.found` member.
|
||||
|
||||
### Properties
|
||||
|
||||
* `minimatch` The minimatch object that the glob uses.
|
||||
* `options` The options object passed in.
|
||||
* `error` The error encountered. When an error is encountered, the
|
||||
glob object is in an undefined state, and should be discarded.
|
||||
* `aborted` Boolean which is set to true when calling `abort()`. There
|
||||
is no way at this time to continue a glob search after aborting, but
|
||||
you can re-use the statCache to avoid having to duplicate syscalls.
|
||||
|
||||
### Events
|
||||
|
||||
* `end` When the matching is finished, this is emitted with all the
|
||||
matches found. If the `nonull` option is set, and no match was found,
|
||||
then the `matches` list contains the original pattern. The matches
|
||||
are sorted, unless the `nosort` flag is set.
|
||||
* `match` Every time a match is found, this is emitted with the matched.
|
||||
* `error` Emitted when an unexpected error is encountered, or whenever
|
||||
any fs error occurs if `options.strict` is set.
|
||||
* `abort` When `abort()` is called, this event is raised.
|
||||
|
||||
### Methods
|
||||
|
||||
* `abort` Stop the search.
|
||||
|
||||
### Options
|
||||
|
||||
All the options that can be passed to Minimatch can also be passed to
|
||||
Glob to change pattern matching behavior. Also, some have been added,
|
||||
or have glob-specific ramifications.
|
||||
|
||||
All options are false by default, unless otherwise noted.
|
||||
|
||||
All options are added to the glob object, as well.
|
||||
|
||||
* `cwd` The current working directory in which to search. Defaults
|
||||
to `process.cwd()`.
|
||||
* `root` The place where patterns starting with `/` will be mounted
|
||||
onto. Defaults to `path.resolve(options.cwd, "/")` (`/` on Unix
|
||||
systems, and `C:\` or some such on Windows.)
|
||||
* `nomount` By default, a pattern starting with a forward-slash will be
|
||||
"mounted" onto the root setting, so that a valid filesystem path is
|
||||
returned. Set this flag to disable that behavior.
|
||||
* `mark` Add a `/` character to directory matches. Note that this
|
||||
requires additional stat calls.
|
||||
* `nosort` Don't sort the results.
|
||||
* `stat` Set to true to stat *all* results. This reduces performance
|
||||
somewhat, and is completely unnecessary, unless `readdir` is presumed
|
||||
to be an untrustworthy indicator of file existence. It will cause
|
||||
ELOOP to be triggered one level sooner in the case of cyclical
|
||||
symbolic links.
|
||||
* `silent` When an unusual error is encountered
|
||||
when attempting to read a directory, a warning will be printed to
|
||||
stderr. Set the `silent` option to true to suppress these warnings.
|
||||
* `strict` When an unusual error is encountered
|
||||
when attempting to read a directory, the process will just continue on
|
||||
in search of other matches. Set the `strict` option to raise an error
|
||||
in these cases.
|
||||
* `statCache` A cache of results of filesystem information, to prevent
|
||||
unnecessary stat calls. While it should not normally be necessary to
|
||||
set this, you may pass the statCache from one glob() call to the
|
||||
options object of another, if you know that the filesystem will not
|
||||
change between calls. (See "Race Conditions" below.)
|
||||
* `sync` Perform a synchronous glob search.
|
||||
* `nounique` In some cases, brace-expanded patterns can result in the
|
||||
same file showing up multiple times in the result set. By default,
|
||||
this implementation prevents duplicates in the result set.
|
||||
Set this flag to disable that behavior.
|
||||
* `nonull` Set to never return an empty set, instead returning a set
|
||||
containing the pattern itself. This is the default in glob(3).
|
||||
* `nocase` Perform a case-insensitive match. Note that case-insensitive
|
||||
filesystems will sometimes result in glob returning results that are
|
||||
case-insensitively matched anyway, since readdir and stat will not
|
||||
raise an error.
|
||||
* `debug` Set to enable debug logging in minimatch and glob.
|
||||
* `globDebug` Set to enable debug logging in glob, but not minimatch.
|
||||
|
||||
## Comparisons to other fnmatch/glob implementations
|
||||
|
||||
While strict compliance with the existing standards is a worthwhile
|
||||
goal, some discrepancies exist between node-glob and other
|
||||
implementations, and are intentional.
|
||||
|
||||
If the pattern starts with a `!` character, then it is negated. Set the
|
||||
`nonegate` flag to suppress this behavior, and treat leading `!`
|
||||
characters normally. This is perhaps relevant if you wish to start the
|
||||
pattern with a negative extglob pattern like `!(a|B)`. Multiple `!`
|
||||
characters at the start of a pattern will negate the pattern multiple
|
||||
times.
|
||||
|
||||
If a pattern starts with `#`, then it is treated as a comment, and
|
||||
will not match anything. Use `\#` to match a literal `#` at the
|
||||
start of a line, or set the `nocomment` flag to suppress this behavior.
|
||||
|
||||
The double-star character `**` is supported by default, unless the
|
||||
`noglobstar` flag is set. This is supported in the manner of bsdglob
|
||||
and bash 4.1, where `**` only has special significance if it is the only
|
||||
thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but
|
||||
`a/**b` will not. **Note that this is different from the way that `**` is
|
||||
handled by ruby's `Dir` class.**
|
||||
|
||||
If an escaped pattern has no matches, and the `nonull` flag is set,
|
||||
then glob returns the pattern as-provided, rather than
|
||||
interpreting the character escapes. For example,
|
||||
`glob.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than
|
||||
`"*a?"`. This is akin to setting the `nullglob` option in bash, except
|
||||
that it does not resolve escaped pattern characters.
|
||||
|
||||
If brace expansion is not disabled, then it is performed before any
|
||||
other interpretation of the glob pattern. Thus, a pattern like
|
||||
`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded
|
||||
**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are
|
||||
checked for validity. Since those two are valid, matching proceeds.
|
||||
|
||||
## Windows
|
||||
|
||||
**Please only use forward-slashes in glob expressions.**
|
||||
|
||||
Though windows uses either `/` or `\` as its path separator, only `/`
|
||||
characters are used by this glob implementation. You must use
|
||||
forward-slashes **only** in glob expressions. Back-slashes will always
|
||||
be interpreted as escape characters, not path separators.
|
||||
|
||||
Results from absolute patterns such as `/foo/*` are mounted onto the
|
||||
root setting using `path.join`. On windows, this will by default result
|
||||
in `/foo/*` matching `C:\foo\bar.txt`.
|
||||
|
||||
## Race Conditions
|
||||
|
||||
Glob searching, by its very nature, is susceptible to race conditions,
|
||||
since it relies on directory walking and such.
|
||||
|
||||
As a result, it is possible that a file that exists when glob looks for
|
||||
it may have been deleted or modified by the time it returns the result.
|
||||
|
||||
As part of its internal implementation, this program caches all stat
|
||||
and readdir calls that it makes, in order to cut down on system
|
||||
overhead. However, this also makes it even more susceptible to races,
|
||||
especially if the statCache object is reused between glob calls.
|
||||
|
||||
Users are thus advised not to use a glob result as a
|
||||
guarantee of filesystem state in the face of rapid changes.
|
||||
For the vast majority of operations, this is never a problem.
|
|
@ -1,9 +0,0 @@
|
|||
var Glob = require("../").Glob
|
||||
|
||||
var pattern = "test/a/**/[cg]/../[cg]"
|
||||
console.log(pattern)
|
||||
|
||||
var mg = new Glob(pattern, {mark: true, sync:true}, function (er, matches) {
|
||||
console.log("matches", matches)
|
||||
})
|
||||
console.log("after")
|
|
@ -1,9 +0,0 @@
|
|||
var Glob = require("../").Glob
|
||||
|
||||
var pattern = "{./*/*,/*,/usr/local/*}"
|
||||
console.log(pattern)
|
||||
|
||||
var mg = new Glob(pattern, {mark: true}, function (er, matches) {
|
||||
console.log("matches", matches)
|
||||
})
|
||||
console.log("after")
|
|
@ -1,643 +0,0 @@
|
|||
// Approach:
|
||||
//
|
||||
// 1. Get the minimatch set
|
||||
// 2. For each pattern in the set, PROCESS(pattern)
|
||||
// 3. Store matches per-set, then uniq them
|
||||
//
|
||||
// PROCESS(pattern)
|
||||
// Get the first [n] items from pattern that are all strings
|
||||
// Join these together. This is PREFIX.
|
||||
// If there is no more remaining, then stat(PREFIX) and
|
||||
// add to matches if it succeeds. END.
|
||||
// readdir(PREFIX) as ENTRIES
|
||||
// If fails, END
|
||||
// If pattern[n] is GLOBSTAR
|
||||
// // handle the case where the globstar match is empty
|
||||
// // by pruning it out, and testing the resulting pattern
|
||||
// PROCESS(pattern[0..n] + pattern[n+1 .. $])
|
||||
// // handle other cases.
|
||||
// for ENTRY in ENTRIES (not dotfiles)
|
||||
// // attach globstar + tail onto the entry
|
||||
// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $])
|
||||
//
|
||||
// else // not globstar
|
||||
// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
|
||||
// Test ENTRY against pattern[n]
|
||||
// If fails, continue
|
||||
// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
|
||||
//
|
||||
// Caveat:
|
||||
// Cache all stats and readdirs results to minimize syscall. Since all
|
||||
// we ever care about is existence and directory-ness, we can just keep
|
||||
// `true` for files, and [children,...] for directories, or `false` for
|
||||
// things that don't exist.
|
||||
|
||||
|
||||
|
||||
module.exports = glob
|
||||
|
||||
var fs = require("graceful-fs")
|
||||
, minimatch = require("minimatch")
|
||||
, Minimatch = minimatch.Minimatch
|
||||
, inherits = require("inherits")
|
||||
, EE = require("events").EventEmitter
|
||||
, path = require("path")
|
||||
, isDir = {}
|
||||
, assert = require("assert").ok
|
||||
|
||||
function glob (pattern, options, cb) {
|
||||
if (typeof options === "function") cb = options, options = {}
|
||||
if (!options) options = {}
|
||||
|
||||
if (typeof options === "number") {
|
||||
deprecated()
|
||||
return
|
||||
}
|
||||
|
||||
var g = new Glob(pattern, options, cb)
|
||||
return g.sync ? g.found : g
|
||||
}
|
||||
|
||||
glob.fnmatch = deprecated
|
||||
|
||||
function deprecated () {
|
||||
throw new Error("glob's interface has changed. Please see the docs.")
|
||||
}
|
||||
|
||||
glob.sync = globSync
|
||||
function globSync (pattern, options) {
|
||||
if (typeof options === "number") {
|
||||
deprecated()
|
||||
return
|
||||
}
|
||||
|
||||
options = options || {}
|
||||
options.sync = true
|
||||
return glob(pattern, options)
|
||||
}
|
||||
|
||||
|
||||
glob.Glob = Glob
|
||||
inherits(Glob, EE)
|
||||
function Glob (pattern, options, cb) {
|
||||
if (!(this instanceof Glob)) {
|
||||
return new Glob(pattern, options, cb)
|
||||
}
|
||||
|
||||
if (typeof cb === "function") {
|
||||
this.on("error", cb)
|
||||
this.on("end", function (matches) {
|
||||
cb(null, matches)
|
||||
})
|
||||
}
|
||||
|
||||
options = options || {}
|
||||
|
||||
this.EOF = {}
|
||||
this._emitQueue = []
|
||||
|
||||
this.maxDepth = options.maxDepth || 1000
|
||||
this.maxLength = options.maxLength || Infinity
|
||||
this.statCache = options.statCache || {}
|
||||
|
||||
this.changedCwd = false
|
||||
var cwd = process.cwd()
|
||||
if (!options.hasOwnProperty("cwd")) this.cwd = cwd
|
||||
else {
|
||||
this.cwd = options.cwd
|
||||
this.changedCwd = path.resolve(options.cwd) !== cwd
|
||||
}
|
||||
|
||||
this.root = options.root || path.resolve(this.cwd, "/")
|
||||
this.root = path.resolve(this.root)
|
||||
if (process.platform === "win32")
|
||||
this.root = this.root.replace(/\\/g, "/")
|
||||
|
||||
this.nomount = !!options.nomount
|
||||
|
||||
if (!pattern) {
|
||||
throw new Error("must provide pattern")
|
||||
}
|
||||
|
||||
// base-matching: just use globstar for that.
|
||||
if (options.matchBase && -1 === pattern.indexOf("/")) {
|
||||
if (options.noglobstar) {
|
||||
throw new Error("base matching requires globstar")
|
||||
}
|
||||
pattern = "**/" + pattern
|
||||
}
|
||||
|
||||
this.strict = options.strict !== false
|
||||
this.dot = !!options.dot
|
||||
this.mark = !!options.mark
|
||||
this.sync = !!options.sync
|
||||
this.nounique = !!options.nounique
|
||||
this.nonull = !!options.nonull
|
||||
this.nosort = !!options.nosort
|
||||
this.nocase = !!options.nocase
|
||||
this.stat = !!options.stat
|
||||
|
||||
this.debug = !!options.debug || !!options.globDebug
|
||||
if (this.debug)
|
||||
this.log = console.error
|
||||
|
||||
this.silent = !!options.silent
|
||||
|
||||
var mm = this.minimatch = new Minimatch(pattern, options)
|
||||
this.options = mm.options
|
||||
pattern = this.pattern = mm.pattern
|
||||
|
||||
this.error = null
|
||||
this.aborted = false
|
||||
|
||||
EE.call(this)
|
||||
|
||||
// process each pattern in the minimatch set
|
||||
var n = this.minimatch.set.length
|
||||
|
||||
// The matches are stored as {<filename>: true,...} so that
|
||||
// duplicates are automagically pruned.
|
||||
// Later, we do an Object.keys() on these.
|
||||
// Keep them as a list so we can fill in when nonull is set.
|
||||
this.matches = new Array(n)
|
||||
|
||||
this.minimatch.set.forEach(iterator.bind(this))
|
||||
function iterator (pattern, i, set) {
|
||||
this._process(pattern, 0, i, function (er) {
|
||||
if (er) this.emit("error", er)
|
||||
if (-- n <= 0) this._finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Glob.prototype.log = function () {}
|
||||
|
||||
Glob.prototype._finish = function () {
|
||||
assert(this instanceof Glob)
|
||||
|
||||
var nou = this.nounique
|
||||
, all = nou ? [] : {}
|
||||
|
||||
for (var i = 0, l = this.matches.length; i < l; i ++) {
|
||||
var matches = this.matches[i]
|
||||
this.log("matches[%d] =", i, matches)
|
||||
// do like the shell, and spit out the literal glob
|
||||
if (!matches) {
|
||||
if (this.nonull) {
|
||||
var literal = this.minimatch.globSet[i]
|
||||
if (nou) all.push(literal)
|
||||
else all[literal] = true
|
||||
}
|
||||
} else {
|
||||
// had matches
|
||||
var m = Object.keys(matches)
|
||||
if (nou) all.push.apply(all, m)
|
||||
else m.forEach(function (m) {
|
||||
all[m] = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (!nou) all = Object.keys(all)
|
||||
|
||||
if (!this.nosort) {
|
||||
all = all.sort(this.nocase ? alphasorti : alphasort)
|
||||
}
|
||||
|
||||
if (this.mark) {
|
||||
// at *some* point we statted all of these
|
||||
all = all.map(function (m) {
|
||||
var sc = this.statCache[m]
|
||||
if (!sc)
|
||||
return m
|
||||
var isDir = (Array.isArray(sc) || sc === 2)
|
||||
if (isDir && m.slice(-1) !== "/") {
|
||||
return m + "/"
|
||||
}
|
||||
if (!isDir && m.slice(-1) === "/") {
|
||||
return m.replace(/\/+$/, "")
|
||||
}
|
||||
return m
|
||||
}, this)
|
||||
}
|
||||
|
||||
this.log("emitting end", all)
|
||||
|
||||
this.EOF = this.found = all
|
||||
this.emitMatch(this.EOF)
|
||||
}
|
||||
|
||||
function alphasorti (a, b) {
|
||||
a = a.toLowerCase()
|
||||
b = b.toLowerCase()
|
||||
return alphasort(a, b)
|
||||
}
|
||||
|
||||
function alphasort (a, b) {
|
||||
return a > b ? 1 : a < b ? -1 : 0
|
||||
}
|
||||
|
||||
Glob.prototype.abort = function () {
|
||||
this.aborted = true
|
||||
this.emit("abort")
|
||||
}
|
||||
|
||||
Glob.prototype.pause = function () {
|
||||
if (this.paused) return
|
||||
if (this.sync)
|
||||
this.emit("error", new Error("Can't pause/resume sync glob"))
|
||||
this.paused = true
|
||||
this.emit("pause")
|
||||
}
|
||||
|
||||
Glob.prototype.resume = function () {
|
||||
if (!this.paused) return
|
||||
if (this.sync)
|
||||
this.emit("error", new Error("Can't pause/resume sync glob"))
|
||||
this.paused = false
|
||||
this.emit("resume")
|
||||
this._processEmitQueue()
|
||||
//process.nextTick(this.emit.bind(this, "resume"))
|
||||
}
|
||||
|
||||
Glob.prototype.emitMatch = function (m) {
|
||||
this._emitQueue.push(m)
|
||||
this._processEmitQueue()
|
||||
}
|
||||
|
||||
Glob.prototype._processEmitQueue = function (m) {
|
||||
while (!this._processingEmitQueue &&
|
||||
!this.paused) {
|
||||
this._processingEmitQueue = true
|
||||
var m = this._emitQueue.shift()
|
||||
if (!m) {
|
||||
this._processingEmitQueue = false
|
||||
break
|
||||
}
|
||||
|
||||
this.log('emit!', m === this.EOF ? "end" : "match")
|
||||
|
||||
this.emit(m === this.EOF ? "end" : "match", m)
|
||||
this._processingEmitQueue = false
|
||||
}
|
||||
}
|
||||
|
||||
Glob.prototype._process = function (pattern, depth, index, cb_) {
|
||||
assert(this instanceof Glob)
|
||||
|
||||
var cb = function cb (er, res) {
|
||||
assert(this instanceof Glob)
|
||||
if (this.paused) {
|
||||
if (!this._processQueue) {
|
||||
this._processQueue = []
|
||||
this.once("resume", function () {
|
||||
var q = this._processQueue
|
||||
this._processQueue = null
|
||||
q.forEach(function (cb) { cb() })
|
||||
})
|
||||
}
|
||||
this._processQueue.push(cb_.bind(this, er, res))
|
||||
} else {
|
||||
cb_.call(this, er, res)
|
||||
}
|
||||
}.bind(this)
|
||||
|
||||
if (this.aborted) return cb()
|
||||
|
||||
if (depth > this.maxDepth) return cb()
|
||||
|
||||
// Get the first [n] parts of pattern that are all strings.
|
||||
var n = 0
|
||||
while (typeof pattern[n] === "string") {
|
||||
n ++
|
||||
}
|
||||
// now n is the index of the first one that is *not* a string.
|
||||
|
||||
// see if there's anything else
|
||||
var prefix
|
||||
switch (n) {
|
||||
// if not, then this is rather simple
|
||||
case pattern.length:
|
||||
prefix = pattern.join("/")
|
||||
this._stat(prefix, function (exists, isDir) {
|
||||
// either it's there, or it isn't.
|
||||
// nothing more to do, either way.
|
||||
if (exists) {
|
||||
if (prefix && isAbsolute(prefix) && !this.nomount) {
|
||||
if (prefix.charAt(0) === "/") {
|
||||
prefix = path.join(this.root, prefix)
|
||||
} else {
|
||||
prefix = path.resolve(this.root, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "win32")
|
||||
prefix = prefix.replace(/\\/g, "/")
|
||||
|
||||
this.matches[index] = this.matches[index] || {}
|
||||
this.matches[index][prefix] = true
|
||||
this.emitMatch(prefix)
|
||||
}
|
||||
return cb()
|
||||
})
|
||||
return
|
||||
|
||||
case 0:
|
||||
// pattern *starts* with some non-trivial item.
|
||||
// going to readdir(cwd), but not include the prefix in matches.
|
||||
prefix = null
|
||||
break
|
||||
|
||||
default:
|
||||
// pattern has some string bits in the front.
|
||||
// whatever it starts with, whether that's "absolute" like /foo/bar,
|
||||
// or "relative" like "../baz"
|
||||
prefix = pattern.slice(0, n)
|
||||
prefix = prefix.join("/")
|
||||
break
|
||||
}
|
||||
|
||||
// get the list of entries.
|
||||
var read
|
||||
if (prefix === null) read = "."
|
||||
else if (isAbsolute(prefix) || isAbsolute(pattern.join("/"))) {
|
||||
if (!prefix || !isAbsolute(prefix)) {
|
||||
prefix = path.join("/", prefix)
|
||||
}
|
||||
read = prefix = path.resolve(prefix)
|
||||
|
||||
// if (process.platform === "win32")
|
||||
// read = prefix = prefix.replace(/^[a-zA-Z]:|\\/g, "/")
|
||||
|
||||
this.log('absolute: ', prefix, this.root, pattern, read)
|
||||
} else {
|
||||
read = prefix
|
||||
}
|
||||
|
||||
this.log('readdir(%j)', read, this.cwd, this.root)
|
||||
|
||||
return this._readdir(read, function (er, entries) {
|
||||
if (er) {
|
||||
// not a directory!
|
||||
// this means that, whatever else comes after this, it can never match
|
||||
return cb()
|
||||
}
|
||||
|
||||
// globstar is special
|
||||
if (pattern[n] === minimatch.GLOBSTAR) {
|
||||
// test without the globstar, and with every child both below
|
||||
// and replacing the globstar.
|
||||
var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ]
|
||||
entries.forEach(function (e) {
|
||||
if (e.charAt(0) === "." && !this.dot) return
|
||||
// instead of the globstar
|
||||
s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)))
|
||||
// below the globstar
|
||||
s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n)))
|
||||
}, this)
|
||||
|
||||
// now asyncForEach over this
|
||||
var l = s.length
|
||||
, errState = null
|
||||
s.forEach(function (gsPattern) {
|
||||
this._process(gsPattern, depth + 1, index, function (er) {
|
||||
if (errState) return
|
||||
if (er) return cb(errState = er)
|
||||
if (--l <= 0) return cb()
|
||||
})
|
||||
}, this)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// not a globstar
|
||||
// It will only match dot entries if it starts with a dot, or if
|
||||
// dot is set. Stuff like @(.foo|.bar) isn't allowed.
|
||||
var pn = pattern[n]
|
||||
if (typeof pn === "string") {
|
||||
var found = entries.indexOf(pn) !== -1
|
||||
entries = found ? entries[pn] : []
|
||||
} else {
|
||||
var rawGlob = pattern[n]._glob
|
||||
, dotOk = this.dot || rawGlob.charAt(0) === "."
|
||||
|
||||
entries = entries.filter(function (e) {
|
||||
return (e.charAt(0) !== "." || dotOk) &&
|
||||
(typeof pattern[n] === "string" && e === pattern[n] ||
|
||||
e.match(pattern[n]))
|
||||
})
|
||||
}
|
||||
|
||||
// If n === pattern.length - 1, then there's no need for the extra stat
|
||||
// *unless* the user has specified "mark" or "stat" explicitly.
|
||||
// We know that they exist, since the readdir returned them.
|
||||
if (n === pattern.length - 1 &&
|
||||
!this.mark &&
|
||||
!this.stat) {
|
||||
entries.forEach(function (e) {
|
||||
if (prefix) {
|
||||
if (prefix !== "/") e = prefix + "/" + e
|
||||
else e = prefix + e
|
||||
}
|
||||
if (e.charAt(0) === "/" && !this.nomount) {
|
||||
e = path.join(this.root, e)
|
||||
}
|
||||
|
||||
if (process.platform === "win32")
|
||||
e = e.replace(/\\/g, "/")
|
||||
|
||||
this.matches[index] = this.matches[index] || {}
|
||||
this.matches[index][e] = true
|
||||
this.emitMatch(e)
|
||||
}, this)
|
||||
return cb.call(this)
|
||||
}
|
||||
|
||||
|
||||
// now test all the remaining entries as stand-ins for that part
|
||||
// of the pattern.
|
||||
var l = entries.length
|
||||
, errState = null
|
||||
if (l === 0) return cb() // no matches possible
|
||||
entries.forEach(function (e) {
|
||||
var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))
|
||||
this._process(p, depth + 1, index, function (er) {
|
||||
if (errState) return
|
||||
if (er) return cb(errState = er)
|
||||
if (--l === 0) return cb.call(this)
|
||||
})
|
||||
}, this)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
Glob.prototype._stat = function (f, cb) {
|
||||
assert(this instanceof Glob)
|
||||
var abs = f
|
||||
if (f.charAt(0) === "/") {
|
||||
abs = path.join(this.root, f)
|
||||
} else if (this.changedCwd) {
|
||||
abs = path.resolve(this.cwd, f)
|
||||
}
|
||||
this.log('stat', [this.cwd, f, '=', abs])
|
||||
if (f.length > this.maxLength) {
|
||||
var er = new Error("Path name too long")
|
||||
er.code = "ENAMETOOLONG"
|
||||
er.path = f
|
||||
return this._afterStat(f, abs, cb, er)
|
||||
}
|
||||
|
||||
if (this.statCache.hasOwnProperty(f)) {
|
||||
var exists = this.statCache[f]
|
||||
, isDir = exists && (Array.isArray(exists) || exists === 2)
|
||||
if (this.sync) return cb.call(this, !!exists, isDir)
|
||||
return process.nextTick(cb.bind(this, !!exists, isDir))
|
||||
}
|
||||
|
||||
if (this.sync) {
|
||||
var er, stat
|
||||
try {
|
||||
stat = fs.statSync(abs)
|
||||
} catch (e) {
|
||||
er = e
|
||||
}
|
||||
this._afterStat(f, abs, cb, er, stat)
|
||||
} else {
|
||||
fs.stat(abs, this._afterStat.bind(this, f, abs, cb))
|
||||
}
|
||||
}
|
||||
|
||||
Glob.prototype._afterStat = function (f, abs, cb, er, stat) {
|
||||
var exists
|
||||
assert(this instanceof Glob)
|
||||
|
||||
if (abs.slice(-1) === "/" && stat && !stat.isDirectory()) {
|
||||
this.log("should be ENOTDIR, fake it")
|
||||
|
||||
er = new Error("ENOTDIR, not a directory '" + abs + "'")
|
||||
er.path = abs
|
||||
er.code = "ENOTDIR"
|
||||
stat = null
|
||||
}
|
||||
|
||||
if (er || !stat) {
|
||||
exists = false
|
||||
} else {
|
||||
exists = stat.isDirectory() ? 2 : 1
|
||||
}
|
||||
this.statCache[f] = this.statCache[f] || exists
|
||||
cb.call(this, !!exists, exists === 2)
|
||||
}
|
||||
|
||||
Glob.prototype._readdir = function (f, cb) {
|
||||
assert(this instanceof Glob)
|
||||
var abs = f
|
||||
if (f.charAt(0) === "/") {
|
||||
abs = path.join(this.root, f)
|
||||
} else if (isAbsolute(f)) {
|
||||
abs = f
|
||||
} else if (this.changedCwd) {
|
||||
abs = path.resolve(this.cwd, f)
|
||||
}
|
||||
|
||||
this.log('readdir', [this.cwd, f, abs])
|
||||
if (f.length > this.maxLength) {
|
||||
var er = new Error("Path name too long")
|
||||
er.code = "ENAMETOOLONG"
|
||||
er.path = f
|
||||
return this._afterReaddir(f, abs, cb, er)
|
||||
}
|
||||
|
||||
if (this.statCache.hasOwnProperty(f)) {
|
||||
var c = this.statCache[f]
|
||||
if (Array.isArray(c)) {
|
||||
if (this.sync) return cb.call(this, null, c)
|
||||
return process.nextTick(cb.bind(this, null, c))
|
||||
}
|
||||
|
||||
if (!c || c === 1) {
|
||||
// either ENOENT or ENOTDIR
|
||||
var code = c ? "ENOTDIR" : "ENOENT"
|
||||
, er = new Error((c ? "Not a directory" : "Not found") + ": " + f)
|
||||
er.path = f
|
||||
er.code = code
|
||||
this.log(f, er)
|
||||
if (this.sync) return cb.call(this, er)
|
||||
return process.nextTick(cb.bind(this, er))
|
||||
}
|
||||
|
||||
// at this point, c === 2, meaning it's a dir, but we haven't
|
||||
// had to read it yet, or c === true, meaning it's *something*
|
||||
// but we don't have any idea what. Need to read it, either way.
|
||||
}
|
||||
|
||||
if (this.sync) {
|
||||
var er, entries
|
||||
try {
|
||||
entries = fs.readdirSync(abs)
|
||||
} catch (e) {
|
||||
er = e
|
||||
}
|
||||
return this._afterReaddir(f, abs, cb, er, entries)
|
||||
}
|
||||
|
||||
fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb))
|
||||
}
|
||||
|
||||
Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) {
|
||||
assert(this instanceof Glob)
|
||||
if (entries && !er) {
|
||||
this.statCache[f] = entries
|
||||
// if we haven't asked to stat everything for suresies, then just
|
||||
// assume that everything in there exists, so we can avoid
|
||||
// having to stat it a second time. This also gets us one step
|
||||
// further into ELOOP territory.
|
||||
if (!this.mark && !this.stat) {
|
||||
entries.forEach(function (e) {
|
||||
if (f === "/") e = f + e
|
||||
else e = f + "/" + e
|
||||
this.statCache[e] = true
|
||||
}, this)
|
||||
}
|
||||
|
||||
return cb.call(this, er, entries)
|
||||
}
|
||||
|
||||
// now handle errors, and cache the information
|
||||
if (er) switch (er.code) {
|
||||
case "ENOTDIR": // totally normal. means it *does* exist.
|
||||
this.statCache[f] = 1
|
||||
return cb.call(this, er)
|
||||
case "ENOENT": // not terribly unusual
|
||||
case "ELOOP":
|
||||
case "ENAMETOOLONG":
|
||||
case "UNKNOWN":
|
||||
this.statCache[f] = false
|
||||
return cb.call(this, er)
|
||||
default: // some unusual error. Treat as failure.
|
||||
this.statCache[f] = false
|
||||
if (this.strict) this.emit("error", er)
|
||||
if (!this.silent) console.error("glob error", er)
|
||||
return cb.call(this, er)
|
||||
}
|
||||
}
|
||||
|
||||
var isAbsolute = process.platform === "win32" ? absWin : absUnix
|
||||
|
||||
function absWin (p) {
|
||||
if (absUnix(p)) return true
|
||||
// pull off the device/UNC bit from a windows path.
|
||||
// from node's lib/path.js
|
||||
var splitDeviceRe =
|
||||
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/
|
||||
, result = splitDeviceRe.exec(p)
|
||||
, device = result[1] || ''
|
||||
, isUnc = device && device.charAt(1) !== ':'
|
||||
, isAbsolute = !!result[2] || isUnc // UNC paths are always absolute
|
||||
|
||||
return isAbsolute
|
||||
}
|
||||
|
||||
function absUnix (p) {
|
||||
return p.charAt(0) === "/" || p === ""
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
node_modules/
|
23
support/process/node_modules/yamljs/node_modules/glob/node_modules/graceful-fs/LICENSE
generated
vendored
23
support/process/node_modules/yamljs/node_modules/glob/node_modules/graceful-fs/LICENSE
generated
vendored
|
@ -1,23 +0,0 @@
|
|||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
33
support/process/node_modules/yamljs/node_modules/glob/node_modules/graceful-fs/README.md
generated
vendored
33
support/process/node_modules/yamljs/node_modules/glob/node_modules/graceful-fs/README.md
generated
vendored
|
@ -1,33 +0,0 @@
|
|||
# graceful-fs
|
||||
|
||||
graceful-fs functions as a drop-in replacement for the fs module,
|
||||
making various improvements.
|
||||
|
||||
The improvements are meant to normalize behavior across different
|
||||
platforms and environments, and to make filesystem access more
|
||||
resilient to errors.
|
||||
|
||||
## Improvements over fs module
|
||||
|
||||
graceful-fs:
|
||||
|
||||
* keeps track of how many file descriptors are open, and by default
|
||||
limits this to 1024. Any further requests to open a file are put in a
|
||||
queue until new slots become available. If 1024 turns out to be too
|
||||
much, it decreases the limit further.
|
||||
* fixes `lchmod` for Node versions prior to 0.6.2.
|
||||
* implements `fs.lutimes` if possible. Otherwise it becomes a noop.
|
||||
* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or
|
||||
`lchown` if the user isn't root.
|
||||
* makes `lchmod` and `lchown` become noops, if not available.
|
||||
* retries reading a file if `read` results in EAGAIN error.
|
||||
|
||||
On Windows, it retries renaming a file for up to one second if `EACCESS`
|
||||
or `EPERM` error occurs, likely because antivirus software has locked
|
||||
the directory.
|
||||
|
||||
## Configuration
|
||||
|
||||
The maximum number of open file descriptors that graceful-fs manages may
|
||||
be adjusted by setting `fs.MAX_OPEN` to a different number. The default
|
||||
is 1024.
|
|
@ -1,316 +0,0 @@
|
|||
// this keeps a queue of opened file descriptors, and will make
|
||||
// fs operations wait until some have closed before trying to open more.
|
||||
|
||||
var fs_ = require("fs")
|
||||
|
||||
var fs = module.exports = {}
|
||||
|
||||
Object.getOwnPropertyNames(fs_).forEach(function(prop) {
|
||||
var desc = Object.getOwnPropertyDescriptor(fs_, prop)
|
||||
Object.defineProperty(fs, prop, desc)
|
||||
})
|
||||
|
||||
var queue = []
|
||||
, constants = require("constants")
|
||||
|
||||
exports = module.exports = fs
|
||||
fs._curOpen = 0
|
||||
|
||||
fs.MIN_MAX_OPEN = 64
|
||||
fs.MAX_OPEN = 1024
|
||||
|
||||
var originalOpen = fs.open
|
||||
, originalOpenSync = fs.openSync
|
||||
, originalClose = fs.close
|
||||
, originalCloseSync = fs.closeSync
|
||||
|
||||
|
||||
// prevent EMFILE errors
|
||||
function OpenReq (path, flags, mode, cb) {
|
||||
this.path = path
|
||||
this.flags = flags
|
||||
this.mode = mode
|
||||
this.cb = cb
|
||||
}
|
||||
|
||||
function noop () {}
|
||||
|
||||
fs.open = gracefulOpen
|
||||
|
||||
function gracefulOpen (path, flags, mode, cb) {
|
||||
if (typeof mode === "function") cb = mode, mode = null
|
||||
if (typeof cb !== "function") cb = noop
|
||||
|
||||
if (fs._curOpen >= fs.MAX_OPEN) {
|
||||
queue.push(new OpenReq(path, flags, mode, cb))
|
||||
setTimeout(flush)
|
||||
return
|
||||
}
|
||||
open(path, flags, mode, function (er, fd) {
|
||||
if (er && er.code === "EMFILE" && fs._curOpen > fs.MIN_MAX_OPEN) {
|
||||
// that was too many. reduce max, get back in queue.
|
||||
// this should only happen once in a great while, and only
|
||||
// if the ulimit -n is set lower than 1024.
|
||||
fs.MAX_OPEN = fs._curOpen - 1
|
||||
return fs.open(path, flags, mode, cb)
|
||||
}
|
||||
cb(er, fd)
|
||||
})
|
||||
}
|
||||
|
||||
function open (path, flags, mode, cb) {
|
||||
cb = cb || noop
|
||||
fs._curOpen ++
|
||||
originalOpen.call(fs, path, flags, mode, function (er, fd) {
|
||||
if (er) onclose()
|
||||
cb(er, fd)
|
||||
})
|
||||
}
|
||||
|
||||
fs.openSync = function (path, flags, mode) {
|
||||
var ret
|
||||
ret = originalOpenSync.call(fs, path, flags, mode)
|
||||
fs._curOpen ++
|
||||
return ret
|
||||
}
|
||||
|
||||
function onclose () {
|
||||
fs._curOpen --
|
||||
flush()
|
||||
}
|
||||
|
||||
function flush () {
|
||||
while (fs._curOpen < fs.MAX_OPEN) {
|
||||
var req = queue.shift()
|
||||
if (!req) return
|
||||
open(req.path, req.flags || "r", req.mode || 0777, req.cb)
|
||||
}
|
||||
}
|
||||
|
||||
fs.close = function (fd, cb) {
|
||||
cb = cb || noop
|
||||
originalClose.call(fs, fd, function (er) {
|
||||
onclose()
|
||||
cb(er)
|
||||
})
|
||||
}
|
||||
|
||||
fs.closeSync = function (fd) {
|
||||
onclose()
|
||||
return originalCloseSync.call(fs, fd)
|
||||
}
|
||||
|
||||
|
||||
// (re-)implement some things that are known busted or missing.
|
||||
|
||||
var constants = require("constants")
|
||||
|
||||
// lchmod, broken prior to 0.6.2
|
||||
// back-port the fix here.
|
||||
if (constants.hasOwnProperty('O_SYMLINK') &&
|
||||
process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
||||
fs.lchmod = function (path, mode, callback) {
|
||||
callback = callback || noop
|
||||
fs.open( path
|
||||
, constants.O_WRONLY | constants.O_SYMLINK
|
||||
, mode
|
||||
, function (err, fd) {
|
||||
if (err) {
|
||||
callback(err)
|
||||
return
|
||||
}
|
||||
// prefer to return the chmod error, if one occurs,
|
||||
// but still try to close, and report closing errors if they occur.
|
||||
fs.fchmod(fd, mode, function (err) {
|
||||
fs.close(fd, function(err2) {
|
||||
callback(err || err2)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fs.lchmodSync = function (path, mode) {
|
||||
var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode)
|
||||
|
||||
// prefer to return the chmod error, if one occurs,
|
||||
// but still try to close, and report closing errors if they occur.
|
||||
var err, err2
|
||||
try {
|
||||
var ret = fs.fchmodSync(fd, mode)
|
||||
} catch (er) {
|
||||
err = er
|
||||
}
|
||||
try {
|
||||
fs.closeSync(fd)
|
||||
} catch (er) {
|
||||
err2 = er
|
||||
}
|
||||
if (err || err2) throw (err || err2)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// lutimes implementation, or no-op
|
||||
if (!fs.lutimes) {
|
||||
if (constants.hasOwnProperty("O_SYMLINK")) {
|
||||
fs.lutimes = function (path, at, mt, cb) {
|
||||
fs.open(path, constants.O_SYMLINK, function (er, fd) {
|
||||
cb = cb || noop
|
||||
if (er) return cb(er)
|
||||
fs.futimes(fd, at, mt, function (er) {
|
||||
fs.close(fd, function (er2) {
|
||||
return cb(er || er2)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fs.lutimesSync = function (path, at, mt) {
|
||||
var fd = fs.openSync(path, constants.O_SYMLINK)
|
||||
, err
|
||||
, err2
|
||||
, ret
|
||||
|
||||
try {
|
||||
var ret = fs.futimesSync(fd, at, mt)
|
||||
} catch (er) {
|
||||
err = er
|
||||
}
|
||||
try {
|
||||
fs.closeSync(fd)
|
||||
} catch (er) {
|
||||
err2 = er
|
||||
}
|
||||
if (err || err2) throw (err || err2)
|
||||
return ret
|
||||
}
|
||||
|
||||
} else if (fs.utimensat && constants.hasOwnProperty("AT_SYMLINK_NOFOLLOW")) {
|
||||
// maybe utimensat will be bound soonish?
|
||||
fs.lutimes = function (path, at, mt, cb) {
|
||||
fs.utimensat(path, at, mt, constants.AT_SYMLINK_NOFOLLOW, cb)
|
||||
}
|
||||
|
||||
fs.lutimesSync = function (path, at, mt) {
|
||||
return fs.utimensatSync(path, at, mt, constants.AT_SYMLINK_NOFOLLOW)
|
||||
}
|
||||
|
||||
} else {
|
||||
fs.lutimes = function (_a, _b, _c, cb) { process.nextTick(cb) }
|
||||
fs.lutimesSync = function () {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// https://github.com/isaacs/node-graceful-fs/issues/4
|
||||
// Chown should not fail on einval or eperm if non-root.
|
||||
|
||||
fs.chown = chownFix(fs.chown)
|
||||
fs.fchown = chownFix(fs.fchown)
|
||||
fs.lchown = chownFix(fs.lchown)
|
||||
|
||||
fs.chownSync = chownFixSync(fs.chownSync)
|
||||
fs.fchownSync = chownFixSync(fs.fchownSync)
|
||||
fs.lchownSync = chownFixSync(fs.lchownSync)
|
||||
|
||||
function chownFix (orig) {
|
||||
if (!orig) return orig
|
||||
return function (target, uid, gid, cb) {
|
||||
return orig.call(fs, target, uid, gid, function (er, res) {
|
||||
if (chownErOk(er)) er = null
|
||||
cb(er, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function chownFixSync (orig) {
|
||||
if (!orig) return orig
|
||||
return function (target, uid, gid) {
|
||||
try {
|
||||
return orig.call(fs, target, uid, gid)
|
||||
} catch (er) {
|
||||
if (!chownErOk(er)) throw er
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function chownErOk (er) {
|
||||
// if there's no getuid, or if getuid() is something other than 0,
|
||||
// and the error is EINVAL or EPERM, then just ignore it.
|
||||
// This specific case is a silent failure in cp, install, tar,
|
||||
// and most other unix tools that manage permissions.
|
||||
// When running as root, or if other types of errors are encountered,
|
||||
// then it's strict.
|
||||
if (!er || (!process.getuid || process.getuid() !== 0)
|
||||
&& (er.code === "EINVAL" || er.code === "EPERM")) return true
|
||||
}
|
||||
|
||||
|
||||
// if lchmod/lchown do not exist, then make them no-ops
|
||||
if (!fs.lchmod) {
|
||||
fs.lchmod = function (path, mode, cb) {
|
||||
process.nextTick(cb)
|
||||
}
|
||||
fs.lchmodSync = function () {}
|
||||
}
|
||||
if (!fs.lchown) {
|
||||
fs.lchown = function (path, uid, gid, cb) {
|
||||
process.nextTick(cb)
|
||||
}
|
||||
fs.lchownSync = function () {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// on Windows, A/V software can lock the directory, causing this
|
||||
// to fail with an EACCES or EPERM if the directory contains newly
|
||||
// created files. Try again on failure, for up to 1 second.
|
||||
if (process.platform === "win32") {
|
||||
var rename_ = fs.rename
|
||||
fs.rename = function rename (from, to, cb) {
|
||||
var start = Date.now()
|
||||
rename_(from, to, function CB (er) {
|
||||
if (er
|
||||
&& (er.code === "EACCES" || er.code === "EPERM")
|
||||
&& Date.now() - start < 1000) {
|
||||
return rename_(from, to, CB)
|
||||
}
|
||||
cb(er)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// if read() returns EAGAIN, then just try it again.
|
||||
var read = fs.read
|
||||
fs.read = function (fd, buffer, offset, length, position, callback_) {
|
||||
var callback
|
||||
if (callback_ && typeof callback_ === 'function') {
|
||||
var eagCounter = 0
|
||||
callback = function (er, _, __) {
|
||||
if (er && er.code === 'EAGAIN' && eagCounter < 10) {
|
||||
eagCounter ++
|
||||
return read.call(fs, fd, buffer, offset, length, position, callback)
|
||||
}
|
||||
callback_.apply(this, arguments)
|
||||
}
|
||||
}
|
||||
return read.call(fs, fd, buffer, offset, length, position, callback)
|
||||
}
|
||||
|
||||
var readSync = fs.readSync
|
||||
fs.readSync = function (fd, buffer, offset, length, position) {
|
||||
var eagCounter = 0
|
||||
while (true) {
|
||||
try {
|
||||
return readSync.call(fs, fd, buffer, offset, length, position)
|
||||
} catch (er) {
|
||||
if (er.code === 'EAGAIN' && eagCounter < 10) {
|
||||
eagCounter ++
|
||||
continue
|
||||
}
|
||||
throw er
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me",
|
||||
"url": "http://blog.izs.me"
|
||||
},
|
||||
"name": "graceful-fs",
|
||||
"description": "A drop-in replacement for fs, making various improvements.",
|
||||
"version": "1.2.1",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/node-graceful-fs.git"
|
||||
},
|
||||
"main": "graceful-fs.js",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
},
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tap test/*.js"
|
||||
},
|
||||
"keywords": [
|
||||
"fs",
|
||||
"module",
|
||||
"reading",
|
||||
"retry",
|
||||
"retries",
|
||||
"queue",
|
||||
"error",
|
||||
"errors",
|
||||
"handling",
|
||||
"EMFILE",
|
||||
"EAGAIN",
|
||||
"EINVAL",
|
||||
"EPERM",
|
||||
"EACCESS"
|
||||
],
|
||||
"license": "BSD",
|
||||
"readme": "# graceful-fs\n\ngraceful-fs functions as a drop-in replacement for the fs module,\nmaking various improvements.\n\nThe improvements are meant to normalize behavior across different\nplatforms and environments, and to make filesystem access more\nresilient to errors.\n\n## Improvements over fs module\n\ngraceful-fs:\n\n* keeps track of how many file descriptors are open, and by default\n limits this to 1024. Any further requests to open a file are put in a\n queue until new slots become available. If 1024 turns out to be too\n much, it decreases the limit further.\n* fixes `lchmod` for Node versions prior to 0.6.2.\n* implements `fs.lutimes` if possible. Otherwise it becomes a noop.\n* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or\n `lchown` if the user isn't root.\n* makes `lchmod` and `lchown` become noops, if not available.\n* retries reading a file if `read` results in EAGAIN error.\n\nOn Windows, it retries renaming a file for up to one second if `EACCESS`\nor `EPERM` error occurs, likely because antivirus software has locked\nthe directory.\n\n## Configuration\n\nThe maximum number of open file descriptors that graceful-fs manages may\nbe adjusted by setting `fs.MAX_OPEN` to a different number. The default\nis 1024.\n",
|
||||
"readmeFilename": "README.md",
|
||||
"_id": "graceful-fs@1.2.1",
|
||||
"_from": "graceful-fs@~1.2.0"
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue